document controller config

document controller config

# /api/App Components/Batman.Controller

All controllers in a batman.js app extend `Batman.Controller`. `Batman.Controller`s are responsible for executing _actions_ which fire off requests for model data, render views, or redirect to other actions in response to navigation state changes. `Batman.Controller` is inspired by [ActionController](http://guides.rubyonrails.org/action_controller_overview.html), a key component of Ruby on Rails.

## Controller Directory

`Batman.Controller`s are singletons and each controller's instance is available at [`@sharedController`](/docs/api/batman.controller.html#class_accessor_sharedcontroller). Controller instances are also available at `MyApp.get('controllers')`( the app's [`ControllerDirectory`](/docs/api/controllerdirectory.html)). You can get the controller instance by the part of its name before "Controller", downcased. For example:

```
Alfred.TodosController.get('sharedController') # => TodosController instance
Alfred.get('controllers.todos')                # => TodosController instance
```

## Actions

Each `Batman.Controller` declares functions which represent actions to be run on a particular page. Typically, these functions will fetch data or render views:

```coffeescript
class Alfred.TodosController extends Batman.Controller
  routingKey: 'todos'
  index: (params) ->
    @set('todos', Alfred.Todo.get('all'))
    # will automatically render Alfred.TodosIndexView with source `todos/index`

  show: (params) ->
    Alfred.Todo.find params.id, (err, record) ->
      throw err if err
      @set('todo', record)
    # will automatically render Alfred.TodosShowView with source `todos/show`
```

Actions are passed a `params` argument, which is an object containing URL parameters. Named route parameters (eg, `todos/:id`) and query string parameters (`?key=value`) are accessible in `params`.

## routingKey and Minification

Each `Batman.Controller` must have a `routingKey`, which is used by the batman.js router. It also makes the app minification-safe. You can set it inside the controller definition:

```coffeescript
class Alfred.TodosController extends Batman.Controller
  routingKey: 'todos'
```

An app will fail to run if a controller's `routingKey` is not defined. To disable this requirement, set `Batman.config.minificationErrors` to false.

## Error Handling

