Began working on arm animation.

Began working on arm animation.

# game

This module contains your game logic.  Its methods are called by the "index"
module to update the game state.

    gamepad = require "./input/gamepad.litcoffee"
    keyboard = require "./input/keyboard.litcoffee"

    context = require "./rendering/context.litcoffee"
    cloud = require "./rendering/cloud.litcoffee"
    matrix = require "./matrix.litcoffee"
    plane = require "./plane.litcoffee"
    misc = require "./misc.litcoffee"
    navmesh = require "./navmesh.litcoffee"
    vector = require "./vector.litcoffee"
    pose = require "./pose.litcoffee"
    ik = require "./ik.litcoffee"

    triangle = undefined

    character = testMap = testNavmesh = undefined
    characterData = require "./characters/test/cloud.coffee"

# load
Called before the first "tick"/"draw" to load any resources needed by the game.
Execute the argument when you have finished successfully.

    load = (callback) ->
        keyboard()
        context.load()
        cloud.load characterData, (character_) ->
            character = character_
            cloud.load (require "./tracks/test/geometry.msc"), (testMap_) ->
                testMap = testMap_
                navmesh.load (require "./tracks/test/navmesh.msn"), (testNavmesh_) ->
                    testNavmesh = testNavmesh_
                    triangle = testNavmesh[0]
                    callback()
                    return
                return
            return
        return

# tick
Called at 20Hz to update game state.  Guaranteed to be called once between
"load" and "draw".  May be called more or than once per call to "draw" or not at
all.

    firstTick = true
    firstDraw = true

    entityTransform = []
    entityTransformToDraw = []
    entityTransformPreviousTick = []
    entityTransformPreviousDraw = []
    matrix.identity entityTransform

    playerPoseOld = pose.create characterData
    playerPoseNew = pose.create characterData

    torsoTransform = []
    torsoTransformToDraw = []
    torsoTransformPreviousTick = []
    torsoTransformPreviousDraw = []

    surfaceCorrectedEntityTransform = []
    matrix.identity surfaceCorrectedEntityTransform

    cameraTransform = []
    cameraTransformPreviousDraw = []
    matrix.identity cameraTransform

    torsoAltitude = 0

    velocity = [0, 0, 0]
    xAxis = []
    yAxis = []
    zAxis = []
    torsoXAxis = []
    torsoZAxis = []
    translation = []
    targetForwardVelocity = []
    targetSidewardVelocity = []
    targetVelocity = []
    torsoTranslation = []

    start = []
    leftFoot = []
    rightFoot = []
    leftHand = []
    leftHandPreviousTick = []
    leftHandToDraw = []
    rightHand = []
    rightHandPreviousTick = []
    rightHandToDraw = []
    walked = 0
    shuffleTicks = 0
    foot = "left"
    ticksSinceLeft = 0
    ticksSinceRight = 0
    offset = []

    yaw = 0
    pitch = 0
    headYawPreviousTick = headYaw = 0

    stick = [0, 0, 0]
    stickAngle = 0

    edgeCallback = (edge) -> vector.flatten velocity, edge.plane.normal, velocity

    tick = ->
        if not firstTick
            matrix.copy entityTransform, entityTransformPreviousTick
            matrix.copy torsoTransform, torsoTransformPreviousTick
            vector.copy leftHand, leftHandPreviousTick
            vector.copy rightHand, rightHandPreviousTick

        matrix.translate velocity, entityTransform
        speed = vector.magnitude velocity
        walked += speed
        moving = speed > 2

        stick[0] = gamepad.right - gamepad.left
        stick[1] = gamepad.forward - gamepad.backward
        stickLength = vector.magnitude stick

        inDeadzone = stickLength < 0.1

        if inDeadzone
            stick[0] = stick[1] = 0
        else
            stickAngle = Math.atan2 -stick[0], stick[1]
            if stickLength > 1
                vector.divide.byScalar stick, stickLength, stick
                stickLength = 1

        # Left/right rotation.
        matrix.rotateY (stick[0] * -0.1), entityTransform, true

        # Apply navmesh triangle collision.
        matrix.getTranslation entityTransform, translation
        triangle = navmesh.constrain translation, triangle, edgeCallback

        # Gravity.
        velocity[1] -= 0.2

        # Forwards/backwards movement.
        matrix.getZ entityTransform, zAxis

        # Determine if we're underground.
        altitude = plane.distance triangle.plane, translation

        if altitude < 0
            velocity = velocity
            plane.project triangle.plane, translation, translation

            # A "bump" when you land.
            matrix.getY entityTransform, yAxis
            impact = Math.abs (vector.dot triangle.plane.normal, velocity) * (vector.dot triangle.plane.normal, yAxis)
            impact -= 1
            if impact < 0 then impact = 0
            impact *= 2
            torsoAltitude -= impact

            # Reflecting the velocity against the hit surface but then
            # flattening it has the effect that hitting a ramp bounces you up it
            # but you don't bounce when falling onto the floor.
            vector.reflect velocity, triangle.plane.normal, velocity
            vector.flatten velocity, triangle.plane.normal, velocity

            if not inDeadzone
                matrix.getX entityTransform, xAxis
                vector.multiply.byScalar zAxis, (stick[1] * 10), targetForwardVelocity
                vector.multiply.byScalar xAxis, (stick[0] * 10), targetSidewardVelocity
                vector.add.vector targetForwardVelocity, targetSidewardVelocity, targetVelocity
            else
                targetVelocity[0] = targetVelocity[1] = targetVelocity[2] = 0
            vector.interpolate velocity, targetVelocity, 0.05, velocity

        # Apply air resistance.
        vector.multiply.byScalar velocity, 0.98, velocity

        # This section attempts to align the entity with the triangle surface.

        # We take the triangle's normal as the Y/up axis.

        # First, flatten the Z/forward axis onto the surface.
        vector.flatten zAxis, triangle.plane.normal, zAxis
        vector.normalize zAxis, zAxis

        # Then, find the X/right axis which is perpendicular to the Z/forward
        # and Y/up axes.
        vector.cross triangle.plane.normal, zAxis, xAxis
        matrix.setX xAxis, surfaceCorrectedEntityTransform
        matrix.setY triangle.plane.normal, surfaceCorrectedEntityTransform
        matrix.setZ zAxis, surfaceCorrectedEntityTransform

        # Blend between our current transform and the aligned one.
        matrix.interpolate entityTransform, surfaceCorrectedEntityTransform, 0.1, entityTransform

        matrix.setTranslation translation, entityTransform

        matrix.copy entityTransform, torsoTransform

        torsoAltitude = misc.interpolate torsoAltitude, (12 - Math.min 2, (speed + if inDeadzone then 0 else 1.5)), 0.4

        matrix.getY entityTransform, yAxis
        vector.multiply.byScalar yAxis, torsoAltitude, torsoTranslation
        vector.add.vector torsoTranslation, translation, torsoTranslation

        yaw = misc.interpolateAngle yaw, stickAngle, 0.1, yaw
        matrix.rotateY yaw, torsoTransform, true

        # Calculating the head angle relative to the torso is complicated by the
        # stick angle being wrapped to 0...2PI, so we have to shift it out of
        # that range to clamp it.
        headYawPreviousTick = headYaw
        headYaw = Math.max Math.PI - 1, Math.min Math.PI + 1, misc.wrapAngle Math.PI + stickAngle - yaw
        headYaw -= Math.PI
        headYaw = misc.interpolateAngle headYawPreviousTick, headYaw, 0.4, headYaw

        matrix.getZ torsoTransform, torsoZAxis # TODO: If the entity transform is ever non-identity at startup we'll need to initialize torsoTransform for this to be right in the first ticks.
        matrix.getX torsoTransform, torsoXAxis # TODO: If the entity transform is ever non-identity at startup we'll need to initialize torsoTransform for this to be right in the first ticks.
        pitch = misc.interpolate pitch, (0.5 * stickLength - 0.1 * vector.dot torsoZAxis, velocity), 0.4
        matrix.rotateX pitch, torsoTransform, true
        matrix.rotateZ (0.1 * vector.dot torsoXAxis, velocity), torsoTransform, true

        matrix.setTranslation torsoTranslation, torsoTransform

        shuffleTicks--
        ticksSinceLeft++
        ticksSinceRight++
        while walked > 5 or shuffleTicks < 0
            shuffleTicks = 5
            walked -= 5
            if (not inDeadzone) or moving
                vector.normalize velocity, offset
                vector.multiply.byScalar offset, 5, offset
            else
                offset[0] = offset[1] = offset[2] = 0
            foot = switch foot
                when "left"
                    matrix.applyToVector playerPoseNew.torso, [-2, -10, 0], leftFoot
                    vector.add.vector offset, leftFoot, leftFoot
                    plane.project triangle.plane, leftFoot, leftFoot
                    ticksSinceLeft = 0
                    "right"
                when "right"
                    matrix.applyToVector playerPoseNew.torso, [2, -10, 0], rightFoot
                    vector.add.vector offset, rightFoot, rightFoot
                    plane.project triangle.plane, rightFoot, rightFoot
                    ticksSinceRight = 0
                    "left"

        if inDeadzone
            leftHand[0] = -6
            rightHand[0] = 6
            leftHand[1] = rightHand[1] = -4
            leftHand[2] = rightHand[2] = 0
        else
            yScale = 7 / (1 + speed)
            rightHand[0] = 2 + (Math.min 4, speed)
            leftHand[0] = -rightHand[0]

            leftHand[1] = rightHand[1] = 3
            motion = Math.pow (Math.cos ticksSinceLeft * 0.25) * 0.5 + 0.5, 4
            leftHand[1] += yScale * motion
            leftHand[2] = 1.5 + 6 * stickLength * motion
            motion = Math.pow (Math.cos ticksSinceRight * 0.25) * 0.5 + 0.5, 4
            rightHand[1] += yScale * motion
            rightHand[2] = 1.5 + 6 * stickLength * motion

        matrix.applyToVector torsoTransform, leftHand, leftHand
        matrix.applyToVector torsoTransform, rightHand, rightHand

        leftHand[1] -= 2
        rightHand[1] -= 2

        if firstTick
            matrix.copy entityTransform, entityTransformPreviousTick
            matrix.copy torsoTransform, torsoTransformPreviousTick
            vector.copy leftHand, leftHandPreviousTick
            vector.copy rightHand, rightHandPreviousTick
            firstTick = false

        lag = 0.15 + 0.4 / (1 + speed / 3)
        if inDeadzone then lag = 0.2
        vector.interpolate leftHandPreviousTick, leftHand, lag, leftHand
        vector.interpolate rightHandPreviousTick, rightHand, lag, rightHand

        return

