isData in valid

isData in valid

Copyright 2014 - 2015
Author: Varuna Jayasiri http://blog.varunajayasiri.com

#Value

    Mod.require 'Models.Properties',
     'Models.Property.Base'
     'Weya.Base'
     'Weya'
     (PROPERTIES, Base, WeyaBase, Weya) ->

Class

      class Value extends Base
       @extend()

       propertyType: 'value'

       @default 'value', (str, stack) ->
        if (typeof str) isnt 'string'
         throw new Error "Exected string: #{typeof str}, #{str}"
        return str

       @default 'string', (value, stack) -> "#{value}"

       @default 'rows', 1
       @default 'columns', 20

       @default 'valid', (str, stack, isData = false) ->
        if (typeof str) isnt 'string'
         return false
        else
         return true

       @default 'search', (str, stack) -> null

       @default 'default', -> ''

       @default 'isDefault', (value, stack) ->
        value is @schema.default()

       parse: (data, stack) ->
        r = super data, stack
        return r unless r is true
        if not @schema.valid data, stack, true
         return @error 'invalid'

        return {
         score: 1
         errors: []
         value: @schema.value data, stack
        }

       toJSON: (value, stack) -> value
       toJSONFull: (value, stack) -> value

       edit: (elem, value, onChanged, stack) ->
        new Edit this, elem, value, onChanged, stack

Edit

      class Edit extends WeyaBase
       @extend()

       @initialize (property, elem, value, onChanged, stack) ->
        @property = property
        @elems =
         parent: elem
        @value = value
        @onChanged = onChanged
        @stack = stack
        @render()

       render: ->
        schema = @property.schema
        width = 2 + Math.round schema.columns * 7.25
        Weya elem: @elems.parent, context: this, ->
         if schema.rows is 1
          @$.elems.input = @input '.value',
           type: 'text'
           placeholder: @$.property._name
           style:
            width: "#{width}px"
         else
          @$.elems.input = @textarea '.value',
           rows: schema.rows
           columns: schema.columns
           style:
            width: "#{width}px"
            height: "#{Math.round schema.rows * 18}px"

         @$.elems.search = @div '.search',
          style:
           display: 'none'
           width: "#{width}px"

        @elems.input.value = schema.string @value, @stack
        @elems.input.addEventListener "input", @on.change
        @elems.input.addEventListener "focus", @on.focus
        @elems.input.addEventListener "blur", @on.blur
        @elems.search.addEventListener 'click', @on.searchClick
        @change()

       search: ->
        value = @elems.input.value
        results = @property.schema.search.call @property, value, @stack
        return if not results?
        return if not Array.isArray results

        if results.length is 0
         @elems.search.style.display = 'none'
         return

        @elems.search.style.display = 'block'
        @elems.search.innerHTML = ''
        Weya elem: @elems.search, ->
         for r, i in results
          break if i > 10
          e = @div r
          e._result = r

       @listen 'searchClick', (e) ->
        n = e.target
        result = null
        while n? and n isnt @elems.search
         if n._result
          result = n._result
          break
         n = n.parentNode

        return if not result?
        @elems.input.value = result
        @elems.search.style.display = 'none'
        @change()

       @listen 'focus', (e) -> @search()
       @listen 'blur', (e) ->
        setTimeout =>
         @elems.search.style.display = 'none'
        , 400

       @listen 'change', (e) ->
        @search()
        @change()

       change: ->
        value = @elems.input.value
        if not @property.schema.valid.call @property, value, @stack
         @elems.input.classList.add 'invalid'
        else
         @elems.input.classList.remove 'invalid'
         value = @property.schema.value.call this, value, @stack
         @onChanged value, true

      PROPERTIES.register 'value', Value

Copyright 2014 - 2015
Author: Varuna Jayasiri http://blog.varunajayasiri.com

#Value

    Mod.require 'Models.Properties',
     'Models.Property.Base'
     'Weya.Base'
     'Weya'
     (PROPERTIES, Base, WeyaBase, Weya) ->

Class

      class Value extends Base
       @extend()

       propertyType: 'value'

       @default 'value', (str, stack) ->
        if (typeof str) isnt 'string'
         throw new Error "Exected string: #{typeof str}, #{str}"
        return str

       @default 'string', (value, stack) -> "#{value}"

       @default 'rows', 1
       @default 'columns', 20

       @default 'valid', (str, stack) ->
        if (typeof str) isnt 'string'
         return false
        else
         return true

       @default 'search', (str, stack) -> null

       @default 'default', -> ''

       @default 'isDefault', (value, stack) ->
        value is @schema.default()

       parse: (data, stack) ->
        r = super data, stack
        return r unless r is true
        if not @schema.valid data, stack
         return @error 'invalid'

        return {
         score: 1
         errors: []
         value: @schema.value data, stack
        }

       toJSON: (value, stack) -> value
       toJSONFull: (value, stack) -> value

       edit: (elem, value, onChanged, stack) ->
        new Edit this, elem, value, onChanged, stack

Edit

      class Edit extends WeyaBase
       @extend()

       @initialize (property, elem, value, onChanged, stack) ->
        @property = property
        @elems =
         parent: elem
        @value = value
        @onChanged = onChanged
        @stack = stack
        @render()

       render: ->
        schema = @property.schema
        width = 2 + Math.round schema.columns * 7.25
        Weya elem: @elems.parent, context: this, ->
         if schema.rows is 1
          @$.elems.input = @input '.value',
           type: 'text'
           placeholder: @$.property._name
           style:
            width: "#{width}px"
         else
          @$.elems.input = @textarea '.value',
           rows: schema.rows
           columns: schema.columns
           style:
            width: "#{width}px"
            height: "#{Math.round schema.rows * 18}px"

         @$.elems.search = @div '.search',
          style:
           display: 'none'
           width: "#{width}px"

        @elems.input.value = schema.string @value, @stack
        @elems.input.addEventListener "input", @on.change
        @elems.input.addEventListener "focus", @on.focus
        @elems.input.addEventListener "blur", @on.blur
        @elems.search.addEventListener 'click', @on.searchClick
        @change()

       search: ->
        value = @elems.input.value
        results = @property.schema.search.call @property, value, @stack
        return if not results?
        return if not Array.isArray results

        if results.length is 0
         @elems.search.style.display = 'none'
         return

        @elems.search.style.display = 'block'
        @elems.search.innerHTML = ''
        Weya elem: @elems.search, ->
         for r, i in results
          break if i > 10
          e = @div r
          e._result = r

       @listen 'searchClick', (e) ->
        n = e.target
        result = null
        while n? and n isnt @elems.search
         if n._result
          result = n._result
          break
         n = n.parentNode

        return if not result?
        @elems.input.value = result
        @elems.search.style.display = 'none'
        @change()

       @listen 'focus', (e) -> @search()
       @listen 'blur', (e) ->
        setTimeout =>
         @elems.search.style.display = 'none'
        , 400

       @listen 'change', (e) ->
        @search()
        @change()

       change: ->
        value = @elems.input.value
        if not @property.schema.valid.call @property, value, @stack
         @elems.input.classList.add 'invalid'
        else
         @elems.input.classList.remove 'invalid'
         value = @property.schema.value.call this, value, @stack
         @onChanged value, true

      PROPERTIES.register 'value', Value


