Rework how arguments are processed when wrapping methods

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

    microtime = require 'microtime'

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

    available   = { }
    initialized = { }
    listeners   = { }

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

    SEARCH_ROOTS  = { }
    WRAPPED       = { }
    _INITIALIZERS = { }
    HYDRATED      = { }
    LOCALS        = { }

    HYRDATION_LISTENERS = { }

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

      _INITIALIZERS[cls].push fn: method, called: false

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'initialize'
          'details'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      details: =>
        name  = @.__proto__.constructor.name
        props = for own key, val of @.__proto__
          if key != 'constructor' &&
             key != 'details'     &&
             key != 'initialize'  && ((
               key[0]            == '_' &&
               @.__proto__[key]? == false
             ) || key[0] != '_')

            if typeof val == 'function'
              value = val.constructor.name
            else if Array.isArray val
              value = for v in val
                if typeof v == 'function'
                  v.constructor.name
                else if typeof v == 'object'
                  v.constructor.name
                else
                  v
              value = value.join ','
            else if typeof val == 'object'
              value = val.constructor.name
            else
              value = val

            "#{key} => #{value}"

        "\n  #{name}\n    #{props.filter((e) -> e?).join '\n    '}"

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

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

      @SEARCH_ROOT: (mod, path) =>
        Madul.FIRE '$.Madul.search_root.register', "#{mod}": path

        SEARCH_ROOTS[mod] = path.substring 0, path.lastIndexOf '/'

      @PARSE_SPEC: (value) =>
        tokens = value.split '='

        if tokens.length == 2
          initer = tokens[1].trim()
          t      = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = r[0].trim()
            t[0] = r[1]

          if t.length == 2
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = n.substring 1, n.length
            else
              local = false
              name  = n

            alias = t[1].trim()
          else if t.length == 1
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = alias = n.substring 1, n.length
            else
              local = false
              name  = alias = n
          else
            return Madul.FIRE '!.Madul.dependency_spec.alias.invalid', tokens[1]

          toks = initer.split ':'

          if toks.length == 2
            initer = toks[0].trim()
            pres   = toks[1].split(',').map (p) => p.trim()
          else if toks.length == 1
            initer = toks[0].trim()
          else
            return Madul.FIRE '!.Madul.dependency_spec.initializer.invalid', tokens[1]

        else if tokens.length == 1
          t = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = r[0].trim()
            t[0] = r[1]

          if t.length == 2
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = n.substring 1, n.length
            else
              local = false
              name  = n

            alias = t[1].trim()
          else if t.length == 1
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = alias = n.substring 1, n.length
            else
              local = false
              name  = alias = n
          else
            return Madul.FIRE '!.Madul.dependency_spec.alias.invalid', tokens[1]

        else
          return Madul.FIRE '!.Madul.dependency_spec.invalid', d

        { ref: alias || name, alias, name, root, initer, pres, local }

      @BUILD_SPEC: ({ search_root, name, alias, initializer, prerequisites }) =>
        unless name?
          return Madul.FIRE '!.Madul.dependency_spec.name-required', arguments[0]

        if prerequisites? && initializer? == false
          return Madul.FIRE '!.Madul.dependency_spec.prerequisites-require-initializer', arguments[0]

        "#{if search_root?   then "#{search_root}#"            else ''}\
         #{name}\
         #{if alias?         then " -> #{alias}"               else ''}\
         #{if initializer?   then " = #{initializer}"          else ''}\
         #{if prerequisites? then ":#{prerequisites.join ','}" else ''}\
        "

      listen: (event, callback) ->
        Madul.LISTEN "*.#{@constructor.name}.#{event}", callback

      fire: (event, args) ->
        Madul.FIRE "@.#{@constructor.name}.#{event}", args

      warn: (event, details) ->
        Madul.FIRE "!.#{@constructor.name}.#{event}", details

      _report: (name, method, state, id, args) =>
        if state == 'reject'
          Madul.FIRE "!.#{name}.#{method}.#{state}",
            uuid:      id
            message:   args
            timestamp: microtime.now()
        else
          Madul.FIRE "@.#{name}.#{method}.#{state}",
            uuid:      id
            args:      args
            timestamp: microtime.now()

      _respond: (proto, method, id, deferred) =>
        (state, data) =>
          process.nextTick =>
            deferred[state] data

            proto._report proto.constructor.name, method, state, id, data

      _prep_invocation: (proto, method, input, def) =>
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def

        if Array.isArray input
          input.push (out) => res 'resolve', out
          input.push (err) => res 'reject',  err
          input.push (out) => res 'notify',  out
        else if typeof input == 'object'
          input.done   = (out) => res 'resolve', out
          input.fail   = (err) => res 'reject',  err
          input.update = (out) => res 'notify',  out

          input = [ input ]
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"
          @warn 'input.invalid', msg
          throw new Error msg

        proto._report proto.constructor.name, method, 'invoke', id, input

        input

      _do_wrap: (proto, method) =>
        if method != 'fire' && method != 'warn' && method != 'listen'
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

          if typeof proto[method] == 'function'
            proto["_#{method}"] = proto[method]

            proto[method] = =>
              def  = q.defer()
              args = Array.prototype.slice.call arguments

              proto["_#{method}"].apply proto, proto._prep_invocation proto, method, args, def

              def.promise
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = proto[method].validate

              proto[method].validate = decs
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = for own key, val of proto[method].validate
                val
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ proto[method].validate ]
            else if typeof proto[method].validate != 'undefined'
              proto.warn.call proto, 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            if Array.isArray proto[method].before
              decs = decs.concat proto[method].before
            else if typeof proto[method].before == 'string'
              decs = decs.concat [ proto[method].before ]

            if Array.isArray proto[method].after
              decs = decs.concat proto[method].after
            else if typeof proto[method].after == 'string'
              decs = decs.concat [ Madul.PARSE_SPEC proto[method].after ]

            Madul.FIRE '$.Madul.decorators.hydrate', decs

            @_do_hydrate proto, decs, =>
              proto["_#{method}"] = proto[method]

              proto[method] = =>
                def = q.defer()
                me  = proto["_#{method}"]

                if args_format == 'ARRAY'
                  args = Array.prototype.slice.call arguments

                  if me.validate?
                    validators = for val, i in me.validate
                      { ref } = Madul.PARSE_SPEC val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[i]
                      proto[ref].EXECUTE.call proto[ref], args[i]
                else if args_format == 'OBJECT'
                  args = arguments[0]

                  if me.validate?
                    validators = for own key, val of me.validate
                      { ref } = Madul.PARSE_SPEC val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[key]
                      proto[ref].EXECUTE.call proto[ref], args[key]
                else
                  proto.warn.call proto, 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                if Array.isArray me.before
                  before = me.before.map (b) => Madul.PARSE_SPEC(b).ref
                else if typeof me.before == 'string'
                  before = [ Madul.PARSE_SPEC(me.before).ref ]
                else
                  before = [ ]

                if Array.isArray me.after
                  after = me.after.map (a) => Madul.PARSE_SPEC(a).ref
                else if typeof me.after == 'string'
                  after = [ Madul.PARSE_SPEC(me.after).ref ]
                else
                  after = [ ]

                q.all validators
                .then =>
                  q.all before.map (b) =>
                    Madul.FIRE '$.Madul.before_filter.execute', "#{b}": args
                    proto[b].before.call proto[b], args
                .then =>
                  me.behavior.apply me, @_prep_invocation proto, method, args, def
                .then (result) =>
                  if after.length > 0
                    q.all after.map (a) =>
                      Madul.FIRE '$.Madul.after_filter.execute', "#{a}": result
                      proto[a].after.call proto[a], result
                  else
                    d = q.defer()

                    process.nextTick => d.resolve result

                    d.promise
                .then  (out) => def.resolve out
                .catch (err) => def.reject  err

                def.promise
          else
            @warn 'cannot-wrap', method

          WRAPPED[proto.constructor.name].push method

      _wrap_methods: (proto, callback) =>
        name    = proto.constructor.name
        to_wrap = [ ]

        while proto? && Object.keys(proto).length > 0 && WRAPPED[name]? == false
          to_wrap.push { proto, name, methods: [ ] }

          for own prop, body of proto
            if prop[0]                  != '_'         &&
               typeof proto["_#{prop}"] == 'undefined' &&
               WRAP(name, prop)         == true

              continue if proto.deps? && proto.deps.indexOf(prop.replace(/_/g, '-')) > -1

              if typeof body == 'function' || typeof body?.behavior == 'function'
                to_wrap[to_wrap.length - 1].methods.push prop

          proto = proto.__proto__
          name  = proto.constructor.name

        async.each to_wrap.reverse(), (wrap, completed) =>
          async.each wrap.methods, (method, next) =>
            wrap.proto._do_wrap wrap.proto, method

            INITIALIZERS wrap.name, method if method[0] == '$'

            next()
          , => @_call_initializers_for wrap.proto, wrap.name, completed
        , callback

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

        available[strip name] = mod

      _hydrate_deps: (proto, done) =>
        protos = [ proto ]

        if proto.__proto__?
          while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            protos.push proto = proto.__proto__

        async.each protos.reverse(), (p, next) =>
          name = p.constructor.name

          if p.hasOwnProperty 'deps'
            if HYDRATED[name] == undefined
              HYDRATED[name]            = false
              HYRDATION_LISTENERS[name] = [ next ]

              p._do_hydrate p, p.deps, =>
                HYDRATED[name] = true

                for listener in HYRDATION_LISTENERS[name]
                  listener()
            else if HYDRATED[name] == false
              HYRDATION_LISTENERS[name].push next
            else if HYDRATED[name] == true
              next()
          else
            next()
        , done

      _init_if_madul: (path, callback) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.name == 'Madul'
          if is_madul                            == false      &&
             proto.constructor.name              != 'Object'   &&
             typeof proto                        == 'function' &&
             typeof proto.__super__?.constructor == 'function'
            proto = proto.__super__.constructor
          else
            proto = undefined

        if is_madul
          new mod()
            .initialize()
            .then callback
        else
          callback mod

      _load: (me, name, path, loaded) =>
        me._init_if_madul path, (mod) =>
          me._make_available name, mod
          loaded mod

      _check: (me, path, dep, ref, finished) =>
        fs.readdir path, (err, files) =>
          if err?
            me.warn 'file-not-found', err

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

              fs.stat depth, (e, s) =>
                if s.isDirectory() && f[0] != '.'
                  me._check me, depth, dep, ref, next
                else if s.isFile() && f.substring(0, f.length - 3) == dep
                  me._load me, ref, depth, (mod) => me._do_add me, mod, ref, next
                else
                  next()
            , finished

      _do_add: (me, mod, ref, next) =>
        Madul.FIRE "$.#{me.constructor.name}.dependency.register", ref

        me[underscore ref] = mod

        next()

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, mod, ref, next

      _do_hydrate: (proto, deps, hydration_complete) =>
        initers = [ ]

        async.each deps, (d, next) =>
          { ref, alias, name, root, initer, pres, local } = Madul.PARSE_SPEC d

          if pres?
            insert_at = for p in pres
              index_for = (sibling) => sibling.alias == p.alias

              initers.find index_for

            insert_at.sort()

            insert_at = if insert_at.length == 0 then 0 else insert_at[insert_at.length - 1]

            initers.splice insert_at, 0, alias: alias, execute: initer

          if proto[underscore ref]? == false
            if available[strip ref]? == true
              proto._do_add proto, available[strip ref], ref, next
            else
              if root?
                Madul.FIRE '$.Madul.search_root.load', { name, alias, root }

                @_do_hydrate proto, [ root ], =>
                  if SEARCH_ROOTS[root] == undefined
                    SEARCH_ROOTS[root] = @_find_code_root root

                  proto._check proto, SEARCH_ROOTS[root], name, ref, next
              else if local
                proto._check proto, LOCALS[proto.constructor.name], name, ref, next
              else
                try
                  proto._add proto, ref, name, next
                catch e
                  cwd = process.cwd()
                  pkg = "#{cwd}/node_modules/#{name}/package.json"

                  fs.stat pkg, (err, stat) =>
                    if stat?.isFile()
                      fs.readFile pkg, 'utf8', (err, data) =>
                        json = JSON.parse data
                        main = json.main || json._main || 'index.js'
                        path = "#{cwd}/node_modules/#{name}/#{main}"

                        proto._add proto, ref, path, next
                    else
                      proto._check proto, LOCALS[proto.constructor.name], name, ref, next
          else
            next()
        , =>
          async.eachSeries initers, (initer, next) =>
            proto[initer.execute].apply(@).then next
          , hydration_complete

      _finish_up: (proto, args) =>
        name = proto.constructor.name

        if listeners[name]?
          async.each listeners[name], (listener, next) =>
            listener @
            next()
          , => @_register_initialized name
        else
          @_register_initialized name

      _register_initialized: (name) =>
        @_make_available name, @

        initialized[name] = true

        Madul.FIRE "$.#{name}.initialized"

      _call_initializers_for: (proto, name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              proto[initializer.fn].apply @
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      _find_code_root: (resource) =>
        file  = resource.toLowerCase()
        found = for own key, val of require.cache
          if key.replace(/_/g, '').toLowerCase().includes file
            key.substring(0, key.lastIndexOf '/').split '/'

        found
          .filter (f) => f?
          .sort((a, b) => a.length - b.length)[0]
          .join '/'

      initialize: =>
        deferred = q.defer()
        proto    = @.__proto__
        name     = proto.constructor.name

        Madul.FIRE "$.#{name}.request_instance"

        if initialized[name] == undefined
          Madul.FIRE "$.#{name}.initialize"

          initialized[name] = false
          listeners[name]   = [ deferred.resolve ]

          if LOCALS[name] == undefined
            LOCALS[name] = @_find_code_root name

          @_hydrate_deps proto, => @_wrap_methods proto, => @_finish_up proto
        else if initialized[name] == false
          listeners[name].push deferred.resolve
        else if initialized[name] == true
          process.nextTick => deferred.resolve available[strip name]

        deferred.promise

    module.exports = Madul

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

    microtime = require 'microtime'

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

    available   = { }
    initialized = { }
    listeners   = { }

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

    SEARCH_ROOTS  = { }
    WRAPPED       = { }
    _INITIALIZERS = { }
    HYDRATED      = { }
    LOCALS        = { }

    HYRDATION_LISTENERS = { }

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

      _INITIALIZERS[cls].push fn: method, called: false

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'initialize'
          'details'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      details: =>
        name  = @.__proto__.constructor.name
        props = for own key, val of @.__proto__
          if key != 'constructor' &&
             key != 'details'     &&
             key != 'initialize'  && ((
               key[0]            == '_' &&
               @.__proto__[key]? == false
             ) || key[0] != '_')

            if typeof val == 'function'
              value = val.constructor.name
            else if Array.isArray val
              value = for v in val
                if typeof v == 'function'
                  v.constructor.name
                else if typeof v == 'object'
                  v.constructor.name
                else
                  v
              value = value.join ','
            else if typeof val == 'object'
              value = val.constructor.name
            else
              value = val

            "#{key} => #{value}"

        "\n  #{name}\n    #{props.filter((e) -> e?).join '\n    '}"

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

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

      @SEARCH_ROOT: (mod, path) =>
        Madul.FIRE '$.Madul.search_root.register', "#{mod}": path

        SEARCH_ROOTS[mod] = path.substring 0, path.lastIndexOf '/'

      @PARSE_SPEC: (value) =>
        tokens = value.split '='

        if tokens.length == 2
          initer = tokens[1].trim()
          t      = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = r[0].trim()
            t[0] = r[1]

          if t.length == 2
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = n.substring 1, n.length
            else
              local = false
              name  = n

            alias = t[1].trim()
          else if t.length == 1
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = alias = n.substring 1, n.length
            else
              local = false
              name  = alias = n
          else
            return Madul.FIRE '!.Madul.dependency_spec.alias.invalid', tokens[1]

          toks = initer.split ':'

          if toks.length == 2
            initer = toks[0].trim()
            pres   = toks[1].split(',').map (p) => p.trim()
          else if toks.length == 1
            initer = toks[0].trim()
          else
            return Madul.FIRE '!.Madul.dependency_spec.initializer.invalid', tokens[1]

        else if tokens.length == 1
          t = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = r[0].trim()
            t[0] = r[1]

          if t.length == 2
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = n.substring 1, n.length
            else
              local = false
              name  = n

            alias = t[1].trim()
          else if t.length == 1
            n = t[0].trim()

            if n[0] == '.'
              local = true
              name  = alias = n.substring 1, n.length
            else
              local = false
              name  = alias = n
          else
            return Madul.FIRE '!.Madul.dependency_spec.alias.invalid', tokens[1]

        else
          return Madul.FIRE '!.Madul.dependency_spec.invalid', d

        { ref: alias || name, alias, name, root, initer, pres, local }

      @BUILD_SPEC: ({ search_root, name, alias, initializer, prerequisites }) =>
        unless name?
          return Madul.FIRE '!.Madul.dependency_spec.name-required', arguments[0]

        if prerequisites? && initializer? == false
          return Madul.FIRE '!.Madul.dependency_spec.prerequisites-require-initializer', arguments[0]

        "#{if search_root?   then "#{search_root}#"            else ''}\
         #{name}\
         #{if alias?         then " -> #{alias}"               else ''}\
         #{if initializer?   then " = #{initializer}"          else ''}\
         #{if prerequisites? then ":#{prerequisites.join ','}" else ''}\
        "

      listen: (event, callback) ->
        Madul.LISTEN "*.#{@constructor.name}.#{event}", callback

      fire: (event, args) ->
        Madul.FIRE "@.#{@constructor.name}.#{event}", args

      warn: (event, details) ->
        Madul.FIRE "!.#{@constructor.name}.#{event}", details

      _report: (name, method, state, id, args) =>
        if state == 'reject'
          Madul.FIRE "!.#{name}.#{method}.#{state}",
            uuid:      id
            message:   args
            timestamp: microtime.now()
        else
          Madul.FIRE "@.#{name}.#{method}.#{state}",
            uuid:      id
            args:      args
            timestamp: microtime.now()

      _respond: (proto, method, id, deferred) =>
        (state, data) =>
          process.nextTick =>
            deferred[state] data

            proto._report proto.constructor.name, method, state, id, data

      _prep_invocation: (proto, method, input, def) =>
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def

        if Array.isArray input
          input.push (out) => res 'resolve', out
          input.push (err) => res 'reject',  err
          input.push (out) => res 'notify',  out
        else if typeof input == 'object'
          input.done   = (out) => res 'resolve', out
          input.fail   = (err) => res 'reject',  err
          input.update = (out) => res 'notify',  out

          input = [ input ]
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"
          @warn 'input.invalid', msg
          throw new Error msg

        proto._report proto.constructor.name, method, 'invoke', id, input

        input

      _do_wrap: (proto, method) =>
        if method != 'fire' && method != 'warn' && method != 'listen'
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

          if typeof proto[method] == 'function'
            proto["_#{method}"] = proto[method]

            proto[method] = =>
              def  = q.defer()
              args = if arguments[0]? then Array.prototype.slice.call arguments else [ ]

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

              def.promise
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = for val in proto[method].validate
                @_parse_handle(val).ref

              proto[method].validate = decs
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = for own key, val of proto[method].validate
                { ref } = @_parse_handle val
                proto[method].validate[key] = ref
                ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ @_parse_handle(proto[method].validate).ref ]
            else if typeof proto[method].validate != 'undefined'
              @warn 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            decs = decs.concat(proto[method].before.map (b, i) =>
              { ref } = @_parse_handle b
              proto[method].before[i] = ref
              ref
            ) if proto[method].before?

            decs = decs.concat(proto[method].after.map (a, i) =>
              { ref } = @_parse_handle a
              proto[method].after[i] = ref
              ref
            ) if proto[method].after?

            Madul.FIRE '$.Madul.decorators.hydrate', decs

            @_do_hydrate proto, decs, =>
              proto["_#{method}"] = proto[method]

              proto[method] = =>
                def = q.defer()
                me  = proto["_#{method}"]

                if args_format == 'ARRAY'
                  args = Array.prototype.slice.call arguments

                  if me.validate?
                    validators = for val, i in me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[i]
                      proto[ref].EXECUTE args[i]
                else if args_format == 'OBJECT'
                  args = arguments[0]

                  if me.validate?
                    validators = for own key, val of me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[key]
                      proto[ref].EXECUTE args[key]
                else
                  @warn 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                me.before = [ ] unless me.before?
                me.after  = [ ] unless me.after?

                q.all validators
                .then =>
                  q.all me.before.map (b) =>
                    Madul.FIRE '$.Madul.before_filter.execute', "#{b}": args
                    proto[b].before args
                .then =>
                  me.behavior.apply @, @_prep_invocation proto, method, args, def
                .then (result) =>
                  if me.after.length > 0
                    q.all me.after.map (b) =>
                      Madul.FIRE '$.Madul.after_filter.execute', "#{b}": result
                      b.after result
                  else
                    d = q.defer()

                    process.nextTick => d.resolve result

                    d.promise
                .then  (out) => def.resolve out
                .catch (err) => def.reject  err

                def.promise
          else
            @warn 'cannot-wrap', method

          WRAPPED[proto.constructor.name].push method

      _wrap_methods: (proto, callback) =>
        name    = proto.constructor.name
        to_wrap = [ ]

        while proto? && Object.keys(proto).length > 0 && WRAPPED[name]? == false
          to_wrap.push { proto, name, methods: [ ] }

          for own prop, body of proto
            if prop[0]                  != '_'         &&
               typeof proto["_#{prop}"] == 'undefined' &&
               WRAP(name, prop)         == true

              continue if proto.deps? && proto.deps.indexOf(prop.replace(/_/g, '-')) > -1

              if typeof body == 'function' || typeof body?.behavior == 'function'
                to_wrap[to_wrap.length - 1].methods.push prop

          proto = proto.__proto__
          name  = proto.constructor.name

        async.each to_wrap.reverse(), (wrap, completed) =>
          async.each wrap.methods, (method, next) =>
            wrap.proto._do_wrap wrap.proto, method

            INITIALIZERS wrap.name, method if method[0] == '$'

            next()
          , => @_call_initializers_for wrap.proto, wrap.name, completed
        , callback

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

        available[strip name] = mod

      _hydrate_deps: (proto, done) =>
        protos = [ proto ]

        if proto.__proto__?
          while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            protos.push proto = proto.__proto__

        async.each protos.reverse(), (p, next) =>
          name = p.constructor.name

          if p.hasOwnProperty 'deps'
            if HYDRATED[name] == undefined
              HYDRATED[name]            = false
              HYRDATION_LISTENERS[name] = [ next ]

              p._do_hydrate p, p.deps, =>
                HYDRATED[name] = true

                for listener in HYRDATION_LISTENERS[name]
                  listener()
            else if HYDRATED[name] == false
              HYRDATION_LISTENERS[name].push next
            else if HYDRATED[name] == true
              next()
          else
            next()
        , done

      _init_if_madul: (path, callback) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.name == 'Madul'
          if is_madul                            == false      &&
             proto.constructor.name              != 'Object'   &&
             typeof proto                        == 'function' &&
             typeof proto.__super__?.constructor == 'function'
            proto = proto.__super__.constructor
          else
            proto = undefined

        if is_madul
          new mod()
            .initialize()
            .then callback
        else
          callback mod

      _load: (me, name, path, loaded) =>
        me._init_if_madul path, (mod) =>
          me._make_available name, mod
          loaded mod

      _check: (me, path, dep, ref, finished) =>
        fs.readdir path, (err, files) =>
          if err?
            me.warn 'file-not-found', err

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

              fs.stat depth, (e, s) =>
                if s.isDirectory() && f[0] != '.'
                  me._check me, depth, dep, ref, next
                else if s.isFile() && f.substring(0, f.length - 3) == dep
                  me._load me, ref, depth, (mod) => me._do_add me, mod, ref, next
                else
                  next()
            , finished

      _do_add: (me, mod, ref, next) =>
        Madul.FIRE "$.#{me.constructor.name}.dependency.register", ref

        me[underscore ref] = mod

        next()

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, mod, ref, next

      _do_hydrate: (proto, deps, hydration_complete) =>
        initers = [ ]

        async.each deps, (d, next) =>
          { ref, alias, name, root, initer, pres, local } = Madul.PARSE_SPEC d

          if pres?
            insert_at = for p in pres
              index_for = (sibling) => sibling.alias == p.alias

              initers.find index_for

            insert_at.sort()

            insert_at = if insert_at.length == 0 then 0 else insert_at[insert_at.length - 1]

            initers.splice insert_at, 0, alias: alias, execute: initer

          if proto[underscore ref]? == false
            if available[strip ref]? == true
              proto._do_add proto, available[strip ref], ref, next
            else
              if root?
                Madul.FIRE '$.Madul.search_root.load', { name, alias, root }

                @_do_hydrate proto, [ root ], =>
                  if SEARCH_ROOTS[root] == undefined
                    SEARCH_ROOTS[root] = @_find_code_root root

                  proto._check proto, SEARCH_ROOTS[root], name, ref, next
              else if local
                proto._check proto, LOCALS[proto.constructor.name], name, ref, next
              else
                try
                  proto._add proto, ref, name, next
                catch e
                  cwd = process.cwd()
                  pkg = "#{cwd}/node_modules/#{name}/package.json"

                  fs.stat pkg, (err, stat) =>
                    if stat?.isFile()
                      fs.readFile pkg, 'utf8', (err, data) =>
                        json = JSON.parse data
                        main = json.main || json._main || 'index.js'
                        path = "#{cwd}/node_modules/#{name}/#{main}"

                        proto._add proto, ref, path, next
                    else
                      proto._check proto, LOCALS[proto.constructor.name], name, ref, next
          else
            next()
        , =>
          async.eachSeries initers, (initer, next) =>
            proto[initer.execute].apply(@).then next
          , hydration_complete

      _finish_up: (proto, args) =>
        name = proto.constructor.name

        if listeners[name]?
          async.each listeners[name], (listener, next) =>
            listener @
            next()
          , => @_register_initialized name
        else
          @_register_initialized name

      _register_initialized: (name) =>
        @_make_available name, @

        initialized[name] = true

        Madul.FIRE "$.#{name}.initialized"

      _call_initializers_for: (proto, name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              proto[initializer.fn].apply @
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      _find_code_root: (resource) =>
        file  = resource.toLowerCase()
        found = for own key, val of require.cache
          if key.replace(/_/g, '').toLowerCase().includes file
            key.substring(0, key.lastIndexOf '/').split '/'

        found
          .filter (f) => f?
          .sort((a, b) => a.length - b.length)[0]
          .join '/'

      initialize: =>
        deferred = q.defer()
        proto    = @.__proto__
        name     = proto.constructor.name

        Madul.FIRE "$.#{name}.request_instance"

        if initialized[name] == undefined
          Madul.FIRE "$.#{name}.initialize"

          initialized[name] = false
          listeners[name]   = [ deferred.resolve ]

          if LOCALS[name] == undefined
            LOCALS[name] = @_find_code_root name

          @_hydrate_deps proto, => @_wrap_methods proto, => @_finish_up proto
        else if initialized[name] == false
          listeners[name].push deferred.resolve
        else if initialized[name] == true
          process.nextTick => deferred.resolve available[strip name]

        deferred.promise

    module.exports = Madul


document the rest of the filters

document the rest of the filters

# /api/App Components/Batman.View/Batman.View Filters

Batman filters are evaluated from left to right, with the output of each filter being injected into the next. This allows you to form filter chains for display purposes. Accessor caching does not apply to filter chains. If any component of the chain changes, the entire chain will be recalculated for each binding in the template.

Batman.js ships with many built-in view filters:

Type | Filters
---|----
__Logical Operators__ |  `and`, `or`, `not`
__Comparison Operators__ | `equals`, `eq`, `neq`, `lt`, `gt`, `lteq`, `gteq`
__General Utilities__ | `get`, `[]`, `meta`, `withArguments`, `default`
__Number Helpers__ | `ceil`, `floor`, `round`, `precision`, `fixed`, `delimitNumber`
__Set Helpers__ |  `join`, `sort`, `map`, `has`, `first`
__String Helpers__ | `interpolate`, `escape`, `capitalize`, `titleize`, `singularize`, `underscore`, `camelize`, `trim`, `raw`, `matches`, `truncate`, `prepend`, `append`, `replace`, `downcase`, `upcase`, `pluralize`, `humanize`
__Debuggers__ | `log`, `logStack`

## Custom Filters

You can define custom filters by setting them on the `Batman.Filters` object. For example, a batman.js view filter that formats a date with [moment.js](http://momentjs.com):

```coffeescript
# `moment` is the moment.js object
Batman.Filters.dateFormat = (date, format) ->
  moment(date).format(format)
```

You can also define custom filters when defining custom views with [`Batman.View.filter`](docs/api/batman.view.html#class_function_filter).

## equals(left, right) or eq(left, right): Boolean

Checks if left content is equal to right content:

```html
<span data-showif="title | equals 'Batman Views'"></span>
<span data-showif="value | eq 10"></span>
<span data-showif="value | eq true"></span>
```

__Note__: there is actually _one_ difference between `eq` and `equals`: `equals` rejects undefined values, but `eq` allows them.

## lt(left, right) : Boolean

Checks if left content is `less than` the right content.

```html
<span data-showif="posts.length | lt 10"></span>
```

## gt(left, right) : Boolean

Checks if left content is `greater than` the right content.

```html
<span data-showif="posts.length | gt 10"></span>
```

## lteq(left, right) : Boolean

Checks if left content is `less than or equal to` the right content.

```html
<span data-showif="posts.length | lteq 10"></span>
```

## gteq(left, right) : Boolean

Checks if left content is `greater than or equal to` the right content.

```html
<span data-showif="posts.length | gteq 10"></span>
```

## neq(left, right) : Boolean

Checks if left content is `is NOT equal to` the right content.

```html
<span data-showif="posts.length | neq 10"></span>
```

## ceil(value) : string

The `ceil` filter will run `Math.ceil` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | ceil"></span>
```

## floor(value) : string

The `floor` filter will run `Math.floor` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | floor"></span>
```

## round(value) : string

The `round` filter will run `Math.round` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | round"></span>
```

## percision(value, toPlace) : string

The `precision` filter will run `toPrecision()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | precision"></span>
<span data-bind="someValue | precision 3"></span>
```

## fixed(value, toPlace) : string

The `fixed` filter will run `toFixed()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | fixed"></span>
<span data-bind="someValue | fixed 3"></span>
```

## delimitNumber(value) : string

The `delimitNumber` filter will comma delimit a 'number'. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | delimitNumber"></span>
```

## raw(value) : string

The `raw` filter renders the unescaped value.

```html
<span data-bind="someHTMLyString | raw"></span>
```

## get(value, key) : value

Calls the get function on the input value with the specified key. Can be used with `Batman.Accessible` and `Batman.TerminalAccessible`:

```html
<span data-bind="accessibleFunction | get 'item'"></span>
```

## value[key] : value

Shorthand for the `get` filter.

## and(inputValue, otherValue) : boolean

Returns `true` if `inputValue` and `otherValue` are truthy:

```html
<p data-showif='post.published | and currentUser.loggedIn'></p>
```

## or(inputValue, otherValue) : boolean

Returns `true` if either `inputValue` or `otherValue` are truthy:

```html
<p data-showif='post.published | or currentUser.isAdmin'></p>
```

## not(value) : boolean

Inverts the truthiness of the input value:

```html
<span data-hideif="title | equals 'Batman Views' | not | and action | equals 'show'"></span>
```

## matches(value, string) : boolean

Tests a string against the input value:

```html
<span data-showif="title | matches 'Bat'"></span>
```

## truncate(value, length, end = '...') : string

Limits the length of output to the specified length and appends the specified text if over the limit:

```html
<span data-bind="page.title | truncate 5, '…'"></span>
```
Would result in:
```html
<span data-bind="page.title | truncate 5, '…'">About…</span>
```

## default(value, defaultValue) : value

Provides a default value if the keypath is falsy:

```html
<input type="text" data-bind="page.title | default 'About Us'"></input>
```

## prepend(value, string) : string

Prepends the string to the input value:

```html
<span data-bind-class="page.tag | prepend 'ico-'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | prepend 'ico-'" class="ico-about"></span>
```

## append(value, string) : string

Appends the string to the input value:

```html
<span data-bind-class="page.tag | append '-ico'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | append '-ico'" class="about-ico"></span>
```

## replace(value, searchString, replaceString[, flags]) : string

Replaces content in the input value matching the `searchString` with the `replaceString` value:

```html
<span data-bind="page.title | replace 'html', 'HTML'"></span>
```

## downcase(value) : string

Downcases the input value:

```html
<span data-bind="page.title | downcase"></span>
```

## upcase(value) : string

Upcases the input value:

```html
<span data-bind="page.title | upcase"></span>
```

## pluralize(value, count, includeCount[=true]) : string

Pluralizes the input value based on the patterns specified in `Batman.helpers.inflector` and the count provided:

```coffeescript
( ->
  @singular /(analysis)$/i, '$1'
  @singular /(analy)ses$/i, '$1sis'
).call(Batman.helpers.inflector)
```

```html
<span data-bind="'analysis' | pluralize page.comments.count"></span>
```

## singularize(string) : string

Returns the singular inflection of `string`.

## humanize(string) : string

Takes a string and makes it human readable, for example 'an_underscored_string' would become 'An underscored string'.

```html
<span data-bind="'about_us_page' | humanize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | humanize">About us page</span>
```

## titleize(value) : string

Humanizes `string` and capitalizes each word. For example,

```html
<span data-bind="'about_us_page' | titleize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | titleize">About Us Page</span>
```

## underscore(string) : string

Converts `string` to underscore case.

## camelize(string, firstLetterLower[=false]) : string

Converts `string` to camel case. if `firstLetterLower` is true, the first letter will be lowercase.

## join(array, separator = '') : string

Joins `array` into a single string with `separator`:

```html
<span data-bind="page.comments | map 'title' | join ', '"></span>
```

## toSentence(array) : string

Joins `array` with `, ` and ` and`, as appropriate. See [helpers.toSentence](/docs/api/batman.helpers.html#class_function_tosentence).

## sort(value) : value

Sorts an `array` using the default comparison:

```html
<span data-foreach-comment="page.comments | sort" data-bind="comment.title"><span>
```

## map(iterable) : value

Maps the specified keypath from an `array` of objects:

```html
<span data-foreach-author="page.comments | map 'author'" data-bind="author"><span>
```

## has(iterable, item) : boolean

Calls the `iterable`'s `has` function to check for the existence of the specified `item`.

```coffeescript
class Sample.FirstController extends Batman.Controller
  index: ->
    @set('things', new Batman.Set('thing1', 'thing2'))
```

```html
<input type="checkbox" data-bind-checked="things | has 'thing1'"></input>
```
If you were to dispatch `first#index`:
```html
<input type="checkbox" data-bind-checked="things | has 'thing1'" checked="true"></input>
```

## first(iterable) : value

Returns the first value from an `array`:

```html
<span data-context-firstComment="page.comments | first"></span>
```

## meta(value, keypath) : value

Looks up `keypath` on `value.meta`. The `value` must have a `meta` property to look up against.

## interpolate(string, valuesObject) : string

Allows you to use string interpolation:

```html
<span data-bind="'The page title is %{title}' | interpolate {'title': 'page.title'}"></span>
```

## withArguments(function, curriedArguments...) : function

Ensures that the function is called with the supplied arguments in addition to the arguments it would normally be called with. This is a form of currying. The argument order will be the curried arguments (those passed to withArguments) first, then the regular arguments. In the case of a click event, the regular arguments are node, event, view.

```coffeescript
class Sample.CloseWindowView extends Batman.View
  html: '<span data-event-click="closeWindow | withArguments true"></span>'

  closeWindow: (actuallyClose) ->
    window.close() if actuallyClose
```

```html
<div data-view="CloseWindowView"></div>
```

## escape(value) : string

Escapes HTML in the input value:

```html
<textarea data-bind="page.body_html | escape"></textarea>
```

# /api/App Components/Batman.View/Batman.View Filters

Batman filters are evaluated from left to right, with the output of each filter being injected into the next. This allows you to form filter chains for display purposes. Accessor caching does not apply to filter chains. If any component of the chain changes, the entire chain will be recalculated for each binding in the template.

Batman.js ships with many built-in view filters:

Type | Filters
---|----
__Logical Operators__ |  `and`, `or`, `not`
__Comparison Operators__ | `equals`, `eq`, `neq`, `lt`, `gt`, `lteq`, `gteq`
__General Utilities__ | `get`, `[]`, `meta`, `withArguments`, `default`
__Number Helpers__ | `ceil`, `floor`, `round`, `precision`, `fixed`, `delimitNumber`
__Set Helpers__ |  `join`, `sort`, `map`, `has`, `first`
__String Helpers__ | `interpolate`, `escape`, `capitalize`, `singularize`, `underscore`, `camelize`, `trim`, `raw`, `matches`, `truncate`, `prepend`, `append`, `replace`, `downcase`, `upcase`, `pluralize`, `humanize`
__Debuggers__ | `log`, `logStack`

## Custom Filters

You can define custom filters by setting them on the `Batman.Filters` object. For example, a batman.js view filter that formats a date with [moment.js](http://momentjs.com):

```coffeescript
# `moment` is the moment.js object
Batman.Filters.dateFormat = (date, format) ->
  moment(date).format(format)
```

You can also define custom filters when defining custom views with [`Batman.View.filter`](docs/api/batman.view.html#class_function_filter).

## equals(left, right) or eq(left, right): Boolean

Checks if left content is equal to right content:

```html
<span data-showif="title | equals 'Batman Views'"></span>
<span data-showif="value | eq 10"></span>
<span data-showif="value | eq true"></span>
```

__Note__: there is actually _one_ difference between `eq` and `equals`: `equals` rejects undefined values, but `eq` allows them.

## lt(left, right) : Boolean

Checks if left content is `less than` the right content.

```html
<span data-showif="posts.length | lt 10"></span>
```

## gt(left, right) : Boolean

Checks if left content is `greater than` the right content.

```html
<span data-showif="posts.length | gt 10"></span>
```

## lteq(left, right) : Boolean

Checks if left content is `less than or equal to` the right content.

```html
<span data-showif="posts.length | lteq 10"></span>
```

## gteq(left, right) : Boolean

Checks if left content is `greater than or equal to` the right content.

```html
<span data-showif="posts.length | gteq 10"></span>
```

## neq(left, right) : Boolean

Checks if left content is `is NOT equal to` the right content.

```html
<span data-showif="posts.length | neq 10"></span>
```

## ceil(value) : string

The `ceil` filter will run `Math.ceil` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | ceil"></span>
```

## floor(value) : string

The `floor` filter will run `Math.floor` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | floor"></span>
```

## round(value) : string

The `round` filter will run `Math.round` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | round"></span>
```

## percision(value, toPlace) : string

The `precision` filter will run `toPrecision()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | precision"></span>
<span data-bind="someValue | precision 3"></span>
```

## fixed(value, toPlace) : string

The `fixed` filter will run `toFixed()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | fixed"></span>
<span data-bind="someValue | fixed 3"></span>
```

## delimitNumber(value) : string

The `delimitNumber` filter will comma delimit a 'number'. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | delimitNumber"></span>
```

## raw(value) : string

The `raw` filter renders the unescaped value.

```html
<span data-bind="someHTMLyString | raw"></span>
```

## get(value, key) : value

Calls the get function on the input value with the specified key. Can be used with `Batman.Accessible` and `Batman.TerminalAccessible`:

```html
<span data-bind="accessibleFunction | get 'item'"></span>
```

## value[key] : value

Shorthand for the `get` filter.

## not(value) : boolean

Inverts the truthiness of the input value:

```html
<span data-hideif="title | equals 'Batman Views' | not | and action | equals 'show'"></span>
```

## matches(value, string) : boolean

Tests a string against the input value:

```html
<span data-showif="title | matches 'Bat'"></span>
```

## truncate(value, length, end = '...') : string

Limits the length of output to the specified length and appends the specified text if over the limit:

```html
<span data-bind="page.title | truncate 5, '…'"></span>
```
Would result in:
```html
<span data-bind="page.title | truncate 5, '…'">About…</span>
```

## default(value, defaultValue) : value

Provides a default value if the keypath is falsy:

```html
<input type="text" data-bind="page.title | default 'About Us'"></input>
```

## prepend(value, string) : string

Prepends the string to the input value:

```html
<span data-bind-class="page.tag | prepend 'ico-'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | prepend 'ico-'" class="ico-about"></span>
```

## append(value, string) : string

Appends the string to the input value:

```html
<span data-bind-class="page.tag | append '-ico'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | append '-ico'" class="about-ico"></span>
```

## replace(value, searchString, replaceString[, flags]) : string

Replaces content in the input value matching the `searchString` with the `replaceString` value:

```html
<span data-bind="page.title | replace 'html', 'HTML'"></span>
```

## downcase(value) : string

Downcases the input value:

```html
<span data-bind="page.title | downcase"></span>
```

## upcase(value) : string

Upcases the input value:

```html
<span data-bind="page.title | upcase"></span>
```

## pluralize(value, count) : string

Pluralizes the input value based on the patterns specified in `Batman.helpers.inflector` and the count provided:

```coffeescript
( ->
  @singular /(analysis)$/i, '$1'
  @singular /(analy)ses$/i, '$1sis'
).call(Batman.helpers.inflector)
```

```html
<span data-bind="'analysis' | pluralize page.comments.count"></span>
```

## humanize(string) : string

Takes a string and makes it human readable, for example 'an_underscored_string' would become 'An underscored string'.

```html
<span data-bind="'about_us_page' | humanize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | humanize">About us page</span>
```

## titleize(value) : string

Humanizes `string` and capitalizes each word. For example,

```html
<span data-bind="'about_us_page' | titleize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | titleize">About Us Page</span>
```

## underscore(string) : string

Converts `string` to underscore case.

## camelize(string, firstLetterLower[=false]) : string

Converts `string` to camel case. if `firstLetterLower` is true, the first letter will be lowercase.

## join(array, separator = '') : string

Joins `array` into a single string with `separator`:

```html
<span data-bind="page.comments | map 'title' | join ', '"></span>
```

## toSentence(array) : string

Joins `array` with `, ` and ` and`, as appropriate. See [helpers.toSentence](/docs/api/batman.helpers.html#class_function_tosentence).

## sort(value) : value

Sorts an `array` using the default comparison:

```html
<span data-foreach-comment="page.comments | sort" data-bind="comment.title"><span>
```

## map(iterable) : value

Maps the specified keypath from an `array` of objects:

```html
<span data-foreach-author="page.comments | map 'author'" data-bind="author"><span>
```

## has(iterable, item) : boolean

Calls the `iterable`'s `has` function to check for the existence of the specified `item`.

```coffeescript
class Sample.FirstController extends Batman.Controller
  index: ->
    @set('things', new Batman.Set('thing1', 'thing2'))
```

```html
<input type="checkbox" data-bind-checked="things | has 'thing1'"></input>
```
If you were to dispatch `first#index`:
```html
<input type="checkbox" data-bind-checked="things | has 'thing1'" checked="true"></input>
```

## first(iterable) : value

Returns the first value from an `array`:

```html
<span data-context-firstComment="page.comments | first"></span>
```

## meta(value, keypath) : value

Looks up `keypath` on `value.meta`. The `value` must have a `meta` property to look up against.

## interpolate(string, valuesObject) : string

Allows you to use string interpolation:

```html
<span data-bind="'The page title is %{title}' | interpolate {'title': 'page.title'}"></span>
```

## withArguments(function, curriedArguments...) : function

Ensures that the function is called with the supplied arguments in addition to the arguments it would normally be called with. This is a form of currying. The argument order will be the curried arguments (those passed to withArguments) first, then the regular arguments. In the case of a click event, the regular arguments are node, event, view.

```coffeescript
class Sample.CloseWindowView extends Batman.View
  html: '<span data-event-click="closeWindow | withArguments true"></span>'

  closeWindow: (actuallyClose) ->
    window.close() if actuallyClose
```

```html
<div data-view="CloseWindowView"></div>
```

## escape(value) : string

Escapes HTML in the input value:

```html
<textarea data-bind="page.body_html | escape"></textarea>
```


format total minutes spent waiting

format total minutes spent waiting

    Template.registerHelper 'totalWaitTimeMinutes', ->
      minutes = (QueueMeta.findOne()?.totalWaitTimeSeconds / 60).toFixed 0
      minutesFormatted = minutes.toString().replace /\B(?=(\d{3})+(?!\d))/g, ','
      "#{minutesFormatted} minutes"

    Template.registerHelper 'totalWaitTimeYears', ->
      secondsInYear = 31556900
      years = (QueueMeta.findOne()?.totalWaitTimeSeconds / secondsInYear ).toFixed 2
      "#{years} years"

    Template.registerHelper 'nameAllowedIn', ->
      QueueMeta.findOne()?.theOnlyConnectionAllowedIn?.name

    Template.registerHelper 'isBeingServed', ->
      queueEntry = Queue.findOne()
      queueMeta = QueueMeta.findOne()

Update timeCurrentTicketExpires hackily here...

      timeCurrentTicketExpires = Session.get 'timeCurrentTicketExpires'
      if timeCurrentTicketExpires isnt queueMeta?.timeCurrentTicketExpires
        Session.set 'timeCurrentTicketExpires', queueMeta?.timeCurrentTicketExpires

Not being served in either queueEntry or queueMeta are non-existant

      return no if not (queueEntry? and queueMeta?)
      now = moment().utc().toDate()
      isBeingServed = queueEntry._id is queueMeta?.currentlyServingQueueId and
        queueMeta.timeCurrentTicketExpires > now
      if isBeingServed
        cachedIsBeingServed = Session.get 'isBeingServed'
        Session.set 'isBeingServed', yes if cachedIsBeingServed is undefined or no
      return isBeingServed

    Template.registerHelper 'totalWaitTimeMinutes', ->
      minutes = (QueueMeta.findOne()?.totalWaitTimeSeconds / 60).toFixed 0
      "#{minutes} minutes"

    Template.registerHelper 'totalWaitTimeYears', ->
      secondsInYear = 31556900
      years = (QueueMeta.findOne()?.totalWaitTimeSeconds / secondsInYear ).toFixed 2
      "#{years} years"

    Template.registerHelper 'nameAllowedIn', ->
      QueueMeta.findOne()?.theOnlyConnectionAllowedIn?.name

    Template.registerHelper 'isBeingServed', ->
      queueEntry = Queue.findOne()
      queueMeta = QueueMeta.findOne()

Update timeCurrentTicketExpires hackily here...

      timeCurrentTicketExpires = Session.get 'timeCurrentTicketExpires'
      if timeCurrentTicketExpires isnt queueMeta?.timeCurrentTicketExpires
        Session.set 'timeCurrentTicketExpires', queueMeta?.timeCurrentTicketExpires

Not being served in either queueEntry or queueMeta are non-existant

      return no if not (queueEntry? and queueMeta?)
      now = moment().utc().toDate()
      isBeingServed = queueEntry._id is queueMeta?.currentlyServingQueueId and
        queueMeta.timeCurrentTicketExpires > now
      if isBeingServed
        cachedIsBeingServed = Session.get 'isBeingServed'
        Session.set 'isBeingServed', yes if cachedIsBeingServed is undefined or no
      return isBeingServed


Document upload route handler

Document upload route handler

    express = require 'express'
    Upload  = require 's3-uploader'
    multer  = require 'multer'
    async   = require 'async'
    dms2dec = require 'dms2dec'

    sentry  = require '../sentry'
    librato = require '../librato'

Make a new Express router object for this part of the application.

    api = express.Router()

## Metrics

Agregate metrics for all requests and wheter they succeded (`finish`) or closed
before the request succeeded (`close`).

    api.use (req, res, next) ->
      librato.logRequest req.method

      res.once 'close', ->
        librato.logResponse 'closed'
        sentry.captureResClose res

      res.once 'finish', ->
        librato.logResponse res.statusCode

      next()

## GET /

    api.get '/', (req, res, next) ->
      res.status(204).end()

## POST /upload

Configure [s3-uploader](https://github.com/Turistforeningen/node-s3-uploader) to
store three versions of the image `320px`, `780px`, and `1040px`. The original
image is also uploaded but not publicly avaiable.

    s3 = new Upload process.env.AWS_BUCKET_NAME,
      aws:
        region: process.env.AWS_BUCKET_REGION
        path: process.env.AWS_BUCKET_PATH
        acl: 'public-read'
        httpOptions: timeout: 60000
      returnExif: true

      versions: [
        original: true
        awsImageAcl: 'private'
      ,
        suffix: '-large'
        quality: 80
        maxHeight: 1040
        maxWidth: 1040
      ,
        suffix: '-medium'
        maxHeight: 780
        maxWidth: 780
      ,
        suffix: '-small'
        maxHeight: 320
        maxWidth: 320
      ]

Configure [multer](https://github.com/expressjs/multer) to store files in the
OS's temorary directory `tempdir()`. This way we should not need to clean up the
uploaded files since that should be the job of the OS.

    multer = require('multer')
      putSingleFilesInArray: true
      dest: require('os').tmpdir()

Configure the `/upload` route handler.

    api.post '/upload', multer, (req, res, next) ->
      librato.logImagesUploaded Object.keys req.files

      files = []
      for key, f of req.files
        files.push file for file in f

      async.mapSeries files, (file, cb) ->
        if file.extension.toLowerCase() not in ['jpg', 'jpeg', 'png', 'gif']
          error = new Error "Invalid Image #{file.extension}"
          error.status = 422
          return cb error

        t1 = new Date().getTime()
        s3.upload file.path, {}, (err, images, meta) ->
          return cb err if err

          librato.logImageProcessingTime t1, new Date().getTime()

          if meta.exif['exif:GPSLatitude'] and meta.exif['exif:GPSLongitude']
            meta.geojson =
              type: 'Point'
              coordinates: dms2dec \
                meta.exif['exif:GPSLatitude'], \
                meta.exif['exif:GPSLatitudeRef'], \
                meta.exif['exif:GPSLongitude'], \
                meta.exif['exif:GPSLongitudeRef']
              .reverse()

          if meta.imageSize.height > meta.imageSize.width
            ratio = meta.imageSize.height / meta.imageSize.width
            edge = 'width'
          else
            ratio = meta.imageSize.width / meta.imageSize.height
            edge = 'height'

          for image in images
            image[edge] = Math.floor(image[edge] / ratio)

            image.path = undefined
            image.src = undefined

          return cb null, versions: images.splice(1), meta: meta
      , (err, files) ->
        return next err if err
        sentry.captureHeaderSent req, files if res._headerSent
        return res.status(201).json files

    module.exports = api

    express = require 'express'
    Upload  = require 's3-uploader'
    multer  = require 'multer'
    async   = require 'async'
    dms2dec = require 'dms2dec'

    sentry  = require '../sentry'
    librato = require '../librato'

    s3 = new Upload process.env.AWS_BUCKET_NAME,
      awsBucketRegion: process.env.AWS_BUCKET_REGION
      awsBucketPath: process.env.AWS_BUCKET_PATH
      awsBucketAcl: 'public-read'
      awsHttpTimeout: 60000
      returnExif: true

      versions: [
        original: true
        awsImageAcl: 'private'
      ,
        suffix: '-large'
        quality: 80
        maxHeight: 1040
        maxWidth: 1040
      ,
        suffix: '-medium'
        maxHeight: 780
        maxWidth: 780
      ,
        suffix: '-small'
        maxHeight: 320
        maxWidth: 320
      ]

    api = express.Router()

    api.use (req, res, next) ->
      librato.logRequest req.method

      res.once 'close', ->
        librato.logResponse 'closed'
        sentry.captureResClose res

      res.once 'finish', ->
        librato.logResponse res.statusCode

      next()

    api.get '/', (req, res, next) ->
      res.status(204).end()

    api.post '/upload', multer(dest: require('os').tmpdir()), (req, res, next) ->
      librato.logImagesUploaded Object.keys req.files

      async.mapSeries Object.keys(req.files), (key, cb) ->
        if req.files[key].extension.toLowerCase() not in ['jpg', 'jpeg', 'png', 'gif']
          error = new Error "Invalid Image #{req.files[key].extension}"
          error.status = 422
          return cb error

        console.log req.files[key]

        t1 = new Date().getTime()
        s3.upload req.files[key].path, {}, (err, images, meta) ->
          return cb err if err

          librato.logImageProcessingTime t1, new Date().getTime()

          if meta.exif['exif:GPSLatitude'] and meta.exif['exif:GPSLongitude']
            meta.geojson =
              type: 'Point'
              coordinates: dms2dec \
                meta.exif['exif:GPSLatitude'], \
                meta.exif['exif:GPSLatitudeRef'], \
                meta.exif['exif:GPSLongitude'], \
                meta.exif['exif:GPSLongitudeRef']
              .reverse()

          if meta.imageSize.height > meta.imageSize.width
            ratio = meta.imageSize.height / meta.imageSize.width
            edge = 'width'
          else
            ratio = meta.imageSize.width / meta.imageSize.height
            edge = 'height'

          for image in images
            image[edge] = Math.floor(image[edge] / ratio)

            image.path = undefined
            image.src = undefined

          return cb null, versions: images.splice(1), meta: meta
      , (err, files) ->
        return next err if err
        sentry.captureHeaderSent req, files if res._headerSent
        return res.status(201).json files

    module.exports = api


Decode URI component part

Decode URI component part

    MongoQS     = require 'mongo-querystring'
    Document    = require './model/Document'
    stringify   = require('JSONStream').stringify

    sentry      = require './db/sentry'
    mongo       = require './db/mongo'

    collections = [
      'turer'
      'steder'
      'grupper'
      'områder'
      'bilder'
      'arrangementer'
    ]

    qs = new MongoQS
      alias:
        tag: 'tags.0'
        gruppe: 'grupper'
        endret: 'after'
      ignore:
        api_key     : true # other use
        order       : true # reserved
        sort        : true # other use
        limit       : true # other use
        skip        : true # other use
        fields      : true # other use
        _id         : true # use API endpoint
      custom:
        bbox: 'geojson'
        near: 'geojson'
        after: 'endret'

## PARAM {collection}

    exports.param = (req, res, next, col) ->
      if col not in collections
        return res.json 404, message: "Type #{col} not found"

      req.type = decodeURIComponent col
      req.db   = col: mongo[req.type], query: {}

      next()

    exports.paramCol2 = (req, res, next, col2) ->
      if col not in collections
        return res.json 404, message: "Type #{col2} not found"

      req.type      = col2
      req.db.col    = mongo[col2]
      req.db.query  = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

      next()

## OPTIONS /{collection}

    exports.options = (req, res, next) ->
      res.setHeader 'Access-Control-Expose-Headers', [
        'ETag', 'Location', 'Last-Modified', 'Count-Return', 'Count-Total'
      ].join(', ')
      res.setHeader 'Access-Control-Max-Age', 86400
      res.setHeader 'Access-Control-Allow-Headers', 'Content-Type'
      res.setHeader 'Access-Control-Allow-Methods', 'HEAD, GET, POST'
      res.send 204

## HEAD /{collection}
## GET /{collection}

    exports.get = (req, res, next) ->

### Query

      req.db.query = qs.parse req.query

Prevent private documents for other API user from being returned when quering
`tilbyder` and `status` fields.

      for key, val of req.query
        switch key
          when 'status'
            req.db.query.tilbyder = req.user.tilbyder if val not in ['Offentlig', 'Slettet']
            break
          when 'tilbyder'
            req.db.query.status = 'Offentlig' if val isnt req.user.tilbyder
            break
          else
            if key.substr(0,6) is 'privat'
              req.db.query.tilbyder = req.user.tilbyder
              break

Apply default access control unless `status` or `tilbyder` fields are already
queried.

      if not req.db.query.tilbyder or req.db.query.status
        req.db.query.$or = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

### Fields

Always return `lisens` and `tilbyder` fields for propper attribution. Document
ObjectID is always returned by MongoDB.

      fields = lisens: true, tilbyder: true

Parse user specified fields to be returned.

      if typeof req.query.fields is 'string' and req.query.fields
        for field in req.query.fields.split ',' when field.substr(0,6) isnt 'privat'
          fields[field] = true

Default fields if unless specified by the user.

      else
        fields.endret = true
        fields.status = true
        fields.navn = true
        fields.tags = true

### Sort

Limit sort to ascending or descending on `endret` and `navn` since they are
indexed, non-indexed fields could be slower.

      if typeof req.query.sort is 'string' and req.query.sort
        sort = switch req.query.sort
          when 'endret' then [['endret', 1]]
          when '-endret' then [['endret', -1]]
          when 'navn' then [['navn', 1]]
          when '-navn' then [['navn', -1]]
          else 'endret'

Only apply default sort if there are no geospatial queries.

      else
        sort = 'endret' if not req.db.query.geojson

### Execute

Set limit, skip and, sort options for documents to be returned.

      options =
        limit: Math.min((parseInt(req.query.limit, 10) or 20), 50)
        skip: parseInt(req.query.skip, 10) or 0
        sort: sort

      cursor = req.db.col.find(req.db.query, fields, options)

Count number of matching documents in MongoDB database.

      cursor.count false, (err, total) ->
        return next err if err

Calculate the total number of documents that will eventually be returned (not
the total number of matching documents) since we don't know that in advanced
(due to the nature of streaming).

        count = Math.min(options.limit, Math.max(total - options.skip, 0))

Set `Count-Return` and `Count-Total` headers so that one can use a `HEAD` query
to look up the number of matched documents for a query without the documents
them selves. This may be useful for statistics purposes.

        res.set 'Count-Return', count
        res.set 'Count-Total', total

Return to the user if this is a `HEAD` query or there are no matching documents.

        return res.send 204 if req.method is 'HEAD'
        return res.json documents: [], count: 0, total: 0 if total is 0

Stream matching documents in order to prevent loading them into memory.

        res.set 'Content-Type', 'application/json; charset=utf-8'

        op = '{"documents":['
        cl = '],"count":' + count + ',"total":' + total + '}'

        cursor.stream().pipe(stringify(op, ',', cl)).pipe(res)

## POST /{collection}

    exports.post = (req, res, next) ->
      return res.json 400, message: 'Body is missing' if Object.keys(req.body).length is 0
      return res.json 422, message: 'Body should be a JSON Hash' if req.body instanceof Array

      req.body.tilbyder = req.user.tilbyder

      new Document(req.type, null).once('error', next).once 'ready', ->
        @insert req.body, (err, warn, data) ->
          if err
            return next(err) if err.name isnt 'ValidationError'

            sentry.captureDocumentError req, err

            return res.json 422,
              document: req.body
              message: 'Validation Failed'
              errors: err.details #TODO(starefossen) document this

          res.set 'ETag', "\"#{data.checksum}\""
          res.set 'Last-Modified', new Date(data.endret).toUTCString()
          # res.set 'Location', req.get 'host'

          return res.json 201,
            document: data
            message: 'Validation Warnings' if warn.length > 0
            warnings: warn if warn.length > 0

    MongoQS     = require 'mongo-querystring'
    Document    = require './model/Document'
    stringify   = require('JSONStream').stringify

    sentry      = require './db/sentry'
    mongo       = require './db/mongo'

    collections = [
      'turer'
      'steder'
      'grupper'
      'områder'
      'bilder'
      'arrangementer'
    ]

    qs = new MongoQS
      alias:
        tag: 'tags.0'
        gruppe: 'grupper'
        endret: 'after'
      ignore:
        api_key     : true # other use
        order       : true # reserved
        sort        : true # other use
        limit       : true # other use
        skip        : true # other use
        fields      : true # other use
        _id         : true # use API endpoint
      custom:
        bbox: 'geojson'
        near: 'geojson'
        after: 'endret'

## PARAM {collection}

    exports.param = (req, res, next, col) ->
      if col not in collections
        return res.json 404, message: "Type #{col} not found"

      req.type = col
      req.db   = col: mongo[col], query: {}

      next()

    exports.paramCol2 = (req, res, next, col2) ->
      if col not in collections
        return res.json 404, message: "Type #{col2} not found"

      req.type      = col2
      req.db.col    = mongo[col2]
      req.db.query  = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

      next()

## OPTIONS /{collection}

    exports.options = (req, res, next) ->
      res.setHeader 'Access-Control-Expose-Headers', [
        'ETag', 'Location', 'Last-Modified', 'Count-Return', 'Count-Total'
      ].join(', ')
      res.setHeader 'Access-Control-Max-Age', 86400
      res.setHeader 'Access-Control-Allow-Headers', 'Content-Type'
      res.setHeader 'Access-Control-Allow-Methods', 'HEAD, GET, POST'
      res.send 204

## HEAD /{collection}
## GET /{collection}

    exports.get = (req, res, next) ->

### Query

      req.db.query = qs.parse req.query

Prevent private documents for other API user from being returned when quering
`tilbyder` and `status` fields.

      for key, val of req.query
        switch key
          when 'status'
            req.db.query.tilbyder = req.user.tilbyder if val not in ['Offentlig', 'Slettet']
            break
          when 'tilbyder'
            req.db.query.status = 'Offentlig' if val isnt req.user.tilbyder
            break
          else
            if key.substr(0,6) is 'privat'
              req.db.query.tilbyder = req.user.tilbyder
              break

Apply default access control unless `status` or `tilbyder` fields are already
queried.

      if not req.db.query.tilbyder or req.db.query.status
        req.db.query.$or = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

### Fields

Always return `lisens` and `tilbyder` fields for propper attribution. Document
ObjectID is always returned by MongoDB.

      fields = lisens: true, tilbyder: true

Parse user specified fields to be returned.

      if typeof req.query.fields is 'string' and req.query.fields
        for field in req.query.fields.split ',' when field.substr(0,6) isnt 'privat'
          fields[field] = true

Default fields if unless specified by the user.

      else
        fields.endret = true
        fields.status = true
        fields.navn = true
        fields.tags = true

### Sort

Limit sort to ascending or descending on `endret` and `navn` since they are
indexed, non-indexed fields could be slower.

      if typeof req.query.sort is 'string' and req.query.sort
        sort = switch req.query.sort
          when 'endret' then [['endret', 1]]
          when '-endret' then [['endret', -1]]
          when 'navn' then [['navn', 1]]
          when '-navn' then [['navn', -1]]
          else 'endret'

Only apply default sort if there are no geospatial queries.

      else
        sort = 'endret' if not req.db.query.geojson

### Execute

Set limit, skip and, sort options for documents to be returned.

      options =
        limit: Math.min((parseInt(req.query.limit, 10) or 20), 50)
        skip: parseInt(req.query.skip, 10) or 0
        sort: sort

      cursor = req.db.col.find(req.db.query, fields, options)

Count number of matching documents in MongoDB database.

      cursor.count false, (err, total) ->
        return next err if err

Calculate the total number of documents that will eventually be returned (not
the total number of matching documents) since we don't know that in advanced
(due to the nature of streaming).

        count = Math.min(options.limit, Math.max(total - options.skip, 0))

Set `Count-Return` and `Count-Total` headers so that one can use a `HEAD` query
to look up the number of matched documents for a query without the documents
them selves. This may be useful for statistics purposes.

        res.set 'Count-Return', count
        res.set 'Count-Total', total

Return to the user if this is a `HEAD` query or there are no matching documents.

        return res.send 204 if req.method is 'HEAD'
        return res.json documents: [], count: 0, total: 0 if total is 0

Stream matching documents in order to prevent loading them into memory.

        res.set 'Content-Type', 'application/json; charset=utf-8'

        op = '{"documents":['
        cl = '],"count":' + count + ',"total":' + total + '}'

        cursor.stream().pipe(stringify(op, ',', cl)).pipe(res)

## POST /{collection}

    exports.post = (req, res, next) ->
      return res.json 400, message: 'Body is missing' if Object.keys(req.body).length is 0
      return res.json 422, message: 'Body should be a JSON Hash' if req.body instanceof Array

      req.body.tilbyder = req.user.tilbyder

      new Document(req.type, null).once('error', next).once 'ready', ->
        @insert req.body, (err, warn, data) ->
          if err
            return next(err) if err.name isnt 'ValidationError'

            sentry.captureDocumentError req, err

            return res.json 422,
              document: req.body
              message: 'Validation Failed'
              errors: err.details #TODO(starefossen) document this

          res.set 'ETag', "\"#{data.checksum}\""
          res.set 'Last-Modified', new Date(data.endret).toUTCString()
          # res.set 'Location', req.get 'host'

          return res.json 201,
            document: data
            message: 'Validation Warnings' if warn.length > 0
            warnings: warn if warn.length > 0