# draw
Called with the progress through the current frame (a number between 0 and 1) to
redraw the scene.

    draw = (progress) ->

        if not firstDraw
            matrix.copy entityTransformToDraw, entityTransformPreviousDraw
            matrix.copy cameraTransform, cameraTransformPreviousDraw
            matrix.copy torsoTransformToDraw, torsoTransformPreviousDraw
            pose.copy playerPoseNew, playerPoseOld

        matrix.interpolate entityTransformPreviousTick, entityTransform, progress, entityTransformToDraw
        matrix.interpolate torsoTransformPreviousTick, torsoTransform, progress, playerPoseNew.torso

        matrix.invert entityTransformToDraw, cameraTransform
        matrix.translate [0,-10, 10], cameraTransform

        matrix.applyToVector playerPoseNew.torso, [-1.5, -2.5, 0], start
        matrix.getX playerPoseNew.torso, xAxis
        ik.computeLimb start, leftFoot, 10, xAxis, playerPoseNew.legLeftUpper, playerPoseNew.legLeftLower

        matrix.applyToVector playerPoseNew.torso, [1.5, -2.5, 0], start
        ik.computeLimb start, rightFoot, 10, xAxis, playerPoseNew.legRightUpper, playerPoseNew.legRightLower

        matrix.getY playerPoseNew.torso, yAxis
        vector.negate xAxis, xAxis
        vector.interpolate xAxis, yAxis, 0.05, offset

        matrix.applyToVector playerPoseNew.torso, [-1.5, 4, 0], start
        vector.interpolate leftHandPreviousTick, leftHand, progress, leftHandToDraw
        ik.computeLimb start, leftHandToDraw, 10, offset, playerPoseNew.armLeftUpper, playerPoseNew.armLeftLower

        vector.negate yAxis, yAxis
        vector.interpolate xAxis, yAxis, 0.05, offset

        matrix.applyToVector playerPoseNew.torso, [1.5, 4, 0], start
        vector.interpolate rightHandPreviousTick, rightHand, progress, rightHandToDraw
        ik.computeLimb start, rightHandToDraw, 10, offset, playerPoseNew.armRightUpper, playerPoseNew.armRightLower

        matrix.copy playerPoseNew.torso, playerPoseNew.head
        matrix.translate [0, 6, 0], playerPoseNew.head, true
        matrix.rotateY (misc.interpolate headYawPreviousTick, headYaw, progress), playerPoseNew.head, true

        if firstDraw
            matrix.copy entityTransformToDraw, entityTransformPreviousDraw
            matrix.copy cameraTransform, cameraTransformPreviousDraw
            pose.copy playerPoseNew, playerPoseOld
            firstDraw = false

        context.begin 0, 0, context.width, context.height, 1, cameraTransformPreviousDraw, cameraTransform, 0.1, 0.5, 0.9
        cloud.draw testMap
        cloud.draw character, playerPoseOld, playerPoseNew

        return

    module.exports = { load, tick, draw }

# game

This module contains your game logic.  Its methods are called by the "index"
module to update the game state.

    gamepad = require "./input/gamepad.litcoffee"
    keyboard = require "./input/keyboard.litcoffee"

    context = require "./rendering/context.litcoffee"
    cloud = require "./rendering/cloud.litcoffee"
    matrix = require "./matrix.litcoffee"
    plane = require "./plane.litcoffee"
    misc = require "./misc.litcoffee"
    navmesh = require "./navmesh.litcoffee"
    vector = require "./vector.litcoffee"
    pose = require "./pose.litcoffee"
    ik = require "./ik.litcoffee"

    triangle = undefined

    character = testMap = testNavmesh = undefined
    characterData = require "./characters/test/cloud.coffee"

# load
Called before the first "tick"/"draw" to load any resources needed by the game.
Execute the argument when you have finished successfully.

    load = (callback) ->
        keyboard()
        context.load()
        cloud.load characterData, (character_) ->
            character = character_
            cloud.load (require "./tracks/test/geometry.msc"), (testMap_) ->
                testMap = testMap_
                navmesh.load (require "./tracks/test/navmesh.msn"), (testNavmesh_) ->
                    testNavmesh = testNavmesh_
                    triangle = testNavmesh[0]
                    callback()
                    return
                return
            return
        return

# tick
Called at 20Hz to update game state.  Guaranteed to be called once between
"load" and "draw".  May be called more or than once per call to "draw" or not at
all.

    firstTick = true
    firstDraw = true

    entityTransform = []
    entityTransformToDraw = []
    entityTransformPreviousTick = []
    entityTransformPreviousDraw = []
    matrix.identity entityTransform

    playerPoseOld = pose.create characterData
    playerPoseNew = pose.create characterData

    torsoTransform = []
    torsoTransformToDraw = []
    torsoTransformPreviousTick = []
    torsoTransformPreviousDraw = []

    surfaceCorrectedEntityTransform = []
    matrix.identity surfaceCorrectedEntityTransform

    cameraTransform = []
    cameraTransformPreviousDraw = []
    matrix.identity cameraTransform

    torsoAltitude = 0

    velocity = [0, 0, 0]
    xAxis = []
    yAxis = []
    zAxis = []
    torsoXAxis = []
    torsoZAxis = []
    translation = []
    targetForwardVelocity = []
    targetSidewardVelocity = []
    targetVelocity = []
    torsoTranslation = []

    start = []
    leftFoot = []
    rightFoot = []
    walked = 0
    shuffleTicks = 0
    foot = "left"
    offset = []

    yaw = 0
    pitch = 0
    headYawPreviousTick = headYaw = 0

    stick = [0, 0, 0]
    stickAngle = 0

    edgeCallback = (edge) -> vector.flatten velocity, edge.plane.normal, velocity

    tick = ->
        if not firstTick
            matrix.copy entityTransform, entityTransformPreviousTick
            matrix.copy torsoTransform, torsoTransformPreviousTick

        matrix.translate velocity, entityTransform
        speed = vector.magnitude velocity
        walked += speed
        moving = speed > 2

        stick[0] = gamepad.right - gamepad.left
        stick[1] = gamepad.forward - gamepad.backward
        stickLength = vector.magnitude stick

        inDeadzone = stickLength < 0.1

        if inDeadzone
            stick[0] = stick[1] = 0
        else
            stickAngle = Math.atan2 -stick[0], stick[1]
            if stickLength > 1
                vector.divide.byScalar stick, stickLength, stick
                stickLength = 1

        # Left/right rotation.
        matrix.rotateY (stick[0] * -0.1), entityTransform, true

        # Apply navmesh triangle collision.
        matrix.getTranslation entityTransform, translation
        triangle = navmesh.constrain translation, triangle, edgeCallback

        # Gravity.
        velocity[1] -= 0.2

        # Forwards/backwards movement.
        matrix.getZ entityTransform, zAxis

        # Determine if we're underground.
        altitude = plane.distance triangle.plane, translation

        if altitude < 0
            velocity = velocity
            plane.project triangle.plane, translation, translation

            # A "bump" when you land.
            matrix.getY entityTransform, yAxis
            impact = Math.abs (vector.dot triangle.plane.normal, velocity) * (vector.dot triangle.plane.normal, yAxis)
            impact -= 1
            if impact < 0 then impact = 0
            impact *= 2
            torsoAltitude -= impact

            # Reflecting the velocity against the hit surface but then
            # flattening it has the effect that hitting a ramp bounces you up it
            # but you don't bounce when falling onto the floor.
            vector.reflect velocity, triangle.plane.normal, velocity
            vector.flatten velocity, triangle.plane.normal, velocity

            if not inDeadzone
                matrix.getX entityTransform, xAxis
                vector.multiply.byScalar zAxis, (stick[1] * 10), targetForwardVelocity
                vector.multiply.byScalar xAxis, (stick[0] * 10), targetSidewardVelocity
                vector.add.vector targetForwardVelocity, targetSidewardVelocity, targetVelocity
            else
                targetVelocity[0] = targetVelocity[1] = targetVelocity[2] = 0
            vector.interpolate velocity, targetVelocity, 0.05, velocity

        # Apply air resistance.
        vector.multiply.byScalar velocity, 0.98, velocity

        # This section attempts to align the entity with the triangle surface.

        # We take the triangle's normal as the Y/up axis.

        # First, flatten the Z/forward axis onto the surface.
        vector.flatten zAxis, triangle.plane.normal, zAxis
        vector.normalize zAxis, zAxis

        # Then, find the X/right axis which is perpendicular to the Z/forward
        # and Y/up axes.
        vector.cross triangle.plane.normal, zAxis, xAxis
        matrix.setX xAxis, surfaceCorrectedEntityTransform
        matrix.setY triangle.plane.normal, surfaceCorrectedEntityTransform
        matrix.setZ zAxis, surfaceCorrectedEntityTransform

        # Blend between our current transform and the aligned one.
        matrix.interpolate entityTransform, surfaceCorrectedEntityTransform, 0.1, entityTransform

        matrix.setTranslation translation, entityTransform

        matrix.copy entityTransform, torsoTransform

        torsoAltitude = misc.interpolate torsoAltitude, (12 - Math.min 2, (speed + if inDeadzone then 0 else 1.5)), 0.4

        matrix.getY entityTransform, yAxis
        vector.multiply.byScalar yAxis, torsoAltitude, torsoTranslation
        vector.add.vector torsoTranslation, translation, torsoTranslation

        yaw = misc.interpolateAngle yaw, stickAngle, 0.1, yaw
        matrix.rotateY yaw, torsoTransform, true

        # Calculating the head angle relative to the torso is complicated by the
        # stick angle being wrapped to 0...2PI, so we have to shift it out of
        # that range to clamp it.
        headYawPreviousTick = headYaw
        headYaw = Math.max Math.PI - 1, Math.min Math.PI + 1, misc.wrapAngle Math.PI + stickAngle - yaw
        headYaw -= Math.PI
        headYaw = misc.interpolateAngle headYawPreviousTick, headYaw, 0.4, headYaw

        matrix.getZ torsoTransform, torsoZAxis # TODO: If the entity transform is ever non-identity at startup we'll need to initialize torsoTransform for this to be right in the first ticks.
        matrix.getX torsoTransform, torsoXAxis # TODO: If the entity transform is ever non-identity at startup we'll need to initialize torsoTransform for this to be right in the first ticks.
        pitch = misc.interpolate pitch, (0.5 * stickLength - 0.1 * vector.dot torsoZAxis, velocity), 0.2
        matrix.rotateX pitch, torsoTransform, true
        matrix.rotateZ (0.1 * vector.dot torsoXAxis, velocity), torsoTransform, true

        matrix.setTranslation torsoTranslation, torsoTransform

        if walked < 5
            shuffleTicks--
        while walked > 5 or shuffleTicks < 0
            shuffleTicks = 5
            walked -= 5
            if (not inDeadzone) or moving
                vector.normalize velocity, offset
                vector.multiply.byScalar offset, 5, offset
            else
                offset[0] = offset[1] = offset[2] = 0
            foot = switch foot
                when "left"
                    matrix.applyToVector playerPoseNew.torso, [-2, -10, 0], leftFoot
                    vector.add.vector offset, leftFoot, leftFoot
                    plane.project triangle.plane, leftFoot, leftFoot
                    "right"
                when "right"
                    matrix.applyToVector playerPoseNew.torso, [2, -10, 0], rightFoot
                    vector.add.vector offset, rightFoot, rightFoot
                    plane.project triangle.plane, rightFoot, rightFoot
                    "left"

        if firstTick
            matrix.copy entityTransform, entityTransformPreviousTick
            matrix.copy torsoTransform, torsoTransformPreviousTick
            firstTick = false
        return

