Fix removal of sockets on shutdown

Fix removal of sockets on shutdown

nodePush Pushserver for Tims Chat
=================================

Copyright Information
---------------------

	"@author	Tim Düsterhus"
	"@copyright	2012-2013 Tim Düsterhus"
	"@license	BSD 3-Clause License <http://opensource.org/licenses/BSD-3-Clause>"
	"@package	be.bastelstu.wcf.nodePush"

Setup
-----

Load required namespaces.

	express = require 'express'
	http = require 'http'
	io = require 'socket.io'
	net = require 'net'
	fs = require 'fs'

Load config

	try
		config = require '../config.js'
	catch e
		config = { }

Initialize sane values.

	config.outbound ?= { }
	config.outbound.useTCP ?= true
	config.outbound.port ?= 9001
	config.outbound.host ?= '0.0.0.0'
	config.outbound.socket ?= __dirname + "/../outbound.sock"
	config.inbound ?= { }
	config.inbound.useTCP ?= false
	config.inbound.port ?= 9002
	config.inbound.host ?= '127.0.0.1'
	config.inbound.socket ?= __dirname + "/../inbound.sock"
	config.user ?= 'nobody'
	config.group ?= 'nogroup'

Prepare environment

	log = (message) ->
		console.log "[be.bastelstu.chat.nodePush] #{message}"

	thousandsSeparator = (number) ->
		String(number).replace /(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1,'

	# Ensure our namespace is present
	be = be ? {}
	be.bastelstu ?= {}
	be.bastelstu.chat ?= {}

be.bastelstu.chat.nodePush
==========================

	class be.bastelstu.chat.nodePush

Attributes
----------

Instance of express.

		app: null

Instance of http

		server: null

Instance of socket.io

		io: null

Statistics for the status page.

		stats:
			status: 0
			outbound:
				total: 0
				current: 0
			inbound: 0
			messages: { }
			bootTime: new Date()

Methods
-------
**constructor()**

		constructor: ->
			log 'Starting nodePush'
			log "PID is #{process.pid}"
			if config.inbound.useTCP
				log "Inbound: #{config.inbound.host}:#{config.inbound.port}"
			else
				log "Inbound: #{config.inbound.socket}"
			if config.outbound.useTCP
				log "Outbound: #{config.outbound.host}:#{config.outbound.port}"
			else
				log "Outbound: #{config.outbound.socket}"

			@stats.bootTime = new Date()

			@initUnixSocket()
			@initServer()

Bind shutdown function to needed events.

			process.on 'exit', @shutdown.bind @
			process.on 'uncaughtException', @shutdown.bind @
			process.on 'SIGINT', @shutdown.bind @
			process.on 'SIGTERM', @shutdown.bind @

Set nice title for PS.

			process.title = 'nodePush - Tims Chat'

**initServer()**
Initialize socket server.

		initServer: ->
			log 'Initializing outbound socket'

Start HTTP service.

			@app = express()
			@server = http.createServer @app
			@io = io.listen @server

			listenCallback = =>

Shed root privilegies.

				if process.getuid() is 0 or process.getgid() is 0
					try
						log 'Trying to shed root privilegies'
						process.setgid config.group
						process.setuid config.user
						log "New User ID: #{process.getuid()}, New Group ID: #{process.getgid()}"
					catch e
						log 'Cowardly refusing to keep the process alive as root.'
						process.exit 1

Initialize intervals for tick events. The ticks are sent every 15 / 30 / 60 / 90 / 120 seconds.

				setInterval =>
					@sendMessage 'tick15'
				, 15e3
				setInterval =>
					@sendMessage 'tick30'
				, 30e3
				setInterval =>
					@sendMessage 'tick60'
				, 60e3
				setInterval =>
					@sendMessage 'tick90'
				, 90e3
				setInterval =>
					@sendMessage 'tick120'
				, 120e3

				log "Done"

			if config.outbound.useTCP
				@server.listen config.outbound.port, config.outbound.host, null, listenCallback
			else
				@server.listen config.outbound.socket, listenCallback
				fs.chmod config.outbound.socket, '777'

Initialize production environment.

			@io.set 'log level', 1
			@io.set 'browser client etag', true
			@io.set 'browser client minification', true
			@io.set 'browser client gzip', true

Development configuration.

			@io.configure 'development', =>
				@io.set 'log level', 3
				@io.set 'browser client etag', false
				@io.set 'browser client minification', false

Record statistics for Websocket connections.

			@io.sockets.on 'connection', (socket) =>
				@stats.outbound.total++
				@stats.outbound.current++

				socket.on 'disconnect', =>
					@stats.outbound.current--

Show the status page when '/' is requested.

			@app.get '/', (req, res) =>
				res.charset = 'utf-8';
				res.type 'txt'

				@stats.status++
				reply = """
				Up since: #{@stats.bootTime}
				Status page: #{thousandsSeparator @stats.status} Requests
				Outbound: #{thousandsSeparator @stats.outbound.current} now - #{thousandsSeparator @stats.outbound.total} Total
				Inbound: #{thousandsSeparator @stats.inbound}
				Messages:
				"""
				for message, amount of @stats.messages
					reply += "\n	#{message}: #{thousandsSeparator amount}"

				res.send reply

**sendMessage(name)**
Sends a message with the given name.

		sendMessage: (name) ->
			return unless /[a-zA-Z0-9-_.]+$/.test name

			@stats.messages[name] ?= 0
			@stats.messages[name]++
			@io.sockets.send name

**initUnixSocket()**
Initialize PHP side unix socket.

		initUnixSocket: ->
			log 'Initializing inbound socket'
			socket = net.createServer (c) =>
				@stats.inbound++

Pass data to the browsers and close connection.

				c.on 'data', (data) =>
					setTimeout =>
						@sendMessage data.toString().trim()
					, 20
					c.end()

				c.on 'end', ->
					c.end()

Kill connection after 5 seconds.

				c.setTimeout 5e3, ->
					c.end()

			if config.inbound.useTCP
				socket.listen config.inbound.port, config.inbound.host
			else
				socket.listen config.inbound.socket
				fs.chmod config.inbound.socket, '777'

**shutdown()**
Performs a clean shutdown of nodePush.

		shutdown: (message) ->
			if not message
				log 'Shutting down'
			else
				log "Shutting down: #{message}"

			fs.unlinkSync config.inbound.socket if not config.inbound.useTCP and fs.existsSync config.inbound.socket
			fs.unlinkSync config.outbound.socket if not config.outbound.useTCP and fs.existsSync config.outbound.socket

			process.removeAllListeners()
			process.exit()

And finally start the service.

	new be.bastelstu.chat.nodePush()

nodePush Pushserver for Tims Chat
=================================

Copyright Information
---------------------

	"@author	Tim Düsterhus"
	"@copyright	2012-2013 Tim Düsterhus"
	"@license	BSD 3-Clause License <http://opensource.org/licenses/BSD-3-Clause>"
	"@package	be.bastelstu.wcf.nodePush"

Setup
-----

Load required namespaces.

	express = require 'express'
	http = require 'http'
	io = require 'socket.io'
	net = require 'net'
	fs = require 'fs'

Load config

	try
		config = require '../config.js'
	catch e
		config = { }

Initialize sane values.

	config.outbound ?= { }
	config.outbound.useTCP ?= true
	config.outbound.port ?= 9001
	config.outbound.host ?= '0.0.0.0'
	config.outbound.socket ?= __dirname + "/../outbound.sock"
	config.inbound ?= { }
	config.inbound.useTCP ?= false
	config.inbound.port ?= 9002
	config.inbound.host ?= '127.0.0.1'
	config.inbound.socket ?= __dirname + "/../inbound.sock"
	config.user ?= 'nobody'
	config.group ?= 'nogroup'

Prepare environment

	log = (message) ->
		console.log "[be.bastelstu.chat.nodePush] #{message}"

	thousandsSeparator = (number) ->
		String(number).replace /(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1,'

	# Ensure our namespace is present
	be = be ? {}
	be.bastelstu ?= {}
	be.bastelstu.chat ?= {}

be.bastelstu.chat.nodePush
==========================

	class be.bastelstu.chat.nodePush

Attributes
----------

Instance of express.

		app: null

Instance of http

		server: null

Instance of socket.io

		io: null

Statistics for the status page.

		stats:
			status: 0
			outbound:
				total: 0
				current: 0
			inbound: 0
			messages: { }
			bootTime: new Date()

Methods
-------
**constructor()**

		constructor: ->
			log 'Starting nodePush'
			log "PID is #{process.pid}"
			if config.inbound.useTCP
				log "Inbound: #{config.inbound.host}:#{config.inbound.port}"
			else
				log "Inbound: #{config.inbound.socket}"
			if config.outbound.useTCP
				log "Outbound: #{config.outbound.host}:#{config.outbound.port}"
			else
				log "Outbound: #{config.outbound.socket}"

			@stats.bootTime = new Date()

			@initUnixSocket()
			@initServer()

Bind shutdown function to needed events.

			process.on 'exit', @shutdown.bind @
			process.on 'uncaughtException', @shutdown.bind @
			process.on 'SIGINT', @shutdown.bind @
			process.on 'SIGTERM', @shutdown.bind @

Set nice title for PS.

			process.title = 'nodePush - Tims Chat'

**initServer()**
Initialize socket server.

		initServer: ->
			log 'Initializing outbound socket'

Start HTTP service.

			@app = express()
			@server = http.createServer @app
			@io = io.listen @server

			listenCallback = =>

Shed root privilegies.

				if process.getuid() is 0 or process.getgid() is 0
					try
						log 'Trying to shed root privilegies'
						process.setgid config.group
						process.setuid config.user
						log "New User ID: #{process.getuid()}, New Group ID: #{process.getgid()}"
					catch e
						log 'Cowardly refusing to keep the process alive as root.'
						process.exit 1

Initialize intervals for tick events. The ticks are sent every 15 / 30 / 60 / 90 / 120 seconds.

				setInterval =>
					@sendMessage 'tick15'
				, 15e3
				setInterval =>
					@sendMessage 'tick30'
				, 30e3
				setInterval =>
					@sendMessage 'tick60'
				, 60e3
				setInterval =>
					@sendMessage 'tick90'
				, 90e3
				setInterval =>
					@sendMessage 'tick120'
				, 120e3

				log "Done"

			if config.outbound.useTCP
				@server.listen config.outbound.port, config.outbound.host, null, listenCallback
			else
				@server.listen config.outbound.socket, listenCallback
				fs.chmod config.outbound.socket, '777'

Initialize production environment.

			@io.set 'log level', 1
			@io.set 'browser client etag', true
			@io.set 'browser client minification', true
			@io.set 'browser client gzip', true

Development configuration.

			@io.configure 'development', =>
				@io.set 'log level', 3
				@io.set 'browser client etag', false
				@io.set 'browser client minification', false

Record statistics for Websocket connections.

			@io.sockets.on 'connection', (socket) =>
				@stats.outbound.total++
				@stats.outbound.current++

				socket.on 'disconnect', =>
					@stats.outbound.current--

Show the status page when '/' is requested.

			@app.get '/', (req, res) =>
				res.charset = 'utf-8';
				res.type 'txt'

				@stats.status++
				reply = """
				Up since: #{@stats.bootTime}
				Status page: #{thousandsSeparator @stats.status} Requests
				Outbound: #{thousandsSeparator @stats.outbound.current} now - #{thousandsSeparator @stats.outbound.total} Total
				Inbound: #{thousandsSeparator @stats.inbound}
				Messages:
				"""
				for message, amount of @stats.messages
					reply += "\n	#{message}: #{thousandsSeparator amount}"

				res.send reply

**sendMessage(name)**
Sends a message with the given name.

		sendMessage: (name) ->
			return unless /[a-zA-Z0-9-_.]+$/.test name

			@stats.messages[name] ?= 0
			@stats.messages[name]++
			@io.sockets.send name

**initUnixSocket()**
Initialize PHP side unix socket.

		initUnixSocket: ->
			log 'Initializing inbound socket'
			socket = net.createServer (c) =>
				@stats.inbound++

Pass data to the browsers and close connection.

				c.on 'data', (data) =>
					setTimeout =>
						@sendMessage data.toString().trim()
					, 20
					c.end()

				c.on 'end', ->
					c.end()

Kill connection after 5 seconds.

				c.setTimeout 5e3, ->
					c.end()

			if config.inbound.useTCP
				socket.listen config.inbound.port, config.inbound.host
			else
				socket.listen config.inbound.socket
				fs.chmod config.inbound.socket, '777'

**shutdown()**
Performs a clean shutdown of nodePush.

		shutdown: (message) ->
			if not message
				log 'Shutting down'
			else
				log "Shutting down: #{message}"

			fs.unlinkSync config.inbound.socket unless config.inbound.useTCP
			fs.unlinkSync config.outbound.socket unless config.outbound.useTCP

			process.removeAllListeners()
			process.exit()

And finally start the service.

	new be.bastelstu.chat.nodePush()


missed the dog

missed the dog

# CLASS: Element
* Extends: [Evented][Evented]
* Parent: [Index][Parent]

A visual element.

---

    module.exports = class Element extends require 'ecl/dist/evented'

## CONSTRUCTOR

### new Element(args)

Creates an Element instance.

      constructor: ->
        super

Copy the element origin if it was set from named arguments

        if @origin then @origin = x:(@origin.x or 0), y:(@origin.y or 0)

Copy the element regions if they were set from named arguments

        if regions = @regions
          @regions = {}
          @regions[name] = region for name, region of regions

Register validating listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Localize the **type** variable.

          do (type) =>

Add capturing listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:yes, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Add normal listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:no, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Register extendable listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Add capturing extendable listener

          @addListener type, this["#{type}CaptureListener"], yes

Add normal extendable listener

          @addListener type, this["#{type}Listener"], no

#### PARAMETERS
* **args**
* Type: [Object][Object] - named arguments

* **args.origin**
* Type: [Object][Object] - origin coordinates

* **args.origin.x**
* Type: [Number][Number] - x coordinate

* **args.origin.y**
* Type: [Number][Number] - y coordinate

* **args.regions** - named regions
* Type: [Object][Object]

* **args.regions.{NAME}**
* Type: [Array][Array] - [x, y, width, height]

---

## PROPERTIES

### #origin
* Type: [Object][Object] - origin coordinates
    * **x**
      * Type: [Number][Number] - x coordinate
    * **y**
      * Type: [Number][Number] - y coordinate

### #regions
* Type: [Object][Object]
    * **{NAME}**
    * Type: [Array][Array] - [x, y, width, height]

---

## METHODS
### #localizeEventCoordinates(event) ->
* Returns: [Element][Element]

Helper method, to localize event coordinates.

      localizeEventCoordinates: (event) ->
        if event

If event already has localized **x**, use it instead of absolute **x**

          x = (if event.localX? then event.localX else event.x)
          event.localX = x - (@origin?.x or 0)

If event already has localized **y**, use it instead of absolute **y**

          y = (if event.localY? then event.localY else event.y)
          event.localY = y - (@origin?.y or 0)

        return this
---

### #getEventRegions(event)
* Returns: [Object][Object] - named set of matching regions

Helper method, to get element regions that match the event.

      getEventRegions: (event) ->

Proceed only if event coordinates are localized

        if event and (x = event.localX)? and (y = event.localY)?
          result = {}

Walk through the element regions

          for name, $ of @regions

and add the region to the result if event localized coordinates are within
the region rectangle.

            if $[0] <= x <= ($[0] + $[2]) and $[1] <= y <= ($[1] + $[3])
              result[name] = $

        return result

---

## LISTENERS
### #mousemoveCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousemove** listener

      mousemoveCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousemoveEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousedownCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousedown** listener

      mousedownCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousedownEvent = event
        @localizeEventCoordinates event

        return this

---

### #mouseupCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mouseup** listener

      mouseupCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mouseupEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousemoveListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousemoveListener: -> this

---

### #mousedownListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousedownListener: -> this

---

### #mouseupListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mouseupListener: -> this

[Element]: ./element

[Parent]: ./index.litcoffee
[Evented]: https://nhzio.github.com/ecl/evented.html
[Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
[Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

# CLASS: Element
* Extends: [Evented][Evented]
* Parent: [Index][Parent]

A visual element.

---

    module.exports = class Element extends require 'ecl/dist/evented'

## CONSTRUCTOR

### new Element(args)

Creates an Element instance.

      constructor: ->
        super

Copy the element origin if it was set from named arguments

        if @origin then @origin = x:(@origin.x or 0), y:(@origin.y or 0)

Copy the element regions if they were set from named arguments

        if regions = @regions
          @regions = {}
          @regions[name] = region for name, region of regions

Register validating listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Localize the **type** variable.

          do (type) =>

Add capturing listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:yes, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Add normal listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:no, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Register extendable listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Add capturing extendable listener

          @addListener type, this["#{type}CaptureListener"], yes

Add normal extendable listener

          @addListener type, this["#{type}Listener"], no

#### PARAMETERS
* **args**
* Type: [Object][Object] - named arguments

* **args.origin**
* Type: [Object][Object] - origin coordinates

* **args.origin.x**
* Type: [Number][Number] - x coordinate

* **args.origin.y**
* Type: [Number][Number] - y coordinate

* **args.regions** - named regions
* Type: [Object][Object]

* **args.regions.{NAME}**
* Type: [Array][Array] - [x, y, width, height]

---

## PROPERTIES

### #origin
* Type: [Object][Object] - origin coordinates
    * **x**
      * Type: [Number][Number] - x coordinate
    * **y**
      * Type: [Number][Number] - y coordinate

### #regions
* Type: [Object][Object]
    * **{NAME}**
    * Type: [Array][Array] - [x, y, width, height]

---

## METHODS
### #localizeEventCoordinates(event) ->
* Returns: [Element][Element]

Helper method, to localize event coordinates.

      localizeEventCoordinates: (event) ->
        if event

If event already has localized **x**, use it instead of absolute **x**

          x = (if event.localX? then event.localX else event.x)
          event.localX = x - (@origin?.x or 0)

If event already has localized **y**, use it instead of absolute **y**

          y = (if event.localY? then event.localY else event.y)
          event.localY = y - (origin?.y or 0)

        return this
---

### #getEventRegions(event)
* Returns: [Object][Object] - named set of matching regions

Helper method, to get element regions that match the event.

      getEventRegions: (event) ->

Proceed only if event coordinates are localized

        if event and (x = event.localX)? and (y = event.localY)?
          result = {}

Walk through the element regions

          for name, $ of @regions

and add the region to the result if event localized coordinates are within
the region rectangle.

            if $[0] <= x <= ($[0] + $[2]) and $[1] <= y <= ($[1] + $[3])
              result[name] = $

        return result

---

## LISTENERS
### #mousemoveCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousemove** listener

      mousemoveCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousemoveEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousedownCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousedown** listener

      mousedownCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousedownEvent = event
        @localizeEventCoordinates event

        return this

---

### #mouseupCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mouseup** listener

      mouseupCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mouseupEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousemoveListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousemoveListener: -> this

---

### #mousedownListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousedownListener: -> this

---

### #mouseupListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mouseupListener: -> this

[Element]: ./element

[Parent]: ./index.litcoffee
[Evented]: https://nhzio.github.com/ecl/evented.html
[Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
[Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array


Document stencil factory.

Document stencil factory.

## StencilFactory
The following class is responsible for instantiating Stencils from Shapes.
Stencils are used to render the elements of a drawing. Stencils are
constructed from Shapes, which are defined by users. Shapes specify both
the abstract and concrete syntax of drawing elements.

    define [
      'viewmodels/drawings/stencils/composite_stencil'
      'viewmodels/drawings/stencils/rectangle_stencil'
      'viewmodels/drawings/stencils/rounded_rectangle_stencil'
      'viewmodels/drawings/stencils/ellipse_stencil'
      'viewmodels/drawings/stencils/regular_polygon_stencil'
      'viewmodels/drawings/stencils/label_stencil'
    ], (CompositeStencil, RectangleStencil, RoundedRectangleStencil, EllipseStencil, RegularPolygonStencil, LabelStencil) ->

A shape will contain an array of elements and possibly a label. We add the
label stencil last, as it acts as a sort of "overlay" for the other stencil(s).

      class StencilFactory
        convert: (shape) =>
          @_addLabel(shape, @_convertElements(shape))

When a shape contains a label, we pass along the label's parameters and the stencil
to be wrapped by the label stencil. Otherwise, we simply return the original,
unlabelled stencil.

        _addLabel: (shape, stencil) =>
          if shape.label
            new LabelStencil(shape.label, stencil)
          else
            stencil

The shape will comprise one or more elements, and we convert each element into a
stencil in turn. We keep track of the number of stencils that were created, returning
a composite stencil only when necessary.

        _convertElements: (shape) =>
          stencils = (@_elementToStencil(element) for element in shape.elements)

          if stencils.length == 1
            stencils[0]
          else
            new CompositeStencil(stencils)

The figure property of an element object indicates which type of stencil must be
instantiated (e.g., `rectangle` or `ellipse`). We first convert the figure.name
property to the name of a Coffeescript class, and then instantiate it.

        _elementToStencil: (element) =>
          type = @_figureToStencilType(element.figure)
          new type(element)

We store a map (object) that allows us to lookup the Coffeescript class to be
instantiated for each type of figure. This could have been implemented using a
switch statement.

        _figureToStencilType: (figure) =>
          type = @_figures[figure]
          throw new Error("#{stencilSpecification.figure} is not a valid type of stencil") unless type
          type

        _figures:
          rectangle: RectangleStencil
          rounded: RoundedRectangleStencil
          ellipse: EllipseStencil
          polygon: RegularPolygonStencil

# Rendering
The following class is responsible for instantiating Stencils from Shapes.
Stencils are used to render the elements of a drawing. Stencils are
constructed from Shapes, which are defined by users. Shapes specify both
the abstract and concrete syntax of drawing elements.

    define [
      'viewmodels/drawings/stencils/composite_stencil'
      'viewmodels/drawings/stencils/rectangle_stencil'
      'viewmodels/drawings/stencils/rounded_rectangle_stencil'
      'viewmodels/drawings/stencils/ellipse_stencil'
      'viewmodels/drawings/stencils/regular_polygon_stencil'
      'viewmodels/drawings/stencils/label_stencil'
    ], (CompositeStencil, RectangleStencil, RoundedRectangleStencil, EllipseStencil, RegularPolygonStencil, LabelStencil) ->

      class StencilFactory
        convert: (shape) =>
          @_addLabel(shape, @_convertElements(shape))

        _addLabel: (shape, stencil) =>
          if shape.label
            new LabelStencil(shape.label, stencil)
          else
            stencil

        _convertElements: (shape) =>
          stencils = (@_elementToStencil(element) for element in shape.elements)

          if stencils.length == 1
            stencils[0]
          else
            new CompositeStencil(stencils)

        _elementToStencil: (element) =>
          type = @_figureToStencilType(element.figure)
          new type(element)

        _figureToStencilType: (figure) =>
          type = @_figures[figure]
          throw new Error("#{stencilSpecification.figure} is not a valid type of stencil") unless type
          type

        _figures:
          rectangle: RectangleStencil
          rounded: RoundedRectangleStencil
          ellipse: EllipseStencil
          polygon: RegularPolygonStencil


Changed validator docstring

Changed validator docstring

#Validator

	module.exports =
		scope:
			_validate: (inputString, data, done) ->
				if @$call(@validate, inputString)
					data
						display: inputString
						value: inputString
				done()

		schema:
			name: 'validator'
			root:
				type: 'value'
				compute: '_validate'
				id: '@value'

#Literal

	module.exports =
		scope:
			_validate: (inputString, data, done) ->
				if @$call(@validate, inputString)
					data
						display: inputString
						value: inputString
				done()

		schema:
			name: 'validator'
			root:
				type: 'value'
				compute: '_validate'
				id: '@value'


added regions, origin, parameters and properties

# CLASS: Element
* Extends: [Evented][Evented]
* Parent: [Index][Parent]

A visual element.

---

    module.exports = class Element extends require 'ecl/dist/evented'

## CONSTRUCTOR

### new Element(args)

Creates an Element instance.

      constructor: ->
        super

Copy the element origin if it was set from named arguments

        if @origin then @origin = x:(@origin.x or 0), y:(@origin.y or 0)

Copy the element regions if they were set from named arguments

        if regions = @regions
          @regions = {}
          @regions[name] = region for name, region of regions

Register validating listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Localize the **type** variable.

          do (type) =>

Add capturing listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:yes, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Add normal listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:no, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Register extendable listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Add capturing extendable listener

          @addListener type, this["#{type}CaptureListener"], yes

Add normal extendable listener

          @addListener type, this["#{type}Listener"], no

#### PARAMETERS
* **args**
* Type: [Object][Object] - named arguments

* **args.origin**
* Type: [Object][Object] - origin coordinates

* **args.origin.x**
* Type: [Number][Number] - x coordinate

* **args.origin.y**
* Type: [Number][Number] - y coordinate

* **args.regions** - named regions
* Type: [Object][Object]

* **args.regions.{NAME}**
* Type: [Array][Array] - [x, y, width, height]

---

## PROPERTIES

### #origin
* Type: [Object][Object] - origin coordinates
    * **x**
      * Type: [Number][Number] - x coordinate
    * **y**
      * Type: [Number][Number] - y coordinate

### #regions
* Type: [Object][Object]
    * **{NAME}**
    * Type: [Array][Array] - [x, y, width, height]

---

## METHODS
### #localizeEventCoordinates(event) ->
* Returns: [Element][Element]

Helper method, to localize event coordinates.

      localizeEventCoordinates: (event) ->
        if event

If event already has localized **x**, use it instead of absolute **x**

          x = (if event.localX? then event.localX else event.x)
          event.localX = x - (@origin?.x or 0)

If event already has localized **y**, use it instead of absolute **y**

          y = (if event.localY? then event.localY else event.y)
          event.localY = y - (origin?.y or 0)

        return this
---

### #getEventRegions(event)
* Returns: [Object][Object] - named set of matching regions

Helper method, to get element regions that match the event.

      getEventRegions: (event) ->

Proceed only if event coordinates are localized

        if event and (x = event.localX)? and (y = event.localY)?
          result = {}

Walk through the element regions

          for name, $ of @regions

and add the region to the result if event localized coordinates are within
the region rectangle.

            if $[0] <= x <= ($[0] + $[2]) and $[1] <= y <= ($[1] + $[3])
              result[name] = $

        return result

---

## LISTENERS
### #mousemoveCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousemove** listener

      mousemoveCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousemoveEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousedownCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousedown** listener

      mousedownCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousedownEvent = event
        @localizeEventCoordinates event

        return this

---

### #mouseupCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mouseup** listener

      mouseupCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mouseupEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousemoveListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousemoveListener: -> this

---

### #mousedownListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousedownListener: -> this

---

### #mouseupListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mouseupListener: -> this

[Element]: ./element

[Parent]: ./index.litcoffee
[Evented]: https://nhzio.github.com/ecl/evented.html
[Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
[Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

# CLASS: Element
* Extends: [Evented][Evented]
* Parent: [Index][Parent]

A visual element.

---

    module.exports = class Element extends require 'ecl/dist/evented'

## CONSTRUCTOR

### new Element()

Creates an Element instance.

      constructor: ->
        super

Register validating listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Localize the **type** variable.

          do (type) =>

Add capturing listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:yes, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Add normal listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:no, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Register extendable listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Add capturing extendable listener

          @addListener type, this["#{type}CaptureListener"], yes

Add normal extendable listener

          @addListener type, this["#{type}Listener"], no

#### PARAMETERS
* **args** - named arguments

---

## PROPERTIES

---

## METHODS
### #localizeEventCoordinates(event) ->
* Returns: [Element][Element]

Helper method, to localize event coordinates.

      localizeEventCoordinates: (event) ->
        if event

If event already has localized **x**, use it instead of absolute **x**

          x = (if event.localX? then event.localX else event.x)
          event.localX = x - (@origin?.x or 0)

If event already has localized **y**, use it instead of absolute **y**

          y = (if event.localY? then event.localY else event.y)
          event.localY = y - (origin?.y or 0)

        return this
---

### #getEventRegions(event)
* Returns: [Object][Object] - named set of matching regions

Helper method, to get element regions that match the event.

      getEventRegions: (event) ->

Proceed only if event coordinates are localized

        if event and (x = event.localX)? and (y = event.localY)?
          result = {}

Walk through the element regions

          for name, $ of @regions

and add the region to the result if event localized coordinates are within
the region rectangle.

            if $[0] <= x <= ($[0] + $[2]) and $[1] <= y <= ($[1] + $[3])
              result[name] = $

        return result

---

## LISTENERS
### #mousemoveCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousemove** listener

      mousemoveCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousemoveEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousedownCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousedown** listener

      mousedownCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mousedownEvent = event
        @localizeEventCoordinates event

        return this

---

### #mouseupCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mouseup** listener

      mouseupCaptureListener: (event) ->

Store the event in the runtime for later and localize event coordinates

        @___runtime.mouseupEvent = event
        @localizeEventCoordinates event

        return this

---

### #mousemoveListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousemoveListener: -> this

---

### #mousedownListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousedownListener: -> this

---

### #mouseupListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mouseupListener: -> this

[Element]: ./element

[Parent]: ./index.litcoffee
[Evented]: https://nhzio.github.com/ecl/evented.html


Use delegates file written in coffeescript

    `#! /usr/bin/env node
    `

    Madul = require 'madul'

    if process.env.SKYLL_MADUL_LOGGING == 'true'
      require 'magnus'

    Skyll = require './index'
    args  = require './arguments'
    uuid  = require 'node-uuid'
    fs    = require 'fs'
    path  = require 'path'

    EXTRACT = [
      'rows'
      'columns'
      'width'
      'height'
      'multiplier'
      'pipeline'
      'block'
      'ground'
      'step_count'
      'wall'
    ]

    new Skyll()
      .initialize args
      .then (mod) ->
        levels = [ ]

        if args._?.length > 0
          levels = levels.concat argv._
        else if args.l?
          for level in [0...argv.l]
            levels.push uuid.v4()
        else if Array.isArray args.levels
          for level in args.levels
            levels.push level
        else if args.levels? == false
          levels.push new Date().toString()

        if args.delegates?
          location = args.delegates
        else
          location = path.join __dirname, 'delegates.js'

        fs.stat location, (err) ->
          if err?
            mod.warn 'file-not-found', location
          else
            delegates = require location
            next      = 0
            input     = { }
            pipe      = [ ]

            for own key, val of args
              input[key] = val if EXTRACT.includes key

            Madul.DUMMY pipe, (dum) ->
              dum.render_pipeline = [ ]

              for p in input.pipeline
                if Array.isArray p
                  new_pipeline = for q in p
                    dum[Madul.PARSE_SPEC(q).ref]

                  dum.render_pipeline.push new_pipeline
                else
                  dum.render_pipeline.push dum[Madul.PARSE_SPEC(p).ref]

              args = { }
              name = new Date().toString()

              for own key, val of input
                args[key] = val if EXTRACT.includes key

              render = (level) ->
                mod.craft level, input, dum.render_pipeline, delegates
                  .then -> render levels[next] if ++next < levels.length

              render levels[next]

    `#! /usr/bin/env node
    `

    Madul = require 'madul'

    if process.env.SKYLL_MADUL_LOGGING == 'true'
      require 'magnus'

    Skyll = require './index'
    args  = require './arguments'
    uuid  = require 'node-uuid'
    fs    = require 'fs'
    path  = require 'path'

    EXTRACT = [
      'rows'
      'columns'
      'width'
      'height'
      'multiplier'
      'pipeline'
      'block'
      'ground'
      'step_count'
      'wall'
    ]

    new Skyll()
      .initialize args
      .then (mod) ->
        levels = [ ]

        if args._?.length > 0
          levels = levels.concat argv._
        else if args.l?
          for level in [0...argv.l]
            levels.push uuid.v4()
        else if Array.isArray args.levels
          for level in args.levels
            levels.push level
        else if args.levels? == false
          levels.push new Date().toString()

        if args.delegates?
          location = args.delegates
        else
          location = path.join process.cwd(), 'skyll.delegates.js'

        fs.stat location, (err) ->
          if err?
            mod.warn 'file-not-found', location
          else
            delegates = require location
            next      = 0
            input     = { }
            pipe      = [ ]

            for own key, val of args
              input[key] = val if EXTRACT.includes key

            Madul.DUMMY pipe, (dum) ->
              dum.render_pipeline = [ ]

              for p in input.pipeline
                if Array.isArray p
                  new_pipeline = for q in p
                    dum[Madul.PARSE_SPEC(q).ref]

                  dum.render_pipeline.push new_pipeline
                else
                  dum.render_pipeline.push dum[Madul.PARSE_SPEC(p).ref]

              args = { }
              name = new Date().toString()

              for own key, val of input
                args[key] = val if EXTRACT.includes key

              render = (level) ->
                mod.craft level, input, dum.render_pipeline, delegates
                  .then -> render levels[next] if ++next < levels.length

              render levels[next]


webpack

webpack

# Webpack Configuration

[Webpack](https://github.com/webpack/webpack) handles asset compilation (Sass, CoffeeScript, etc),
and processes JS `require`, Sass `@import`, and CSS `url()`.

First, require the dependencies:

    path    = require('path')
    webpack = require('webpack')
    _       = require('lodash')

## CSS configuration

List of loader names for CSS files:

    cssLoaders = ['style', 'css', 'autoprefixer-loader?last 2 versions']

Style module loaders (used later):

    styleLoaders = [
      { test: /\.scss$/, loaders: cssLoaders.concat(["sass?precision=10&outputStyle=expanded&includePaths[]=" + path.resolve(__dirname, './bower_components')]) }
      { test: /\.css$/, loaders: cssLoaders }
    ]

`ExtractTextPlugin` is an experimental plugin to output CSS in `.css` and not `.js` files. Create plugin instance (used later):

    ExtractTextPlugin = require("extract-text-webpack-plugin")
    extractTextPlugin = new ExtractTextPlugin("[name].css", allChunks: true)

Override style loaders to use `ExtractTextPlugin`:

    styleLoaders = styleLoaders.map (e) ->
      test: e.test
      loader: ExtractTextPlugin.extract(e.loaders.slice(1).join('!'))

## Configuration

    module.exports =

List of bundle entry points, i.e. packages to compile in the distribution. See [docs](http://webpack.github.io/docs/configuration.html#entry).

      entry:
        main             : "./src/scripts/main.litcoffee"
        "styles"         : "./src/styles/styles.scss"
        "vendor/es5-shim": "./bower_components/es5-shim/es5-shim.js"
        "vendor/es5-sham": "./bower_components/es5-shim/es5-sham.js"

Set compilation target to "web". See [docs](http://webpack.github.io/docs/configuration.html#target).

      target: "web"

Set development options by default:

      debug: true
      # We are watching in Gulp, so tell webpack not to watch
      watch: false
      # watchDelay: 300

Output options:

      output:
        path         : path.join(__dirname, "dist", "assets")
        publicPath   : "/assets/"
        filename     : "[name].js"
        chunkFilename: "[name].[id].[chunkhash].js"

Look for required files in bower and node

      resolve:
        modulesDirectories: ['bower_components', 'node_modules']

Define how modules should be loaded based on path extension:

      module:
        loaders: styleLoaders.concat [
          { test: /\.gif$/, loader: "url?limit=10000&minetype=image/gif" }
          { test: /\.jpg$/, loader: "url?limit=10000&minetype=image/jpg" }
          { test: /\.png$/, loader: "url?limit=10000&minetype=image/png" }
          { test: /\.js$/, loader: "jsx" }
          { test: /\.coffee$/, loader: "jsx!coffee" }
          { test: /\.litcoffee$/, loader: "jsx!coffee?literate"}
          # url-loader embeds DataUrls.
          { test: /\.woff$/, loader: "url?limit=10000&minetype=application/font-woff" }
          # file-loader emits files.
          { test: /\.ttf$/, loader: "file?mimetype=application/vnd.ms-fontobject" }
          { test: /\.eot$/, loader: "file?mimetype=application/x-font-ttf" }
          { test: /\.svg$/, loader: "file?mimetype=image/svg+xml" }
        ]
        noParse: /\.min\.js$/

Define the plugins:

      plugins: [

`DefinePlugin` defines a variable that will be substituted in the assets (a la macro):

        new webpack.DefinePlugin(__PRODUCTION__: JSON.stringify(false))

`extractTextPlugin` (defined above) will compile CSS to a .css file, as opposed to inlining it as a string in a .js file.

        extractTextPlugin
      ]

## Production

Export a method that applies production settings (used in gulpfile):

      useProductionSettings: ->

Production plugins:

        plugins = @plugins.concat [

Minify JavaScript with UglifyJS:

          new webpack.optimize.UglifyJsPlugin()
        ]

Set `__PRODUCTION__` to true in DefinePlugin:

        for plugin in plugins when plugin.definitions?.__PRODUCTION__
          plugin.definitions.__PRODUCTION__ = JSON.stringify(true)

Tell `ExtractTextPlugin` to append hashes:

        for plugin in plugins when plugin.filename == '[name].css'
          plugin.filename = '[name]-[hash].css'

Merge in production config (deep merge):

        _.merge @,

Disable development settings:

          debug: false
          watch: false
          devtool: null

Add content hashes to the output filenames:

          output:
            filename: "[name]-[hash].js"

Production-only plugins:

          plugins: plugins

# Webpack Configuration

[Webpack](https://github.com/webpack/webpack) handles asset compilation (Sass, CoffeeScript, etc),
and processes JS `require`, Sass `@import`, and CSS `url()`.

First, require the dependencies:

    path    = require('path')
    webpack = require('webpack')
    _       = require('lodash')

## CSS configuration

List of loader names for CSS files:

    cssLoaders = ['style', 'css', 'autoprefixer-loader?last 2 versions']

Style module loaders (used later):

    styleLoaders = [
      { test: /\.scss$/, loaders: cssLoaders.concat(["sass?precision=10&outputStyle=expanded&includePaths[]=" + path.resolve(__dirname, './bower_components')]) }
      { test: /\.css$/, loaders: cssLoaders }
    ]

`ExtractTextPlugin` is an experimental plugin to output CSS in `.css` and not `.js` files. Create plugin instance (used later):

    ExtractTextPlugin = require("extract-text-webpack-plugin")
    extractTextPlugin = new ExtractTextPlugin("[name].css", allChunks: true)

Override style loaders to use `ExtractTextPlugin`:

    styleLoaders = styleLoaders.map (e) ->
      test: e.test
      loader: ExtractTextPlugin.extract(e.loaders.slice(1).join('!'))

## Configuration

    module.exports =

List of bundle entry points, i.e. packages to compile in the distribution. See [docs](http://webpack.github.io/docs/configuration.html#entry).

      entry:
        main             : "./src/scripts/main.litcoffee"
        "styles"         : "./src/styles/styles.scss"
        "vendor/es5-shim": "./bower_components/es5-shim/es5-shim.js"
        "vendor/es5-sham": "./bower_components/es5-shim/es5-sham.js"

Set compilation target to "web". See [docs](http://webpack.github.io/docs/configuration.html#target).

      target: "web"

Set development options by default:

      debug: true
      # We are watching in Gulp, so tell webpack not to watch
      watch: false
      # watchDelay: 300

Output options:

      output:
        path         : path.join(__dirname, "dist", "assets")
        publicPath   : "/assets/"
        filename     : "[name].js"
        chunkFilename: "[name].[id].[chunkhash].js"

Look for required files in bower and node

      resolve:
        modulesDirectories: ['bower_components', 'node_modules']

Define how modules should be loaded based on path extension:

      module:
        loaders: styleLoaders.concat [
          { test: /\.gif$/, loader: "url?limit=10000&minetype=image/gif" }
          { test: /\.jpg$/, loader: "url?limit=10000&minetype=image/jpg" }
          { test: /\.png$/, loader: "url?limit=10000&minetype=image/png" }
          { test: /\.js$/, loader: "jsx" }
          { test: /\.coffee$/, loader: "jsx!coffee" }
          { test: /\.litcoffee$/, loader: "jsx!coffee?literate"}
          # url-loader embeds DataUrls.
          { test: /\.woff$/, loader: "url?limit=10000&minetype=application/font-woff" }
          # file-loader emits files.
          { test: /\.ttf$/, loader: "file?mimetype=application/vnd.ms-fontobject" }
          { test: /\.eot$/, loader: "file?mimetype=application/x-font-ttf" }
          { test: /\.svg$/, loader: "file?mimetype=image/svg+xml" }
        ]
        noParse: /\.min\.js$/

Define the plugins:

      plugins: [

`DefinePlugin` defines a variable that will be substituted in the assets (a la macro):

        new webpack.DefinePlugin(__PRODUCTION__: JSON.stringify(false))

`extractTextPlugin` (defined above) will compile CSS to a .css file, as opposed to inlining it as a string in a .js file.

        extractTextPlugin
      ]

## Production

Export a method that applies production settings (used in gulpfile):

      useProductionSettings: ->

Production plugins:

        plugins = @plugins.concat([

Minify JavaScript with UglifyJS:

          new webpack.optimize.UglifyJsPlugin()
        ])

Set `__PRODUCTION__` to true in DefinePlugin.

        for plugin in plugins when plugin.definitions?.__PRODUCTION__
          plugin.definitions.__PRODUCTION__ = JSON.stringify(true)

        for plugin in plugins when plugin.filename == '[name].css'
          plugin.filename = '[name]-[hash].css'

Merge in production config (deep merge):

        _.merge @,

Disable development settings:

          debug: false
          watch: false
          devtool: null

Add content hashes to the output filenames:

          output:
            filename: "[name]-[hash].js"

Production-only plugins:

          plugins: plugins


changed validator function name

changed validator function name

#Validator

	module.exports =
		scope:
			validate: (inputString, data, done) ->
				@$call @validate, inputString, (err, isValid) ->
					return done(err) if err?
					if isValid
						data
							display: inputString
							value: inputString
				done()

		schema:
			name: 'validator'
			root:
				type: 'value'
				compute: 'validate'
				id: '@value'

#Validator

	module.exports =
		scope:
			_validate: (inputString, data, done) ->
				@$call @validate, inputString, (err, isValid) ->
					return done(err) if err?
					if isValid
						data
							display: inputString
							value: inputString
				done()

		schema:
			name: 'validator'
			root:
				type: 'value'
				compute: '_validate'
				id: '@value'


docs(document): remove Params and Return headings to make docs more coherent

    ObjectID  = require('mongodb').ObjectID

Import event emitter stuff.

    EventEmitter = require('events').EventEmitter
    inherits = require('util').inherits

Import data storage modules.

    mongo   = require '../db/mongo'
    redis   = require '../db/redis'

    parse   = require '../helper/parse'
    cache   = require '../helper/cache'

    collections = require('../helper/schema').types

---

## Class: Doc

### new Doc(type, id)

* **string** `type` - document type (collection name)
* **string** `id` - document id

---

    module.exports = Doc = (type, id) ->
      throw new Error('Missing Doc type param') if not type
      throw new Error('Missing or invalid ID param') if typeof id isnt 'string' and id isnt null

      EventEmitter.call @

### doc.db

MongoDB collection instance where the document is stored.

      @db   = mongo[type]

### doc.id

Unique `ObjectID` for the document. Access through `doc.getId()`.

      @id   = if typeof id is 'string' then new ObjectID(id) else null

### doc.type

Document collection name (object type).

      @type = type

### doc.data

Cached document data from Redis. This gets poppulated automaticly when the
a new document is instanciated.

      @data = {}

### doc.chit

Cache hit indicator. Accessed through `doc.wasCacheHit()`.

      @chit = false

---

      if @id
        redis.hgetall "#{@type}:#{@id.toString()}", (err, data) =>
          return @emit 'error', err if err

          if Object.keys(data).length
            @data = cache.arrayify @type, data
            @chit = true
            return @emit 'ready'

          @db.findOne _id: @id, cache.getFilter(@type), (err, data) =>
            return @emit 'error', err if err

            @data = data or status: 'Slettet'
            redis.hmset "#{@type}:#{@id}", @data, (err) =>
              return @emit 'ready'
      else
        process.nextTick => @emit 'ready'

      return @

    inherits Doc, EventEmitter

### doc.exists()

Check if document exists. Returns `true` if document exists; otherwise `false`.

---

    Doc.prototype.exists = ->
      return @data.status? and @data.status isnt 'Slettet'

### doc.getId()

Get the unique id for current document. Returns an `ObjectID` if the document
exists; otherwise `null`.

---

    Doc.prototype.getId = ->
      @id

### doc.wasCacheHit()

Check if document request was a cache hit. Returns `true` if document request
was a cache hit; otherwise `false`.

---

    Doc.prototype.wasCacheHit = ->
      @chit

### doc.isNotModifiedSince(time)

* **string** `time` - timestamp to check against.

Check if document has not been modified since a given timestamp. Returns `true`
if document has not been modified since given timestamp; otherwise `false`.

---

    Doc.prototype.isModifiedSince = (time) -> @modifiedSince time, false
    Doc.prototype.isNotModifiedSince = (time) -> @modifiedSince time, true

    Doc.prototype.modifiedSince = (time, negate) ->
      return false if not time or not @data.endret

      if not isNaN time
        # Make UNIX timestamp into milliseconds
        time = time + '000' if (time + '').length is 10
        time = parseInt time

      org = new Date(@data.endret)
      chk = new Date(time)

      # HTTP-date's don't have milliseconds
      org.setMilliseconds(0)

      return false if chk.toString() is 'Invalid Date'

      return chk >= org if negate
      return chk <  org

### doc.isMatch(checksum)

* **string** `checksum` - checksum to check against.

Check if checksum, or Etag, matches current document checksum. Returns `true`
if checksum matches the current checksum; otherwise `false`.

---

    Doc.prototype.isMatch = (checksum) ->
      return false if not checksum or not @data.checksum
      return (checksum is "\"#{@data.checksum}\"" or checksum is '*')

### doc.isNoneMatch(checksum)

* **string** `checksum` - checksum to check against.

Check if checksum, or Etag, doesn't match current document checksum. Return
`true` if checksum does not match or document has no checksum; otherwise
`false`.

---

    Doc.prototype.isNoneMatch = (checksum) ->
      return false if not checksum
      return true if not @data.checksum
      return checksum isnt "\"#{@data.checksum}\""

### doc.get([key])

* **string** `key` - get specific object property

Get cached data for the current document. Returns an `object` if `key` is
`undefined`; otherwise `string`. Will return `undefined` if the given key does
not exist.

---

    Doc.prototype.get = (key) ->
      return @data if not key
      return @data[key]

### doc.getFull(filter[, cb])

* **object** `filter` - control which object properties are returned
* **function** `cb` - callback function (**Error** `err`, **object** `data`)

Get the full document data from the database asynchronously. Returns a cursor
stream if `cb` is undefined.

---

    Doc.prototype.getFull = (filter, cb) ->
      if not cb
        throw new Error('Document doesnt exists') if not @exists()
        return @db.find _id: @id, filter, limit: 1
      else
        return cb new Error('Document doesnt exists') if not @exists()
        @db.findOne _id: @id, filter, cb

### doc.getExpanded(filter, expand, query, cb)

* **object** `filter` - control which object properties are returned
* **array** `expand` - sub-document property names to expand
* **object** `query` - query for expanded sub-documents
* **function** `cb` - callback function (**Error** `err`, **object** `data`)

Get the full document with expanded sub-documents from the database
asynchronously. To expand a given collection jsut pass the collection name to
the `expand` parameter and it will be merged with the document data.

---

    Doc.prototype.getExpanded = (filter, expand, query, cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      count = 0
      mapped = {}

Since `expand` might be a user supplied input parameter we need to limit it to
properties which are expandable (`collections`). We also remove properties which
holds no value for this document.

      expand = expand
        .filter (v) => @data[v] and v in collections

Next we map the string array into an object array on the following format:
`{ type: String, ids: Array }` where `ids` are ObjectIDs to an document of the
collection `type`.

        .map (v) => type: v, ids: @data[v].map (d) -> new ObjectID d

Set up a `final` function which is called when expanded data is ready to be
mapped to the original document.

      final = () =>
        @db.findOne _id: @id, filter, (err, doc) ->
          cb err, Object.assign doc or {}, mapped

If there are no fields to expand, we just call the `final` function instantly
and no fields will get expanded.

      return final() if expand.length is 0

Set up a `next` function which is called for each expanded data returned from
the database. Expanded data is stored in the `mapped` object which is merged
with the main document in `final`. When all expanded fields are mapped `final`
is called.

      next = (type, _, docs) ->
        mapped[type] = docs or []
        return final() if Object.keys(mapped).length == expand.length

Get the expanded sub-documents from the database.

      expand.forEach (x) ->
        mongo[x.type]

We find the sub-documents using the ObjectIDs in the expanded fields, that is
the easy part. The tricky part is to prevent information leakage of private
documents. This the second part is a `query` limiting the results to public
documents or those owned by the current API user.

          .find Object.assign {_id: $in: x.ids}, query

We reuse the projection filter from the original document, but since we do not
know in advanced who owns a given sub-document we remove the `private` property
to prevent information leakage.

          .project Object.assign filter, privat: false

Bundle all the sub-documents in one array and pass it to the `next` function.

          .toArray next.bind null, x.type

### doc.insert(data, cb)

* **object** `data` - data to insert for document.
* **function** `cb` - callback function (**Error** `err`, **Array** `warn`, **object** `data`).

Inserts a new document into database.

---

    Doc.prototype.insert = (data, cb) ->
      return cb new Error('Document already exists') if @exists()
      return cb new Error('Document is deleted') if @data.status is 'Slettet'

      parse.docInsert @type, data, (err, warn, data) =>
        return cb err if err

        @db.insertOne data, w: 1, (err) =>
          return cb err if err

          @id   = new ObjectID(data._id)
          @data = cache.filterData @type, data

          redis.hmset "#{@type}:#{@id.toString()}", @data

          cb err, warn, data

### doc.replace(data, cb)

* **object** `data` - replacement data for document.
* **function** `cb` - callback function (**Error** `err`, **Array** `warn`, **object** `data`).

Replaces all document data in database.

---

    Doc.prototype.replace = (data, cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      parse.docReplace @type, data, (err, warn, data) =>
        return cb err if err

        @db.replaceOne _id: @id, data, w: 1, (err) =>
          return cb err if err

          @data = cache.filterData @type, data

          redis.del "#{@type}:#{@id.toString()}"
          redis.hmset "#{@type}:#{@id.toString()}", @data

          data._id = @id
          cb err, warn, data

### doc.update(data, cb)

* **object** `data` - replacement object for document.
* **function** `cb` - callback function (**Error** `err`, **Array** `warn`, **object** `data`).

Partially update the document-data in database. This is some times referred to as
PATCH in a HTTP / REST context.

---

    Doc.prototype.update = (query, cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      parse.docPatch @type, query, (err, warn, query) =>
        return cb err if err

        @db.updateOne _id: @id, query, w: 1, (err) =>
          return cb err if err

          @getFull {}, (err, doc) =>
            @data = cache.filterData @type, doc

            redis.del "#{@type}:#{@id.toString()}"
            redis.hmset "#{@type}:#{@id.toString()}", @data

            cb err, warn, doc

### doc.delete(cb)

* **function** `cb` - callback function (**Error** `err`).

Delete a document from the database by removing all document properties and
setting the `status` property to `Slettet`.

---

    Doc.prototype.delete = (cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      @data = status: 'Slettet', endret: new Date()
      @db.replaceOne _id: @id, @data, w: 1, (err) =>
        return cb err if err

        redis.del "#{@type}:#{@id.toString()}"
        redis.hmset "#{@type}:#{@id.toString()}", @data

        cb null

    ObjectID  = require('mongodb').ObjectID

Import event emitter stuff.

    EventEmitter = require('events').EventEmitter
    inherits = require('util').inherits

Import data storage modules.

    mongo   = require '../db/mongo'
    redis   = require '../db/redis'

    parse   = require '../helper/parse'
    cache   = require '../helper/cache'

    collections = require('../helper/schema').types

---

## Class: Doc

### Params

* **string** `type` - document type
* **string** `id` - document id

### Return

New `Doc`.

---

    module.exports = Doc = (type, id) ->
      throw new Error('Missing Doc type param') if not type
      throw new Error('Missing or invalid ID param') if typeof id isnt 'string' and id isnt null

      EventEmitter.call @

      @db   = mongo[type]
      @id   = if typeof id is 'string' then new ObjectID(id) else null
      @type = type
      @data = {}
      @chit = false

      if @id
        redis.hgetall "#{@type}:#{@id.toString()}", (err, data) =>
          return @emit 'error', err if err

          if Object.keys(data).length
            @data = cache.arrayify @type, data
            @chit = true
            return @emit 'ready'

          @db.findOne _id: @id, cache.getFilter(@type), (err, data) =>
            return @emit 'error', err if err

            @data = data or status: 'Slettet'
            redis.hmset "#{@type}:#{@id}", @data, (err) =>
              return @emit 'ready'
      else
        process.nextTick => @emit 'ready'

      return @

    inherits Doc, EventEmitter

## doc.exists()

Check if document exists.

### Return

Returns `true` if document exists; otherwise `false`.

---

    Doc.prototype.exists = ->
      return @data.status? and @data.status isnt 'Slettet'

## doc.getId()

Get document id (ObjectID) for current document.

### Return

Returns an `ObjectID` if the document has an id; otherwise `null`.

---

    Doc.prototype.getId = ->
      @id

## doc.wasCacheHit()

Check if document request was a cache hit.

### Return

Returns `true` if document request was a cache hit; otherwise `false`.

---

    Doc.prototype.wasCacheHit = ->
      @chit

## doc.isNotModifiedSince()

Check if document has not been modified since a given timestamp.

### Params

* **string** `time` - timestamp to check against.

### Return

Returns `true` if document has not been modified since given timestamp; otherwise
`false`.

---

    Doc.prototype.isModifiedSince = (time) -> @modifiedSince time, false
    Doc.prototype.isNotModifiedSince = (time) -> @modifiedSince time, true

    Doc.prototype.modifiedSince = (time, negate) ->
      return false if not time or not @data.endret

      if not isNaN time
        # Make UNIX timestamp into milliseconds
        time = time + '000' if (time + '').length is 10
        time = parseInt time

      org = new Date(@data.endret)
      chk = new Date(time)

      # HTTP-date's don't have milliseconds
      org.setMilliseconds(0)

      return false if chk.toString() is 'Invalid Date'

      return chk >= org if negate
      return chk <  org

## doc.isMatch

Check if checksum, or Etag, matches current document checksum.

### Params

* **string** `checksum` - checksum to check against.

### Return

Returns `true` if checksum matches the current checksum; otherwise `false`.

---

    Doc.prototype.isMatch = (checksum) ->
      return false if not checksum or not @data.checksum
      return (checksum is "\"#{@data.checksum}\"" or checksum is '*')

## doc.isNoneMatch

Check if checksum, or Etag, doesn't match current document checksum.

### Params

* **string** `checksum` - checksum to check against.

### Return

Return `true` if checksum does not match or document has no checksum; otherwise
`false`.

---

    Doc.prototype.isNoneMatch = (checksum) ->
      return false if not checksum
      return true if not @data.checksum
      return checksum isnt "\"#{@data.checksum}\""

## doc.get()

Get cached data for current document.

### Params

* **string** `key` - get specific object property

### Return

Returns an `object` if `key` is `undefined`; otherwise `string`. Will return
`undefined` if the given key does not exist.

---

    Doc.prototype.get = (key) ->
      return @data if not key
      return @data[key]

## doc.getFull

### Params

* **object** `filter` - control which object properties are returned
* **function** `cb` - callback function (**Error** `err`, **object** `data`)

### Return

Returns `undefined`.

---

    Doc.prototype.getFull = (filter, cb) ->
      if not cb
        throw new Error('Document doesnt exists') if not @exists()
        return @db.find _id: @id, filter, limit: 1
      else
        return cb new Error('Document doesnt exists') if not @exists()
        @db.findOne _id: @id, filter, cb

### doc.getExpanded(filter, expand, query, cb)

* **object** `filter` - control which object properties are returned
* **array** `expand` - sub-document property names to expand
* **object** `query` - query for expanded sub-documents
* **function** `cb` - callback function (**Error** `err`, **object** `data`)

### Return

Returns `undefined`.

---

    Doc.prototype.getExpanded = (filter, expand, query, cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      count = 0
      mapped = {}

Since `expand` might be a user supplied input parameter we need to limit it to
properties which are expandable (`collections`). We also remove properties which
holds no value for this document.

      expand = expand
        .filter (v) => @data[v] and v in collections

Next we map the string array into an object array on the following format:
`{ type: String, ids: Array }` where `ids` are ObjectIDs to an document of the
collection `type`.

        .map (v) => type: v, ids: @data[v].map (d) -> new ObjectID d

Set up a `final` function which is called when expanded data is ready to be
mapped to the original document.

      final = () =>
        @db.findOne _id: @id, filter, (err, doc) ->
          cb err, Object.assign doc or {}, mapped

If there are no fields to expand, we just call the `final` function instantly
and no fields will get expanded.

      return final() if expand.length is 0

Set up a `next` function which is called for each expanded data returned from
the database. Expanded data is stored in the `mapped` object which is merged
with the main document in `final`. When all expanded fields are mapped `final`
is called.

      next = (type, _, docs) ->
        mapped[type] = docs or []
        return final() if Object.keys(mapped).length == expand.length

Get the expanded sub-documents from the database.

      expand.forEach (x) ->
        mongo[x.type]

We find the sub-documents using the ObjectIDs in the expanded fields, that is
the easy part. The tricky part is to prevent information leakage of private
documents. This the second part is a `query` limiting the results to public
documents or those owned by the current API user.

          .find Object.assign {_id: $in: x.ids}, query

We reuse the projection filter from the original document, but since we do not
know in advanced who owns a given sub-document we remove the `private` property
to prevent information leakage.

          .project Object.assign filter, privat: false

Bundle all the sub-documents in one array and pass it to the `next` function.

          .toArray next.bind null, x.type

## doc.insert()

Inserts a document into database.

### Params

* **object** `data` - data to insert for document.
* **function** `cb` - callback function (**Error** `err`, **Array** `warn`, **object** `data`).

### Return

Returns `undefined`.

---

    Doc.prototype.insert = (data, cb) ->
      return cb new Error('Document already exists') if @exists()
      return cb new Error('Document is deleted') if @data.status is 'Slettet'

      parse.docInsert @type, data, (err, warn, data) =>
        return cb err if err

        @db.insertOne data, w: 1, (err) =>
          return cb err if err

          @id   = new ObjectID(data._id)
          @data = cache.filterData @type, data

          redis.hmset "#{@type}:#{@id.toString()}", @data

          cb err, warn, data

## doc.replace()

Replaces all document data in database.

### Params

* **object** `data` - replacement data for document.
* **function** `cb` - callback function (**Error** `err`, **Array** `warn`, **object** `data`).

### Return

Returns `undefined`.

---

    Doc.prototype.replace = (data, cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      parse.docReplace @type, data, (err, warn, data) =>
        return cb err if err

        @db.replaceOne _id: @id, data, w: 1, (err) =>
          return cb err if err

          @data = cache.filterData @type, data

          redis.del "#{@type}:#{@id.toString()}"
          redis.hmset "#{@type}:#{@id.toString()}", @data

          data._id = @id
          cb err, warn, data

## doc.update()

Partially update the document-data in database. This is some times referred to as
PATCH in a HTTP / REST context.

### Params

* **object** `data` - replacement object for document.
* **function** `cb` - callback function (**Error** `err`, **Array** `warn`, **object** `data`).

### Return

Returns `undefined`.

---

    Doc.prototype.update = (query, cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      parse.docPatch @type, query, (err, warn, query) =>
        return cb err if err

        @db.updateOne _id: @id, query, w: 1, (err) =>
          return cb err if err

          @getFull {}, (err, doc) =>
            @data = cache.filterData @type, doc

            redis.del "#{@type}:#{@id.toString()}"
            redis.hmset "#{@type}:#{@id.toString()}", @data

            cb err, warn, doc

## doc.delete()

Delete a document from the database by removing all document properties and
setting the `status` property to `Slettet`.

### Params

* **function** `cb` - callback function (**Error** `err`).

### Return

Returns `undefined`.

---

    Doc.prototype.delete = (cb) ->
      return cb new Error('Document doesnt exists') if not @exists()

      @data = status: 'Slettet', endret: new Date()
      @db.replaceOne _id: @id, @data, w: 1, (err) =>
        return cb err if err

        redis.del "#{@type}:#{@id.toString()}"
        redis.hmset "#{@type}:#{@id.toString()}", @data

        cb null


More robust path normzalization

More robust path normzalization

# Package manager

*Registers packages and handles hook registration and invocation as well as
introspection.*

    debug = require('debug') 'shrub:pkgman'
    debugSilly = require('debug') 'shrub-silly:pkgman'

Index by hook and path for faster invocation and introspection.

    hookIndex = {}
    pathIndex = {}

A list of registered packages.

    _packages = []

    class PkgmanRegistrar

Registrar function passed to packages to allow them to register hooks and/or
recur into their own subpackages to allow them to.

## *constructor*

*Instantiate the registrar with the current (sub)package path.*

      constructor: (@_path) ->

## PkgmanRegistrar#path

*Get the current (sub) package path.*

      path: -> @_path

## PkgmanRegistrar#recur

* (string array) `paths` - The list of submodule paths to register.

*Recur into subpackages to register them and allow them to register hooks
and/or recur further.*

      recur: (paths) ->

        for path in paths

          subpath = "#{@_path}/#{path}"

          debugSilly "Requiring #{subpath}"
          submodule = require subpath
          debugSilly "Required #{subpath}"

          debugSilly "Registering hooks for #{subpath}"
          submodule.pkgmanRegister? new PkgmanRegistrar subpath
          debugSilly "Registered hooks for #{subpath}"

        return

## PkgmanRegistrar#registerHook

* (optional string) `submodule` - Register this hook under a submodule. This is
  a convenience for when you might need to register more than one
  implementation of a hook, bur prefer to keep both implementations in the same
  physical file.

* (string) `hook` - The name of the hook to register.

* (function) `impl` - The hook implementation function. This is invoked when
  the hook is invoked. The signature of the implementation function may vary,
  consult the documentation for the specific hook to learn more.

###### TODO: Link to an instance of using the `submodule` arg in core if one exists.

      registerHook: (submodule, hook, impl) ->

If `submodule` was passed in, modify the path this hook is registered against.

        if impl?

          path = "#{@_path}/#{submodule}"

Otherwise, fix up the args.

        else

          path = @_path
          impl = hook
          hook = submodule

Populate the indexes with the registered hook.

        debugSilly "Registering hook #{hook}"

        (hookIndex[hook] ?= []).push path
        (pathIndex[path] ?= {})[hook] = impl

        debugSilly "Registered hook #{hook}"

## pkgman.rebuildPackageCache

*Rebuild the package cache.* **Do not invoke this unless you are absolutely
sure you know what you're doing.**

    exports.rebuildPackageCache = ->
      modules = {}
      hookIndex = {}
      pathIndex = {}

      for name in _packages

Try to require the package module.

        try

          debugSilly "Requiring package #{name}"

          module_ = require name

        catch error

Suppress missing package errors.

          if error.toString() is "Error: Cannot find module '#{name}'"
            debug "Missing package #{name}."
            continue

          throw error

        debugSilly "Required package #{name}"

        modules[name] = module_

Register hooks.

      for path, module_ of modules

        debugSilly "Registering hooks for #{path}"
        module_.pkgmanRegister? new PkgmanRegistrar path
        debugSilly "Registered hooks for #{path}"

      return

## pkgman.registerPackageList

* (string array) `packages` - The list of packages to register.

*Register a list of packages.*

    exports.registerPackageList = (packages) ->
      _packages.push.apply _packages, packages
      exports.rebuildPackageCache()

## pkgman.invoke

* (string) `hook` - The name of the hook to invoke.
* (args...) `args` - Arguments to pass along to implementations of the hook.

*Invoke a hook with arguments. Return the result as an object, keyed by package
path.*

    exports.invoke = (hook, args...) ->

      results = {}

      for path in exports.packagesImplementing hook
        results[path] = exports.invokePackage path, hook, args...

      return results

## pkgman.invokeFlat

* (string) `hook` - The name of the hook to invoke.
* (args...) `args` - Arguments to pass along to implementations of the hook.

*Invoke a hook with arguments. Return the result as an array.*

    exports.invokeFlat = (hook, args...) ->

      for path in exports.packagesImplementing hook
        exports.invokePackage path, hook, args...

## pkgman.invokePackage

* (string) `path` - The path of the package whose implementation we're
  invoking.
* (string) `hook` - The name of the hook to invoke.
* (args...) `args` - Arguments to pass along to the hook implementation.

*Invoke a package's implementation of a hook with arguments. Return the
result.*

    exports.invokePackage = (path, hook, args...) ->
      pathIndex?[path]?[hook]? args...

## pkgman.packageExists

* (string) `name` - The name of the package to check.

*Check whether a package exists.*

    exports.packageExists = (name) -> -1 isnt _packages.indexOf name

## pkgman.packagesImplementing

* (string) `hook` - The hook to check.

*Return a list of packages implementing the hook.*

    exports.packagesImplementing = (hook) -> hookIndex?[hook] ? []

## pkgman.normalizePath

* (string) `path` - The path to normalize.
* (Boolean) `capitalize` - Whether to capitalize the first letter.

*Converts a package path (e.g. `shrub-user/login`) to a normalized path (e.g.
`shrubUserLogin`).*

    exports.normalizePath = (path, capitalize = false) ->

      i8n = require 'inflection'

      parts = for part, i in path.split '/'
        i8n.camelize i8n.underscore(
          part.replace /[^\w]/g, '_'
          0 is i
        )

      i8n.camelize (i8n.underscore parts.join ''), not capitalize

# Package manager

*Registers packages and handles hook registration and invocation as well as
introspection.*

    debug = require('debug') 'shrub:pkgman'
    debugSilly = require('debug') 'shrub-silly:pkgman'

Index by hook and path for faster invocation and introspection.

    hookIndex = {}
    pathIndex = {}

A list of registered packages.

    _packages = []

    class PkgmanRegistrar

Registrar function passed to packages to allow them to register hooks and/or
recur into their own subpackages to allow them to.

## *constructor*

*Instantiate the registrar with the current (sub)package path.*

      constructor: (@_path) ->

## PkgmanRegistrar#path

*Get the current (sub) package path.*

      path: -> @_path

## PkgmanRegistrar#recur

* (string array) `paths` - The list of submodule paths to register.

*Recur into subpackages to register them and allow them to register hooks
and/or recur further.*

      recur: (paths) ->

        for path in paths

          subpath = "#{@_path}/#{path}"

          debugSilly "Requiring #{subpath}"
          submodule = require subpath
          debugSilly "Required #{subpath}"

          debugSilly "Registering hooks for #{subpath}"
          submodule.pkgmanRegister? new PkgmanRegistrar subpath
          debugSilly "Registered hooks for #{subpath}"

        return

## PkgmanRegistrar#registerHook

* (optional string) `submodule` - Register this hook under a submodule. This is
  a convenience for when you might need to register more than one
  implementation of a hook, bur prefer to keep both implementations in the same
  physical file.

* (string) `hook` - The name of the hook to register.

* (function) `impl` - The hook implementation function. This is invoked when
  the hook is invoked. The signature of the implementation function may vary,
  consult the documentation for the specific hook to learn more.

###### TODO: Link to an instance of using the `submodule` arg in core if one exists.

      registerHook: (submodule, hook, impl) ->

If `submodule` was passed in, modify the path this hook is registered against.

        if impl?

          path = "#{@_path}/#{submodule}"

Otherwise, fix up the args.

        else

          path = @_path
          impl = hook
          hook = submodule

Populate the indexes with the registered hook.

        debugSilly "Registering hook #{hook}"

        (hookIndex[hook] ?= []).push path
        (pathIndex[path] ?= {})[hook] = impl

        debugSilly "Registered hook #{hook}"

## pkgman.rebuildPackageCache

*Rebuild the package cache.* **Do not invoke this unless you are absolutely
sure you know what you're doing.**

    exports.rebuildPackageCache = ->
      modules = {}
      hookIndex = {}
      pathIndex = {}

      for name in _packages

Try to require the package module.

        try

          debugSilly "Requiring package #{name}"

          module_ = require name

        catch error

Suppress missing package errors.

          if error.toString() is "Error: Cannot find module '#{name}'"
            debug "Missing package #{name}."
            continue

          throw error

        debugSilly "Required package #{name}"

        modules[name] = module_

Register hooks.

      for path, module_ of modules

        debugSilly "Registering hooks for #{path}"
        module_.pkgmanRegister? new PkgmanRegistrar path
        debugSilly "Registered hooks for #{path}"

      return

## pkgman.registerPackageList

* (string array) `packages` - The list of packages to register.

*Register a list of packages.*

    exports.registerPackageList = (packages) ->
      _packages.push.apply _packages, packages
      exports.rebuildPackageCache()

## pkgman.invoke

* (string) `hook` - The name of the hook to invoke.
* (args...) `args` - Arguments to pass along to implementations of the hook.

*Invoke a hook with arguments. Return the result as an object, keyed by package
path.*

    exports.invoke = (hook, args...) ->

      results = {}

      for path in exports.packagesImplementing hook
        results[path] = exports.invokePackage path, hook, args...

      return results

## pkgman.invokeFlat

* (string) `hook` - The name of the hook to invoke.
* (args...) `args` - Arguments to pass along to implementations of the hook.

*Invoke a hook with arguments. Return the result as an array.*

    exports.invokeFlat = (hook, args...) ->

      for path in exports.packagesImplementing hook
        exports.invokePackage path, hook, args...

## pkgman.invokePackage

* (string) `path` - The path of the package whose implementation we're
  invoking.
* (string) `hook` - The name of the hook to invoke.
* (args...) `args` - Arguments to pass along to the hook implementation.

*Invoke a package's implementation of a hook with arguments. Return the
result.*

    exports.invokePackage = (path, hook, args...) ->
      pathIndex?[path]?[hook]? args...

## pkgman.packageExists

* (string) `name` - The name of the package to check.

*Check whether a package exists.*

    exports.packageExists = (name) -> -1 isnt _packages.indexOf name

## pkgman.packagesImplementing

* (string) `hook` - The hook to check.

*Return a list of packages implementing the hook.*

    exports.packagesImplementing = (hook) -> hookIndex?[hook] ? []

## pkgman.normalizePath

* (string) `path` - The path to normalize.
* (Boolean) `capitalize` - Whether to capitalize the first letter.

*Converts a package path (e.g. `shrub-user/login`) to a normalized path (e.g.
`shrubUserLogin`).*

    exports.normalizePath = (path, capitalize = false) ->

      i8n = require 'inflection'

      parts = for part, i in path.split '/'
        i8n.camelize(
          part.replace /[^\w]/g, '_'
          0 is i
        )

      i8n.camelize (i8n.underscore parts.join ''), not capitalize


cleanup

cleanup

# The cut - Tool

This creates a function that cuts a simple polygon ring along
an infinite line through `s1` and `s2`.

The ring does not need to be convex, but it must be simple, i.e.
not contain self-intersections or zero-length edges.

    module.exports = ([s1,s2])->(ring)->

Most of our lower-level utility functions are already defined

      {coefficients, vInterpolate, vProject, vSubst, vAlmostZero, almostZero
       coefficient, ringEdges, ringArea} = require './common'
      ccw = require './ccw'
      group = require './group'
      flatMap = (arr, transform) -> [].concat((arr.map(transform))...)
      mu = coefficient([s1,s2])
      interpolate = vInterpolate(s1,s2)

We calculate the oriented area of the ring.
A positive sign means vertices are labled in counter-clock-wise order
(assuming positive y points "up")
We need this info later.

      area = ringArea ring
      ringIsCCW = (area > 0)

The algorithem comprises two phases:

- in the first phase, the input ring is
  cut down into fragments such that each fragment completly lies on either the
  left or the right side of the cutting line

- in the second phase, the fragments are connected to rings.

## Phase I: cutting the ring into fragments

We start by transforming our ring into a list of edges that are either on the left or the right side
of the cutting line.

      edges = flatMap ringEdges(ring), ([a,b])->
        sideA = - ccw s1, s2, a, true
        sideB = - ccw s1, s2, b, true

We have to handle four (five, actually) different cases:
- when the edge intersects the cutting line we output *two* edges, one on each side.
- when the edge is a subset of the cutting line, we can still associate it with one side:
  If it is in the same direction as the cutting line, and the vertices are labeld counter-clock-wise,
  then we associate it with the left side since the inside of the ring is left. Otherwise we label it right.
- If one of the two edges is on the cutting line, we need to calculate the associated coefficient
  so we can later connect the fragments correctly. (see below)
- the remaining two cases are edges that are entirely on one side.

        switch
          when sideA * sideB < 0
            [lambda] = coefficients [s1,s2],[a,b]
            x = interpolate lambda
            [
              start:a
              end: x
              endAt: lambda
              side: Math.sign sideA
            ,
              start: x
              end: b
              startAt: lambda
              side: Math.sign sideB
            ]
          when sideA is 0 and sideB is 0 # edge is subset of cutting line
            lambdaA = mu a
            lambdaB = mu b
            [
              start: a
              startAt: lambdaA
              end: b
              endAt: lambdaB
              side: if ringIsCCW and lambdaA < lambdaB then -1 else 1
            ]
          when sideA is 0
            [
              start: a
              startAt: mu a
              end: b
              side: Math.sign sideB
            ]
          when sideB is 0
            [
              start: a
              end: b
              endAt: mu b
              side: Math.sign sideA
            ]
          else # same side, none zero
            [
              start: a
              end: b
              side: Math.sign sideA #or sideB, doesn't matter.
            ]

Next we collect consecutive edges that are on the same side into groups. We then transform the
edge groups into fragments.

      fragments = group edges, (edge)->edge.side
        .map ({value, elements})->
          [firstEdge,..., lastEdge] = elements
          firstVertex = firstEdge.start
          otherVertices = elements.map (edge)->edge.end

          startAt: firstEdge.startAt # maybe undefined for the very first fragment
          endAt: lastEdge.endAt # maybe undefined for the very last fragment
          vertices: [firstVertex, otherVertices...]
          side: value

## Phase II: Connecting the fragments

All but the first fragment start at the cutting line.
All but the last fragment end at the cutting line.
(Actually, also the first and the last fragment may start/end at the cutting line, but we don't care.)
These points, where fragments touch the cutting line each have an associated coefficient (I tend to call "lambda").
These lambdas are stored in the `startAt`, `endAt` properties of the fragments and describe the position said start or end
point with respect to the cutting line, i.e. `x = s1 + lambda * (s2 - s1)`.

Let's extract these lambdas and sort them along the cutting line.

      lambdas = flatMap fragments, ({startAt,endAt})->[startAt, endAt]
        .sort()
        .filter (lambda,i,arr)-> lambda? and lambda isnt arr[i-1]

Now that our lambdas are nicely aligned, we observe that when connecting the fragments back together, we always have to connect endpoints
that are lying next to each other on the cutting line. Assuming counter-clock-wise labeling, when we are looking at a fragment on the left
side that ends at `lambda_i`, we need to find the fragment that starts at `lambda_(i+1)` and connect it. For fragments on the right side,
it would be `lambda_(i-1)` instead. If vertices are labeled clock-wise, it's the other way arround.
So let's build a lookup table where we can lookup fragments by their `startAt` property

      fragmentsStartingAt = {}
      fragmentsStartingAt[fragment.startAt] = fragment for fragment in fragments when fragment.startAt?

Next, we create a data structure that will lookup the "peer" of each intersection lambda.

      peerLambdas = {}
      for i in [0...Math.floor(lambdas.length/2)]
        a = lambdas[2*i]
        b = lambdas[2*i+1]
        peerLambdas[a] = b
        peerLambdas[b] = a

We combin both lookups to create a function that can look at the `endAt`-Property of one
fragment and find another fragment to continue the ring with.

      findContinuation = (fragment)-> fragmentsStartingAt[peerLambdas[fragment.endAt]]

Now everything is prepared for connecting the fragments to rings. We take one fragment from our list and try to connect
other fragments to using our lookup table and the rule defined above. All connected fragments are marked "done"; we do not
want to start a ring on a fragment that is already contained in a ring. When we cannot conect any more fragments, we
start the next ring with the next unmarked fragment. We cary on until all fragments are marked done.

      leftRings = []
      rightRings = []

      for startFragment in fragments when not startFragment.done
        ring = startFragment.vertices.slice()
        side = startFragment.side
        fragment = findContinuation startFragment
        while fragment? and fragment isnt startFragment
          ring.push fragment.vertices...
          fragment.done = true
          fragment = findContinuation fragment

        # if the ring did not start at a pseudo vertex,
        # the first and the last vertex will be identical.
        # Fix it.
        ring.pop() if ring[0] is ring[ring.length-1]

        switch
          when side < 0
            leftRings.push ring
          when side > 0
            rightRings.push ring
          else
            throw new Error("Srsly, wtf?!")

      [leftRings, rightRings]

# The cut - Tool

This creates a function that cuts a simple polygon ring along
an infinite line through `s1` and `s2`.

The ring does not need to be convex, but it must be simple, i.e.
not contain self-intersections or zero-length edges.

    module.exports = ([s1,s2])->(ring)->

Most of our lower-level utility functions are already defined

      {coefficients, vInterpolate, vProject, vSubst, vAlmostZero, almostZero
       coefficient, ringEdges, ringArea} = require './common'
      ccw = require './ccw'

      group = require './group'
      flatMap = (arr, transform) -> [].concat((arr.map(transform))...)

We define a special intersection test. Any segment intersects our cutting line
if its end points are not on the same side of the line.
In particular we assume a segment to be "intersecting" if it is actually a subset of the cutting line
i.e. both end points reside *on* the cutting line.
We will, however, need to do some special treatment of these "intersections" later on.

      intersects = (a,b)-> ccw(s1,s2,a,true) * ccw(s1,s2,b,true) <= 0

Each intersection point x lies on the cutting line, so we can describe them
using a coefficient lambda such that x = s1 + lambda (s2-s1).
We will later use this to sort the pseudo-vertices resulting from intersections along
the cutting line.

      mu = coefficient([s1,s2])
      lambda = (a,b)->
        l=coefficients([s1,s2],[a,b])?[0]
        l
      interpolate = vInterpolate(s1,s2)

We calculate the oriented area of the ring.
A positive sign means vertices are labled in counter-clock-wise order
(assuming positive y points "up")
We need this info later.

      area = ringArea ring
      ringIsCCW = (area > 0)

The algorithem comprises two phases:

- in the first phase, the input ring is
  cut down into fragments such that each fragment completly lies on either the
  left or the right side of the cutting line

- int the second phase, the fragments are connected to rings.

## Phase I: cutting the ring into fragments

We start by transforming our ring into a list of edges that are either on the left or the right side
of the cutting line.

      edges = flatMap ringEdges(ring), ([a,b])->
        sideA = - ccw s1, s2, a, true
        sideB = - ccw s1, s2, b, true

We have to handle four (five, actually) different cases:
- when the edge intersects the cutting line we output *two* edges, one on each side.
- when the edge is a subset of the cutting line, we can still associate it with one side:
  If it is in the same direction as the cutting line, and the vertices are labeld counter-clock-wise,
  then we associate it with the left side since the inside of the ring is left. Otherwise we label it right.
- If one of the two edges is on the cutting line, we need to calculate the associated coefficient
  so we can later connect the fragments correctly. (see below)
- the remaining two cases are edges that are entirely on one side.

        switch

          when sideA * sideB < 0
            [lambda] = coefficients [s1,s2],[a,b]
            x = interpolate lambda
            [
              start:a
              end: x
              endAt: lambda
              side: Math.sign sideA
            ,
              start: x
              end: b
              startAt: lambda
              side: Math.sign sideB
            ]

          when sideA is 0 and sideB is 0 # edge is subset of cutting line
            lambdaA = mu a
            lambdaB = mu b
            [
              start: a
              startAt: lambdaA
              end: b
              endAt: lambdaB
              side: if ringIsCCW and lambdaA < lambdaB then -1 else 1
            ]

          when sideA is 0
            [
              start: a
              startAt: mu a
              end: b
              side: Math.sign sideB
            ]
          when sideB is 0
            [
              start: a
              end: b
              endAt: mu b
              side: Math.sign sideA
            ]
          else # same side, none zero
            [
              start: a
              end: b
              side: Math.sign sideA #or sideB, doesn't matter.
            ]

Next we collect consecutive edges that are on the same side into groups. We then transform the
edge groups into fragments.

      fragments = group edges, (edge)->edge.side
        .map ({value, elements})->
          [firstEdge,..., lastEdge] = elements
          firstVertex = firstEdge.start
          otherVertices = elements.map (edge)->edge.end

          startAt: firstEdge.startAt # maybe undefined for the very first fragment
          endAt: lastEdge.endAt # maybe undefined for the very last fragment
          vertices: [firstVertex, otherVertices...]
          side: value

## Phase II: Connecting the fragments

All but the first fragment start at the cutting line.
All but the last fragment end at the cutting line.
(Actually, also the first and the last fragment may start/end at the cutting line, but we don't care.)
These points, where fragments touch the cutting line each have an associated coefficient (I tend to call "lambda").
These lambdas are stored in the `startAt`, `endAt` properties of the fragments and describe the position said start or end
point with respect to the cutting line, i.e. `x = s1 + lambda * (s2 - s1)`.

Let's extract these lambdas and sort them along the cutting line.

      lambdas = flatMap fragments, ({startAt,endAt})->[startAt, endAt]
        .sort()
        .filter (lambda,i,arr)-> lambda? and lambda isnt arr[i-1]

Now that our lambdas are nicely aligned, we observe that when connecting the fragments back together, we always have to connect endpoints
that are lying next to each other on the cutting line. Assuming counter-clock-wise labeling, when we are looking at a fragment on the left
side that ends at `lambda_i`, we need to find the fragment that starts at `lambda_(i+1)` and connect it. For fragments on the right side,
it would be `lambda_(i-1)` instead. If vertices are labeled clock-wise, it's the other way arround.
So let's build a lookup table where we can lookup fragments by their `startAt` property

      fragmentsStartingAt = {}
      fragmentsStartingAt[fragment.startAt] = fragment for fragment in fragments when fragment.startAt?

      peerLambdas = {}
      for i in [0...Math.floor(lambdas.length/2)]
        a = lambdas[2*i]
        b = lambdas[2*i+1]
        peerLambdas[a] = b
        peerLambdas[b] = a

      findContinuation = (fragment)-> fragmentsStartingAt[peerLambdas[fragment.endAt]]

Now everything is prepared for connecting the fragments to rings. We take one fragment from our list and try to connect
other fragments to using our lookup table and the rule defined above. All connected fragments are marked "done"; we do not
want to start a ring on a fragment that is already contained in a ring. When we cannot conect any more fragments, we
start the next ring with the next unmarked fragment. We cary on until all fragments are marked done.

      leftRings = []
      rightRings = []

      for startFragment in fragments when not startFragment.done
        ring = startFragment.vertices.slice()
        side = startFragment.side
        fragment = findContinuation startFragment
        while fragment? and fragment isnt startFragment
          ring.push fragment.vertices...
          fragment.done = true
          fragment = findContinuation fragment

        # if the ring did not start at a pseudo vertex,
        # the first and the last vertex will be identical.
        # Fix it.
        ring.pop() if ring[0] is ring[ring.length-1]

        switch
          when side < 0
            leftRings.push ring
          when side > 0
            rightRings.push ring
          else
            throw new Error("Srsly, wtf?!")

      [leftRings, rightRings]