`Batman.Controller` has a built-in structure for handling errors that occur during controller actions. Inside a controller definition, you can map errors to handlers using `@catchError`. Then, you can wrap a storage operation callback with `@errorHandler` to have any errors caught by the defined handlers. If you use `@errorHandler`, errors without declared handlers will be thrown (since they aren't passed to the callback).

```coffeescript
class Alfred.TodosController extends Batman.Controller
  routingKey: 'todos'
  # declare a handler with `@catchError`:
  @catchError Batman.StorageAdapter.NotFoundError, with: 'render404'

  show: (params) ->
    # wrap your storage operation in `@errorHandler`
    App.Todo.find params.id, @errorHandler (record, env) =>
      @set('todo', record)

  # error is passed to the handler
  render404: (error) -> @render(source: "errors/404")
```

Usually, you want to declare error handlers in `MyApp.ApplicationController`, then extend `MyApp.ApplicationController` in your other controllers:

```coffeescript
class Alfred.ApplicationController extends Batman.Controller
  @catchError Batman.StorageAdapter.NotFoundError, with: 'render404'
  # etc...

class Alfred.TodosController extends Alfred.ApplicationController
  # will use ApplicationController's handlers for @errorHandler
```

For a full list of storage errors, see [`Batman.StorageAdapter` Errors](/docs/api/batman.storageadapter_errors.html).

## ::render([options : [Object|Boolean]]) : View

`render` is used to control the rendering of the current action. Unless specified otherwise, `Batman.Controller` actions render automatically.

Passing `false` will prevent the current action from rendering the view.

```coffeescript
class Alfred.TodosController extends Batman.Controller
  actionWithNoRender: ->
    @render(false) # no view will be rendered

  actionWithDelayedRender: ->
    setTimeout (-> @render()), 1000 # view rendered after 1 second
    @render(false)
```

By passing an `options` object, you may override the default `view`, `source`, `viewClass` or `yield` block.

```coffeescript
class Alfred.TodosController extends Batman.Controller
  actionWithCustomSource: ->
    @render(source: 'errors/404')

  actionWithCustomYield: ->
    @render(into: 'not-main')
```

`render` options include:

- `view`: a view instance to render
- `viewClass`: a class to instantiate and render
- `source`: An HTML source path to use for the rendered view
- `into`: The yield where the view should be rendered
- Other options are passed to the `viewClass` constructor, if provided.

For more information on yield blocks, see [`Controller::.defaultRenderYield`](/docs/api/batman.controller.html#prototype_property_defaultrenderyield).

## @beforeAction([options : [string|Object],] filter : [string|Function])

Declares that a function should be executed should be executed before this controller's actions. If any `beforeAction` filter returns `false` or calls [`@redirect`](/docs/api/batman.controller.html#prototype_function_redirect), the controller action won't be executed. `@beforeAction` accepts:

-  `options` representing which action(s) to execute the filter before (optional)
-  `filter`, either a string naming a function _or_ a function to execute.

The `options` argument can take three forms:

1. `undefined`: this filter should be executed before all actions.
2. `String`: this filter should be executed before the action named by the string.
3. `Object`: this filter should be executed before the actions named by an Array at the `only` key in the options object, or before all actions excluding those named by an Array at the `except` key in the options object.

<!-- tests -->

    test "@beforeAction allows declaration of filters to execute before an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "index", -> results.push "before!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "before!"
      equal results[1], "action!"

    test "@beforeAction allows declaration of named filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "show", "fetchTodo"
        fetchTodo: -> @set("todo", {isDone: true})
        show: ->
          @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "show"
      deepEqual controller.get("todo"), {isDone: true}

    test "@beforeAction allows whitelisting or blacklisting filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: ["show", "edit"], "fetchTodo"
        @beforeAction except: ["index"], "prepareNewTodo"
        fetchTodo: -> @set "todo", {isDone: true}
        prepareNewTodo: -> @set "newTodo", {isDone: false}
        index: -> @render false
        show: -> @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "show"
      deepEqual controller.get("todo"), {isDone: true}
      deepEqual controller.get("newTodo"), {isDone: false}

    test "@beforeAction allows declaration of filters to execute before all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction -> results.push "before!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "before!"
      equal results[1], "action!"

## @afterAction([options : [string|Object],] filter : [string|Function])

Declares that a function should be executed after this controller's actions (and after any `render` or `redirect`s). `@afterAction` accepts `options` and `filter` (see [`@beforeAction`](/docs/api/batman.controller.html#class_function_beforeaction)).

    test "@afterAction allows declaration of filters to execute after an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @afterAction only: "index", -> results.push "after!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "action!"
      equal results[1], "after!"

    test "@afterAction allows declaration of named filters to execute after an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: "test"
        @afterAction only: "create", "notify"
        notify: -> result = "Todo created successfully."
        create: -> @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "create"
      equal result, "Todo created successfully."

    test "@afterAction allows whitelisting or blacklisting filters to execute after an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: "test"
        @afterAction only: ["create", "update"], "notify"
        index: -> @render false
        create: -> @render false
        notify: -> result = "Todo created successfully."

      controller = TodoController.get("sharedController")
      controller.dispatch "index"
      equal result, null
      controller.dispatch "create"
      equal result, "Todo created successfully."

    test "@afterAction allows declaration of filters to execute after all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @afterAction -> results.push "after!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "action!"
      equal results[1], "after!"

## ::executeAction(action: string[, params: Object])

Runs the `action` specified, including all applicable `@beforeAction`s and `@afterAction`s. Optionally, `params` can be passed into the new action for processing. If no params are passed, it will default to the params of the current action.

    test "executeAction will run the action and all @beforeAction and @afterAction filters", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "index", -> results.push "before!"
        @afterAction only: "index", -> results.push "after!"
        index: ->
          results.push "action!"
          @render false
        other: ->
          @executeAction("index")

      controller = TestController.get("sharedController")
      controller.dispatch "other"
      deepEqual results, ["before!", "action!", "after!"]

## ::redirect(options: [string|Object])

Properly handles the controller filter chain and loads a new page with [`Batman.redirect`](/docs/api/batman.html#class_function_redirect). See [`Batman.redirect`](/docs/api/batman.html#class_function_redirect) for allowed `options`. If `options` is an object, the current controller will be added as the object's `controller` attribute (if it isn't already present), so calling `@redirect({action: "show", id: itemId})` is equivalent to calling `@redirect({action: 'show', id: itemId, controller: 'items'})`.

## ::scrollToHash([hash: string])

`scrollToHash` emulates the native scrolling behaviour of the browser by allowing the URL to link to a specific ID on the page. The code will look for an element with a matching ID to `hash` if it is provided otherwise using the `#` parameter in the URL. If an element is found, the page will scroll to the matching element.

## ::.autoScrollToHash[= true] : boolean

Specifies if the controller should automatically scroll to the element with ID equal to the `hash` parameter. This behaviour emulates the native behaviour of the same nature, but is implemented in Batman so the functionality works after each dispatch (instead of each page refresh) and when Batman is using hash bang routing.

## ::.defaultRenderYield[= 'main'] : string

`defaultRenderYield` specifies which yield (see [`data-yield`](/docs/api/batman.view_bindings.html#data-yield)) a controller should automatically render into if no yield is declared.

## ::.coerceIntegerParams[=true] : boolean

If true, strings like `"123"` will be coerced to integers when passed in controller params. This is good for `Batman.Model` IDs. To disable this, set it to false in your controller class definition:

```coffeescript
class MyApp.MyController extends MyApp.ApplicationController
  coerceIntegerParams: false
```

## @%sharedController : Controller

The singleton instance of the `Controller`.

## @catchError(errorClasses..., {with : [String|Array]})

Declares that errors which are `instanceof` any of `errorClasses` should be handled by `with` when using [`@errorHandler`](/docs/api/batman.controller.html#class_function_errorhandler). `with` is the name of a prototype function (or an array of names) which will be invoked with the error. See ["Error Handling"](/docs/api/batman.controller.html#error_handling).

## @errorHandler(callback)

Wraps a storage action, passing the first argument (`error`) to error handlers declared with [`@catchError`](/docs/api/batman.controller.html#class_function_catcherror). Callback should take arguments `result, env` (`error` is not present because it was passed to error handlers). See ["Error Handling"](/docs/api/batman.controller.html#error_handling).

# /api/App Components/Batman.Controller

All controllers in a batman.js app extend `Batman.Controller`. `Batman.Controller`s are responsible for executing _actions_ which fire off requests for model data, render views, or redirect to other actions in response to navigation state changes. `Batman.Controller` is inspired by [ActionController](http://guides.rubyonrails.org/action_controller_overview.html), a key component of Ruby on Rails.

## Controller Directory

`Batman.Controller`s are singletons and each controller's instance is available at [`@sharedController`](/docs/api/batman.controller.html#class_accessor_sharedcontroller). Controller instances are also available at `MyApp.get('controllers')`( the app's [`ControllerDirectory`](/docs/api/controllerdirectory.html)). You can get the controller instance by the part of its name before "Controller", downcased. For example:

```
Alfred.TodosController.get('sharedController') # => TodosController instance
Alfred.get('controllers.todos')                # => TodosController instance
```

## Actions

Each `Batman.Controller` declares functions which represent actions to be run on a particular page. Typically, these functions will fetch data or render views:

```coffeescript
class Alfred.TodosController extends Batman.Controller
  routingKey: 'todos'
  index: (params) ->
    @set('todos', Alfred.Todo.get('all'))
    # will automatically render Alfred.TodosIndexView with source `todos/index`

  show: (params) ->
    Alfred.Todo.find params.id, (err, record) ->
      throw err if err
      @set('todo', record)
    # will automatically render Alfred.TodosShowView with source `todos/show`
```

Actions are passed a `params` argument, which is an object containing URL parameters. Named route parameters (eg, `todos/:id`) and query string parameters (`?key=value`) are accessible in `params`.

## routingKey and Minification

Each `Batman.Controller` must have a `routingKey`, which is used by the batman.js router. It also makes the app minification-safe. You can set it inside the controller definition:

```coffeescript
class Alfred.TodosController extends Batman.Controller
  routingKey: 'todos'
```

An app will fail to run if a controller's `routingKey` is not defined. To disable this requirement, set `Batman.config.minificationErrors` to false.

## Error Handling

`Batman.Controller` has a built-in structure for handling errors that occur during controller actions. Inside a controller definition, you can map errors to handlers using `@catchError`. Then, you can wrap a storage operation callback with `@errorHandler` to have any errors caught by the defined handlers. If you use `@errorHandler`, errors without declared handlers will be thrown (since they aren't passed to the callback).

```coffeescript
class Alfred.TodosController extends Batman.Controller
  routingKey: 'todos'
  # declare a handler with `@catchError`:
  @catchError Batman.StorageAdapter.NotFoundError, with: 'render404'

  show: (params) ->
    # wrap your storage operation in `@errorHandler`
    App.Todo.find params.id, @errorHandler (record, env) =>
      @set('todo', record)

  # error is passed to the handler
  render404: (error) -> @render(source: "errors/404")
```

Usually, you want to declare error handlers in `MyApp.ApplicationController`, then extend `MyApp.ApplicationController` in your other controllers:

```coffeescript
class Alfred.ApplicationController extends Batman.Controller
  @catchError Batman.StorageAdapter.NotFoundError, with: 'render404'
  # etc...

class Alfred.TodosController extends Alfred.ApplicationController
  # will use ApplicationController's handlers for @errorHandler
```

For a full list of storage errors, see [`Batman.StorageAdapter` Errors](/docs/api/batman.storageadapter_errors.html).

## ::render([options : [Object|Boolean]]) : View

`render` is used to control the rendering of the current action. Unless specified otherwise, `Batman.Controller` actions render automatically.

Passing `false` will prevent the current action from rendering the view.

```coffeescript
class Alfred.TodosController extends Batman.Controller
  actionWithNoRender: ->
    @render(false) # no view will be rendered

  actionWithDelayedRender: ->
    setTimeout (-> @render()), 1000 # view rendered after 1 second
    @render(false)
```

By passing an `options` object, you may override the default `view`, `source`, `viewClass` or `yield` block.

```coffeescript
class Alfred.TodosController extends Batman.Controller
  actionWithCustomSource: ->
    @render(source: 'errors/404')

  actionWithCustomYield: ->
    @render(into: 'not-main')
```

`render` options include:

- `view`: a view instance to render
- `viewClass`: a class to instantiate and render
- `source`: An HTML source path to use for the rendered view
- `into`: The yield where the view should be rendered
- Other options are passed to the `viewClass` constructor, if provided.

For more information on yield blocks, see [`Controller::.defaultRenderYield`](/docs/api/batman.controller.html#prototype_property_defaultrenderyield).

## @beforeAction([options : [string|Object],] filter : [string|Function])

Declares that a function should be executed should be executed before this controller's actions. If any `beforeAction` filter returns `false` or calls [`@redirect`](/docs/api/batman.controller.html#prototype_function_redirect), the controller action won't be executed. `@beforeAction` accepts:

-  `options` representing which action(s) to execute the filter before (optional)
-  `filter`, either a string naming a function _or_ a function to execute.

The `options` argument can take three forms:

1. `undefined`: this filter should be executed before all actions.
2. `String`: this filter should be executed before the action named by the string.
3. `Object`: this filter should be executed before the actions named by an Array at the `only` key in the options object, or before all actions excluding those named by an Array at the `except` key in the options object.

<!-- tests -->

    test "@beforeAction allows declaration of filters to execute before an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "index", -> results.push "before!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "before!"
      equal results[1], "action!"

    test "@beforeAction allows declaration of named filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "show", "fetchTodo"
        fetchTodo: -> @set("todo", {isDone: true})
        show: ->
          @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "show"
      deepEqual controller.get("todo"), {isDone: true}

    test "@beforeAction allows whitelisting or blacklisting filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: ["show", "edit"], "fetchTodo"
        @beforeAction except: ["index"], "prepareNewTodo"
        fetchTodo: -> @set "todo", {isDone: true}
        prepareNewTodo: -> @set "newTodo", {isDone: false}
        index: -> @render false
        show: -> @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "show"
      deepEqual controller.get("todo"), {isDone: true}
      deepEqual controller.get("newTodo"), {isDone: false}

    test "@beforeAction allows declaration of filters to execute before all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction -> results.push "before!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "before!"
      equal results[1], "action!"

## @afterAction([options : [string|Object],] filter : [string|Function])

Declares that a function should be executed after this controller's actions (and after any `render` or `redirect`s). `@afterAction` accepts `options` and `filter` (see [`@beforeAction`](/docs/api/batman.controller.html#class_function_beforeaction)).

    test "@afterAction allows declaration of filters to execute after an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @afterAction only: "index", -> results.push "after!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "action!"
      equal results[1], "after!"

    test "@afterAction allows declaration of named filters to execute after an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: "test"
        @afterAction only: "create", "notify"
        notify: -> result = "Todo created successfully."
        create: -> @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "create"
      equal result, "Todo created successfully."

    test "@afterAction allows whitelisting or blacklisting filters to execute after an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: "test"
        @afterAction only: ["create", "update"], "notify"
        index: -> @render false
        create: -> @render false
        notify: -> result = "Todo created successfully."

      controller = TodoController.get("sharedController")
      controller.dispatch "index"
      equal result, null
      controller.dispatch "create"
      equal result, "Todo created successfully."

    test "@afterAction allows declaration of filters to execute after all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @afterAction -> results.push "after!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "action!"
      equal results[1], "after!"

## ::executeAction(action: string[, params: Object])

Runs the `action` specified, including all applicable `@beforeAction`s and `@afterAction`s. Optionally, `params` can be passed into the new action for processing. If no params are passed, it will default to the params of the current action.

    test "executeAction will run the action and all @beforeAction and @afterAction filters", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "index", -> results.push "before!"
        @afterAction only: "index", -> results.push "after!"
        index: ->
          results.push "action!"
          @render false
        other: ->
          @executeAction("index")

      controller = TestController.get("sharedController")
      controller.dispatch "other"
      deepEqual results, ["before!", "action!", "after!"]

## ::redirect(options: [string|Object])

Properly handles the controller filter chain and loads a new page with [`Batman.redirect`](/docs/api/batman.html#class_function_redirect). See [`Batman.redirect`](/docs/api/batman.html#class_function_redirect) for allowed `options`. If `options` is an object, the current controller will be added as the object's `controller` attribute (if it isn't already present), so calling `@redirect({action: "show", id: itemId})` is equivalent to calling `@redirect({action: 'show', id: itemId, controller: 'items'})`.

## ::scrollToHash([hash: string])

`scrollToHash` emulates the native scrolling behaviour of the browser by allowing the URL to link to a specific ID on the page. The code will look for an element with a matching ID to `hash` if it is provided otherwise using the `#` parameter in the URL. If an element is found, the page will scroll to the matching element.

## ::.autoScrollToHash[= true] : boolean

Specifies if the controller should automatically scroll to the element with ID equal to the `hash` parameter. This behaviour emulates the native behaviour of the same nature, but is implemented in Batman so the functionality works after each dispatch (instead of each page refresh) and when Batman is using hash bang routing.

## ::.defaultRenderYield[= 'main'] : string

`defaultRenderYield` specifies which yield (see [`data-yield`](/docs/api/batman.view_bindings.html#data-yield)) a controller should automatically render into if no yield is declared.

## @%sharedController : Controller

The singleton instance of the `Controller`.

## @catchError(errorClasses..., {with : [String|Array]})

Declares that errors which are `instanceof` any of `errorClasses` should be handled by `with` when using [`@errorHandler`](/docs/api/batman.controller.html#class_function_errorhandler). `with` is the name of a prototype function (or an array of names) which will be invoked with the error. See ["Error Handling"](/docs/api/batman.controller.html#error_handling).

## @errorHandler(callback)

Wraps a storage action, passing the first argument (`error`) to error handlers declared with [`@catchError`](/docs/api/batman.controller.html#class_function_catcherror). Callback should take arguments `result, env` (`error` is not present because it was passed to error handlers). See ["Error Handling"](/docs/api/batman.controller.html#error_handling).


Don't overrite config properites in initialize

    Module = require './module'
    q      = require 'q'
    argv   = require './arguments'
    path   = require 'path'
    fs     = require 'fs'

    process.env.CGAPI_LOG_LEVEL = if argv?.verbosity? then argv.verbosity else 3

    class Config extends Module

      pathfinder: (neighbors) ->
        o = [ ]

        for n in [1..(neighbors.length / 1)]
          c = 1 / neighbors.length

          if neighbors[n - 1] == 'RIGHT'
            o.push "#{neighbors[n - 1]}": ((c * n) * ((2 / c) * 0.5)) * c
          else
            o.push "#{neighbors[n - 1]}": ((c * n) * (0.5 / c)) * c

        chance = Math.random()

        for option in o
          neighbor = Object.keys(option)[0]

          return neighbor if option[neighbor] > chance

      initialize: (params) =>
        deferred = q.defer()
        levels   = [ ]
        base     = if params?.location? then params.location else path.join __dirname, '..'
        config   = path.join base, '.skyll.conf.js'

        fs.stat config, (err) =>
          if err? || params?.cli?
            if argv?._?.length > 0
              levels = levels.concat argv._
            else if argv?.l?
              for level in [0...argv.l]
                levels.push new Date(Date.now() - (((argv.l - 1) - level) * 1000)).toString()
            else if argv?.levels? == false
              levels.push new Date().toString()
            for key, val of argv
              if key.length > 2 && typeof val != 'undefined'
                if key == 'levels'
                  levels = levels.concat val
                else
                  @[key] = val
          else
            for key, val of require config
              unless @[key]?
                if key == 'levels'
                  for level in [0...val]
                    levels.push new Date(Date.now() - (((val - 1) - level) * 1000)).toString()
                else
                  @[key] = val

          levels.push new Date().toString() if levels.length == 0

          @levels = levels
          @grid   = ((false for j in [0..@columns]) for i in [0..@rows])
          @width  = @width  * @multiplier
          @height = @height * @multiplier

          super().then => deferred.resolve @

        deferred.promise

    module.exports = Config

    Module = require './module'
    q      = require 'q'
    argv   = require './arguments'
    path   = require 'path'
    fs     = require 'fs'

    process.env.CGAPI_LOG_LEVEL = if argv?.verbosity? then argv.verbosity else 3

    class Config extends Module

      pathfinder: (neighbors) ->
        o = [ ]

        for n in [1..(neighbors.length / 1)]
          c = 1 / neighbors.length

          if neighbors[n - 1] == 'RIGHT'
            o.push "#{neighbors[n - 1]}": ((c * n) * ((2 / c) * 0.5)) * c
          else
            o.push "#{neighbors[n - 1]}": ((c * n) * (0.5 / c)) * c

        chance = Math.random()

        for option in o
          neighbor = Object.keys(option)[0]

          return neighbor if option[neighbor] > chance

      initialize: (params) =>
        deferred = q.defer()
        levels   = [ ]
        base     = if params?.location? then params.location else path.join __dirname, '..'
        config   = path.join base, '.skyll.conf.js'

        fs.stat config, (err) =>
          if err? || params?.cli?
            if argv?._?.length > 0
              levels = levels.concat argv._
            else if argv?.l?
              for level in [0...argv.l]
                levels.push new Date(Date.now() - (((argv.l - 1) - level) * 1000)).toString()
            else if argv?.levels? == false
              levels.push new Date().toString()
            for key, val of argv
              if key.length > 2 && typeof val != 'undefined'
                if key == 'levels'
                  levels = levels.concat val
                else
                  @[key] = val
          else
            for key, val of require config
              if key == 'levels'
                for level in [0...val]
                  levels.push new Date(Date.now() - (((val - 1) - level) * 1000)).toString()
              else
                @[key] = val

          levels.push new Date().toString() if levels.length == 0

          @levels = levels
          @grid   = ((false for j in [0..@columns]) for i in [0..@rows])
          @width  = @width  * @multiplier
          @height = @height * @multiplier

          super().then => deferred.resolve @

        deferred.promise

    module.exports = Config


Fix some bad advice I put in the StorageAdapter docs

# Batman.StorageAdapter

`Batman.StorageAdapter`s handle persistence of [`Batman.Model`s](/docs/api/batman.model.html). Any `Batman.Model` which will be created, read, updated or deleted must have a storage adapter, which is declared with [`Batman.Model@persist`](/docs/api/batman.model.html#class_function_persist):

```coffeescript
class App.Superhero extends Batman.Model
  @persist Batman.RestStorage # a StorageAdapter subclass
```

__Note:__ `@persist` instantiates a StorageAdapter instance during model definition, so it will use `@storageKey` and `@resourceName` from the model where it was instantiated, but it won't play well with inheritance. For example:

```coffeescript
class App.Model extends Batman.Model
  @storageKey: 'model'
  @persist Batman.LocalStorage

class App.Superhero extends App.Model
  # have to do it again here, or else it will use @storageKey of 'model'
  @storageKey: 'superhero'
  @persist Batman.LocalStorage
```

### Batman's Included StorageAdapters

Batman ships with a few storage adapters to get you up and coding quickly:

- `Batman.LocalStorage` uses [`window.localStorage`](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#localStorage) to persist records.
- `Batman.SessionStorage` extends `Batman.LocalStorage` and uses [`window.sessionStorage`](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#sessionStorage) to persist records.
- `Batman.RestStorage` uses [HTTP REST](http://en.wikipedia.org/wiki/REST) to persist records, mapping HTTP verbs to storage operations and handling HTTP response codes appropriately. _Note: Because `Batman.RestStorage` depends on [`Batman.Request`](/docs/api/batman.request.html), you'll need a [platform library](/docs/api/batman.request.html#platform_request_implementation_libraries) to implement `Batman.Request`._

### Batman.RailsStorage
Also, `Batman.RailsStorage` (available in separate file: [Coffee](https://github.com/batmanjs/batman/blob/master/src/extras/batman.rails.coffee), JS) extends `Batman.RestStorage` and provides some helpful Rails integrations:

- If the response's status code is 422 (`Unprocessable Entity`), Any `errors` defined in the JSON response will be added to the `Batman.Model`'s [errors](/docs/api/batman.model.html#prototype_accessor_errors).
- By default, Batman will get the Rails CSRF token from the `<head>`and send it as a request header. (This can be prevented by setting `Batman.config.protectFromCSRF = false`.)
- If a record's URL doesn't end in `.json` and doesn't include a query string, `.json` is automatically appended to the URL.

_Note: Like `Batman.RestStorage`, `Batman.RailsStorage` depends on [`Batman.Request`](/docs/api/batman.request.html), so you'll need a [platform library](/docs/api/batman.request.html#platform_request_implementation_libraries) to implement `Batman.Request`._

If you're using Batman and Rails, be sure to check out the [batman-rails](https://github.com/batmanjs/batman-rails) gem.

## Subclassing Batman.StorageAdapter

You may want to customize Batman's storage operations for your own app, for example:

- Adding before- and after-operation callbacks
- Overriding default storage operations

To do this, extend `Batman.StorageAdapter` (or one of the provided subclasses), then use your storage adapter to persist your models.
```
class App.HeroicStorageAdapter extends Batman.LocalStorage
  # filters, overrides

class App.Superhero extends Batman.Model
  @persist App.HeroicStorageAdapter
```
### `env` and `next`

Storage operations and callbacks each take two arguments: `env` and `next`.

`env` is a vanilla JS object which is passed to each function in the chain. `Batman.StorageAdapter` sets these attributes on `env`:

- `env.subject` is the `Batman.Model` record which had the storage operation called on it.
- `env.options` contains the options passed to the operation on the subject.
- `env.action` is the storage operation that will be executed by the storage adapter.
- `env.error` stores any errors that occur during the chain. It becomes the first argument to the operation callback.
- `env.result` contains the record(s) returned by the operation and should be set by the storage adapter implementation. It becomes the second argument to the operation's callback.

Storage adapters may use `env` to collect any extra information needed by their operations. For example, `Batman.RestStorage` adds some attributes to `env` and `env.options`:

- `env.request` is the `Batman.Request` which implements the storage operation.
- `env.options.method` is the HTTP method used by `Batman.Request` to implement the storage operation.
- `env.options.url` is the URL used by `Batman.Request` to implement the storage operation.

`next` is a reference to the next function in the call chain for the current storage operation. `Batman.StorageAdapter` uses this to execute before-filters, storage operations and after-filters in the correct sequence.

`next` should be called (`next()`) when the current function has completed. This indicates that the operation should proceed with the next function in its call chain. To ensure the completion of the call chain, consider wrapping your function in [`@skipIfError`](/docs/api/batman.storageadapter.html#class_function_skipiferror).

### Adding Callbacks

Callbacks can be registered with [`before`](/docs/api/batman.storageadapter.html#prototype_function_before) and [`after`](/docs/api/batman.storageadapter.html#prototype_function_after) on any storage operation (listed below) or `'all'` (which runs the callback before or after any operation). Callbacks accept two arguments, `env` and `next`, discussed below.

```coffeescript
class App.SpecificHeaderStorageAdapter extends Batman.RestStorage
  # include a specific header in all requests:
  @::before 'all', (env, next) ->
    headers = env.options.headers ||= {}
    headers["App-Specific-Header"] = App.getSpecificHeader()
    next()

  @::after 'create', (env, next) ->
    console.log "A #{env.subject.constructor.name} was created!"
    next()
```

## Storage Operations

Any `StorageAdapter` must implement these operations as instance methods, for example:

```
class App.ModifiedStorageAdapter extends Batman.RestStorage
  destroy: (env, next) ->
    # your custom destroy operation
    next()
```

When a record is saved, destroyed or loaded, `Batman.StorageAdapter` invokes these methods. Although you may reimplement them, you probably don't need to call them in your application code.

## ::create(env : Object, next : Function)
Called to save a new record. When `save` is called on a record and `isNew` returns `true`, the storage adapter's `create` method is called.

## ::read(env : Object, next : Function)
Called to load a record from storage.

## ::update(env : Object, next : Function)
Called to update an existing record. When `save` is called on a record and `isNew` returns `false`, the storage adapter's `update` method is called.

## ::destroy(env : Object, next : Function)
Called to destroy an existing record.

## ::readAll(env : Object, next : Function)
Called to load all records of a particular type from storage.

## Other Useful Methods

## @skipIfError(wrappedFunction : Function )

Wraps a function, bypassing the function body and calling next() if an error has already occurred.

    test "StorageAdapter@skipIfError doesn't call the function if env.error?", ->
      insideFunction = createSpy()
      nextFunction = createSpy()

      functionWithWrapper = Batman.LocalStorage.skipIfError (env, next) ->
        insideFunction()

      dummyEnv = {error: true}

      functionWithWrapper(dummyEnv, nextFunction)

      equal dummyEnv.error?, true, 'an error is present'
      equal insideFunction.called, false, 'insideFunction was skipped'
      equal nextFunction.called, true, 'nextFunction was called'

Inside a storage adapter definition, this function is referenced as `@skipIfError`, for example:

```
class App.SpecialStorageAdapter extends Batman.RestStorage
  @::before 'create', @skipIfError (env, next) ->
    console.log("This will be skipped if env.error? is true!")
    next()
```

## ::before (keys... : Strings, filter : Function)
Registers `filter` as a before-operation callback for the storage operations named by `keys...`.

## ::after (keys... : Strings, filter : Function)
Registers `filter` as a after-operation callback for the storage operations named by `keys...`.

# Batman.StorageAdapter

`Batman.StorageAdapter`s handle persistence of [`Batman.Model`s](/docs/api/batman.model.html). Any `Batman.Model` which will be created, read, updated or deleted must have a storage adapter, which is declared with [`Batman.Model@persist`](/docs/api/batman.model.html#class_function_persist):

```coffeescript
class App.Superhero extends Batman.Model
  @persist Batman.RestStorage # a StorageAdapter subclass
```

__Protip:__ Consider setting the storage adapter in one `Batman.Model` subclass, then extending that subclass in the rest of your app. Then, you won't have to call `@persist` every time:

```coffeescript
class App.Model extends Batman.Model
  @persist Batman.LocalStorage

class App.Superhero extends App.Model
  # no need to call @persist here!

class App.Sidekick extends App.Model
  # or here!
```

### Batman's Included StorageAdapters

Batman ships with a few storage adapters to get you up and coding quickly:

- `Batman.LocalStorage` uses [`window.localStorage`](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#localStorage) to persist records.
- `Batman.SessionStorage` extends `Batman.LocalStorage` and uses [`window.sessionStorage`](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#sessionStorage) to persist records.
- `Batman.RestStorage` uses [HTTP REST](http://en.wikipedia.org/wiki/REST) to persist records, mapping HTTP verbs to storage operations and handling HTTP response codes appropriately. _Note: Because `Batman.RestStorage` depends on [`Batman.Request`](/docs/api/batman.request.html), you'll need a [platform library](/docs/api/batman.request.html#platform_request_implementation_libraries) to implement `Batman.Request`._

### Batman.RailsStorage
Also, `Batman.RailsStorage` (available in separate file: [Coffee](https://github.com/batmanjs/batman/blob/master/src/extras/batman.rails.coffee), JS) extends `Batman.RestStorage` and provides some helpful Rails integrations:

- If the response's status code is 422 (`Unprocessable Entity`), Any `errors` defined in the JSON response will be added to the `Batman.Model`'s [errors](/docs/api/batman.model.html#prototype_accessor_errors).
- By default, Batman will get the Rails CSRF token from the `<head>`and send it as a request header. (This can be prevented by setting `Batman.config.protectFromCSRF = false`.)
- If a record's URL doesn't end in `.json` and doesn't include a query string, `.json` is automatically appended to the URL.

_Note: Like `Batman.RestStorage`, `Batman.RailsStorage` depends on [`Batman.Request`](/docs/api/batman.request.html), so you'll need a [platform library](/docs/api/batman.request.html#platform_request_implementation_libraries) to implement `Batman.Request`._

If you're using Batman and Rails, be sure to check out the [batman-rails](https://github.com/batmanjs/batman-rails) gem.

## Subclassing Batman.StorageAdapter

You may want to customize Batman's storage operations for your own app, for example:

- Adding before- and after-operation callbacks
- Overriding default storage operations

To do this, extend `Batman.StorageAdapter` (or one of the provided subclasses), then use your storage adapter to persist your models.
```
class App.HeroicStorageAdapter extends Batman.LocalStorage
  # filters, overrides

class App.Superhero extends Batman.Model
  @persist App.HeroicStorageAdapter
```
### `env` and `next`

Storage operations and callbacks each take two arguments: `env` and `next`.

`env` is a vanilla JS object which is passed to each function in the chain. `Batman.StorageAdapter` sets these attributes on `env`:

- `env.subject` is the `Batman.Model` record which had the storage operation called on it.
- `env.options` contains the options passed to the operation on the subject.
- `env.action` is the storage operation that will be executed by the storage adapter.
- `env.error` stores any errors that occur during the chain. It becomes the first argument to the operation callback.
- `env.result` contains the record(s) returned by the operation and should be set by the storage adapter implementation. It becomes the second argument to the operation's callback.

Storage adapters may use `env` to collect any extra information needed by their operations. For example, `Batman.RestStorage` adds some attributes to `env` and `env.options`:

- `env.request` is the `Batman.Request` which implements the storage operation.
- `env.options.method` is the HTTP method used by `Batman.Request` to implement the storage operation.
- `env.options.url` is the URL used by `Batman.Request` to implement the storage operation.

`next` is a reference to the next function in the call chain for the current storage operation. `Batman.StorageAdapter` uses this to execute before-filters, storage operations and after-filters in the correct sequence.

`next` should be called (`next()`) when the current function has completed. This indicates that the operation should proceed with the next function in its call chain. To ensure the completion of the call chain, consider wrapping your function in [`@skipIfError`](/docs/api/batman.storageadapter.html#class_function_skipiferror).

### Adding Callbacks

Callbacks can be registered with [`before`](/docs/api/batman.storageadapter.html#prototype_function_before) and [`after`](/docs/api/batman.storageadapter.html#prototype_function_after) on any storage operation (listed below) or `'all'` (which runs the callback before or after any operation). Callbacks accept two arguments, `env` and `next`, discussed below.

```coffeescript
class App.SpecificHeaderStorageAdapter extends Batman.RestStorage
  # include a specific header in all requests:
  @::before 'all', (env, next) ->
    headers = env.options.headers ||= {}
    headers["App-Specific-Header"] = App.getSpecificHeader()
    next()

  @::after 'create', (env, next) ->
    console.log "A #{env.subject.constructor.name} was created!"
    next()
```

## Storage Operations

Any `StorageAdapter` must implement these operations as instance methods, for example:

```
class App.ModifiedStorageAdapter extends Batman.RestStorage
  destroy: (env, next) ->
    # your custom destroy operation
    next()
```

When a record is saved, destroyed or loaded, `Batman.StorageAdapter` invokes these methods. Although you may reimplement them, you probably don't need to call them in your application code.

## ::create(env : Object, next : Function)
Called to save a new record. When `save` is called on a record and `isNew` returns `true`, the storage adapter's `create` method is called.

## ::read(env : Object, next : Function)
Called to load a record from storage.

## ::update(env : Object, next : Function)
Called to update an existing record. When `save` is called on a record and `isNew` returns `false`, the storage adapter's `update` method is called.

## ::destroy(env : Object, next : Function)
Called to destroy an existing record.

## ::readAll(env : Object, next : Function)
Called to load all records of a particular type from storage.

## Other Useful Methods

## @skipIfError(wrappedFunction : Function )

Wraps a function, bypassing the function body and calling next() if an error has already occurred.

    test "StorageAdapter@skipIfError doesn't call the function if env.error?", ->
      insideFunction = createSpy()
      nextFunction = createSpy()

      functionWithWrapper = Batman.LocalStorage.skipIfError (env, next) ->
        insideFunction()

      dummyEnv = {error: true}

      functionWithWrapper(dummyEnv, nextFunction)

      equal dummyEnv.error?, true, 'an error is present'
      equal insideFunction.called, false, 'insideFunction was skipped'
      equal nextFunction.called, true, 'nextFunction was called'

Inside a storage adapter definition, this function is referenced as `@skipIfError`, for example:

```
class App.SpecialStorageAdapter extends Batman.RestStorage
  @::before 'create', @skipIfError (env, next) ->
    console.log("This will be skipped if env.error? is true!")
    next()
```

## ::before (keys... : Strings, filter : Function)
Registers `filter` as a before-operation callback for the storage operations named by `keys...`.

## ::after (keys... : Strings, filter : Function)
Registers `filter` as a after-operation callback for the storage operations named by `keys...`.


Fix rendering pipeline execution

Fix rendering pipeline execution

A single rendering pipeline as well as a collection of pipelines can
now be rendered successfully

    Madul = require 'madul'

    class Skyll extends Madul
      deps: [ 'config', 'carver', 'async' ]
      pub:  [ 'craft' ]

      render_pipeline: [ ]
      renderers:       [ ]

      post_initialize: =>
        pipe = [ ]

        for p in @config.pipeline
          if Array.isArray p
            for q in p
              pipe.push q unless pipe.includes q
          else
            pipe.push p unless pipe.includes p

        @hydrate pipe, =>
          renderer_pushed = false
          for p in @config.pipeline
            if Array.isArray p
              @renderers.push @[p[0]]

              new_pipeline = for q in p
                @[q]

              @render_pipeline.push new_pipeline
            else
              unless renderer_pushed
                @renderers.push @[p]
                renderer_pushed = true

              @render_pipeline.push @[p]

          @carver.starting_row = Math.floor @config.grid.length / 2

          @done()

      do_flush: (i, level_name, next) =>
        if @renderers[i].flush?
          flushed = @renderers[i].flush level_name

          if typeof flushed?.then == 'function'
            flushed.then => next()
          else
            next()
        else
          next()

      do_render: (step, path, level_name, next) =>
        console.log 'rendering', step.constructor.name

        status = step.render path, level_name

        if typeof status?.then == 'function'
          status.then => next()
        else
          next()

      craft: (level_name) =>
        @carver.clear_state()

        path = @carver.carve_path()

        @async.eachOfSeries @render_pipeline, (pipeline, i, next) =>
          if Array.isArray pipeline
            @async.eachSeries pipeline, (step, nxt) =>
              @do_render step, path, level_name, nxt
            , => @do_flush i, level_name, next
          else
            @do_render pipeline, path, level_name, =>
              if i == @render_pipeline.length - 1
                @do_flush 0, level_name, next
              else
                next()
        , => @done()

    module.exports = Skyll

    Madul = require 'madul'

    class Skyll extends Madul
      deps: [ 'config', 'carver', 'async' ]
      pub:  [ 'craft' ]

      render_pipeline: [ ]
      renderers:       [ ]

      post_initialize: =>

        super().then =>
          for p in @config.pipeline
            if Array.isArray p
              for q in p
                @deps.push q unless @deps.includes q
            else
              @deps.push p unless @deps.includes p

          @hydrate_dependencies().then =>
            for p in @config.pipeline
              if Array.isArray p
                @renderers.push @[p[0]]

                new_pipeline = for q in p
                  @[q]

                @render_pipeline.push new_pipeline
              else
                @renderers.push @[p]
                @render_pipeline.push @[p]

            @carver.starting_row = params.starting_row

            deferred.resolve @

        deferred.promise

      craft: (level_name) =>
        @carver.clear_state()

        path = @carver.carve_path()

        @async.mapSeries @render_pipeline, (step, next) =>
          i = @render_pipeline.indexOf step

          if Array.isArray step
            @q.all step.map (pipeline) => pipeline.render path, level_name
              .then => @renderers[i].flush level_name
              .then => next()
          else
            step.render path, level_name
              .then => @renderers[i].flush level_name
              .then => next()
        , => @done()

    module.exports = Skyll


Added more accordion litcoffee pesudo code

手風琴
======

手風琴能夠開關閉合其面板。

    Name = 'Accordion'

設定
---------------

    Settings =
        # 消音所有提示，甚至是錯誤訊息。
        silent        : false
        # 顯示除錯訊息。
        debug         : true
        # 是否僅允許單個手風琴只有一個分頁能被打開。
        exclusive     : true
        # 展開的手風琴是否可以被關閉。
        collapsible   : true
        # 當手風琴被關閉時，是否一同閉合子手風琴。
        closeNested   : true

回呼
---------------

    Callbacks =
        # 當手風琴正在展開時所會呼叫的函式。
        onOpening     : =>
        # 當手風琴展開時所會呼叫的函式。
        onOpen        : =>
        # 當手風琴正在關閉時所會呼叫的函式。
        onClosing     : =>
        # 當手風琴關閉時所會呼叫的函式。
        onClose       : =>
        # 當手風琴被切換開關時所會呼叫的函式。
        onChange      : =>

內部資料
---------------

    Data =
        items: []

模板
---------------

    Template = """

        <template v-for="(item, index) in items">

                {{ item.title }}

                {{ item.content }}

        </template>

    """

對外方法
---------------

    ExportedMethods =
        # open 會打開指定的手風琴。
        open: (index) ->
            @open index

        # close 會關閉指定的手風琴。
        close: (index) ->
            @close index

        # closeOthers 會關閉指定手風琴以外的其他手風琴。
        closeOthers: (index) ->
            for item, i in @$data.items
                if index isnt i
                    item.visible = false

內建方法
---------------

    Methods =
        # toggle 能夠切換一個手風琴，如果手風琴是開的則閉合，反之亦然。
        toggle: (index) ->
            @$data.items[index].visible = !@$data[index].visible

        # open 能夠打開一個手風琴。
        open : (index) ->
            @$data.items[index].visible = yes

        # close 能夠關閉一個手風琴。
        close: (index) ->
            @$data.items[index].visible = no

初始器
---------------

    Initializer = (Data) ->
        ts(@).find(':scope > .title').each (element) =>
            Data.items.push
                title  : ts(element).html()
                content: ts(element).next().html()
                visible: false

註冊
---------------

    ts.register {
        Name,
        Settings,
        Data,
        Template,
        ExportedMethods,
        Methods,
        Initializer
    }

手風琴
======

手風琴能夠開關閉合其面板。

    Name = 'Accordion'

設定
---------------

    Settings =
        # 消音所有提示，甚至是錯誤訊息。
        silent        : false
        # 顯示除錯訊息。
        debug         : true
        # 是否僅允許單個手風琴只有一個分頁能被打開。
        exclusive     : true
        # 展開的手風琴是否可以被關閉。
        collapsible   : true
        # 當手風琴被關閉時，是否一同閉合子手風琴。
        closeNested   : true

回呼
---------------

    Callbacks =
        # 當手風琴正在展開時所會呼叫的函式。
        onOpening     : =>
        # 當手風琴展開時所會呼叫的函式。
        onOpen        : =>
        # 當手風琴正在關閉時所會呼叫的函式。
        onClosing     : =>
        # 當手風琴關閉時所會呼叫的函式。
        onClose       : =>
        # 當手風琴被切換開關時所會呼叫的函式。
        onChange      : =>

內部資料
---------------

    Data = {}

模板
---------------

    Template = """

        <template v-for="(item, index) in items">

                {{ item.title }}

                {{ item.content }}

        </template>

    """

對外方法
---------------

    ExportedMethods =
        # open 會打開指定的手風琴。
        open: (index) =>

        # close 會關閉指定的手風琴。
        close: (index) =>

        # closeOthers 會關閉指定手風琴以外的其他手風琴。
        closeOthers: (index) =>

內建方法
---------------

    Methods =
        # toggle 能夠切換一個手風琴，如果手風琴是開的則閉合，反之亦然。
        toggle: (index) ->
            @$data[index].visible = !@$data[index].visible

        # open 能夠打開一個手風琴。
        open : (index) ->
            @$data[index].visible = yes

        # close 能夠關閉一個手風琴。
        close: (index) ->
            @$data[index].visible = no

初始器
---------------

    Initializer = ->
        data = []
        ts(@).find(':scope > .title').each (element) =>
            data.push
                title  : ts(element).html()
                content: ts(element).next().html()
                visible: false

註冊
---------------

    ts.register {
        Name,
        Settings,
        Data,
        Template,
        ExportedMethods,
        Methods,
        Initializer
    }


Added functions to the matrix module for transforming vectors and getting vectors from a matrix.

Matrices are arrays of 16 numbers forming a 4x4 matrix.

    temp1 = []
    temp2 = []
    rotationTemp = []
    vectorTemp = []

    makeRotate = (axis1, axis2, axis3, axis4) ->
        temp3 = []
        rotationTemp.push temp3
        (radians, output) ->
            sin = Math.sin radians
            cos = Math.cos radians
            temp3[axis1] = cos
            temp3[axis2] = -sin
            temp3[axis3] = sin
            temp3[axis4] = cos
            module.exports.multiply output, temp3, output
            return

    vector = require "./vector.litcoffee"

    module.exports =

Given a matrix, calling the "identity" property writes the identity matrix to
it.

        identity: (output) ->
            for row in [0...4]
                for column in [0...4]
                    output[row * 4 + column] = if row is column then 1 else 0
            return

Given two matrices, calling the "copy" property copies every component from the
first to the second.

        copy: (input, output) ->
            output[index] = value for value, index in input
            return

Given three matrices, calling the "multiply" property multiplies the first two
together and writes the result to the third.

        multiply: (a, b, output) ->
            module.exports.copy a, temp1
            module.exports.copy b, temp2

            for row in [0...4]
                for column in [0...4]
                    temp = 0
                    for component in [0...4]
                        temp += temp1[component * 4 + column] * temp2[row * 4 + component]
                    output[row * 4 + column] = temp
            return

Given a number of radians and a matrix, calling the "rotateX" property modifies
the matrix to have been rotated by that number of radians about the X axis.

        rotateX: makeRotate 5, 6, 9, 10

Given a number of radians and a matrix, calling the "rotateY" property modifies
the matrix to have been rotated by that number of radians about the Y axis.

        rotateY: makeRotate 0, 2, 8, 10

Given a number of radians and a matrix, calling the "rotateZ" property modifies
the matrix to have been rotated by that number of radians about the Z axis.

        rotateZ: makeRotate 0, 1, 4, 5

Given a vector specifying the scaling factor on each axis and a matrix, calling
the "scale" property scales the matrix by those scaling factors.

        scale: (vector, output) ->
            output[index] *= vector[0] for index in [0...4]
            output[index] *= vector[1] for index in [4...8]
            output[index] *= vector[2] for index in [8...12]
            return

Given a vector specifying a translation and a matrix to translate, calling the
"translate" property applies that translation to that matrix.

        translate: (vector, output) ->
            output[3] += vector[0]
            output[7] += vector[1]
            output[11] += vector[2]
            return

Given a matrix, X, Y, Z and W values (defaulting to 0, 0, 0 and 1 respectively
if not given), calling the "apply" property returns an array of four numbers
representing the transformed vector.

        apply: (matrix, x, y, z, w) ->
            if x is undefined then x = 0
            if y is undefined then y = 0
            if z is undefined then z = 0
            if w is undefined then w = 1

            [
                x * matrix[0] + y * matrix[1] + z * matrix[2] + w * matrix[3]
                x * matrix[4] + y * matrix[5] + z * matrix[6] + w * matrix[7]
                x * matrix[8] + y * matrix[9] + z * matrix[10] + w * matrix[11]
                x * matrix[12] + y * matrix[13] + z * matrix[14] + w * matrix[15]
            ]

Given a matrix, input vector and output vector, calling the "applyToVector"
property writes the input vector transformed by the matrix to the output vector.

        applyToVector: (matrix, input, output) ->
            vector.copy input, vectorTemp
            output[0] = vectorTemp[0] * matrix[0] + vectorTemp[1] * matrix[1] + vectorTemp[2] * matrix[2] + matrix[3]
            output[1] = vectorTemp[0] * matrix[4] + vectorTemp[1] * matrix[5] + vectorTemp[2] * matrix[6] + matrix[7]
            output[2] = vectorTemp[0] * matrix[8] + vectorTemp[1] * matrix[9] + vectorTemp[2] * matrix[10] + matrix[11]
            return

Given a matrix and output vector, calling the "getTranslation" property writes
the translation applied by the matrix to the output vector.

        getTranslation: (matrix, output) ->
            output[0] = matrix[12]
            output[1] = matrix[13]
            output[2] = matrix[14]

Given a matrix and output vector, calling the "getX" property writes the vector
of the matrix's X axis (a scaled normal) to the output vector.

        getX: (matrix, output) ->
            output[0] = matrix[0]
            output[1] = matrix[4]
            output[2] = matrix[8]

Given a matrix and output vector, calling the "getY" property writes the vector
of the matrix's Y axis (a scaled normal) to the output vector.

        getY: (matrix, output) ->
            output[0] = matrix[1]
            output[1] = matrix[5]
            output[2] = matrix[9]

Given a matrix and output vector, calling the "getZ" property writes the vector
of the matrix's Z axis (a scaled normal) to the output vector.

        getZ: (matrix, output) ->
            output[0] = matrix[2]
            output[1] = matrix[6]
            output[2] = matrix[10]

    module.exports.identity temp1
    module.exports.identity temp2
    for mat in rotationTemp
        module.exports.identity mat

Matrices are arrays of 16 numbers forming a 4x4 matrix.

    temp1 = []
    temp2 = []
    rotationTemp = []

    makeRotate = (axis1, axis2, axis3, axis4) ->
        temp3 = []
        rotationTemp.push temp3
        (radians, output) ->
            sin = Math.sin radians
            cos = Math.cos radians
            temp3[axis1] = cos
            temp3[axis2] = -sin
            temp3[axis3] = sin
            temp3[axis4] = cos
            module.exports.multiply output, temp3, output
            return

    module.exports =

Given a matrix, calling the "identity" property writes the identity matrix to
it.

        identity: (output) ->
            for row in [0...4]
                for column in [0...4]
                    output[row * 4 + column] = if row is column then 1 else 0
            return

Given two matrices, calling the "copy" property copies every component from the
first to the second.

        copy: (input, output) ->
            output[index] = value for value, index in input
            return

Given three matrices, calling the "multiply" property multiplies the first two
together and writes the result to the third.

        multiply: (a, b, output) ->
            module.exports.copy a, temp1
            module.exports.copy b, temp2

            for row in [0...4]
                for column in [0...4]
                    temp = 0
                    for component in [0...4]
                        temp += temp1[component * 4 + column] * temp2[row * 4 + component]
                    output[row * 4 + column] = temp
            return

Given a number of radians and a matrix, calling the "rotateX" property modifies
the matrix to have been rotated by that number of radians about the X axis.

        rotateX: makeRotate 5, 6, 9, 10

Given a number of radians and a matrix, calling the "rotateY" property modifies
the matrix to have been rotated by that number of radians about the Y axis.

        rotateY: makeRotate 0, 2, 8, 10

Given a number of radians and a matrix, calling the "rotateZ" property modifies
the matrix to have been rotated by that number of radians about the Z axis.

        rotateZ: makeRotate 0, 1, 4, 5

Given a vector specifying the scaling factor on each axis and a matrix, calling
the "scale" property scales the matrix by those scaling factors.

        scale: (vector, output) ->
            output[index] *= vector[0] for index in [0...4]
            output[index] *= vector[1] for index in [4...8]
            output[index] *= vector[2] for index in [8...12]
            return

Given a vector specifying a translation and a matrix to translate, calling the
"translate" property applies that translation to that matrix.

        translate: (vector, output) ->
            output[3] += vector[0]
            output[7] += vector[1]
            output[11] += vector[2]
            return

Given a matrix, X, Y, Z and W values (defaulting to 0, 0, 0 and 1 respectively
if not given), calling the "apply" property returns an array of four numbers
representing the transformed vector.

        apply: (matrix, x, y, z, w) ->
            if x is undefined then x = 0
            if y is undefined then y = 0
            if z is undefined then z = 0
            if w is undefined then w = 1

            [
                x * matrix[0] + y * matrix[1] + z * matrix[2] + w * matrix[3]
                x * matrix[4] + y * matrix[5] + z * matrix[6] + w * matrix[7]
                x * matrix[8] + y * matrix[9] + z * matrix[10] + w * matrix[11]
                x * matrix[12] + y * matrix[13] + z * matrix[14] + w * matrix[15]
            ]

    module.exports.identity temp1
    module.exports.identity temp2
    for mat in rotationTemp
        module.exports.identity mat


Remove debugging from the league module

Remove debugging from the league module

League Status
=============

The league status is a function of the completed matches. Completed
matches are themselves a function of a match schedule -- specifically,
a filter on those with defined outcomes (scores).

    completedMatches =
        Data.matchSchedule.map (matches) ->
            _.filter matches, (match) ->
                match.scores?

    completedMatches = completedMatches.toProperty []

It is also useful to have a common source combining the completed
matches and the team roster.

    dataSource =
        Bacon.combineTemplate
            matches: completedMatches
            teams: Data.teams

We publicise two properties under the *League* object - the
*leaderboard* and the *scores*.

Scores
------

The scores are a map from team IDs to their current league scores
- naturally, a map over the common data source.

First, we define the *teamScore* function, taking the list of
completed matches and a team as arguments.

    teamScore = (matches, team) ->

We first match scores to the score gained by this team from each
match.

        scores = (for match in matches
            if team not in match.teams
                0
            else
                match.scores[_.indexOf(match.teams, team)])

The total score is then simply a summation reduction over the
individual match scores.

        _.reduce scores, ( (a, b) -> a + b ), 0

The actual scores property makes use of the *teamScore* function,
looping over it for each present team.

    scores = dataSource.map (data) ->
        teams = (team for team, settings of data.teams when settings.present)
        _.object ([team, teamScore(data.matches, team)] for team in teams)

Finally the scores property is changed to avoid duplicates.

    scores = scores.skipDuplicates()

Leaderboard
-----------

The *leaderboard* is a list of entries, each of which contains:

* A team TLA,
* Its position on the leaderboard,
* Its score.

It is defined as a map over the scores.

    leaderboard = scores.map (teamScores) ->

We first take the team scores as [team, score] pairs, grouped by
score.

        _.chain(teamScores)
         .pairs()
         .groupBy( (x) -> x[1] )
         .pairs()

We then sort by score high to low and run a second simple grouping
pass -- yielding a list of [score, [team]] entries.

         .sortBy( (x) -> -x[0] )
         .map( (x) -> [x[0], _.map(x[1], (x) -> x[0])] )

We then run a reduction to assign leaderboard numbers.

         .reduce( ( (a, b) ->
             a.concat([1 + a.length, x, b[0]] for x in b[1]) ), [] )

Finally, a map pass converts to the desired output format.

         .map( (x) ->
            [position, team, score] = x
            {position: position, team: team, score: score} )
         .value()

The leaderboard is then filtered to remove duplicates.

    leaderboard = leaderboard.skipDuplicates()

Public Properties
-----------------

We publicise both the score table and the leaderboard.

    window.League =
        scores: scores
        leaderboard: leaderboard

League Status
=============

The league status is a function of the completed matches. Completed
matches are themselves a function of a match schedule -- specifically,
a filter on those with defined outcomes (scores).

    completedMatches =
        Data.matchSchedule.map (matches) ->
            _.filter matches, (match) ->
                match.scores?

    completedMatches = completedMatches.toProperty []

It is also useful to have a common source combining the completed
matches and the team roster.

    dataSource =
        Bacon.combineTemplate
            matches: completedMatches
            teams: Data.teams

We publicise two properties under the *League* object - the
*leaderboard* and the *scores*.

Scores
------

The scores are a map from team IDs to their current league scores
- naturally, a map over the common data source.

First, we define the *teamScore* function, taking the list of
completed matches and a team as arguments.

    teamScore = (matches, team) ->

We first match scores to the score gained by this team from each
match.

        scores = (for match in matches
            if team not in match.teams
                0
            else
                match.scores[_.indexOf(match.teams, team)])

The total score is then simply a summation reduction over the
individual match scores.

        _.reduce scores, ( (a, b) -> a + b ), 0

The actual scores property makes use of the *teamScore* function,
looping over it for each present team.

    scores = dataSource.map (data) ->
        teams = (team for team, settings of data.teams when settings.present)
        _.object ([team, teamScore(data.matches, team)] for team in teams)

Finally the scores property is changed to avoid duplicates.

    scores = scores.skipDuplicates()

Leaderboard
-----------

The *leaderboard* is a list of entries, each of which contains:

* A team TLA,
* Its position on the leaderboard,
* Its score.

It is defined as a map over the scores.

    leaderboard = scores.map (teamScores) ->

We first take the team scores as [team, score] pairs, grouped by
score.

        _.chain(teamScores)
         .pairs()
         .groupBy( (x) -> x[1] )
         .pairs()

We then sort by score high to low and run a second simple grouping
pass -- yielding a list of [score, [team]] entries.

         .sortBy( (x) -> -x[0] )
         .map( (x) -> [x[0], _.map(x[1], (x) -> x[0])] )

We then run a reduction to assign leaderboard numbers.

         .reduce( ( (a, b) ->
             a.concat([1 + a.length, x, b[0]] for x in b[1]) ), [] )

Finally, a map pass converts to the desired output format.

         .map( (x) ->
            [position, team, score] = x
            {position: position, team: team, score: score} )
         .value()

The leaderboard is then filtered to remove duplicates.

    leaderboard = leaderboard.skipDuplicates()

Debugging
---------

We debug changes to both scores and leaderboard.

    completedMatches.onValue (x) ->
        console.log "Matches done", x
    dataSource.onValue (x) ->
        console.log "LS source", x
    leaderboard.onValue (x) ->
        console.log "Leaderboard", x
    scores.onValue (x) ->
        console.log "Scores", x

Public Properties
-----------------

We publicise both the score table and the leaderboard.

    window.League =
        scores: scores
        leaderboard: leaderboard


Beauty

Beauty

# Application entry point.

Top-level module.

    angular.module 'shrub', ['shrub.core']

Include core Angular dependencies.

    coreDependencies = []
    coreDependencies.push 'ngRoute'
    coreDependencies.push 'ngSanitize'

`packageDependencies` will be automatically generated and populated by Grunt.
Packages implement the hook `angularPackageDependencies` to specify their
3rd-party module dependencies.

###### TODO: Link this to where this happens in Grunt for illustration.

    coreDependencies.push packageDependencies...

Include core shrub dependencies.

    coreDependencies.push 'shrub.config'
    coreDependencies.push 'shrub.packages'
    coreDependencies.push 'shrub.require'

Define the core Shrub module.

    angular.module('shrub.core', coreDependencies)

      .config([
        '$injector', 'shrub-pkgmanProvider'
        ({invoke}, {invokeFlat}) ->

#### Invoke hook `appConfig`.

Invoked when the Angular application is in the configuration phase.
Implementations should return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

          invoke injectable for injectable in invokeFlat 'appConfig'

      ])

      .run([

        '$injector', 'shrub-pkgman'
        ({invoke}, {invokeFlat}) ->

#### Invoke hook `appRun`.

Invoked when the Angular application is the run phase. Implementations should
return an
[annotated function](http://docs.angularjs.org/guide/di#dependency-annotation).

          invoke injectable for injectable in invokeFlat 'appRun'

      ])

# Application entry point.

Top-level module.

    angular.module 'shrub', ['shrub.core']

Include core Angular dependencies.

    coreDependencies = []
    coreDependencies.push 'ngRoute'
    coreDependencies.push 'ngSanitize'

`packageDependencies` will be automatically generated and populated by Grunt.
Packages implement the hook `angularPackageDependencies` to specify their
3rd-party module dependencies.

###### TODO: Link this to where this happens in Grunt for illustration.

    coreDependencies.push packageDependencies...

Include core shrub dependencies.

    coreDependencies.push 'shrub.config'
    coreDependencies.push 'shrub.packages'
    coreDependencies.push 'shrub.require'

Define the core Shrub module.

    angular.module('shrub.core', coreDependencies)

      .config([
        '$injector', 'shrub-pkgmanProvider'
        ({invoke}, {invokeFlat}) ->

#### Invoke hook `appConfig`.

Invoked when the Angular application is in the configuration phase.

          invoke injectable for injectable in invokeFlat 'appConfig'

      ])

      .run([

        '$injector', 'shrub-pkgman'
        ({invoke}, {invokeFlat}) ->

#### Invoke hook `appRun`.

Invoked when the Angular application is the run phase. This is where things
begin to get interesting. :)

          invoke injectable for injectable in invokeFlat 'appRun'

      ])


improve support for local caching to local storage and subsequent delta updates

# glg-hummingbird
Polymer element to maintain a hummingbird typeahead index that persists between browser restarts.

    hummingbird = require 'hummingbird'
    # shim for chrome file system access
    window.requestFileSystem = window.requestFileSystem ? window.webkitRequestFileSystem

    Polymer 'glg-hummingbird',

## Events
### hb-results
This event is emitted when there are new hummingbird results returned where the payload is the results array.

### no-hb-index
This event is emitted when attempting to load a non-existent hummingbird index from persistence or when
it found an index file but was unable to load it into hummingbird.

### hb-fs-error
This event is emitted when there is an error interacting with the file system where the payload is the error object.

### hb-loaded
This event is emitted after a persisted index is finished loading.

### hb-purged
This event is emitted after a persisted index is successfully deleted from local storage and memory.

## Methods
### search
Method for retrieving results from a humminbird index
* query (required) - a string to be tokenized and searched

      search: (query) ->
        hbOptions =
          scoreThreshold: @scoreThreshold ? 0
          secondarySortField: @secondarySortField
          secondarySortOrder: @secondarySortOrder
          howMany: @howMany ? 10
          startPos: @startPos ? 0

        #lookup by fuzzy name match
        @idx.search query, (results) =>
          @fire 'hb-results', results
        , hbOptions

### jump
Method for retrieving a single result from a hummingbird index by ID
* id (required) - the ID of the document to be returned

      jump: (id) ->
        #lookup by ID
        @idx.jump id, (results) =>
          @fire 'hb-results', results

### upsert
Method to insert new entries into the index or update existing entries

      upsert: (doc) ->
        unless doc?.name? and doc?.id?
          console.error "glg-hb: every hummingbird document must have a minimum of 'name' and 'id' properties"
        else
          @idx.add doc

### bulkLoad
Method to insert new entries into the index or update existing entries

      bulkLoad: (docs) ->
        (@upsert doc for doc in docs)

### numItems
Method to insert new entries into the index or update existing entries

      numItems: () ->
        Object.keys(@idx?.metaStore?.root).length

### persist
Method to persist hummingbird index to localStorage

      persist: () ->
        window.requestFileSystem window.TEMPORARY, null
        , (fs) =>
          # success handler
          fs.root.getFile @indexName, {create: true}, (fileEntry) =>
            fileEntry.createWriter (fileWriter) =>
              fileWriter.onerror = @__fileErrorHandler(@indexName)
              fileWriter.onabort = () => console.debug "#{@indexName} write aborted"
              fileWriter.onprogress = () => console.debug "#{@indexName} write progress"
              fileWriter.onwritestart = () => console.debug "#{@indexName} write started"
              fileWriter.onwrite = () => console.debug "#{@indexName} writing"
              fileWriter.onwriteend = (evt) =>
                console.debug "Successfully persisted #{@indexName}"
                return
              try
                idxJson = @idx.toJSON()
                idxJsonStr = JSON.stringify(idxJson)
                fileWriter.write new Blob([idxJsonStr], {type: 'text/plain'})
              catch err
                console.error "glg-hb: unable to persist #{@indexName} index: #{JSON.stringify err}"
            , @__fileErrorHandler(@indexName)
          , @__fileErrorHandler(@indexName)
        , @__fileErrorHandler(@indexName)

### purge
Method to delete persisted file from disk

      purge: () ->
        window.requestFileSystem window.TEMPORARY, null
        , (fs) =>
          # success handler
          fs.root.getFile @indexName, { create: false }, (fileEntry) =>
            fileEntry.remove =>
              console.debug "glg-hb: purged persisted #{@indexName} index."
              @idx = new hummingbird()
              @fire 'hb-purged', @indexName
            , @__fileErrorHandler(@indexName)
          , @__fileErrorHandler(@indexName)
        , @__fileErrorHandler(@indexName)

### getCreateTime
Method that returns the timestamp for the index creation (not persist or load).
It has become the norm to incrementally add new documents to a hummingbird index, but not remove 'deleted' or obsolete documents.
Given that convention, this method enables the consuming application to determine whether the persisted index is 'old' and
should be purged from local storage and fully rebuilt from scratch to take into account documents that should no longer be in the index.

      getCreateTime: () ->
        @idx.createTime

### getLastUpdateTime
Method that returns the timestamp for the last time the index was updated (including create, add, or remove, but not persist or load)

      getLastUpdateTime: () ->
        @idx.lastUpdate

### __fileErrorHandler
Internal method to handle various filesystem errors

      __fileErrorHandler: (indexName) ->
        #closure to maintain reference to Polymer object in scope
        (err) =>
          if err.name is "NotFoundError"
            console.debug "glg-hb: #{indexName} - #{err.name}: #{err.message}"
            @fire 'no-hb-index', @indexName
          else
            console.error "glg-hb: #{indexName} - #{err.name}: #{err.message}"
            err.message = "#{@indexName}: #{err.message}"
            @fire 'hb-fs-error', err

## Polymer Lifecycle
On element creation, load the named index if it exists and make it immediately available for use.

      created: ->
        # create an empty index
        @idx = new hummingbird()
        window.requestFileSystem window.TEMPORARY, null
        , (fs) =>
          # success handler
          fs.root.getFile @indexName, {}, (fileEntry) =>
            fileEntry.file (file) =>
              reader = new FileReader()
              reader.onerror = @__fileErrorHandler(@indexName)
              reader.onloadend = (evt) ->
                # @result is the text of the file read
                if @result? and @result isnt ''
                  try
                    # if we found a persisted index, replace our empty index with it
                    console.debug "glg-hb: loading index #{_this.indexName} from localStorage"
                    _this.idx = hummingbird.Index.load JSON.parse(@result)
                    _this.fire 'hb-loaded', _this.indexName
                  catch err
                    console.error "glg-hb: unable to load persisted #{_this.indexName} index: #{JSON.stringify err}"
                    _this.fire 'no-hb-index', _this.indexName
                else
                  console.warn "glg-hb: found an empty file when trying to load persisted #{_this.indexName} index."
                  _this.fire 'no-hb-index', _this.indexName
              reader.readAsText file
            , @__fileErrorHandler(@indexName)
          , @__fileErrorHandler(@indexName)
        , @__fileErrorHandler(@indexName)

      ready: ->

      attached: ->

      domReady: ->

      detached: ->

# glg-hummingbird
Polymer element to maintain a hummingbird typeahead index that persists between browser restarts.

    hummingbird = require 'hummingbird'
    # shim for chrome file system access
    window.requestFileSystem = window.requestFileSystem ? window.webkitRequestFileSystem

    Polymer 'glg-hummingbird',

## Events
### HB_RESULTS
This event is emitted when there are new hummingbird results returned where the payload is the results array.

### NO_HB_INDEX
This event is emitted when attempting to load a non-existent hummingbird index from persistence.

### FS_ERROR
This event is emitted when there is an error interacting with the file system where the payload is the error object.

## Methods
### search
Method for retrieving results from a humminbird index
* query (required) - a string to be tokenized and searched

      search: (query) ->
        hbOptions =
          scoreThreshold: @scoreThreshold ? 0
          secondarySortField: @secondarySortField
          secondarySortOrder: @secondarySortOrder
          howMany: @howMany ? 10
          startPos: @startPos ? 0

        #lookup by fuzzy name match
        @idx.search query, (results) =>
          @fire 'HB_RESULTS', results
        , hbOptions

### jump
Method for retrieving a single result from a hummingbird index by ID
* id (required) - the ID of the document to be returned

      jump: (id) ->
        #lookup by ID
        @idx.jump id, (results) =>
          @fire 'HB_RESULTS', results

### upsert
Method to insert new entries into the index or update existing entries

      upsert: (doc) ->
        unless doc?.name? and doc?.id?
          console.error "glg-hb: every hummingbird document must have a minimum of 'name' and 'id' properties"
        else
          @idx.add doc

### bulkLoad
Method to insert new entries into the index or update existing entries

      bulkLoad: (docs) ->
        (@upsert doc for doc in docs)

### persist
Method to persist hummingbird index to localStorage

      persist: () ->
        window.requestFileSystem window.TEMPORARY, null
        , (fs) =>
          # success handler
          fs.root.getFile @indexName, {create: true}, (fileEntry) =>
            fileEntry.createWriter (fileWriter) =>
              fileWriter.onerror = @__fileErrorHandler()
              fileWriter.onwriteend = (evt) ->
                # Do we care to share success?
                return
              try
                fileWriter.write new Blob([JSON.stringify(@idx.toJSON())], {type: 'text/plain'})
              catch err
                console.error "glg-hb: unable to persist #{@indexName} index: #{JSON.stringify err}"
            , @__fileErrorHandler()
          , @__fileErrorHandler()
        , @__fileErrorHandler()

### purge
Method to delete persisted file from disk

      purge: () ->
        window.requestFileSystem window.TEMPORARY, null, (fs) =>
          fs.root.getFile @indexName, { create: false }, (fileEntry) =>
            fileEntry.remove =>
              console.log "glg-hb: purged persisted #{@indexName} index."
            , @__fileErrorHandler()
          , @__fileErrorHandler()
        , @__fileErrorHandler()

### getCreateTime
Method that returns the timestamp for the index creation (not persist or load).
It has become the norm to incrementally add new documents to a hummingbird index, but not remove 'deleted' or obsolete documents.
Given that convention, this method enables the consuming application to determine whether the persisted index is 'old' and
should be purged from local storage and fully rebuilt from scratch to take into account documents that should no longer be in the index.

      getCreateTime: () ->
        @idx.createTime

### getLastUpdateTime
Method that returns the timestamp for the last time the index was updated (including create, add, or remove, but not persist or load)

      getLastUpdateTime: () ->
        @idx.lastUpdate

### __fileErrorHandler
Internal method to handle various filesystem errors

      __fileErrorHandler: () ->
        #closure to maintain reference to Polymer object in scope
        (err) =>
          switch err.code
            when FileError.QUOTA_EXCEEDED_ERR
              console.error 'glg-hb: QUOTA_EXCEEDED_ERR'
              @fire 'FS_ERROR', err
            when FileError.NOT_FOUND_ERR
              console.debug "glg-hb: no persisted index: #{JSON.stringify err}"
              @fire 'NO_HB_INDEX'
            when FileError.SECURITY_ERR
              console.error 'glg-hb: SECURITY_ERR'
              @fire 'FS_ERROR', err
            when FileError.INVALID_MODIFICATION_ERR
              console.error 'glg-hb: INVALID_MODIFICATION_ERR'
              @fire 'FS_ERROR', err
            when FileError.INVALID_STATE_ERR
              console.error 'glg-hb: INVALID_STATE_ERR'
              @fire 'FS_ERROR', err
            else
              console.error 'glg-hb: unknown file system error'
              @fire 'FS_ERROR', err

## Polymer Lifecycle
On element creation, load the named index if it exists and make it immediately available for use.

      created: ->
        # create an empty index
        @idx = new hummingbird()
        window.requestFileSystem window.TEMPORARY, null
        , (fs) =>
          # success handler
          fs.root.getFile @indexName, {}, (fileEntry) =>
            fileEntry.file (file) =>
              reader = new FileReader()
              reader.onerror = @__fileErrorHandler()
              reader.onloadend = (evt) ->
                # @result is the text of the file read
                if @result? and @result isnt ''
                  try
                    # if we found a persisted index, replace our empty index with it
                    console.log "glg-hb: loading index #{_this.indexName} from localStorage"
                    _this.idx = hummingbird.Index.load JSON.parse(@result)
                  catch err
                    console.error "glg-hb: unable to load persisted #{_this.indexName} index: #{JSON.stringify err}"
                else
                  console.warn "glg-hb: found an empty file when trying to load persisted #{_this.indexName} index."
                  _this.__fileErrorHandler() {code:FileError.NOT_FOUND_ERR}
              reader.readAsText file
            , @__fileErrorHandler()
          , @__fileErrorHandler()
        , @__fileErrorHandler()

      ready: ->

      attached: ->

      domReady: ->

      detached: ->