# draw
Called with the progress through the current frame (a number between 0 and 1) to
redraw the scene.

    draw = (progress) ->

        if not firstDraw
            matrix.copy entityTransformToDraw, entityTransformPreviousDraw
            matrix.copy cameraTransform, cameraTransformPreviousDraw
            matrix.copy torsoTransformToDraw, torsoTransformPreviousDraw
            pose.copy playerPoseNew, playerPoseOld

        matrix.interpolate entityTransformPreviousTick, entityTransform, progress, entityTransformToDraw
        matrix.interpolate torsoTransformPreviousTick, torsoTransform, progress, playerPoseNew.torso

        matrix.invert entityTransformToDraw, cameraTransform
        matrix.translate [0,-10, 10], cameraTransform

        matrix.applyToVector playerPoseNew.torso, [-1.5, -2.5, 0], start
        matrix.getX playerPoseNew.torso, xAxis
        ik.computeLimb start, leftFoot, 10, xAxis, playerPoseNew.legLeftUpper, playerPoseNew.legLeftLower

        matrix.applyToVector playerPoseNew.torso, [1.5, -2.5, 0], start
        ik.computeLimb start, rightFoot, 10, xAxis, playerPoseNew.legRightUpper, playerPoseNew.legRightLower

        matrix.copy playerPoseNew.torso, playerPoseNew.head
        matrix.translate [0, 6, 0], playerPoseNew.head, true
        matrix.rotateY (misc.interpolate headYawPreviousTick, headYaw, progress), playerPoseNew.head, true

        if firstDraw
            matrix.copy entityTransformToDraw, entityTransformPreviousDraw
            matrix.copy cameraTransform, cameraTransformPreviousDraw
            pose.copy playerPoseNew, playerPoseOld
            firstDraw = false

        context.begin 0, 0, context.width, context.height, 1, cameraTransformPreviousDraw, cameraTransform, 0.1, 0.5, 0.9
        cloud.draw testMap
        cloud.draw character, playerPoseOld, playerPoseNew

        return

    module.exports = { load, tick, draw }


modify README

modify README

# loopback-with-admin

run loopback server with admin and push notification features.

# install

```bash
npm install loopback-with-admin
```

# simplest run

    models =
        'user':
            base: 'User'

    require('loopback-with-admin').run(models).then (lbInfo) ->

        console.log lbInfo.getURL()         # loopback api root
        console.log lbInfo.getAccessToken() # access token of admin

# run with config dir

before running, you can prepare a directory which contains custom config information.

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
`-- production
    `-- datasources.coffee
```

    lbWithAdmin = require 'loopback-with-admin'

    configDir = '/path/to/config-dir'

    lbWithAdmin.run(configDir).then ->
        # loopback started

# run with config

    lbWithAdmin = require 'loopback-with-admin'

    lbWithAdmin.run(models, server: port: 3001).then ->

# admin
(coming soon)

# push notification
(coming soon)

# configs

these are the config names.

- admin
- datasources
- middleware
- server
- push-credentials

see JSON files in "default-values/non-model-configs" directory.
you can set the same properties as these JSONs.

## admin

 config key  | meaning
-------------|-----------------------
 accessToken | accessToken for admin

## datasources

 config key  | meaning
-------------|-----------------------
 memory      | on memory datasource
 db          | datasource for custom entities

## server

 config key  | meaning       | default
-------------|---------------|----------------
 restApiRoot | REST api root | /api
 port        | port number   | 3000

## push-credentials

 config key      | meaning
-----------------|-------------------------------------------
 gcmServerApiKey | api key for Google Cloud Messaging (GCM)
 apnsCertData    | certificate pem contents for APNs
 apnsKeyData     | key pem contents for APNs

# model definitions

    models =
        player: # model name
            base: 'User'
            aclType: 'admin' # specific for this system

        instrument:
            aclType: 'owner-read'

the same format as [loopback model definition](http://docs.strongloop.com/display/public/LB/Customizing+models)
except "aclType" value.
name is automatically set from definition information.
plural is set to the same value as name if not set manually.

## aclType
loopback-with-admin generates acls from aclType.

three types are available.

 aclType     | meaning
-------------|-----------------------------------------------------
 admin       | only admin can CRUD the model
 owner       | admin and the owner of the model can CRUD
 public-read | everyone can READ the model and admin can CRUD
 none        | everyone can CRUD the model

# switching environment

running script with environment variable "NODE\_ENV" like

```bash
$ NODE_ENV=production node app.js
```

"development" is selected by default.

when your config dir is

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
|-- local
|   `-- datasources.coffee
|-- production
|   `-- datasources.coffee
```

and launching script like

```bash
$ NODE_ENV=local node app.js
```
then, loopback-with-admin selects configs in "local" directory.

## passing custom environment with argument

    env = 'production'

    lbWithAdmin.run(configDir, env)

env is prior to NODE\_ENV settings.

# modified loopback-datasource-juggler