added some more standard JS global objects

heterarchy
==========

> This file is part of [Heterarchy](http://sinusoid.es/heterarchy).
> - **View me [on a static web](http://sinusoid.es/heterarchy/heterarchy.html)**
> - **View me [on GitHub](https://github.com/arximboldi/heterarchy/blob/master/heterarchy.litcoffee)**

Adds multiple inheritance support to CoffeeScript (and JavaScript).
It uses the C3 linearization algorithm as described in the [famous
Dylan paper](http://192.220.96.201/dylan/linearization-oopsla96.html).

    {head, tail, map, find, some, without, isEmpty, every, memoize, reject,
     partial, isEqual} =
        require 'underscore'

    assert = (value, error) ->
        if not value
           throw new Error(if error? then error else "Assertion failed")

Multiple inheritance
--------------------

The **multi** function takes a list of classes and returns a *special*
class object that merges the class hierarchies, as linearized by the
C3 algorithm. Limitations of the approach are:

- `instanceof` does not always work as expected. For example:

  > ```coffee
  > class A
  > class B extends A
  > class C extends A
  > class D extends multi B, C
  > assert new D not instanceof B
  > ```

  Instead, one should use the provided `isinstance` function.

- Some of the bases of a multi-inherited hierarchy are *frozen* when
  the sub-class is defined -- i.e. later modifications to the
  superclass are not visible to the subclass or its instances.  For
  example, in the previous heterarchy:

  > ```coffee
  > B::newProperty = 42
  > assert D::newProperty == undefined
  > ```

The `multi` function memoizes its results such that identity is
maintained, implying `multi X, Y is multi X, Y`.

    exports.multi = (bases...) ->
        generate merge map(bases, mro).concat [bases]

This takes a list of classes representing a hierarchy (from most to
least derived) and generates a single-inheritance hierarchy that
behaves like a class that would be have such a hierarchy.

    generate = memoize (linearization) ->
        next = head linearization
        if isEqual linearization, hierarchy next
            next
        else
            class Result extends generate tail linearization
                __mro__: linearization
                constructor: reparent next, @, next::constructor
                copyOwn next, @
                copyOwn next::, @::, partial reparent, next, @

This utility lets us copy own properties of a *from* object that are
not own properties of a *to* object into the *to* object, optionally
transformed via a projection function.

    copyOwn = (from, to, project = (x) -> x) ->
        for own key, value of from
            if not to.hasOwnProperty key
                to[key] = project value
        to

Methods in CoffeeScript call super directly, so we have to change the
`__super__` attribute of the original class during the scope of the
method so it calls the right super of the linearization.  Also,
programmers don't call super in constructor of root classes --indeed
doing so would rise an error-- so we have to inject such a call when
there are classes after these in the linearization.  The **reparent**
function takes care of all these and given an original class, and the
new class that is replacing it a linearized heterarchy, returns a
wrapped copy of a value of the former that is suitable for replacing
it in the later.

    reparent = (oldklass, newklass, value) ->
        if value not instanceof Function
            value
        else if value is oldklass::constructor and inherited(oldklass) is Object
            superctor = inherited(newklass)::constructor
            ->
                superctor.apply @, arguments
                value.apply @, arguments
        else
            newsuper = inherited(newklass)::
            oldsuper = oldklass.__super__
            ->
                oldklass.__super__ = newsuper
                try
                    value.apply @, arguments
                finally
                    oldklass.__super__ = oldsuper

This is the C3 linearization algorithm, as translated from the
original paper.

    merge = (inputs) ->
        while not isEmpty inputs
            next = find (map inputs, head), (candidate) ->
                every inputs, (input) -> candidate not in tail input
            assert next?, "Inconsistent multiple inheritance"
            inputs = reject map(inputs, (lst) -> without lst, next), isEmpty
            next

Introspection
-------------

The **mro** function returns the method resolution order
(linearization) of a given class:

> ```coffee
> class A
> class B extends A
> class C extends B
> assert mro(C).equals [C, B, A]
> ```

It returns the original classes that were mixed in when used with
mult-inherited classes:

> ```coffee
> class A
> class B extends A
> class C extends A
> class D extends multi B, C
> assert mro(D).equals [D, B, C, A, Object]
> ```

    isJavaScriptClass = (cls) ->
        standardClasses = [
            Array
            Boolean
            Date
            Error
            Function
            Number
            RegExp
            String
            Object
            EvalError
            RangeError
            ReferenceError
            SyntaxError
            TypeError
            URIError
        ]

        if cls in standardClasses
            true
        else
            # according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
            nonStandardClasses = [
                "Symbol"
                # typed arrays
                "Int8Array"
                "Uint8Array"
                "Uint8ClampedArray"
                "Int16Array"
                "Uint16Array"
                "Int32Array"
                "Uint32Array"
                "Float32Array"
                "Float64Array"
                # keyed Keyed collections
                "Map"
                "Set"
                "WeakMap"
                "WeakSet"
                # Structured data
                "ArrayBuffer"
                "DataView"
                # Control abstraction objects
                "Promise"
                "Generator"
                "GeneratorFunction"
                # Reflection
                "Reflect"
                "Proxy"
            ]
            for nonStandardClass in nonStandardClasses when cls is window[nonStandardClass]
                return true
            false

    exports.mro = mro = (cls) ->
        if not cls? or not cls::?
            []
        else if not cls::hasOwnProperty '__mro__'
            result = [cls].concat mro inherited(cls)
            cls::__mro__ = result unless isJavaScriptClass cls
            result
        else
            cls::__mro__

The **inherited** function returns the CoffeeScript superclass of an
object, for example:

> ```coffee
> class A
> class B extends A
> assert inherited(B) == A
> ```

Note that for multiple inherited classes, this returns the mixed
object, not the next class in the MRO, as in:

> ```coffee
> class C extends multi A, B
> assert inherited(C) == multi(A, B)
> ```

    exports.inherited = inherited = (cls) ->
        Object.getPrototypeOf(cls.prototype)?.constructor

The **hierarchy** returns the CoffeeScript hierarchy of classes of a
given class, including the class itself.  For multiple inherited
classes, it may return speciall classes that were generated to produce
the flattening, as in:

> ```coffee
> class A
> class B extends A
> class C extends A
> class D extends multi B, C
> assert not mro(D).equals hierarchy(D)
> assert hierarchy(D).equals
>     [ D, multi(B, C), inherited(multi B, C), A, Object ]
> ```

    exports.hierarchy = hierarchy = (cls) ->
        if not cls?
            []
        else
            [cls].concat hierarchy inherited cls

The **isinstance** function takes an object and a class or classes and
returns whether the object is an instance of any of those classes. It
is compatible with multi-inherited classes.

    exports.isinstance = (obj, classes...) ->
        exports.issubclass obj?.constructor, classes...

The **issubclass** tells whether a class is a subtype of another type.

    exports.issubclass = (klass, classes...) ->
        linearization = mro klass
        some classes, (cls) -> cls in linearization

License
-------

> Copyright (c) 2013, 2015 Juan Pedro Bolivar Puente <raskolnikov@gnu.org>
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.

heterarchy
==========

> This file is part of [Heterarchy](http://sinusoid.es/heterarchy).
> - **View me [on a static web](http://sinusoid.es/heterarchy/heterarchy.html)**
> - **View me [on GitHub](https://github.com/arximboldi/heterarchy/blob/master/heterarchy.litcoffee)**

Adds multiple inheritance support to CoffeeScript (and JavaScript).
It uses the C3 linearization algorithm as described in the [famous
Dylan paper](http://192.220.96.201/dylan/linearization-oopsla96.html).

    {head, tail, map, find, some, without, isEmpty, every, memoize, reject,
     partial, isEqual} =
        require 'underscore'

    assert = (value, error=undefined) ->
        if not value
           throw new Error(if error? then error else "Assertion failed")

Multiple inheritance
--------------------

The **multi** function takes a list of classes and returns a *special*
class object that merges the class hierarchies, as linearized by the
C3 algorithm. Limitations of the approach are:

- `instanceof` does not always work as expected. For example:

  > ```coffee
  > class A
  > class B extends A
  > class C extends A
  > class D extends multi B, C
  > assert new D not instanceof B
  > ```

  Instead, one should use the provided `isinstance` function.

- Some of the bases of a multi-inherited hierarchy are *frozen* when
  the sub-class is defined -- i.e. later modifications to the
  superclass are not visible to the subclass or its instances.  For
  example, in the previous heterarchy:

  > ```coffee
  > B::newProperty = 42
  > assert D::newProperty == undefined
  > ```

The `multi` function memoizes its results such that identity is
maintained, implying `multi X, Y is multi X, Y`.

    exports.multi = (bases...) ->
        generate merge map(bases, mro).concat [bases]

This takes a list of classes representing a hierarchy (from most to
least derived) and generates a single-inheritance hierarchy that
behaves like a class that would be have such a hierarchy.

    generate = memoize (linearization) ->
        next = head linearization
        if isEqual linearization, hierarchy next
            next
        else
            class result extends generate tail linearization
                __mro__: linearization
                constructor: reparent next, @, next::constructor
                copyOwn next, @
                copyOwn next::, @::, partial reparent, next, @

This utility lets us copy own properties of a *from* object that are
not own properties of a *to* object into the *to* object, optionally
transformed via a projection function.

    copyOwn = (from, to, project = (x) -> x) ->
        for own key, value of from
            if not to.hasOwnProperty key
                to[key] = project value
        to

Methods in CoffeeScript call super directly, so we have to change the
`__super__` attribute of the original class during the scope of the
method so it calls the right super of the linearization.  Also,
programmers don't call super in constructor of root classes --indeed
doing so would rise an error-- so we have to inject such a call when
there are classes after these in the linearization.  The **reparent**
function takes care of all these and given an original class, and the
new class that is replacing it a linearized heterarchy, returns a
wrapped copy of a value of the former that is suitable for replacing
it in the later.

    reparent = (oldklass, newklass, value) ->
        if value not instanceof Function
            value
        else if value == oldklass::constructor and inherited(oldklass) == Object
            superctor = inherited(newklass)::constructor
            ->
                superctor.apply @, arguments
                value.apply @, arguments
        else
            newsuper = inherited(newklass)::
            oldsuper = oldklass.__super__
            ->
                oldklass.__super__ = newsuper
                try
                    value.apply @, arguments
                finally
                    oldklass.__super__ = oldsuper

This is the C3 linearization algorithm, as translated from the
original paper.

    merge = (inputs) ->
        while not isEmpty inputs
            next = find (map inputs, head), (candidate) ->
                every inputs, (input) -> candidate not in tail input
            assert next?, "Inconsistent multiple inheritance"
            inputs = reject map(inputs, (lst) -> without lst, next), isEmpty
            next

Introspection
-------------

The **mro** function returns the method resolution order
(linearization) of a given class:

> ```coffee
> class A
> class B extends A
> class C extends B
> assert mro(C).equals [C, B, A]
> ```

It returns the original classes that were mixed in when used with
mult-inherited classes:

> ```coffee
> class A
> class B extends A
> class C extends A
> class D extends multi B, C
> assert mro(D).equals [D, B, C, A, Object]
> ```

    isJavaScriptClass = (cls) ->
        return cls in [
            Array
            Boolean
            Date
            Error
            Function
            Number
            RegExp
            String
            Object
        ]

    exports.mro = mro = (cls) ->
        if not cls? or not cls::?
            []
        else if not cls::hasOwnProperty '__mro__'
            result = [cls].concat mro inherited(cls)
            cls::__mro__ = result unless isJavaScriptClass cls
            result
        else
            cls::__mro__

The **inherited** function returns the CoffeeScript superclass of an
object, for example:

> ```coffee
> class A
> class B extends A
> assert inherited(B) == A
> ```

Note that for multiple inherited classes, this returns the mixed
object, not the next class in the MRO, as in:

> ```coffee
> class C extends multi A, B
> assert inherited(C) == multi(A, B)
> ```

    exports.inherited = inherited = (cls) ->
        Object.getPrototypeOf(cls.prototype)?.constructor

The **hierarchy** returns the CoffeeScript hierarchy of classes of a
given class, including the class itself.  For multiple inherited
classes, it may return speciall classes that were generated to produce
the flattening, as in:

> ```coffee
> class A
> class B extends A
> class C extends A
> class D extends multi B, C
> assert not mro(D).equals hierarchy(D)
> assert hierarchy(D).equals
>     [ D, multi(B, C), inherited(multi B, C), A, Object ]
> ```

    exports.hierarchy = hierarchy = (cls) ->
        if not cls?
            []
        else
            [cls].concat hierarchy inherited cls

The **isinstance** function takes an object and a class or classes and
returns whether the object is an instance of any of those classes. It
is compatible with multi-inherited classes.

    exports.isinstance = (obj, classes...) ->
        exports.issubclass obj?.constructor, classes...

The **issubclass** tells whether a class is a subtype of another type.

    exports.issubclass = (klass, classes...) ->
        linearization = mro klass
        some classes, (cls) -> cls in linearization

License
-------

> Copyright (c) 2013, 2015 Juan Pedro Bolivar Puente <raskolnikov@gnu.org>
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.


redirect index to page/index

redirect index to page/index

# Application Routes

The purpose of a route is to connect URL resources with underlying code.  I
also do explicit data normalization (input -> dictionary to pass to method/dict
from method -> view) at this stage.

To configure routes, the only object we need access to is `app`.  This module
can be called with `require("./lib/routes")(app)` as long as `app` is an
already initialized ExpressJS application.

Also note, app.models contians:

- **app.models.db** - Mongoose MongoDB connection
- **app.models.MODELNAME** - model objects

    module.exports = (app) ->

## GET /

Render the main index page.

      app.get '/', (req, res) ->
        fs = require('fs')
        res.redirect '/page/index'

## GET /page/:name

Render static pages at /view/page/name.html

      app.get '/page/:name', (req, res) ->
        app.models.page.get req.params.name, (err, page) ->
          if err
            console.error 'page '+req.params.name+' not found in db, showing static'
            res.render 'page/'+req.params.name
          else
            res.render 'page/dynamic', page

## POST /page/_post

Post a page into the database

WARNING no security! .. then again, it doesn't read input at the moment either.
<!-- ' -->

      app.post '/page/_post', (req, res) ->
        sample =
          name: 'test'
          title: 'Test Page'
          content: 'Hello world, from inside the DB'
        app.models.page sample, (err, page) ->
          if err
            page =
              name: 'error'
              title: 'Error'
              content: 'There was an error posting your page, please try again.'
          res.render 'page/dynamic', page

## GET /login

Render static pages at /view/login/index.html

And never cache the login page, it breaks csrf

      app.get '/login', (req, res) ->
        res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
        res.render 'login'

## POST /login/_post

Do Login action, and redirect as appropriate.

      app.post '/login/_post', (req, res) ->
        require('../login').checkUser req.body.username, req.body.password, (user, securityLevel) ->
          console.info 'login callback = '+user+', '+securityLevel
          req.session.user = user
          req.session.securityLevel = securityLevel
          res.cookie 'nocache', '1'
          if securityLevel
            res.redirect '/'
          else
            res.redirect '/login'

## GET /login/clear

Logout from the website by clearing the session

      app.get '/login/clear', (req, res) ->
        req.session.destroy (err) ->
          res.clearCookie 'nocache'
          res.redirect '/login'

## GET /directory

Download PDF to browser

      app.get '/directory', (req, res) ->
        if req.session.securityLevel
          request = require 'request'
          request app.directory_url, (err, cbres, data) ->
            if err or cbres.statusCode != 200
              res.render 500, 'Error retrieving full directory'
            else
              dir = JSON.parse data
              page =
                name: 'Full Directory'
                title: 'Full Directory'
                directory: dir.data
                helpers:
                  month: (num) ->
                    return [null, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][num]
              res.render 'directory', page
        else
          res.redirect '/login'

## GET /directory/directory.pdf

Download PDF to browser

      app.get '/directory/directory.pdf', (req, res) ->
        if req.session.securityLevel
          res.download 'protected/directory.pdf'
        else
          res.redirect '/login'

## Copying

This software is released under the ISC License.

Copyright (c) 2013, Cameron King <cking@ecc12.com>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

<!-- vim: ts=2 sts=2 sw=2 expandtab
     CoffeeScript-friendly tabstops in vim. -->

# Application Routes

The purpose of a route is to connect URL resources with underlying code.  I
also do explicit data normalization (input -> dictionary to pass to method/dict
from method -> view) at this stage.

To configure routes, the only object we need access to is `app`.  This module
can be called with `require("./lib/routes")(app)` as long as `app` is an
already initialized ExpressJS application.

Also note, app.models contians:

- **app.models.db** - Mongoose MongoDB connection
- **app.models.MODELNAME** - model objects

    module.exports = (app) ->

## GET /

Render the main index page.

      app.get '/', (req, res) ->
        fs = require('fs')
        res.render 'index', {
          title: 'Welcome',
          extra_head_css: fs.readFileSync('views/extra/nivo.css'),
          extra_foot_js: fs.readFileSync('views/extra/nivo.js')
        }

## GET /page/:name

Render static pages at /view/page/name.html

      app.get '/page/:name', (req, res) ->
        app.models.page.get req.params.name, (err, page) ->
          if err
            console.error 'page '+req.params.name+' not found in db, showing static'
            res.render 'page/'+req.params.name
          else
            res.render 'page/dynamic', page

## POST /page/_post

Post a page into the database

WARNING no security! .. then again, it doesn't read input at the moment either.
<!-- ' -->

      app.post '/page/_post', (req, res) ->
        sample =
          name: 'test'
          title: 'Test Page'
          content: 'Hello world, from inside the DB'
        app.models.page sample, (err, page) ->
          if err
            page =
              name: 'error'
              title: 'Error'
              content: 'There was an error posting your page, please try again.'
          res.render 'page/dynamic', page

## GET /login

Render static pages at /view/login/index.html

And never cache the login page, it breaks csrf

      app.get '/login', (req, res) ->
        res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
        res.render 'login'

## POST /login/_post

Do Login action, and redirect as appropriate.

      app.post '/login/_post', (req, res) ->
        require('../login').checkUser req.body.username, req.body.password, (user, securityLevel) ->
          console.info 'login callback = '+user+', '+securityLevel
          req.session.user = user
          req.session.securityLevel = securityLevel
          res.cookie 'nocache', '1'
          if securityLevel
            res.redirect '/'
          else
            res.redirect '/login'

## GET /login/clear

Logout from the website by clearing the session

      app.get '/login/clear', (req, res) ->
        req.session.destroy (err) ->
          res.clearCookie 'nocache'
          res.redirect '/login'

## GET /directory

Download PDF to browser

      app.get '/directory', (req, res) ->
        if req.session.securityLevel
          request = require 'request'
          request app.directory_url, (err, cbres, data) ->
            if err or cbres.statusCode != 200
              res.render 500, 'Error retrieving full directory'
            else
              dir = JSON.parse data
              page =
                name: 'Full Directory'
                title: 'Full Directory'
                directory: dir.data
                helpers:
                  month: (num) ->
                    return [null, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][num]
              res.render 'directory', page
        else
          res.redirect '/login'

## GET /directory/directory.pdf

Download PDF to browser

      app.get '/directory/directory.pdf', (req, res) ->
        if req.session.securityLevel
          res.download 'protected/directory.pdf'
        else
          res.redirect '/login'

## Copying

This software is released under the ISC License.

Copyright (c) 2013, Cameron King <cking@ecc12.com>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

<!-- vim: ts=2 sts=2 sw=2 expandtab
     CoffeeScript-friendly tabstops in vim. -->


its listeners, not methods

its listeners, not methods

# CLASS: Component
* Extends: [Shape][Shape]
* Parent: [Index][Parent]

An interactive component

---

    Event = require 'ecl/dist/event'
    module.exports = class Component extends require './shape'

## CONSTRUCTOR
### new Component()
* Returns: [Component][Component]

Creates Component instance.

      constructor: ->
        super

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

        for type in ['grab', 'release', 'drag']

Localize the **type** variable.

          do (type) =>

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

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

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

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

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

        for type in ['grab', 'release', 'drag']

Add capturing extendable listener

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

Add normal extendable listener

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

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

---

## PROPERTIES

---

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

Capture **mousemove** event passing throught this component

      mousemoveCaptureListener: (event) ->
        super

Proceed only for valid event

        if event
          $ = @___runtime

Reset component state.

          @state = null

If component is grabbed then set the state to **active**.

          if $.grab
            @state = 'active'

Create **drag** Event and broadcast it to this component if drag event is enabled,

            if @events?.drag
              @broadcastEvent new Event
                type:'drag', x:event.x, y:event.y

setting the drag offset.

                offsetX: event.x - ($.dragEvent?.x or $.grabEvent?.x or 0)
                offsetY: event.y - ($.dragEvent?.y or $.grabEvent?.y or 0)

Otherwise, set the state to the name of the first matching region in order.

          else if regions = event.regions
            @state = (if regions.hover then 'hover' else if regions.normal then 'normal')

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

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

Receive **mousedown** event.

      mousedownListener: (event) ->
        super

Proceed only for valid event

        if event

If component is in active state and **grab** event is enabled then grab this component.

          if (@state is 'active') and @events?.grab
            ($ = @___runtime).grab = true

Create **grab** event and deliver it to this component.

            $.dragEvent = null
            @broadcastEvent new Event
              type:'grab', x:event.x, y:event.y

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

### #dragCaptureListener(event)
* Returns: [Component][Component]

Capture **drag** events passing through this component

      dragCaptureListener: (event) ->

Proceed only for valid event

        if event

Save the event and localize event coordinates.

          @___runtime.dragEvent = event
          localizeEventCoordinates event, @origin

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

### #grabCaptureListener(event)
* Returns: [Component][Component]

Capture **grab** events passing through this component.

      grabCaptureListener: (event) ->

Proceed only for valid event

        if event

Save the event and localize event coordinates.

          @___runtime.grabEvent = event
          localizeEventCoordinates event, @origin

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

* Returns: [Component][Component]

Capture **release** events passing through this component.

      releaseCaptureListener: (event) ->

Proceed only for valid event

        if event

Save the event and localize event coordinates.

          @___runtime.releaseEvent = event
          localizeEventCoordinates event, @origin

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

* Returns: [Component][Component]

#### #dragListener(event)
* Returns: [Component][Component]

**drag** event receiver stub.

      dragListener: -> this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

### #grabListener(event)
* Returns: [Component][Component]

**grab** event receiver stub.

      grabListener: -> this

#### PARAMETERS
**event**
* Type: [Event][Event]

---
### #releaseListener(event)
* Returns: [Component][Component]

**release** event receiver stub.

      releaseListener: -> this

#### PARAMETERS
**event**
* Type: [Event][Event]

[Parent]: ./index.litcoffee
[Shape]: ./shape.litcoffee
[Component]: ./component.litcoffee

# CLASS: Component
* Extends: [Shape][Shape]
* Parent: [Index][Parent]

An interactive component

---

    Event = require 'ecl/dist/event'
    module.exports = class Component extends require './shape'

## CONSTRUCTOR
### new Component()
* Returns: [Component][Component]

Creates Component instance.

      constructor: ->
        super

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

        for type in ['grab', 'release', 'drag']

Localize the **type** variable.

          do (type) =>

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

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

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

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

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

        for type in ['grab', 'release', 'drag']

Add capturing extendable listener

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

Add normal extendable listener

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

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

---

## PROPERTIES

---

## METHODS
### #mousemoveCaptureListener(event)
* Returns: [Component][Component]

Capture **mousemove** event passing throught this component

      mousemoveCaptureListener: (event) ->
        super

Proceed only for valid event

        if event
          $ = @___runtime

Reset component state.

          @state = null

If component is grabbed then set the state to **active**.

          if $.grab
            @state = 'active'

Create **drag** Event and broadcast it to this component if drag event is enabled,

            if @events?.drag
              @broadcastEvent new Event
                type:'drag', x:event.x, y:event.y

setting the drag offset.

                offsetX: event.x - ($.dragEvent?.x or $.grabEvent?.x or 0)
                offsetY: event.y - ($.dragEvent?.y or $.grabEvent?.y or 0)

Otherwise, set the state to the name of the first matching region in order.

          else if regions = event.regions
            @state = (if regions.hover then 'hover' else if regions.normal then 'normal')

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

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

Receive **mousedown** event.

      mousedownListener: (event) ->
        super

Proceed only for valid event

        if event

If component is in active state and **grab** event is enabled then grab this component.

          if (@state is 'active') and @events?.grab
            ($ = @___runtime).grab = true

Create **grab** event and deliver it to this component.

            $.dragEvent = null
            @broadcastEvent new Event
              type:'grab', x:event.x, y:event.y

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

### #dragCaptureListener(event)
* Returns: [Component][Component]

Capture **drag** events passing through this component

      dragCaptureListener: (event) ->

Proceed only for valid event

        if event

Save the event and localize event coordinates.

          @___runtime.dragEvent = event
          localizeEventCoordinates event, @origin

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

### #grabCaptureListener(event)
* Returns: [Component][Component]

Capture **grab** events passing through this component.

      grabCaptureListener: (event) ->

Proceed only for valid event

        if event

Save the event and localize event coordinates.

          @___runtime.grabEvent = event
          localizeEventCoordinates event, @origin

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

* Returns: [Component][Component]

Capture **release** events passing through this component.

      releaseCaptureListener: (event) ->

Proceed only for valid event

        if event

Save the event and localize event coordinates.

          @___runtime.releaseEvent = event
          localizeEventCoordinates event, @origin

        return this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

* Returns: [Component][Component]

#### #dragListener(event)
* Returns: [Component][Component]

**drag** event receiver stub.

      dragListener: -> this

#### PARAMETERS
**event**
* Type: [Event][Event]

---

### #grabListener(event)
* Returns: [Component][Component]

**grab** event receiver stub.

      grabListener: -> this

#### PARAMETERS
**event**
* Type: [Event][Event]

---
### #releaseListener(event)
* Returns: [Component][Component]

**release** event receiver stub.

      releaseListener: -> this

#### PARAMETERS
**event**
* Type: [Event][Event]

[Parent]: ./index.litcoffee
[Shape]: ./shape.litcoffee
[Component]: ./component.litcoffee


Inserted target features in documentation

Docco++
=======

What makes Docco++ better than Docco ?
-----------------------------------
While Docco does what it does in a quick and dirty way, there are some things
missing in its feature set:
- Seperate code *comments* from literate programming style *descriptions* by
  using different tags to denote them.
- Use multiline comments for the documentation.
- Include Mathjax to directly support mathematics with Latex-equations
  and make it markdown compatible.
- Pack documentation in *one* single html-document, including all css-assets,
  fonts, etc. This is helpful e.g. for code reviews, since you then only have
  to send one single file instead of a whole zip file.

Documentation of the original
============================

**Docco** is a quick-and-dirty documentation generator, written in
[Literate CoffeeScript](http://coffeescript.org/#literate).
It produces an HTML document that displays your comments intermingled with your
code. All prose is passed through
[Markdown](http://daringfireball.net/projects/markdown/syntax), and code is
passed through [Highlight.js](http://highlightjs.org/) syntax highlighting.
This page is the result of running Docco against its own
[source file](https://github.com/jashkenas/docco/blob/master/docco.litcoffee).

1. Install Docco with **npm**: `sudo npm install -g docco`

2. Run it against your code: `docco src/*.coffee`

There is no "Step 3". This will generate an HTML page for each of the named
source files, with a menu linking to the other pages, saving the whole mess
into a `docs` folder (configurable).

The [Docco source](http://github.com/jashkenas/docco) is available on GitHub,
and is released under the [MIT license](http://opensource.org/licenses/MIT).

Docco can be used to process code written in any programming language. If it
doesn't handle your favorite yet, feel free to
[add it to the list](https://github.com/jashkenas/docco/blob/master/resources/languages.json).
Finally, the ["literate" style](http://coffeescript.org/#literate) of *any*
language is also supported — just tack an `.md` extension on the end:
`.coffee.md`, `.py.md`, and so on.

Partners in Crime:
------------------

* If Node.js doesn't run on your platform, or you'd prefer a more
convenient package, get [Ryan Tomayko](http://github.com/rtomayko)'s
[Rocco](http://rtomayko.github.io/rocco/rocco.html), the **Ruby** port that's
available as a gem.

* If you're writing shell scripts, try
[Shocco](http://rtomayko.github.io/shocco/), a port for the **POSIX shell**,
also by Mr. Tomayko.

* If **Python** is more your speed, take a look at
[Nick Fitzgerald](http://github.com/fitzgen)'s [Pycco](http://fitzgen.github.io/pycco/).

* For **Clojure** fans, [Fogus](http://blog.fogus.me/)'s
[Marginalia](http://fogus.me/fun/marginalia/) is a bit of a departure from
"quick-and-dirty", but it'll get the job done.

* There's a **Go** port called [Gocco](http://nikhilm.github.io/gocco/),
written by [Nikhil Marathe](https://github.com/nikhilm).

* For all you **PHP** buffs out there, Fredi Bach's
[sourceMakeup](http://jquery-jkit.com/sourcemakeup/) (we'll let the faux pas
with respect to our naming scheme slide), should do the trick nicely.

* **Lua** enthusiasts can get their fix with
[Robert Gieseke](https://github.com/rgieseke)'s [Locco](http://rgieseke.github.io/locco/).

* And if you happen to be a **.NET**
aficionado, check out [Don Wilson](https://github.com/dontangg)'s
[Nocco](http://dontangg.github.io/nocco/).

* Going further afield from the quick-and-dirty, [Groc](http://nevir.github.io/groc/)
is a **CoffeeScript** fork of Docco that adds a searchable table of contents,
and aims to gracefully handle large projects with complex hierarchies of code.

Note that not all ports will support all Docco features ... yet.

Main Documentation Generation Functions
---------------------------------------

Generate the documentation for our configured source file by copying over static
assets, reading all the source files in, splitting them up into prose+code
sections, highlighting each file in the appropriate language, and printing them
out in an HTML template.

    document = (options = {}, callback) ->
      config = configure options

      fs.mkdirs config.output, ->

        callback or= (error) -> throw error if error
        copyAsset  = (file, callback) ->
          fs.copy file, path.join(config.output, path.basename(file)), callback
        complete   = ->
          copyAsset config.css, (error) ->
            if error then callback error
            else if fs.existsSync config.public then copyAsset config.public, callback
            else callback()

        files = config.sources.slice()

        nextFile = ->
          source = files.shift()
          fs.readFile source, (error, buffer) ->
            return callback error if error

            code = buffer.toString()
            sections = parse source, code, config
            format source, sections, config
            write source, sections, config
            if files.length then nextFile() else complete()

        nextFile()

Given a string of source code, **parse** out each block of prose and the code that
follows it — by detecting which is which, line by line — and then create an
individual **section** for it. Each section is an object with `docsText` and
`codeText` properties, and eventually `docsHtml` and `codeHtml` as well.

    parse = (source, code, config = {}) ->
      lines    = code.split '\n'
      sections = []
      lang     = getLanguage source, config
      hasCode  = docsText = codeText = ''

      save = ->
        sections.push {docsText, codeText}
        hasCode = docsText = codeText = ''

Our quick-and-dirty implementation of the literate programming style. Simply
invert the prose and code relationship on a per-line basis, and then continue as
normal below.

      if lang.literate
        isText = maybeCode = yes
        for line, i in lines
          lines[i] = if maybeCode and match = /^([ ]{4}|[ ]{0,3}\t)/.exec line
            isText = no
            line[match[0].length..]
          else if maybeCode = /^\s*$/.test line
            if isText then lang.symbol else ''
          else
            isText = yes
            lang.symbol + ' ' + line

      for line in lines
        if line.match(lang.commentMatcher) and not line.match(lang.commentFilter)
          save() if hasCode
          docsText += (line = line.replace(lang.commentMatcher, '')) + '\n'
          save() if /^(---+|===+)$/.test line
        else
          hasCode = yes
          codeText += line + '\n'
      save()

      sections

To **format** and highlight the now-parsed sections of code, we use **Highlight.js**
over stdio, and run the text of their corresponding comments through
**Markdown**, using [Marked](https://github.com/chjj/marked).

    format = (source, sections, config) ->
      language = getLanguage source, config

Tell Marked how to highlight code blocks within comments, treating that code
as either the language specified in the code block or the language of the file
if not specified.

      marked.setOptions {
        highlight: (code, lang) ->
          lang or= language.name

          if highlightjs.getLanguage(lang)
            highlightjs.highlight(lang, code).value
          else
            console.warn "docco: couldn't highlight code block with unknown language '#{lang}' in #{source}"
            code
      }

      for section, i in sections
        code = highlightjs.highlight(language.name, section.codeText).value
        code = code.replace(/\s+$/, '')
        section.codeHtml = "

#{code}

"
        section.docsHtml = marked(section.docsText)

Once all of the code has finished highlighting, we can **write** the resulting
documentation file by passing the completed HTML sections into the template,
and rendering it to the specified output path.

    write = (source, sections, config) ->

      destination = (file) ->
        path.join(config.output, path.basename(file, path.extname(file)) + '.html')

The **title** of the file is either the first heading in the prose, or the
name of the source file.

      first = marked.lexer(sections[0].docsText)[0]
      hasTitle = first and first.type is 'heading' and first.depth is 1
      title = if hasTitle then first.text else path.basename source

      html = config.template {sources: config.sources, css: path.basename(config.css),
        title, hasTitle, sections, path, destination,}

      console.log "docco: #{source} -> #{destination source}"
      fs.writeFileSync destination(source), html

Configuration
-------------

Default configuration **options**. All of these may be extended by
user-specified options.

    defaults =
      layout:     'parallel'
      output:     'docs'
      template:   null
      css:        null
      extension:  null
      languages:  {}

**Configure** this particular run of Docco. We might use a passed-in external
template, or one of the built-in **layouts**. We only attempt to process
source files for languages for which we have definitions.

    configure = (options) ->
      config = _.extend {}, defaults, _.pick(options, _.keys(defaults)...)

      config.languages = buildMatchers config.languages
      if options.template
        config.layout = null
      else
        dir = config.layout = path.join __dirname, 'resources', config.layout
        config.public       = path.join dir, 'public' if fs.existsSync path.join dir, 'public'
        config.template     = path.join dir, 'docco.jst'
        config.css          = options.css or path.join dir, 'docco.css'
      config.template = _.template fs.readFileSync(config.template).toString()

      config.sources = options.args.filter((source) ->
        lang = getLanguage source, config
        console.warn "docco: skipped unknown type (#{path.basename source})" unless lang
        lang
      ).sort()

      config

Helpers & Initial Setup
-----------------------

Require our external dependencies.

    _           = require 'underscore'
    fs          = require 'fs-extra'
    path        = require 'path'
    marked      = require 'marked'
    commander   = require 'commander'
    highlightjs = require 'highlight.js'

Enable nicer typography with marked.

    marked.setOptions smartypants: yes

Languages are stored in JSON in the file `resources/languages.json`.
Each item maps the file extension to the name of the language and the
`symbol` that indicates a line comment. To add support for a new programming
language to Docco, just add it to the file.

    languages = JSON.parse fs.readFileSync(path.join(__dirname, 'resources', 'languages.json'))

Build out the appropriate matchers and delimiters for each language.

    buildMatchers = (languages) ->
      for ext, l of languages

Does the line begin with a comment?

        l.commentMatcher = ///^\s*#{l.symbol}\s?///

Ignore [hashbangs](http://en.wikipedia.org/wiki/Shebang_%28Unix%29) and interpolations...

        l.commentFilter = /(^#![/]|^\s*#\{)/
      languages
    languages = buildMatchers languages

A function to get the current language we're documenting, based on the
file extension. Detect and tag "literate" `.ext.md` variants.

    getLanguage = (source, config) ->
      ext  = config.extension or path.extname(source) or path.basename(source)
      lang = config.languages[ext] or languages[ext]
      if lang and lang.name is 'markdown'
        codeExt = path.extname(path.basename(source, ext))
        if codeExt and codeLang = languages[codeExt]
          lang = _.extend {}, codeLang, {literate: yes}
      lang

Keep it DRY. Extract the docco **version** from `package.json`

    version = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'))).version

Command Line Interface
----------------------

Finally, let's define the interface to run Docco from the command line.
Parse options using [Commander](https://github.com/visionmedia/commander.js).

    run = (args = process.argv) ->
      c = defaults
      commander.version(version)
        .usage('[options] files')
        .option('-L, --languages [file]', 'use a custom languages.json', _.compose JSON.parse, fs.readFileSync)
        .option('-l, --layout [name]',    'choose a layout (parallel, linear or classic)', c.layout)
        .option('-o, --output [path]',    'output to a given folder', c.output)
        .option('-c, --css [file]',       'use a custom css file', c.css)
        .option('-t, --template [file]',  'use a custom .jst template', c.template)
        .option('-e, --extension [ext]',  'assume a file extension for all inputs', c.extension)
        .parse(args)
        .name = "docco"
      if commander.args.length
        document commander
      else
        console.log commander.helpInformation()

Public API
----------

    Docco = module.exports = {run, document, parse, format, version}

Docco
=====

**Docco** is a quick-and-dirty documentation generator, written in
[Literate CoffeeScript](http://coffeescript.org/#literate).
It produces an HTML document that displays your comments intermingled with your
code. All prose is passed through
[Markdown](http://daringfireball.net/projects/markdown/syntax), and code is
passed through [Highlight.js](http://highlightjs.org/) syntax highlighting.
This page is the result of running Docco against its own
[source file](https://github.com/jashkenas/docco/blob/master/docco.litcoffee).

1. Install Docco with **npm**: `sudo npm install -g docco`

2. Run it against your code: `docco src/*.coffee`

There is no "Step 3". This will generate an HTML page for each of the named
source files, with a menu linking to the other pages, saving the whole mess
into a `docs` folder (configurable).

The [Docco source](http://github.com/jashkenas/docco) is available on GitHub,
and is released under the [MIT license](http://opensource.org/licenses/MIT).

Docco can be used to process code written in any programming language. If it
doesn't handle your favorite yet, feel free to
[add it to the list](https://github.com/jashkenas/docco/blob/master/resources/languages.json).
Finally, the ["literate" style](http://coffeescript.org/#literate) of *any*
language is also supported — just tack an `.md` extension on the end:
`.coffee.md`, `.py.md`, and so on.

Partners in Crime:
------------------

* If Node.js doesn't run on your platform, or you'd prefer a more
convenient package, get [Ryan Tomayko](http://github.com/rtomayko)'s
[Rocco](http://rtomayko.github.io/rocco/rocco.html), the **Ruby** port that's
available as a gem.

* If you're writing shell scripts, try
[Shocco](http://rtomayko.github.io/shocco/), a port for the **POSIX shell**,
also by Mr. Tomayko.

* If **Python** is more your speed, take a look at
[Nick Fitzgerald](http://github.com/fitzgen)'s [Pycco](http://fitzgen.github.io/pycco/).

* For **Clojure** fans, [Fogus](http://blog.fogus.me/)'s
[Marginalia](http://fogus.me/fun/marginalia/) is a bit of a departure from
"quick-and-dirty", but it'll get the job done.

* There's a **Go** port called [Gocco](http://nikhilm.github.io/gocco/),
written by [Nikhil Marathe](https://github.com/nikhilm).

* For all you **PHP** buffs out there, Fredi Bach's
[sourceMakeup](http://jquery-jkit.com/sourcemakeup/) (we'll let the faux pas
with respect to our naming scheme slide), should do the trick nicely.

* **Lua** enthusiasts can get their fix with
[Robert Gieseke](https://github.com/rgieseke)'s [Locco](http://rgieseke.github.io/locco/).

* And if you happen to be a **.NET**
aficionado, check out [Don Wilson](https://github.com/dontangg)'s
[Nocco](http://dontangg.github.io/nocco/).

* Going further afield from the quick-and-dirty, [Groc](http://nevir.github.io/groc/)
is a **CoffeeScript** fork of Docco that adds a searchable table of contents,
and aims to gracefully handle large projects with complex hierarchies of code.

Note that not all ports will support all Docco features ... yet.

Main Documentation Generation Functions
---------------------------------------

Generate the documentation for our configured source file by copying over static
assets, reading all the source files in, splitting them up into prose+code
sections, highlighting each file in the appropriate language, and printing them
out in an HTML template.

    document = (options = {}, callback) ->
      config = configure options

      fs.mkdirs config.output, ->

        callback or= (error) -> throw error if error
        copyAsset  = (file, callback) ->
          fs.copy file, path.join(config.output, path.basename(file)), callback
        complete   = ->
          copyAsset config.css, (error) ->
            if error then callback error
            else if fs.existsSync config.public then copyAsset config.public, callback
            else callback()

        files = config.sources.slice()

        nextFile = ->
          source = files.shift()
          fs.readFile source, (error, buffer) ->
            return callback error if error

            code = buffer.toString()
            sections = parse source, code, config
            format source, sections, config
            write source, sections, config
            if files.length then nextFile() else complete()

        nextFile()

Given a string of source code, **parse** out each block of prose and the code that
follows it — by detecting which is which, line by line — and then create an
individual **section** for it. Each section is an object with `docsText` and
`codeText` properties, and eventually `docsHtml` and `codeHtml` as well.

    parse = (source, code, config = {}) ->
      lines    = code.split '\n'
      sections = []
      lang     = getLanguage source, config
      hasCode  = docsText = codeText = ''

      save = ->
        sections.push {docsText, codeText}
        hasCode = docsText = codeText = ''

Our quick-and-dirty implementation of the literate programming style. Simply
invert the prose and code relationship on a per-line basis, and then continue as
normal below.

      if lang.literate
        isText = maybeCode = yes
        for line, i in lines
          lines[i] = if maybeCode and match = /^([ ]{4}|[ ]{0,3}\t)/.exec line
            isText = no
            line[match[0].length..]
          else if maybeCode = /^\s*$/.test line
            if isText then lang.symbol else ''
          else
            isText = yes
            lang.symbol + ' ' + line

      for line in lines
        if line.match(lang.commentMatcher) and not line.match(lang.commentFilter)
          save() if hasCode
          docsText += (line = line.replace(lang.commentMatcher, '')) + '\n'
          save() if /^(---+|===+)$/.test line
        else
          hasCode = yes
          codeText += line + '\n'
      save()

      sections

To **format** and highlight the now-parsed sections of code, we use **Highlight.js**
over stdio, and run the text of their corresponding comments through
**Markdown**, using [Marked](https://github.com/chjj/marked).

    format = (source, sections, config) ->
      language = getLanguage source, config

Tell Marked how to highlight code blocks within comments, treating that code
as either the language specified in the code block or the language of the file
if not specified.

      marked.setOptions {
        highlight: (code, lang) ->
          lang or= language.name

          if highlightjs.getLanguage(lang)
            highlightjs.highlight(lang, code).value
          else
            console.warn "docco: couldn't highlight code block with unknown language '#{lang}' in #{source}"
            code
      }

      for section, i in sections
        code = highlightjs.highlight(language.name, section.codeText).value
        code = code.replace(/\s+$/, '')
        section.codeHtml = "

#{code}

"
        section.docsHtml = marked(section.docsText)

Once all of the code has finished highlighting, we can **write** the resulting
documentation file by passing the completed HTML sections into the template,
and rendering it to the specified output path.

    write = (source, sections, config) ->

      destination = (file) ->
        path.join(config.output, path.basename(file, path.extname(file)) + '.html')

The **title** of the file is either the first heading in the prose, or the
name of the source file.

      first = marked.lexer(sections[0].docsText)[0]
      hasTitle = first and first.type is 'heading' and first.depth is 1
      title = if hasTitle then first.text else path.basename source

      html = config.template {sources: config.sources, css: path.basename(config.css),
        title, hasTitle, sections, path, destination,}

      console.log "docco: #{source} -> #{destination source}"
      fs.writeFileSync destination(source), html

Configuration
-------------

Default configuration **options**. All of these may be extended by
user-specified options.

    defaults =
      layout:     'parallel'
      output:     'docs'
      template:   null
      css:        null
      extension:  null
      languages:  {}

**Configure** this particular run of Docco. We might use a passed-in external
template, or one of the built-in **layouts**. We only attempt to process
source files for languages for which we have definitions.

    configure = (options) ->
      config = _.extend {}, defaults, _.pick(options, _.keys(defaults)...)

      config.languages = buildMatchers config.languages
      if options.template
        config.layout = null
      else
        dir = config.layout = path.join __dirname, 'resources', config.layout
        config.public       = path.join dir, 'public' if fs.existsSync path.join dir, 'public'
        config.template     = path.join dir, 'docco.jst'
        config.css          = options.css or path.join dir, 'docco.css'
      config.template = _.template fs.readFileSync(config.template).toString()

      config.sources = options.args.filter((source) ->
        lang = getLanguage source, config
        console.warn "docco: skipped unknown type (#{path.basename source})" unless lang
        lang
      ).sort()

      config

Helpers & Initial Setup
-----------------------

Require our external dependencies.

    _           = require 'underscore'
    fs          = require 'fs-extra'
    path        = require 'path'
    marked      = require 'marked'
    commander   = require 'commander'
    highlightjs = require 'highlight.js'

Enable nicer typography with marked.

    marked.setOptions smartypants: yes

Languages are stored in JSON in the file `resources/languages.json`.
Each item maps the file extension to the name of the language and the
`symbol` that indicates a line comment. To add support for a new programming
language to Docco, just add it to the file.

    languages = JSON.parse fs.readFileSync(path.join(__dirname, 'resources', 'languages.json'))

Build out the appropriate matchers and delimiters for each language.

    buildMatchers = (languages) ->
      for ext, l of languages

Does the line begin with a comment?

        l.commentMatcher = ///^\s*#{l.symbol}\s?///

Ignore [hashbangs](http://en.wikipedia.org/wiki/Shebang_%28Unix%29) and interpolations...

        l.commentFilter = /(^#![/]|^\s*#\{)/
      languages
    languages = buildMatchers languages

A function to get the current language we're documenting, based on the
file extension. Detect and tag "literate" `.ext.md` variants.

    getLanguage = (source, config) ->
      ext  = config.extension or path.extname(source) or path.basename(source)
      lang = config.languages[ext] or languages[ext]
      if lang and lang.name is 'markdown'
        codeExt = path.extname(path.basename(source, ext))
        if codeExt and codeLang = languages[codeExt]
          lang = _.extend {}, codeLang, {literate: yes}
      lang

Keep it DRY. Extract the docco **version** from `package.json`

    version = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'))).version

Command Line Interface
----------------------

Finally, let's define the interface to run Docco from the command line.
Parse options using [Commander](https://github.com/visionmedia/commander.js).

    run = (args = process.argv) ->
      c = defaults
      commander.version(version)
        .usage('[options] files')
        .option('-L, --languages [file]', 'use a custom languages.json', _.compose JSON.parse, fs.readFileSync)
        .option('-l, --layout [name]',    'choose a layout (parallel, linear or classic)', c.layout)
        .option('-o, --output [path]',    'output to a given folder', c.output)
        .option('-c, --css [file]',       'use a custom css file', c.css)
        .option('-t, --template [file]',  'use a custom .jst template', c.template)
        .option('-e, --extension [ext]',  'assume a file extension for all inputs', c.extension)
        .parse(args)
        .name = "docco"
      if commander.args.length
        document commander
      else
        console.log commander.helpInformation()

Public API
----------

    Docco = module.exports = {run, document, parse, format, version}


We don't need the starting_row param in Skyll anymore

    Module = require './module'
    q      = require 'q'

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

      render_pipeline: [ ]
      renderers:       [ ]

      initialize: (params) =>
        deferred = q.defer()

        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

    Module = require './module'
    q      = require 'q'

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

      render_pipeline: [ ]
      renderers:       [ ]

      initialize: (params) =>
        deferred      = q.defer()
        @starting_row = params.starting_row

        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