using [CureApp/loopback-datasource-juggler](https://github.com/CureApp/loopback-datasource-juggler).

this repository is almost the same as original one except 'memory' connector handles id as string
(orignally integer).

# loopback-with-admin

run loopback server with admin and push notification features.

# install

```bash
npm install loopback-with-admin
```

# simplest run

    require('loopback-with-admin').run().then (lbInfo) ->

        console.log lbInfo.getURL()         # loopback api root
        console.log lbInfo.getAccessToken() # access token of admin

# run with config dir

before running, you can prepare a directory which contains custom config information.

```text
(config-dir) # any name is acceptable
|-- model-definitions.coffee
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
`-- production
    `-- datasources.coffee
```

    lbWithAdmin = require 'loopback-with-admin'

    configDir = '/path/to/config-dir'

    lbWithAdmin.run(configDir).then ->
        # loopback started

# run with config dir

    lbWithAdmin = require 'loopback-with-admin'

    lbWithAdmin.run(server: port: 3001).then ->

# admin
(coming soon)

# push notification
(coming soon)

# configs

these are the config names.

- admin
- datasources
- middleware
- server
- push-credentials

see JSON files in "default-values/non-model-configs" directory.
you can set the same properties as these JSONs.

## admin

 config key  | meaning
-------------|-----------------------
 accessToken | accessToken for admin

## datasources

 config key  | meaning
-------------|-----------------------
 memory      | on memory datasource
 db          | datasource for custom entities

## server

 config key  | meaning       | default
-------------|---------------|----------------
 restApiRoot | REST api root | /api
 port        | port number   | 3000

## push-credentials

 config key      | meaning
-----------------|-------------------------------------------
 gcmServerApiKey | api key for Google Cloud Messaging (GCM)
 apnsCertData    | certificate pem contents for APNs
 apnsKeyData     | key pem contents for APNs

# model definitions

    module.exports =
        player: # model name
            base: 'User'  # the same as loopback model settings.base
            aclType: 'admin' # specific for this system

        instrument:
            aclType: 'owner-read'

the same format as [loopback model definition](http://docs.strongloop.com/display/public/LB/Customizing+models)
except "aclType" value.
name is automatically set from definition information.
plural is set to the same value as name if not set manually.

## aclType
loopback-with-admin generates acls from aclType.

three types are available.

 aclType     | meaning
-------------|-----------------------------------------------------
 admin       | only admin can CRUD the model
 owner       | admin and the owner of the model can CRUD
 public-read | everyone can READ the model and admin can CRUD
 none        | everyone can CRUD the model

# switching environment

running script with environment variable "NODE\_ENV" like

```bash
$ NODE_ENV=production node app.js
```

"development" is selected by default.

when your config dir is

```text
(config-dir) # any name is acceptable
|-- common
|   |-- server.coffee
|   `-- admin.coffee
|-- development
|   `-- datasources.coffee
|-- local
|   `-- datasources.coffee
|-- production
|   `-- datasources.coffee
```

and launching script like

```bash
$ NODE_ENV=local node app.js
```
then, loopback-with-admin selects configs in "local" directory.

## passing custom environment with argument

    env = 'production'

    lbWithAdmin.run(configDir, env)

env is prior to NODE\_ENV settings.

# modified loopback-datasource-juggler

using [CureApp/loopback-datasource-juggler](https://github.com/CureApp/loopback-datasource-juggler).

this repository is almost the same as original one except 'memory' connector handles id as string
(orignally integer).


fix for cases when element update/merge into a new extension

# Element - cascading element tree

## Class Element

    debug = require('debug')('yang:element')
    delegate = require 'delegates'
    Emitter = require('events').EventEmitter
    Emitter.defaultMaxListeners = 100

    kIndex = Symbol.for('element:index');
    kCache = Symbol.for('element:cache');

    class Element

      @property: (prop, desc) ->
        Object.defineProperty @prototype, prop, desc

      @use: ->
        res = [].concat(arguments...)
          .filter (x) -> x?
          .map (elem) =>
            exists = Element::match.call this, elem.kind, elem.tag
            if exists?
              debug "use: using previously loaded '#{elem.kind}:#{elem.tag}'"
              return exists
            try Element::merge.call this, elem
            catch e
              throw @error "use: unable to merge '#{elem.kind}:#{elem.tag}'", e
        return switch
          when res.length > 1  then res
          when res.length is 1 then res[0]
          else undefined

      @debug: -> debug @uri, arguments...

      @error: (err, ctx) ->
        err = new Error err unless err instanceof Error
        err.uri = @uri
        err.src = this
        err.ctx = ctx
        return err

      constructor: (@kind, @tag, scope) ->
        unless @kind?
          throw @error "must supply 'kind' to create a new Element"

        @scope = scope if scope?

        Object.defineProperties this,
          parent: value: null, writable: true
          origin: value: null, writable: true
          state:  value: {}, writable: true
          [kIndex]: value: 0, writable: true
          emitter: value: new Emitter

      error: @error
      debug: @debug

      delegate @prototype, 'emitter'
        .method 'emit'
        .method 'once'
        .method 'on'
        .method 'off'

### Computed Properties

      @property 'datakey',
        get: -> @tag ? @kind

      @property 'uri',
        get: -> switch
          when @parent instanceof Element
            mark = @kind
            mark += "(#{@tag})" if @tag? and @parent.scope?[@kind] in [ '0..n', '1..n', '*' ]
            "#{@parent.uri}/#{mark}"
          when @tag?
            "#{@kind}(#{@tag})"
          else
            @kind

      @property 'root',
        get: -> switch
          when @parent instanceof Element then @parent.root
          when @origin instanceof Element then @origin.root
          else this

      @property 'children',
        get: ->
          unless this[kCache]?
            elements = (v for own k, v of this when k not in [ 'parent', 'origin', 'tag', kCache, 'source' ])
              .reduce ((a,b) -> switch
                when b instanceof Element then a.concat b
                when b instanceof Array
                  a.concat b.filter (x) -> x instanceof Element
                else a
              ), []
            this[kCache] = elements.sort (a,b) -> a[kIndex] - b[kIndex]
          return this[kCache];

      @property '*',  get: -> @children
      @property '..', get: -> @parent

## Instance-level methods

### clone

      clone: (opts={}) ->
        { origin = @origin, relative = true } = opts
        @debug "cloning #{@kind}:#{@tag} with #{@children.length} elements"
        copy = (new @constructor @kind, @tag, @source).extends @children.map (x) -> x.clone opts
        copy.state = Object.create(@state)
        copy.state.relative = relative
        copy.origin = origin ? this
        return copy

### extends (elements...)

This is the primary mechanism for defining sub-elements to become part
of the element tree

      extends: ->
        elems = ([].concat arguments...).filter (x) -> x? and !!x
        return this unless elems.length > 0
        elems.forEach (expr) => @merge expr
        @emit 'change', elems...
        return this

### merge (element)

This helper method merges a specific Element into current Element
while performing `@scope` validations.

      merge: (elem, opts={}) ->
        unless elem instanceof Element
          throw @error "cannot merge invalid element into Element", elem

        elem.parent = this
        elem[kIndex] = @children.length if @children?
        this[kCache] = null

        _merge = (item) ->
          if not item.node or opts.append or item.datakey not in (@keys ? [])
            @push item
            true
          else if opts.replace is true
            for x, i in this when x.datakey is item.datakey
              @splice i, 1, item
              break
            true
          else false

        unless @scope?
          unless @hasOwnProperty elem.kind
            @[elem.kind] = elem
            return elem

          unless Array.isArray @[elem.kind]
            exists = @[elem.kind]
            @[elem.kind] = [ exists ]
            Object.defineProperty @[elem.kind], 'keys',
              get: (-> @map (x) -> x.datakey ).bind @[elem.kind]
          unless _merge.call @[elem.kind], elem
            throw @error "constraint violation for '#{elem.kind} #{elem.datakey}' - cannot define more than once"

          return elem

        unless elem.kind of @scope
          if elem.scope? and (not elem.source.state.unbound and not @source.state.unbound)
            @debug @scope
            throw @error "scope violation - invalid '#{elem.kind}' extension found"
          else
            @scope[elem.kind] = '*' # this is hackish...

        switch @scope[elem.kind]
          when '0..n', '1..n', '*'
            unless @hasOwnProperty elem.kind
              @[elem.kind] = []
              Object.defineProperty @[elem.kind], 'keys',
                get: (-> @map (x) -> x.datakey ).bind @[elem.kind]
            unless Array.isArray @[elem.kind]
              exists = @[elem.kind]
              @[elem.kind] = [ exists ]
              Object.defineProperty @[elem.kind], 'keys',
                get: (-> @map (x) -> x.datakey ).bind @[elem.kind]
            unless _merge.call @[elem.kind], elem
              throw @error "constraint violation for '#{elem.kind} #{elem.datakey}' - already defined"
          when '0..1', '1'
            unless @hasOwnProperty elem.kind
              @[elem.kind] = elem
            else if opts.replace is true
              @debug "replacing pre-existing #{elem.kind}"
              @[elem.kind] = elem
            else
              throw @error "constraint violation for '#{elem.kind}' - cannot define more than once"
          else
            throw @error "unrecognized scope constraint defined for '#{elem.kind}' with #{@scope[elem.kind]}"

        return elem

      removes: ->
        elems = ([].concat arguments...).filter (x) -> x? and !!x
        return this unless elems.length > 0
        elems.forEach (expr) => @remove expr
        @emit 'change', elems...
        return this

      remove: (elem) ->
        unless elem instanceof Element
          throw @error "cannot remove a non-Element from an Element", elem

        exists = Element::match.call this, elem.kind, elem.datakey
        return this unless exists?

        if Array.isArray @[elem.kind]
          @[elem.kind] = @[elem.kind].filter (x) -> x.datakey isnt elem.datakey
          delete @[elem.kind] unless @[elem.kind].length
        else
          delete @[elem.kind]

        this[kCache] = null
        return this

### update (element)

This alternative form of [merge](#merge-element) performs conditional
merge based on existence check. It is considered *safer* alternative
to direct [merge](#merge-element) call.

      # performs conditional merge based on existence
      update: (elem) ->
        unless elem instanceof Element
          throw @error "cannot update a non-Element into an Element", elem

        #@debug "update with #{elem.kind}/#{elem.tag}"
        exists = switch
          when elem.tag? then Element::match.call this, elem.kind, elem.datakey
          else Element::match.call this, elem.kind
        return @merge elem unless exists?

        #@debug "update #{exists.kind} in-place for #{elem.children.length} elements"
        exists.update target for target in elem.children
        return exists

      # Looks for matching Elements using kind and tag
      # Direction: up the hierarchy (towards root)
      lookup: (kind, tag) ->
        #@debug "lookup: #{kind}(#{tag})..."
        res = switch
          when this not instanceof Object then undefined
          when this instanceof Element then @match kind, tag
          else Element::match.call this, kind, tag
        res ?= switch
          when @origin? then Element::lookup.apply @origin, arguments
          when @parent? then Element::lookup.apply @parent, arguments
          else Element::match.call @constructor, kind, tag
        #@debug "lookup: #{kind}(#{tag}) got result: #{res?}"
        return res

      # Looks for matching Elements using YPATH notation
      # Direction: down the hierarchy (away from root)
      at: -> @locate arguments...
      locate: (ypath) ->
        return unless ypath?
        if typeof ypath is 'string'
          @debug "locate: #{ypath}"
          ypath = ypath.replace /\s/g, ''
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = ypath.split('/').filter (e) -> !!e
        else
          @debug "locate: #{ypath.join('/')}"
          [ key, rest... ] = ypath
        return this unless key?

        match = switch
          when key is '..' then @match key
          else @match '*', key

        match ?= @match key if @scope[key] in ['0..1', '1']

        return switch
          when rest.length > 0 then match?.locate rest
          else match

      # Looks for a matching Element(s) in immediate sub-elements
      match: (kind, tag) ->
        return unless kind? and @[kind]?
        return @[kind] unless tag?

        match = @[kind]
        match = [ match ] unless match instanceof Array
        return match if tag is '*'

        for elem in match when elem instanceof Element
          return elem if tag is elem.datakey or tag is elem.tag
        return undefined

### toJSON

Converts the Element into a JS object

      toJSON: (opts={ tag: true, extended: false }) ->
        #@debug "converting #{@kind} toJSON with #{@children.length}"
        sub =
          @children
            .filter (x) => opts.extended or x.parent is this
            .reduce ((a,b) ->
              for k, v of b.toJSON()
                if a[k] instanceof Object
                  a[k][kk] = vv for kk, vv of v if v instanceof Object
                else
                  a[k] = v
              return a
            ), {}
        if opts.tag
          "#{@kind}": switch
            when Object.keys(sub).length > 0
              if @tag? then "#{@tag}": sub else sub
            when @tag instanceof Object then "#{@tag}"
            else @tag
        else sub

## Export Element Class

    module.exports = Element

# Element - cascading element tree

## Class Element

    debug = require('debug')('yang:element')
    delegate = require 'delegates'
    Emitter = require('events').EventEmitter
    Emitter.defaultMaxListeners = 100

    kIndex = Symbol.for('element:index');
    kCache = Symbol.for('element:cache');

    class Element

      @property: (prop, desc) ->
        Object.defineProperty @prototype, prop, desc

      @use: ->
        res = [].concat(arguments...)
          .filter (x) -> x?
          .map (elem) =>
            exists = Element::match.call this, elem.kind, elem.tag
            if exists?
              debug "use: using previously loaded '#{elem.kind}:#{elem.tag}'"
              return exists
            try Element::merge.call this, elem
            catch e
              throw @error "use: unable to merge '#{elem.kind}:#{elem.tag}'", e
        return switch
          when res.length > 1  then res
          when res.length is 1 then res[0]
          else undefined

      @debug: -> debug @uri, arguments...

      @error: (err, ctx) ->
        err = new Error err unless err instanceof Error
        err.uri = @uri
        err.src = this
        err.ctx = ctx
        return err

      constructor: (@kind, @tag, scope) ->
        unless @kind?
          throw @error "must supply 'kind' to create a new Element"

        @scope = scope if scope?

        Object.defineProperties this,
          parent: value: null, writable: true
          origin: value: null, writable: true
          state:  value: {}, writable: true
          [kIndex]: value: 0, writable: true
          emitter: value: new Emitter

      error: @error
      debug: @debug

      delegate @prototype, 'emitter'
        .method 'emit'
        .method 'once'
        .method 'on'
        .method 'off'

### Computed Properties

      @property 'datakey',
        get: -> @tag ? @kind

      @property 'uri',
        get: -> switch
          when @parent instanceof Element
            mark = @kind
            mark += "(#{@tag})" if @tag? and @parent.scope?[@kind] in [ '0..n', '1..n', '*' ]
            "#{@parent.uri}/#{mark}"
          when @tag?
            "#{@kind}(#{@tag})"
          else
            @kind

      @property 'root',
        get: -> switch
          when @parent instanceof Element then @parent.root
          when @origin instanceof Element then @origin.root
          else this

      @property 'children',
        get: ->
          unless this[kCache]?
            elements = (v for own k, v of this when k not in [ 'parent', 'origin', 'tag', kCache, 'source' ])
              .reduce ((a,b) -> switch
                when b instanceof Element then a.concat b
                when b instanceof Array
                  a.concat b.filter (x) -> x instanceof Element
                else a
              ), []
            this[kCache] = elements.sort (a,b) -> a[kIndex] - b[kIndex]
          return this[kCache];

      @property '*',  get: -> @children
      @property '..', get: -> @parent

## Instance-level methods

### clone

      clone: (opts={}) ->
        { origin = @origin, relative = true } = opts
        @debug "cloning #{@kind}:#{@tag} with #{@children.length} elements"
        copy = (new @constructor @kind, @tag, @source).extends @children.map (x) -> x.clone opts
        copy.state = Object.create(@state)
        copy.state.relative = relative
        copy.origin = origin ? this
        return copy

### extends (elements...)

This is the primary mechanism for defining sub-elements to become part
of the element tree

      extends: ->
        elems = ([].concat arguments...).filter (x) -> x? and !!x
        return this unless elems.length > 0
        elems.forEach (expr) => @merge expr
        @emit 'change', elems...
        return this

### merge (element)

This helper method merges a specific Element into current Element
while performing `@scope` validations.

      merge: (elem, opts={}) ->
        unless elem instanceof Element
          throw @error "cannot merge invalid element into Element", elem

        elem.parent = this
        elem[kIndex] = @children.length if @children?
        this[kCache] = null

        _merge = (item) ->
          if not item.node or opts.append or item.datakey not in (@keys ? [])
            @push item
            true
          else if opts.replace is true
            for x, i in this when x.datakey is item.datakey
              @splice i, 1, item
              break
            true
          else false

        unless @scope?
          unless @hasOwnProperty elem.kind
            @[elem.kind] = elem
            return elem

          unless Array.isArray @[elem.kind]
            exists = @[elem.kind]
            @[elem.kind] = [ exists ]
            Object.defineProperty @[elem.kind], 'keys',
              get: (-> @map (x) -> x.datakey ).bind @[elem.kind]

          unless _merge.call @[elem.kind], elem
            throw @error "constraint violation for '#{elem.kind} #{elem.datakey}' - cannot define more than once"

          return elem

        unless elem.kind of @scope
          if elem.scope? and (not elem.source.state.unbound and not @source.state.unbound)
            @debug @scope
            throw @error "scope violation - invalid '#{elem.kind}' extension found"
          else
            @scope[elem.kind] = '*' # this is hackish...

        switch @scope[elem.kind]
          when '0..n', '1..n', '*'
            unless @hasOwnProperty elem.kind
              @[elem.kind] = []
              Object.defineProperty @[elem.kind], 'keys',
                get: (-> @map (x) -> x.datakey ).bind @[elem.kind]
            unless _merge.call @[elem.kind], elem
              throw @error "constraint violation for '#{elem.kind} #{elem.datakey}' - already defined"
          when '0..1', '1'
            unless @hasOwnProperty elem.kind
              @[elem.kind] = elem
            else if opts.replace is true
              @debug "replacing pre-existing #{elem.kind}"
              @[elem.kind] = elem
            else
              throw @error "constraint violation for '#{elem.kind}' - cannot define more than once"
          else
            throw @error "unrecognized scope constraint defined for '#{elem.kind}' with #{@scope[elem.kind]}"

        return elem

      removes: ->
        elems = ([].concat arguments...).filter (x) -> x? and !!x
        return this unless elems.length > 0
        elems.forEach (expr) => @remove expr
        @emit 'change', elems...
        return this

      remove: (elem) ->
        unless elem instanceof Element
          throw @error "cannot remove a non-Element from an Element", elem

        exists = Element::match.call this, elem.kind, elem.datakey
        return this unless exists?

        if Array.isArray @[elem.kind]
          @[elem.kind] = @[elem.kind].filter (x) -> x.datakey isnt elem.datakey
          delete @[elem.kind] unless @[elem.kind].length
        else
          delete @[elem.kind]

        this[kCache] = null
        return this

### update (element)

This alternative form of [merge](#merge-element) performs conditional
merge based on existence check. It is considered *safer* alternative
to direct [merge](#merge-element) call.

      # performs conditional merge based on existence
      update: (elem) ->
        unless elem instanceof Element
          throw @error "cannot update a non-Element into an Element", elem

        #@debug "update with #{elem.kind}/#{elem.tag}"
        exists = switch
          when elem.tag? then Element::match.call this, elem.kind, elem.datakey
          else Element::match.call this, elem.kind
        return @merge elem unless exists?

        #@debug "update #{exists.kind} in-place for #{elem.children.length} elements"
        exists.update target for target in elem.children
        return exists

      # Looks for matching Elements using kind and tag
      # Direction: up the hierarchy (towards root)
      lookup: (kind, tag) ->
        #@debug "lookup: #{kind}(#{tag})..."
        res = switch
          when this not instanceof Object then undefined
          when this instanceof Element then @match kind, tag
          else Element::match.call this, kind, tag
        res ?= switch
          when @origin? then Element::lookup.apply @origin, arguments
          when @parent? then Element::lookup.apply @parent, arguments
          else Element::match.call @constructor, kind, tag
        #@debug "lookup: #{kind}(#{tag}) got result: #{res?}"
        return res

      # Looks for matching Elements using YPATH notation
      # Direction: down the hierarchy (away from root)
      at: -> @locate arguments...
      locate: (ypath) ->
        return unless ypath?
        if typeof ypath is 'string'
          @debug "locate: #{ypath}"
          ypath = ypath.replace /\s/g, ''
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = ypath.split('/').filter (e) -> !!e
        else
          @debug "locate: #{ypath.join('/')}"
          [ key, rest... ] = ypath
        return this unless key?

        match = switch
          when key is '..' then @match key
          else @match '*', key

        match ?= @match key if @scope[key] in ['0..1', '1']

        return switch
          when rest.length > 0 then match?.locate rest
          else match

      # Looks for a matching Element(s) in immediate sub-elements
      match: (kind, tag) ->
        return unless kind? and @[kind]?
        return @[kind] unless tag?

        match = @[kind]
        match = [ match ] unless match instanceof Array
        return match if tag is '*'

        for elem in match when elem instanceof Element
          return elem if tag is elem.datakey or tag is elem.tag
        return undefined

### toJSON

Converts the Element into a JS object

      toJSON: (opts={ tag: true, extended: false }) ->
        #@debug "converting #{@kind} toJSON with #{@children.length}"
        sub =
          @children
            .filter (x) => opts.extended or x.parent is this
            .reduce ((a,b) ->
              for k, v of b.toJSON()
                if a[k] instanceof Object
                  a[k][kk] = vv for kk, vv of v if v instanceof Object
                else
                  a[k] = v
              return a
            ), {}
        if opts.tag
          "#{@kind}": switch
            when Object.keys(sub).length > 0
              if @tag? then "#{@tag}": sub else sub
            when @tag instanceof Object then "#{@tag}"
            else @tag
        else sub

## Export Element Class

    module.exports = Element


Update audio.litcoffee

Update audio.litcoffee

See [this blog](http://srchea.com/experimenting-with-web-audio-api-three-js-webgl) for a very helpful tutorial.

First set up a context within upon all the functions
used to parse the audio will be called:

	try audio = new AudioContext()

Then open an HTTP request to asynchronously get your audio file:

	url = 'data/11 Where I\'m Trying To Go (Marvel Years Remix).mp3';
	request = new XMLHttpRequest();
	request.open('GET', url, true);
	request.responseType = "arraybuffer";

When the request returns, onload is called, which in turn calls setup.

	request.onload = ()->
		audio.decodeAudioData(
			request.response,
			(buffer) ->

The AudioBufferSourceNode contains the input audio data and outputs to the analyser and output.

				source = audio.createBufferSource();
				source.buffer = buffer;

The ScriptProcessorNode takes data from the analyser as its input and outputs to the destination node which plays the sound.

				sourceJs = audio.createScriptProcessor(2048,1,1)
				sourceJs.buffer = buffer

The AnalyserNode takes the current frequency data from the AudioBufferSourceNode, smoothes it, and outputs to the ScriptProcessorNode

				analyser = audio.createAnalyser();
				analyser.smoothingTimeConstant = 1;
				analyser.fftSize = 512;
				source.connect(analyser);
				analyser.connect(sourceJs);

Create the oscilloscope and connect the AudioBufferSourceNode to it

				myOscilloscope = new WavyJones(audio, 'oscilloscope');
				source.connect(myOscilloscope);
				source.connect(audio.destination);
				sourceJs.onaudioprocess = (e) ->
					array = new Uint8Array(analyser.frequencyBinCount);
					analyser.getByteFrequencyData(array);
				source.start(0)
				return
			);

Finally, send the request which begins the flow that ends with the source.start function being called.

	request.send()

First set up a context within upon all the functions
used to parse the audio will be called:

	try audio = new AudioContext()

Then open an HTTP request to asynchronously get your audio file:

	url = 'data/11 Where I\'m Trying To Go (Marvel Years Remix).mp3';
	request = new XMLHttpRequest();
	request.open('GET', url, true);
	request.responseType = "arraybuffer";

When the request returns, onload is called, which in turn calls setup.

	request.onload = ()->
		audio.decodeAudioData(
			request.response,
			(buffer) ->

The AudioBufferSourceNode contains the buffer that is loaded asynchronously with decodeAudioData.

				source = audio.createBufferSource();
				source.buffer = buffer;

The ScriptProcessorNode takes the audio data as its input and outputs to the destination node which plays the sound.

				sourceJs = audio.createScriptProcessor(2048,1,1)
				sourceJs.buffer = buffer

The AnalyserNode takes the current frequency data from the AudioBufferSourceNode, smoothes it, and outputs to the ScriptProcessorNode

				analyser = audio.createAnalyser();
				analyser.smoothingTimeConstant = 1;
				analyser.fftSize = 512;
				source.connect(analyser);
				analyser.connect(sourceJs);

Create the oscilloscope and connect the AnalyserNode to it

				myOscilloscope = new WavyJones(audio, 'oscilloscope');
				analyser.connect(myOscilloscope);
				sourceJs.onaudioprocess = (e) ->
					array = new Uint8Array(analyser.frequencyBinCount);
					analyser.getByteFrequencyData(array);
				source.start(0)
				return
			);

Finally, send the request which begins the flow that ends with the source.start function being called.

	request.send()


more tweaks for correctness and documentedness

*This is [Literate Coffeescript](http://coffeescript.org/#literate): code interleaved with Markdown
comments. The Coffeescript compiler will strip the Markdown and compile it like any other file.*

	module.exports =

## platform-ng config defaults

This file defines the default configuration options for platform-ng and explains
how can modify the configuration to suit your needs.

When you call `Platform#config()` with your configuration object, this configuration is deep-extended with
yours to produce the working configuration.

### General application configuration

What's the app called (`name`), and what environment is it running in (`env`)? For `env`, anything other
than the string `'production'` is automatically considered `'development'` for debuggability.

		app:
			name: 'unnamed-app'
			env: 'development'

#### Sessions

For sessions, you can choose to entirely disable them by setting `enabled` to `false`. Otherwise, your
choices for `type` are currently `cookie` or `vanilla`.

The `cookie` type stores all session data in a garbled (not encrypted) client-side cookie, signed using
the `secret`.

The `vanilla` type stores the session in a server-side session store and only transmits a signed session
ID to the client.

`cookie` is default for now, but `vanilla` will replace it in the next major version. The `secure` option
determines whether the cookies are HTTPS-only or not.

			session:
				enabled: true
				type: 'cookie'
				secret: 'change-me'
				secure: false

#### Cookie parser

The cookie parser transforms the `cookie` header into `request.cookies`, `request.signedCookies`, and
`request.secureCookies` objects. You still have to use `response.cookie(...)` and/or
`response.clearCookie(...)` to actually manipulate cookies. The `secret` defined here will be used to
verify signed cookies, and, if you set `{signed: true}` in the third argument to `response.cookie(...)`,
this `secret` will be used to sign the outbound cookies too.

			cookies:
				enabled: true
				secret: 'change-me'

### HTTP server configuration

The `server` sections deals with how platform-ng handles the exchange, parsing, and encoding of HTTP
requests and responses.

		server:
			# Use automatic gzip compression for responses?
			compress: true

			# TCP port to listen on (overriden by PORT environment variable)
			port: 8001

			# Is the app behind a proxy? If so, replace request.ip with X-Forwarded-For, and trust
			# all cookies for HTTPS-only mode.
			behind_proxy: false

			# Enable/disable various body parsers, for performance and security reasons
			parsers:
				urlencoded: true
				json: true
				multipart: false # potential security problem; read http://goo.gl/N4Bci1

			# Allow requests to change HTTP verb using 'X-HTTP-Method-Override' header?
			method_override: false

### Language configuration

This section controls which protolanguages platform-ng will compile, as well as language-specific options
for some of the languages. (The NPM dependencies for these languages are listed in `package.json` as
`optionalDependencies` and can be skipped entirely by calling `npm install --no-optional`.)

		languages:
			coffeescript:
				enabled: true

			stylus:
				enabled: true
				include_css: true	# Whether to inline @include()'d CSS files
				nib: true			# Whether to automatically load the nib library

`compile` controls generic compilation options for all language compilers. The `minify` option will
cause the compiler to munge the output in order to produce the smallest possible code. The `expose_sources`
option will cause the server to serve the original files (e.g. .coffee, .styl, etc) if requested, AND it
will ask the compiler to generate source maps, if supported.

		compile:
			minify: true
			expose_sources: true

platform-ng is powered by Express. You can directly configure Express settings here. The settings are
documented on [this page](http://expressjs.com/3x/api.html#app-settings).

		express:
			'view engine': 'jade'

	module.exports =

## platform-ng config defaults

This literate Coffeescript file defines the default configuration options for platform-ng and explains
how can modify the configuration to suit your needs.

When you call `Platform#config()` with your configuration object, this configuration is deep-extended with
yours to produce the working configuration.

### General application configuration

What's the app called (`name`), and what environment is it running in (`env`)? For `env`, anything other
than the string `'production'` is automatically considered `'development'` for debuggability.

		app:
			name: 'unnamed-app'
			env: 'development'

#### Sessions

For sessions, you can choose to entirely disable them by setting `enabled` to `false`. Otherwise, your
choices for `type` are currently `cookie` or `vanilla`.

The `cookie` type stores all session data in a garbled (not encrypted) client-side cookie, signed using
the `secret`.

The `vanilla` type stores the session in a server-side session store and only transmits a signed session
ID to the client.

`cookie` is default for now, but `vanilla` will replace it in the next major version. The `secure` option
determines whether the cookies are HTTPS-only or not.

			session:
				enabled: true
				type: 'cookie'
				secret: 'change-me'
				secure: false

#### Cookie parser

The cookie parser transforms the `cookie` header into `request.cookies`, `request.signedCookies`, and
`request.secureCookies` objects. You still have to use `response.cookie(...)` and/or
`response.clearCookie(...)` to actually manipulate cookies. The `secret` defined here will be used to
verify signed cookies, and, if you set `{signed: true}` in the third argument to `response.cookie(...)`,
this `secret` will be used to sign the outbound cookies too.

			cookies:
				enabled: true
				secret: 'change-me'

### HTTP server configuration

The `server` sections deals with how platform-ng handles the exchange, parsing, and encoding of HTTP
requests and responses.

		server:
			# Use automatic gzip compression for responses?
			compress: true

			# TCP port to listen on (overriden by PORT environment variable)
			port: 8001

			# Is the app behind a proxy? If so, replace request.ip with X-Forwarded-For, and trust
			# all cookies for HTTPS-only mode.
			behind_proxy: false

			# Enable/disable various body parsers, for performance and security reasons
			parsers:
				urlencoded: true
				json: true
				multipart: false # potential security problem; read http://goo.gl/N4Bci1

			# Allow requests to change HTTP verb using 'X-HTTP-Method-Override' header?
			method_override: false

### Language configuration

This section controls which protolanguages platform-ng will compile, as well as language-specific options
for some of the languages. (The NPM dependencies for these languages are listed in `package.json` as
`optionalDependencies` and can be skipped entirely by calling `npm install --no-optional`.)

		languages:
			coffeescript:
				enabled: true

			stylus:
				enabled: true
				include_css: true	# Whether to inline @include()'d CSS files
				nib: true			# Whether to automatically load the nib library

`compile` controls generic compilation options for all language compilers. The `minify` option will
cause the compiler to munge the output in order to produce the smallest possible code. The `expose_sources`
option will cause the server to serve the original files (e.g. .coffee, .styl, etc) if requested, AND it
will ask the compiler to generate source maps, if supported.

		compile:
			minify: true
			expose_sources: true

platform-ng is powered by Express. You can directly configure Express settings here. The settings are
documented on [this page](http://expressjs.com/3x/api.html#app-settings).

		express:
			'view engine': 'jade'


Add rollback to snapshot

Add rollback to snapshot

Dependencies
============

    _      = require "underscore"
    fs     = require "fs"
    path   = require "path"
    colors = require "cli-color"

VOSCO
=====

    script =

Setup
-----

      'install': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        if isInstalled then process.exit 1
        await @vosco.install defer(error)

      'uninstall': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.uninstall defer(error)

Repository
----------

      'get-status': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getStatus defer(error, status)
        getType = (file) -> file.type
        getPath = (file) -> colors.xterm(240)("  #{file.path}")
        groups  = _.groupBy status, getType
        for group, paths of groups
          console.log """
          #{group}
          #{paths.map(getPath).join("\n")}
          """

      'get-history': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getHistory defer(error, history)
        for commit in history
          hash = commit.hash.substr(0, 7)
          date = new Date(commit.date).toDateString()
          msg  = commit.message
          console.log colors.xterm(240)("  #{hash}  #{date}  #{msg}")

      'get-content-history': (path) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        # show warning if file doesn"t exist
        console.log "content history"

Snapshots
---------

      'preview-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        hash = hash or 'HEAD'
        await @vosco.previewSnapshot hash, defer(error, diff)
        console.log diff

      'create-snapshot': (message) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        message = message or 'Untitled Snapshot'
        await @vosco.createSnapshot message, defer(error)

      'rollback-to-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.rollbackToSnapshot hash, defer(error)

Branches
--------

      'list-branches': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "branches list"

      'select-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "select branch"

      'create-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "create new branch"

      'delete-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "delete branch"

Export Module
-------------

    module.exports = (vosco) ->
      script.vosco = vosco
      return script

Dependencies
============

    _      = require "underscore"
    fs     = require "fs"
    path   = require "path"
    colors = require "cli-color"

VOSCO
=====

    script =

Setup
-----

      'install': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        if isInstalled then process.exit 1
        await @vosco.install defer(error)

      'uninstall': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.uninstall defer(error)

Repository
----------

      'get-status': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getStatus defer(error, status)
        getType = (file) -> file.type
        getPath = (file) -> colors.xterm(240)("  #{file.path}")
        groups  = _.groupBy status, getType
        for group, paths of groups
          console.log """
          #{group}
          #{paths.map(getPath).join("\n")}
          """

      'get-history': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        await @vosco.getHistory defer(error, history)
        for commit in history
          hash = commit.hash.substr(0, 7)
          date = new Date(commit.date).toDateString()
          msg  = commit.message
          console.log colors.xterm(240)("  #{hash}  #{date}  #{msg}")

      'get-content-history': (path) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        # show warning if file doesn"t exist
        console.log "content history"

Snapshots
---------

      'preview-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        hash = hash or 'HEAD'
        await @vosco.previewSnapshot hash, defer(error, diff)
        console.log diff

      'create-snapshot': (message) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        message = message or 'Untitled Snapshot'
        await @vosco.createSnapshot message, defer(error)

      'rollback-to-snapshot': (hash) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "rollback to snapshot"

Branches
--------

      'list-branches': () ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "branches list"

      'select-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "select branch"

      'create-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "create new branch"

      'delete-branch': (branch) ->
        await @vosco.isInstalled defer(error, isInstalled)
        unless isInstalled then process.exit 1
        console.log "delete branch"

Export Module
-------------

    module.exports = (vosco) ->
      script.vosco = vosco
      return script


Fix link for github

Fix link for github

This is where shrub's package system meets Angular's module system. Packages'
implementations of controllers, services, filters, providers, and directives
are gathered and registered into Angular.

	angular.module('shrub.packages', [
		'shrub.require'
		'shrub.pkgman'
	])

		.config([
			'$compileProvider', '$controllerProvider', '$filterProvider'
			'$injector', '$provide', 'shrub-pkgmanProvider'
			'shrub-requireProvider'
			(
				$compileProvider, $controllerProvider, $filterProvider
				$injector, $provide, pkgman, {require}
			) ->

				config = require 'config'
				debug = require('debug') 'shrub:angular'

Set an injector so that Angular injection can occur out of band.

				angular_ = require 'angular'
				angular_.setInjector $injector

Invoke hook `controller`.
Allows packages to define Angular controllers. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				debug 'Registering controllers...'

				for path, injected of pkgman.invoke 'controller'
					controllerName = pkgman.normalizePath path
					debug controllerName
					$controllerProvider.register controllerName, injected

				debug 'Controllers registered.'

				debug 'Registering directives...'

Normalize, augment, and register a directive.

				registerDirective = (name, path, injected) -> ($injector) ->
					directive = $injector.invoke injected

Ensure a compilation function exists for the directive, and ensure that by
default it returns the `link` function.

					if angular.isFunction directive
						directive = link: directive
						directive.compile = -> directive.link
					else if not directive.compile
						directive.compile = -> directive.link

Proxy any defined link function, firing any attached any controllers' `link`
method, as well as passing execution on to the original `link` function.

					link = directive.link
					directive.link = (scope, element, attrs, controllers) ->
						if controllers?
							unless angular.isArray controllers
								controllers = [controllers]

							for controller in controllers
								controller.link? arguments...

						link? arguments...

Ensure the directive has a name. Defaults to the normalized path of the
implementing package.

					directive.name ?= name

If controller binding is specified, the controller defaults to the directive
name. In other words, if you define a directive and a controller in the same
package, and specify `directive.bindToController = true`, your directive will
include the controller automatically.

					if directive.bindToController
						directive.controller ?= directive.name

Handle a bunch of internal Angular normalization.

					directive.require ?= directive.controller and directive.name
					directive.priority ?= 0
					directive.restrict ?= 'EA'

					if angular.isObject directive.scope
						directiveIsolateBindings directive

Invoke hook `augmentDirective`.
Allows packages to augment the directives defined by packages. One example is
the automatic relinking functionality implemented by
[shrub-skin](../packages/shrub-skin/client/index.coffee#L12).

					for injectedDirective in pkgman.invokeFlat(
						'augmentDirective', directive, path
					)
						$injector.invoke injectedDirective

Haven't gone deep enough into Angular to understand why this has to be, but it
does.

					directive.index = 0
					return [directive]

Internal Angular state that we have to reset.

				directiveIsolateBindings = (directive) ->

					LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/

					bindings = {}

					for scopeName, definition of directive.scope
						match = definition.match LOCAL_REGEXP

						unless match
							throw angular.$$minErr('$compile')(
								'iscp'
								"Invalid isolate scope definition for directive
								'{0}'. Definition: {... {1}: '{2}' ...}"
								directive.name, scopeName, definition
							)

						bindings[scopeName] =
							mode: match[1][0]
							collection: match[2] is '*'
							optional: match[3] is '?'
							attrName: match[4] or scopeName

					directive.$$isolateBindings = bindings

Invoke hook `directive`.
Allows packages to define Angular directives. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				for path, injected of pkgman.invoke 'directive'
					do (path, injected) ->
						directiveName = pkgman.normalizePath path

						debug directiveName

First, register it through Angular's normal registration mechanism. This sets
a bunch of internal state we don't have access to.

						$compileProvider.directive directiveName, injected

Follow that by normalizing, augmenting, and registering the directive again.
It will run over the previous definition, ensuring everything works nicely.

						$provide.factory "#{directiveName}Directive", [
							'$injector'
							registerDirective directiveName, path, injected
						]

				debug 'Directives registered.'

				debug 'Registering filters...'

Invoke hook `filter`.
Allows packages to define Angular filters. Implementations should return a
function.

				for path, injected of pkgman.invoke 'filter'
					filterName = pkgman.normalizePath path

					debug filterName

					$filterProvider.register filterName, injected

				debug 'Filters registered.'

Invoke hook `provider`.
Allows packages to define Angular providers. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				debug 'Registering providers...'

				for path, provider of pkgman.invoke 'provider'
					debug path

					$provide.provider path, provider

				debug 'Providers registered.'

Invoke hook `service`.
Allows packages to define Angular services. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				debug 'Registering services...'

				for path, injected of pkgman.invoke 'service'
					debug path

					$provide.service path, injected

				debug 'Services registered.'

		])

The module that provides Angular with access to Shrub's package manager.

	angular.module('shrub.pkgman', [
		'shrub.require'
	])

		.provider 'shrub-pkgman', [
			'$provide', 'shrub-requireProvider'
			($provide, {require}) ->

				config = require 'config'
				debug = require('debug') 'shrub:pkgman'
				pkgman = require 'pkgman'

				debug 'Loading packages...'

Load the package list from configuration.

				pkgman.registerPackageList config.get 'packageList'

				debug 'Packages loaded.'

Simply pass along pkgman as the 'service'.

				pkgman.$get = -> pkgman

				return pkgman
		]

This is where shrub's package system meets Angular's module system. Packages'
implementations of controllers, services, filters, providers, and directives
are gathered and registered into Angular.

	angular.module('shrub.packages', [
		'shrub.require'
		'shrub.pkgman'
	])

		.config([
			'$compileProvider', '$controllerProvider', '$filterProvider'
			'$injector', '$provide', 'shrub-pkgmanProvider'
			'shrub-requireProvider'
			(
				$compileProvider, $controllerProvider, $filterProvider
				$injector, $provide, pkgman, {require}
			) ->

				config = require 'config'
				debug = require('debug') 'shrub:angular'

Set an injector so that Angular injection can occur out of band.

				angular_ = require 'angular'
				angular_.setInjector $injector

Invoke hook `controller`.
Allows packages to define Angular controllers. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				debug 'Registering controllers...'

				for path, injected of pkgman.invoke 'controller'
					controllerName = pkgman.normalizePath path
					debug controllerName
					$controllerProvider.register controllerName, injected

				debug 'Controllers registered.'

				debug 'Registering directives...'

Normalize, augment, and register a directive.

				registerDirective = (name, path, injected) -> ($injector) ->
					directive = $injector.invoke injected

Ensure a compilation function exists for the directive, and ensure that by
default it returns the `link` function.

					if angular.isFunction directive
						directive = link: directive
						directive.compile = -> directive.link
					else if not directive.compile
						directive.compile = -> directive.link

Proxy any defined link function, firing any attached any controllers' `link`
method, as well as passing execution on to the original `link` function.

					link = directive.link
					directive.link = (scope, element, attrs, controllers) ->
						if controllers?
							unless angular.isArray controllers
								controllers = [controllers]

							for controller in controllers
								controller.link? arguments...

						link? arguments...

Ensure the directive has a name. Defaults to the normalized path of the
implementing package.

					directive.name ?= name

If controller binding is specified, the controller defaults to the directive
name. In other words, if you define a directive and a controller in the same
package, and specify `directive.bindToController = true`, your directive will
include the controller automatically.

					if directive.bindToController
						directive.controller ?= directive.name

Handle a bunch of internal Angular normalization.

					directive.require ?= directive.controller and directive.name
					directive.priority ?= 0
					directive.restrict ?= 'EA'

					if angular.isObject directive.scope
						directiveIsolateBindings directive

Invoke hook `augmentDirective`.
Allows packages to augment the directives defined by packages. One example is
the automatic relinking functionality implemented by [shrub-skin](../packages/shrub-skin/client/index.html#implementshookaugmentdirective).

					for injectedDirective in pkgman.invokeFlat(
						'augmentDirective', directive, path
					)
						$injector.invoke injectedDirective

Haven't gone deep enough into Angular to understand why this has to be, but it
does.

					directive.index = 0
					return [directive]

Internal Angular state that we have to reset.

				directiveIsolateBindings = (directive) ->

					LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/

					bindings = {}

					for scopeName, definition of directive.scope
						match = definition.match LOCAL_REGEXP

						unless match
							throw angular.$$minErr('$compile')(
								'iscp'
								"Invalid isolate scope definition for directive
								'{0}'. Definition: {... {1}: '{2}' ...}"
								directive.name, scopeName, definition
							)

						bindings[scopeName] =
							mode: match[1][0]
							collection: match[2] is '*'
							optional: match[3] is '?'
							attrName: match[4] or scopeName

					directive.$$isolateBindings = bindings

Invoke hook `directive`.
Allows packages to define Angular directives. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				for path, injected of pkgman.invoke 'directive'
					do (path, injected) ->
						directiveName = pkgman.normalizePath path

						debug directiveName

First, register it through Angular's normal registration mechanism. This sets
a bunch of internal state we don't have access to.

						$compileProvider.directive directiveName, injected

Follow that by normalizing, augmenting, and registering the directive again.
It will run over the previous definition, ensuring everything works nicely.

						$provide.factory "#{directiveName}Directive", [
							'$injector'
							registerDirective directiveName, path, injected
						]

				debug 'Directives registered.'

				debug 'Registering filters...'

Invoke hook `filter`.
Allows packages to define Angular filters. Implementations should return a
function.

				for path, injected of pkgman.invoke 'filter'
					filterName = pkgman.normalizePath path

					debug filterName

					$filterProvider.register filterName, injected

				debug 'Filters registered.'

Invoke hook `provider`.
Allows packages to define Angular providers. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				debug 'Registering providers...'

				for path, provider of pkgman.invoke 'provider'
					debug path

					$provide.provider path, provider

				debug 'Providers registered.'

Invoke hook `service`.
Allows packages to define Angular services. Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

				debug 'Registering services...'

				for path, injected of pkgman.invoke 'service'
					debug path

					$provide.service path, injected

				debug 'Services registered.'

		])

The module that provides Angular with access to Shrub's package manager.

	angular.module('shrub.pkgman', [
		'shrub.require'
	])

		.provider 'shrub-pkgman', [
			'$provide', 'shrub-requireProvider'
			($provide, {require}) ->

				config = require 'config'
				debug = require('debug') 'shrub:pkgman'
				pkgman = require 'pkgman'

				debug 'Loading packages...'

Load the package list from configuration.

				pkgman.registerPackageList config.get 'packageList'

				debug 'Packages loaded.'

Simply pass along pkgman as the 'service'.

				pkgman.$get = -> pkgman

				return pkgman
		]


Removed unneeded property

Removed unneeded property

    Array.prototype.last = -> this[this.length - 1]

    q     = require 'q'
    fs    = require 'fs'
    async = require 'async'
    uuid  = require 'uuid-1345'

    microtime = require 'microtime'

    EventEmitter2 = require('eventemitter2').EventEmitter2
    emitter = new EventEmitter2 wildcard: true

    available   = { }
    initialized = { }

    code_root = process.env.MADUL_ROOT || 'dist'

    underscore = (value) -> value.replace /\W+/g, '_'

    WRAPPED = { }

    _INITIALIZERS = { }

    INITIALIZERS = (cls, method) ->
      _INITIALIZERS[cls] = [ ] unless _INITIALIZERS[cls]?

      _INITIALIZERS[cls].push method

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'listen'
          'fire'
          'warn'
          'report'
          'do_wrap'
          'wrap_methods'
          'strip'
          'make_available'
          'hydrate'
          'finish_up'
          'initialize'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      @LISTEN: (event, callback) => emitter.on event, callback

      @FIRE: (event, args) => emitter.emit event, args

      listen: (event, callback) => Madul.LISTEN "*.#{@clazz}.#{event}", callback

      fire: (event, args) => Madul.FIRE "@.#{@clazz}.#{event}", args

      warn: (event, details) => Madul.FIRE "!.#{@clazz}.#{event}", details

      report: (method, state, id, args) =>
        @fire "#{method}.#{state}",
          uuid:      id
          args:      args
          timestamp: microtime.now()

      do_wrap: (method) =>
        callMe = @[method]

        Madul.FIRE "$.#{@clazz}.#{method}.wrap"

        @["_#{method}"] = @[method]

        respond = (id, deferred) =>
          (state, data) =>
            process.nextTick =>
              deferred[state] data

              @report method, state, id, data

        WRAPPED[@clazz].push method

        @[method] = =>
          id   = uuid.v4fast()
          def  = q.defer()
          args = if arguments[0]? then Array.prototype.slice.call arguments else [ ]
          res  = respond id, def

          args.push (out) => res 'resolve', out
          args.push (err) => res 'reject',  err
          args.push (out) => res 'notify',  out

          @report method, 'invoke', id, args

          @["_#{method}"].apply @, args

          def.promise

      wrap_methods: =>
        props = Object.keys @constructor.prototype

        for prop in props
          if prop[0] != '_'                      &&
             typeof @[prop] == 'function'        &&
             typeof @["_#{prop}"] == 'undefined' &&
             WRAP(@clazz, prop) == true

            @do_wrap prop

            INITIALIZERS @clazz, prop if prop[0] == '$'

      strip: (name) => name.toLowerCase().replace /\W+/g, ''

      make_available: (name, mod) =>
        Madul.FIRE "$.#{name}.available"

        available[@strip name] = mod

      hydrate: (deps, done) =>
        load = (name, path, loaded) =>
          mod = require path

          if typeof mod == 'function'
            new mod name
              .initialize @ctor_params?[name]
              .then (mod) =>
                @make_available name, mod
                loaded()
          else
            @make_available name, mod
            loaded()

        check = (path, dep, finished) =>
          fs.readdir path, (err, files) =>
            if err?
              Madul.FIRE '$.error', err

              done type: 'ERROR', info: err
            else
              async.each files, (f, next) =>
                depth = "#{path}/#{f}"

                fs.stat depth, (e, s) =>
                  if s.isDirectory() && f[0] != '.'
                    check depth, dep, next
                  else if s.isFile() && f.substring(0, f.length - 3) == dep
                    load f.substring(0, f.length - 3), depth, => do_add dep, next
                  else
                    next()
              , finished

        add_dependency = (name, mod) =>
          Madul.FIRE "$.#{@clazz}.dependency.register", name
          @[underscore name] = mod

        do_add = (name, next) =>
          add_dependency name, available[@strip name]
          next()

        add = (name, resource, next) =>
          @make_available name, require resource
          do_add name, next

        async.each deps, (d, next) =>
          if @[underscore d]? == false
            if available[@strip d]? == true
              do_add d, next
            else
              try
                add d, d, next
              catch e
                cwd = process.cwd()
                pkg = "#{cwd}/node_modules/#{d}/package.json"

                fs.stat pkg, (err, stat) =>
                  if stat?.isFile()
                    fs.readFile pkg, 'utf8', (err, data) =>
                      json = JSON.parse data
                      main = json.main || json._main || 'index.js'

                      add d, "#{cwd}/node_modules/#{d}/#{main}", next
                  else
                    check "#{cwd}/#{code_root}", d, next
          else
            next()
        , done

      finish_up: (resolve, args) =>
        async.each _INITIALIZERS[@clazz], (initializer, next) =>
          @[initializer] args
            .then next
        , =>
          @make_available @clazz, @
          resolve @
          Madul.FIRE "$.#{@clazz}.initialized"

      initialize: =>
        deferred = q.defer()
        args     = if arguments[0]? then Array.prototype.slice.call arguments else undefined

        @clazz = @constructor.name unless @clazz?

        Madul.FIRE "$.#{@clazz}.request_instance", args

        if initialized[@clazz] != true
          Madul.FIRE "$.#{@clazz}.initialize", args

          initialized[@clazz] = true

          @wrap_methods()

          if @deps?
            @hydrate @deps, => @finish_up deferred.resolve, args
          else
            @finish_up deferred.resolve, args
        else
          process.nextTick => deferred.resolve available[@strip @clazz]

        deferred.promise

    module.exports = Madul

    Array.prototype.last = -> this[this.length - 1]

    q     = require 'q'
    fs    = require 'fs'
    async = require 'async'
    uuid  = require 'uuid-1345'

    microtime = require 'microtime'

    EventEmitter2 = require('eventemitter2').EventEmitter2
    emitter = new EventEmitter2 wildcard: true

    available   = { }
    initialized = { }

    code_root = process.env.MADUL_ROOT || 'dist'

    underscore = (value) -> value.replace /\W+/g, '_'

    WRAPPED = { }

    _INITIALIZERS = { }

    INITIALIZERS = (cls, method) ->
      _INITIALIZERS[cls] = [ ] unless _INITIALIZERS[cls]?

      _INITIALIZERS[cls].push method

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'listen'
          'fire'
          'warn'
          'report'
          'do_wrap'
          'wrap_methods'
          'strip'
          'make_available'
          'hydrate'
          'finish_up'
          'initialize'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      INITIALIZERS: [ ]

      @LISTEN: (event, callback) => emitter.on event, callback

      @FIRE: (event, args) => emitter.emit event, args

      listen: (event, callback) => Madul.LISTEN "*.#{@clazz}.#{event}", callback

      fire: (event, args) => Madul.FIRE "@.#{@clazz}.#{event}", args

      warn: (event, details) => Madul.FIRE "!.#{@clazz}.#{event}", details

      report: (method, state, id, args) =>
        @fire "#{method}.#{state}",
          uuid:      id
          args:      args
          timestamp: microtime.now()

      do_wrap: (method) =>
        callMe = @[method]

        Madul.FIRE "$.#{@clazz}.#{method}.wrap"

        @["_#{method}"] = @[method]

        respond = (id, deferred) =>
          (state, data) =>
            process.nextTick =>
              deferred[state] data

              @report method, state, id, data

        WRAPPED[@clazz].push method

        @[method] = =>
          id   = uuid.v4fast()
          def  = q.defer()
          args = if arguments[0]? then Array.prototype.slice.call arguments else [ ]
          res  = respond id, def

          args.push (out) => res 'resolve', out
          args.push (err) => res 'reject',  err
          args.push (out) => res 'notify',  out

          @report method, 'invoke', id, args

          @["_#{method}"].apply @, args

          def.promise

      wrap_methods: =>
        props = Object.keys @constructor.prototype

        for prop in props
          if prop[0] != '_'                      &&
             typeof @[prop] == 'function'        &&
             typeof @["_#{prop}"] == 'undefined' &&
             WRAP(@clazz, prop) == true

            @do_wrap prop

            INITIALIZERS @clazz, prop if prop[0] == '$'

      strip: (name) => name.toLowerCase().replace /\W+/g, ''

      make_available: (name, mod) =>
        Madul.FIRE "$.#{name}.available"

        available[@strip name] = mod

      hydrate: (deps, done) =>
        load = (name, path, loaded) =>
          mod = require path

          if typeof mod == 'function'
            new mod name
              .initialize @ctor_params?[name]
              .then (mod) =>
                @make_available name, mod
                loaded()
          else
            @make_available name, mod
            loaded()

        check = (path, dep, finished) =>
          fs.readdir path, (err, files) =>
            if err?
              Madul.FIRE '$.error', err

              done type: 'ERROR', info: err
            else
              async.each files, (f, next) =>
                depth = "#{path}/#{f}"

                fs.stat depth, (e, s) =>
                  if s.isDirectory() && f[0] != '.'
                    check depth, dep, next
                  else if s.isFile() && f.substring(0, f.length - 3) == dep
                    load f.substring(0, f.length - 3), depth, => do_add dep, next
                  else
                    next()
              , finished

        add_dependency = (name, mod) =>
          Madul.FIRE "$.#{@clazz}.dependency.register", name
          @[underscore name] = mod

        do_add = (name, next) =>
          add_dependency name, available[@strip name]
          next()

        add = (name, resource, next) =>
          @make_available name, require resource
          do_add name, next

        async.each deps, (d, next) =>
          if @[underscore d]? == false
            if available[@strip d]? == true
              do_add d, next
            else
              try
                add d, d, next
              catch e
                cwd = process.cwd()
                pkg = "#{cwd}/node_modules/#{d}/package.json"

                fs.stat pkg, (err, stat) =>
                  if stat?.isFile()
                    fs.readFile pkg, 'utf8', (err, data) =>
                      json = JSON.parse data
                      main = json.main || json._main || 'index.js'

                      add d, "#{cwd}/node_modules/#{d}/#{main}", next
                  else
                    check "#{cwd}/#{code_root}", d, next
          else
            next()
        , done

      finish_up: (resolve, args) =>
        async.each _INITIALIZERS[@clazz], (initializer, next) =>
          @[initializer] args
            .then next
        , =>
          @make_available @clazz, @
          resolve @
          Madul.FIRE "$.#{@clazz}.initialized"

      initialize: =>
        deferred = q.defer()
        args     = if arguments[0]? then Array.prototype.slice.call arguments else undefined

        @clazz = @constructor.name unless @clazz?

        Madul.FIRE "$.#{@clazz}.request_instance", args

        if initialized[@clazz] != true
          Madul.FIRE "$.#{@clazz}.initialize", args

          initialized[@clazz] = true

          @wrap_methods()

          if @deps?
            @hydrate @deps, => @finish_up deferred.resolve, args
          else
            @finish_up deferred.resolve, args
        else
          process.nextTick => deferred.resolve available[@strip @clazz]

        deferred.promise

    module.exports = Madul