Added CodeShip badge

Added CodeShip badge

[ ![Codeship Status for SoftwareMarbles/frugal-couch](https://www.codeship.io/projects/42664c00-dcbd-0131-867d-7e56761d162f/status)](https://www.codeship.io/projects/24565)

# Frugal Couch in Node

## Initialization

For logging and other tasks we use several external modules.

    _       = require 'lodash'
    debug   = (require 'debug') 'frugal-couch'

## Exports

### `overwriteBulk`

`overwriteBulk` is a function designed to perform bulk updating of given documents even when their revision values are out of date.

Bulk updating documents have two significant advantages over updating them one by one:

1.It's much faster as it requires only two trips to CouchDb for all the docs vs. two trips for each doc (one trip to try to update and if that fails then a new trip with corrected revision value)
2.It's much cheaper if used on DaaS like Cloudant which charge the same for bulk requests and non-bulk requests (so if you have 10,000 docs that you need to update you'll be charged for 2 requests and not for 20,000 requests)

Bulk updating shouldn't be used always unless you are absolutely certain that nothing else is updating your database. It can be very useful even in multi-client databases as some types of documents may considered to be stable and depending only on external values (e.g. importing Facebook Graph data)

This function accepts three parameters:

1.`database`: [`nano`](https://github.com/dscape/nano) database object (or an object with equivalent semantics) used to access the database

2.`docs`: an array of documents that need to be bulk-updated

3.`callback`: function with `(err, result)` signature. `result` is an object containing `inserted`, `updated`, `resurected` arrays and `revs` and `errors` objects. The three arrays hold the ids of inserted, updated and resurected documents (previously deleted and now re-inserted) while the two objects have properties matching document ids and their latest revisions or CouchDb generated errors respectively. `callback` is always invoked asynchronously

    exports.overwriteBulk = (database, docs, callback) ->

        getResultObject = (inserted, updated, resurected, revs, errors) ->
            return {
                inserted:   inserted or []
                updated:    updated or []
                resurected: resurected or []
                revs:       revs or {}
                errors:     errors or {}
            }

All parameters must be valid.

        if not _.isFunction(callback)
            throw new Error('Callback parameter required')

        if not database or not _.isArray(docs)
            debug 'Bad input parameters passed to overwriteBulk function'
            return process.nextTick ->
                callback new Error('Bad input parameters')

        if _.isEmpty(docs)
            return process.nextTick ->
                callback null, getResultObject()

Since CouchDb doesn't support bulk updating without _rev we first retreive all the revision numbers of all given docs. That allows us to update the _rev values of the docs we are supposed to update and only then do we bulk upload the docs.

        debug 'Overwritting', docs.length, 'docs in bulk'

Construct the map of doc ids with doc objects so that we can both access just the list of doc ids as well as be able to later update the revisions of docs in `O(n log n)`.

        idDocsMap = {}
        _.each docs, (doc) ->
            idDocsMap[doc._id] = doc

Query the database for the revisions of all the docs. Once we have the revisions we will update the docs and then bulk upload them.

        debug 'Fetching doc revisions'

        return database.fetch_revs { keys: Object.keys idDocsMap }, (err, revisions) ->
            return callback err if err
            return callback new Error 'Invalid document revisions returned.' unless revisions

Update the revisions of the documents with the revision values we got from the server. The conditions to update the revision value are:

1. Row object exists and has both value and id properties.
2. The document with the same id already exists in the db (even if it's deleted as CouchDb keeps *all* docs forever).

            debug 'Updating docs with correct revisions'

            inserted = []
            updated = []
            resurected = []
            _.each revisions.rows, (row) ->

We update the doc if and only if everything is correct (doc id exists among our docs, rev was correctly returned from the server, doc isn't deleted on the server, etc.)

                return debug 'Bad revision item received' unless row

If the row error is `not_found` then this document has a new ID in the database.

                docId = row.key
                return debug 'Bad document id received', docId unless docId

                if row.error
                    if row.error == 'not_found'
                        # We delete the revision just in case there is one as CouchDb will otherwise reject it.
                        delete idDocsMap[docId]._rev
                        inserted.push docId
                    else
                        debug 'Error received', row.error
                    return

                return debug 'Bad revision value received' unless row.value?.rev
                doc = idDocsMap[docId]
                return debug 'Bad document id', docId unless doc

If the document with the same id already existed but was deleted then CouchDb will expect from us to *not* pass revision number. But if it exists right now (it hasn't been deleted) then we have to pass its current revision number (freshly retrieved from the database).

                if row.value.deleted
                    delete doc._rev
                    resurected.push docId
                else
                    doc._rev = row.value.rev
                    updated.push docId

After the document revs have been updated, we bulk load them and pass on the results to the given `callback`

            debug 'Inserting', inserted.length, 'docs'
            debug 'Updating', updated.length, 'docs'
            debug 'Resurecting', resurected.length, 'docs'

            database.bulk { docs: docs }, (err, body) ->
                revs = {}
                errors = {}
                _.each body, (row) ->
                    if row.ok
                        revs[row.id] = row.rev
                    else
                        errors[row.id] = {
                            id:     row.id
                            error:  row.error
                            reason: row.reason
                        }

                callback err, getResultObject(inserted, updated, resurected, revs, errors)

### `partialUpdateBulk`

`partialUpdateBulk` function performs partial updates of the documents with the given IDs.

CouchDb allows partial server-side modification of documents through its update handler feature. However, this feature doesn't work for arrays of documents and is thus too slow for massive document updates.

The alternative is to retrieve all the documents, apply the modification function to them and then bulk upload them. This is what `partialUpdateBulk` does.

This function accepts the following parameters:

1.`database`    -   `nano` database object or an object with equivalent semantics

2.`docIds`      -   the array of IDs of the documents to update

3.`partialUpdater`  -   the function accepting a single parameter (`doc` representing a database document) that does the document update and which will be invoked for each retrieved document

4.`callback`    -   function accepting `err` and `result` parameters:

 - `err`      -   error value in case of any error, falsy otherwise
 - `result`   -   object with `revs` and `errors` object properties. `revs` maps the document IDs to their post-operation revision while errors maps any CouchDb errors to document ID related to it

    exports.partialUpdateBulk = (database, docIds, partialUpdater, callback) ->

        getResultObject = (revs, errors) ->
            return {
                revs:       revs or {},
                errors:     errors or {}
            }

All parameters must be valid.

        if not _.isFunction(callback)
            throw new Error('Callback parameter required')

        if not database or not _.isArray(docIds) or not _.isFunction(partialUpdater)
            debug 'Bad input parameters passed to partialUpdateBulk function'
            return process.nextTick ->
                callback new Error('Bad input parameters')

        if _.isEmpty(docIds)
            return process.nextTick ->
                callback null, getResultObject()

To update the docs we fetch them, update them in-place and then bulk upload them again.

        debug 'Partial bulk updating', docIds.length, 'docs'

        return database.fetch { keys: docIds }, (err, body) ->
            return callback err if err
            return callback new Error 'Invalid documents returned.' if _.isEmpty(body?.rows)

            docs = []
            _.each body.rows, (row) ->
                doc = row.doc
                docs.push doc
                partialUpdater doc

            database.bulk { docs: docs }, (err, body) ->
                revs = {}
                errors = {}
                _.each body, (row) ->
                    if row.ok
                        revs[row.id] = row.rev
                    else
                        errors[row.id] = {
                            id:     row.id
                            error:  row.error
                            reason: row.reason
                        }

                callback err, getResultObject(revs, errors)

### `iterateViewBulk`

`iterateViewBulk` function is used to iterate over CouchDb views.

This function accepts the following parameters:

1.`database`    -   `nano` database object or an object with equivalent semantics

2.`designDoc`   -   the name of the design document in which the view is to be found.

3.`viewName`    -   the name of the view which will be queried.

4.`options`     -   standard CouchDb options like `startkey` and `endkey`. It also holds the number of documents in each desired iteration in its `limit` property. If it doesn't then the default batch size is 1,000 documents (completely arbitrary number). One property that this function ignores is `skip` as it's needed to perform correct and optimal iterations.

5.`iterator`    -   function accepting `err`, `docs` and `next` parameters:

 - `err`      -   error value in case of any error, falsy otherwise
 - `rows`     -   the array of view entries in the current iteration
 - `next`     -   the function to be invoked when the next iteration should be performed

    exports.iterateViewBulk = (database, designDoc, viewName, options, iterator) ->

If iterator doesn't exist, options parameter is our iterator.

        if not iterator
            iterator = options
            options = undefined

Create a clone of the given `options` so that we don't change them during iteration.

        options = _.clone(options) or {}
        options.skip = 0
        options.limit = options.limit or 1000

All parameters must be valid.

        if not _.isFunction(iterator)
            throw new Error('Iterator parameter required')

        if not database or not designDoc or not viewName or not options
            debug 'Bad input parameters passed to iterateViewBulk function'
            return process.nextTick ->
                iterator new Error('Bad input parameters')

`nextIteration` function performs all the work of querying the view, checking the results and invoking the `iterator` function.

        nextIteration = ->
            database.view designDoc, viewName, options, (err, body) ->
                return iterator err if err
                return iterator null, [] if not body or _.isEmpty(body.rows)

Increment the skip count depending on the amount of data we got in this iteration.

                options.skip = options.skip + body.rows.length

Indirect recursion call. This will invoke the `iterator` function which in turn will invoke `nextIteration` itself when it finishes processing the current batch.

                iterator null, body.rows, nextIteration

Start iteration by invoking `nextIteration` for the first time.

        nextIteration()

## License

The MIT License (MIT)

Copyright (c) 2014 Software Marbles SpA

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.


Added support for arrays of validators for properties when args_format is OBJECT

    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"
          proto.warn.call proto, 'input.invalid', msg
          throw new Error msg

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

        input

      _process_decorators: (proto, type) =>
        if Array.isArray proto[type]
          proto[type].map (b) => Madul.PARSE_SPEC(b).ref
        else if typeof proto[type] == 'string'
          [ Madul.PARSE_SPEC(proto[type]).ref ]
        else
          [ ]

      _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].validators = for val, i in decs
                "#{i}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = [ ]

              for own key, val of proto[method].validate
                if Array.isArray val
                  for v in val
                    decs.push v
                else
                  decs.push val

              proto[method].validators = for own key, val of proto[method].validate
                if Array.isArray val
                  "#{key}": for v in val
                    Madul.PARSE_SPEC(v).ref
                else
                  "#{key}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ proto[method].validate ]

              proto[method].validators = [ { 0: Madul.PARSE_SPEC(proto[method].validate).ref }]
            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
                else if args_format == 'OBJECT'
                  args = arguments[0]
                else
                  proto.warn.call proto, 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                validators = [ ]

                for v in me.validators
                  arg       = Object.keys(v)[0]
                  validator = v[arg]

                  if Array.isArray validator
                    for v in validator
                      Madul.FIRE '$.Madul.validator.execute', "#{v}": args[arg]

                      validators.push proto[v].EXECUTE.call proto[v], arg, args[arg]
                  else
                    Madul.FIRE '$.Madul.validator.execute', "#{validator}": args[arg]

                    validators.push proto[validator].EXECUTE.call proto[validator], arg, args[arg]

                before = @_process_decorators me, 'before'
                after  = @_process_decorators me, '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
            proto.warn.call proto, '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 proto
                .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"
          proto.warn.call proto, 'input.invalid', msg
          throw new Error msg

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

        input

      _process_decorators: (proto, type) =>
        if Array.isArray proto[type]
          proto[type].map (b) => Madul.PARSE_SPEC(b).ref
        else if typeof proto[type] == 'string'
          [ Madul.PARSE_SPEC(proto[type]).ref ]
        else
          [ ]

      _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].validators = for val, i in decs
                "#{i}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = for own key, val of proto[method].validate
                val

              proto[method].validators = for own key, val of proto[method].validate
                "#{key}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ proto[method].validate ]

              proto[method].validators = [ { 0: Madul.PARSE_SPEC(proto[method].validate).ref }]
            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
                else if args_format == 'OBJECT'
                  args = arguments[0]
                else
                  proto.warn.call proto, 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                validators = for v in me.validators
                  arg       = Object.keys(v)[0]
                  validator = v[arg]

                  Madul.FIRE '$.Madul.validator.execute', "#{validator}": args[arg]

                  proto[validator].EXECUTE.call proto[validator], args[arg]

                before = @_process_decorators 'before'
                after  = @_process_decorators '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
            proto.warn.call proto, '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 proto
                .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


Add usage examples

Add usage examples

    ###!
    jQuery.TextFade v1.0.0
    https://github.com/mdesantis/jquery-textfade

    Copyright 2014-2018 Maurizio De Santis
    Released under the MIT license
    https://github.com/mdesantis/jquery-textfade/LICENSE
    ###

# jQuery.TextFade

## Description

**jQuery.TextFade** is a jQuery plugin which provides some nice fading effects to the contents of
the selected elements.

The fading effect is obtained replacing every character of the text with a blank character in the
case of a fade-out effect, and conversely replacing the text with blank characters and replacing
every blank character with the corresponding character in the text in the case of a fade-in effect.

If more elements are selected, their contents will be animated simultaneously.

## API

* **jQuery.textFade(action, options)**: main function
* **jQuery.textFadeIn(options)**: alias for `jQuery.textFade('in', options)`
* **jQuery.textFadeOut(options)**: alias for `jQuery.textFade('out', options)`

### Arguments

**jQuery.textFade** takes two arguments:
- **action**: the fading action; can be `'in'`, which causes the text to appear, or `'out'`, which
  causes the text to disappear. *Default value:* none
- **options**: the available options, which are:
  - **text**: if this option is specified, its value will replace the content of the selected
    element, so as to be used for the fading effect; otherwise the fading text is the content of the
    selected element. *Default value:* `null`
  - **sequence**: an array of characters indexes, which determine the order of the text fading.
    *Default value:* `'random'`. The value can be any of these types:
    - *array*: it will be iterated in sequence using each value as the index of the character to be
      replaced
    - *string*: it selects one between the preset sequences (more on this [below](#sequences))
    - *function*: it takes the fading text as argument and returns an array containing the
      characters indexes
  - **steps**: a step is the action of the character replacement. These are the available
    options:
    - **duration**: the duration of each character replacement in milliseconds. *Default value:
      `10`*
    - **threads**: the amount of character replacements for each step. *Default value:* `1`

**jQuery.textFadeIn** and **jQuery.textFadeOut** take the **options** argument only.

### Events

jQuery.textFade triggers two events, **start** and **stop**. In order to listen for them you can use
the following event identifiers:
- **start.textFadeIn**: start of a fade-in
- **stop.textFadeIn**: stop of a fade-in
- **start.textFadeOut**: start of a fade-out
- **stop.textFadeOut**: stop of a fade-out
- **start.textFade**: start of a fade of any action
- **stop.textFade**: stop of a fade of any action

In any case the action is passed as value of the `'action'` key of the first extra parameter, which
happens to be an object.

### Examples

- Fade out the text "HEY THERE!" one character every second:

```coffeescript
$('#text').textFadeIn({
  'text': 'HEY THERE!',
  'steps': { 'duration': 1000, 'threads': 1 }
})
```

- Fade out the text "SEE YA!" three characters every two seconds, in a
*left to right - top to bottom* order:

```coffeescript
$('#text').textFadeOut({
  'text': 'SEE YA!',
  'sequence': 'ltr_ttb',
  'steps': { 'duration': 2000, threads: 3 }
})
```

## Source

**TextFade** is the core function: in addition to the arguments described [above](#arguments), it
takes the `@$element` argument, that is the jQuery element/s whose text is going to be animated

    TextFade = (@$element, @action, options) ->

### Constants

      $                  = jQuery
      BLANK_TEXT_REGEXP  = /[^\n]/g
      LINES_SPLIT_REGEXP = /.+\n?|\n/g

#### Sequences

      SEQUENCES          =

`SEQUENCES` includes some preset sequences, selectable passing the corresponding identifier to
jQuery.textFade. The available identifiers are:

- **random**: the characters fading sequence is random

        'random'  : (text) -> shuffle times text.length

- **ltr_ttb** *(left-to-right character, top-to-bottom line)*: the text fading starts at the first
character of the first line, up to the end of line; then it moves to the next line

        'ltr_ttb' : (text) -> times text.length

- **ltr_btt** *(left-to-right character, bottom-to-top line)*: the text fading starts at the first
character of the last line, up to the end of line; then it moves to the previous line

        'ltr_btt' : (text) -> flatten (textToSequences text).reverse()

- **rtl_ttb** *(right-to-left character, top-to-bottom line)*: the text fading starts at the last
character of the first line, up to the start of line; then it moves to the next line

        'rtl_ttb' : (text) -> flatten textToSequences(text).map((v) -> v.reverse())

- **rtl_btt** *(right-to-left character, bottom-to-top line)*: the text fading starts at the last
character of the last line, up to the start of line; then it moves to the previous line

        'rtl_btt' : (text) -> flatten textToSequences(text).map((v) -> v.reverse()).reverse()

- **ttb_ltr** *(top-to-bottom character, left-to-right line)*: the text fading starts at the first
character of the first line, up to the first character of the last line; then it moves to the next
character of the first line

        'ttb_ltr' : (text) -> flatten zip textToSequences text

- **ttb_rtl** *(top-to-bottom character, right-to-left line)*: the text fading starts at the last
character of the first line, up to the last character of the last line; then it moves to the
previous character of the first line

        'ttb_rtl' : (text) -> flatten (zip textToSequences(text).reverse()).reverse()

- **btt_ltr** *(bottom-to-top character, left-to-right line)*: the text fading starts at the first
character of the last line, up to the first character of the first line; then it moves to the next
character of the last line

        'btt_ltr' : (text) -> flatten zip textToSequences(text).reverse()

- **btt_rtl** *(bottom-to-top character, right-to-left line)*: the text fading starts at the last
character of the last line, up to the first character of the last line; then it moves to the next
character of the last line

        'btt_rtl' : (text) -> flatten (zip textToSequences text).reverse()

### Utility functions

      capitalize = (s) -> "#{s.charAt(0).toUpperCase()}#{s.slice(1)}"

      flatten = (a) -> a.reduce (p, c) -> p.concat c

      max = (a) -> a.reduce ((p, c) -> Math.max p, c), -Infinity

      shuffle = (a) ->
        i = a.length

        while i
          j = Math.floor Math.random()*i
          x = a[--i]
          a[i] = a[j]
          a[j] = x

        a

      times = (n, fn) ->
        i   = 0
        fn ?= (i) -> i

        fn i++ while i < n

      zip = (a) ->
        result = []

        times (max a.map (v) -> v.length), (i) ->
          for v in a
            (result[i] ?= []).push v[i] if v[i]?

        result

Take a text and return an array of arrays, each containing the text index of each
character of the corresponding line

      textToSequences = (text) ->
        sequences = []
        charIndex = 0
        lines     = text.match LINES_SPLIT_REGEXP

        for line, lineIndex in lines
          sequences[lineIndex] = []
          times line.length, () -> sequences[lineIndex].push charIndex++

        sequences

### Default options

      defaultOptions = ->
        'text'     : null
        'sequence' : 'random'
        'steps'    :
          'duration' : 10
          'threads'  : 1

### Private instance methods

Trigger both of the supported event namespaces

      @_trigger = (eventName) ->
        extraParameters = [{ 'action' : @action }]
        @$element.trigger "#{eventName}.textFade#{capitalize(@action)}", extraParameters
        @$element.trigger "#{eventName}.textFade", extraParameters

Replace the character at the given index

      @_replace = (index) ->
        text     = @$element.text()
        prevChar = @begText.charAt index
        nextChar = @endText.charAt index

The replacement is skipped if the character is the same

        return if prevChar is nextChar

        @$element.text "#{text.substr 0, index}#{nextChar}#{text.substr index+nextChar.length}"

The function executed for each character replacement, until the sequence gets empty

      @_step = (sequence) ->
        times @options.steps.threads, () =>
          return if sequence.length is 0

          @_replace sequence.shift()

        if sequence.length is 0
          clearInterval @_interval
          @_trigger 'stop'

### Constructor

      @options = $.extend true, defaultOptions(), options

      text = @options.text ? @$element.text()

      if $.type(@options.sequence) is 'string'
        @options.sequence = SEQUENCES[@options.sequence] text
      else if $.isFunction @options.sequence
        @options.sequence = @options.sequence text
      # else assert @options.sequence to be an array; leave it unchanged

Use an `@options.sequence` clone in order to keep it unchanged

      sequenceClone = @options.sequence[0..]

Newlines are preserved in order to preserve the text structure

      blankText = text.replace BLANK_TEXT_REGEXP, ' '

The only difference between fade-in and fade-out is that on fade-in we start with a blank text and
finish with the submitted text, while on fade-out we start with the submitted text and finish with
a blank text

      switch @action
        when 'in'
          @begText = blankText
          @endText = text
        when 'out'
          @begText = text
          @endText = blankText

      @$element.text @begText

      @_trigger 'start'

      @_interval = setInterval =>
        @_step sequenceClone
      , @options.steps.duration

      @

### jQuery bindings

    $.fn.textFade = (action, options) ->
      @.each -> new TextFade $(@), action, options

    $.fn.textFadeIn = (options) ->
      @.textFade 'in', options

    $.fn.textFadeOut = (options) ->
      @.textFade 'out', options

    ###!
    jQuery.TextFade v1.0.0
    https://github.com/mdesantis/jquery-textfade

    Copyright 2014-2018 Maurizio De Santis
    Released under the MIT license
    https://github.com/mdesantis/jquery-textfade/LICENSE
    ###

# jQuery.TextFade

## Description

**jQuery.TextFade** is a jQuery plugin which provides some nice fading effects to the contents of
the selected elements.

The fading effect is obtained replacing every character of the text with a blank character in the
case of a fade-out effect, and conversely replacing the text with blank characters and replacing
every blank character with the corresponding character in the text in the case of a fade-in effect.

If more elements are selected, their contents will be animated simultaneously.

## API

* **jQuery.textFade(action, options)**: main function
* **jQuery.textFadeIn(options)**: alias for `jQuery.textFade('in', options)`
* **jQuery.textFadeOut(options)**: alias for `jQuery.textFade('out', options)`

### Arguments

**jQuery.textFade** takes two arguments:
- **action**: the fading action; can be `'in'`, which causes the text to appear, or `'out'`, which
  causes the text to disappear. *Default value:* none
- **options**: the available options, which are:
  - **text**: if this option is specified, its value will replace the content of the selected
    element, so as to be used for the fading effect; otherwise the fading text is the content of the
    selected element. *Default value:* `null`
  - **sequence**: an array of characters indexes, which determine the order of the text fading.
    *Default value:* `'random'`. The value can be any of these types:
    - *array*: it will be iterated in sequence using each value as the index of the character to be
      replaced
    - *string*: it selects one between the preset sequences (more on this [below](#sequences))
    - *function*: it takes the fading text as argument and returns an array containing the
      characters indexes
  - **steps**: a step is the action of the character replacement. These are the available
    options:
    - **duration**: the duration of each character replacement in milliseconds. *Default value:
      `10`*
    - **threads**: the amount of character replacements for each step. *Default value:* `1`

**jQuery.textFadeIn** and **jQuery.textFadeOut** take the **options** argument only.

### Events

jQuery.textFade triggers two events, **start** and **stop**. In order to listen for them you can use
the following event identifiers:
- **start.textFadeIn**: start of a fade-in
- **stop.textFadeIn**: stop of a fade-in
- **start.textFadeOut**: start of a fade-out
- **stop.textFadeOut**: stop of a fade-out
- **start.textFade**: start of a fade of any action
- **stop.textFade**: stop of a fade of any action

In any case the action is passed as value of the `'action'` key of the first extra parameter, which
happens to be an object.

### Examples

TODO

## Source

**TextFade** is the core function: in addition to the arguments described [above](#arguments), it
takes the `@$element` argument, that is the jQuery element/s whose text is going to be animated

    TextFade = (@$element, @action, options) ->

### Constants

      $                  = jQuery
      BLANK_TEXT_REGEXP  = /[^\n]/g
      LINES_SPLIT_REGEXP = /.+\n?|\n/g

#### Sequences

      SEQUENCES          =

`SEQUENCES` includes some preset sequences, selectable passing the corresponding identifier to
jQuery.textFade. The available identifiers are:

- **random**: the characters fading sequence is random

        'random'  : (text) -> shuffle times text.length

- **ltr_ttb** *(left-to-right character, top-to-bottom line)*: the text fading starts at the first
character of the first line, up to the end of line; then it moves to the next line

        'ltr_ttb' : (text) -> times text.length

- **ltr_btt** *(left-to-right character, bottom-to-top line)*: the text fading starts at the first
character of the last line, up to the end of line; then it moves to the previous line

        'ltr_btt' : (text) -> flatten (textToSequences text).reverse()

- **rtl_ttb** *(right-to-left character, top-to-bottom line)*: the text fading starts at the last
character of the first line, up to the start of line; then it moves to the next line

        'rtl_ttb' : (text) -> flatten textToSequences(text).map((v) -> v.reverse())

- **rtl_btt** *(right-to-left character, bottom-to-top line)*: the text fading starts at the last
character of the last line, up to the start of line; then it moves to the previous line

        'rtl_btt' : (text) -> flatten textToSequences(text).map((v) -> v.reverse()).reverse()

- **ttb_ltr** *(top-to-bottom character, left-to-right line)*: the text fading starts at the first
character of the first line, up to the first character of the last line; then it moves to the next
character of the first line

        'ttb_ltr' : (text) -> flatten zip textToSequences text

- **ttb_rtl** *(top-to-bottom character, right-to-left line)*: the text fading starts at the last
character of the first line, up to the last character of the last line; then it moves to the
previous character of the first line

        'ttb_rtl' : (text) -> flatten (zip textToSequences(text).reverse()).reverse()

- **btt_ltr** *(bottom-to-top character, left-to-right line)*: the text fading starts at the first
character of the last line, up to the first character of the first line; then it moves to the next
character of the last line

        'btt_ltr' : (text) -> flatten zip textToSequences(text).reverse()

- **btt_rtl** *(bottom-to-top character, right-to-left line)*: the text fading starts at the last
character of the last line, up to the first character of the last line; then it moves to the next
character of the last line

        'btt_rtl' : (text) -> flatten (zip textToSequences text).reverse()

### Utility functions

      capitalize = (s) -> "#{s.charAt(0).toUpperCase()}#{s.slice(1)}"

      flatten = (a) -> a.reduce (p, c) -> p.concat c

      max = (a) -> a.reduce ((p, c) -> Math.max p, c), -Infinity

      shuffle = (a) ->
        i = a.length

        while i
          j = Math.floor Math.random()*i
          x = a[--i]
          a[i] = a[j]
          a[j] = x

        a

      times = (n, fn) ->
        i   = 0
        fn ?= (i) -> i

        fn i++ while i < n

      zip = (a) ->
        result = []

        times (max a.map (v) -> v.length), (i) ->
          for v in a
            (result[i] ?= []).push v[i] if v[i]?

        result

Take a text and return an array of arrays, each containing the text index of each
character of the corresponding line

      textToSequences = (text) ->
        sequences = []
        charIndex = 0
        lines     = text.match LINES_SPLIT_REGEXP

        for line, lineIndex in lines
          sequences[lineIndex] = []
          times line.length, () -> sequences[lineIndex].push charIndex++

        sequences

Here are the default options

      defaultOptions = ->
        'text'     : null
        'sequence' : 'random'
        'steps'    :
          'duration' : 10
          'threads'  : 1

### Private instance methods

Trigger both of the supported event namespaces

      @_trigger = (eventName) ->
        extraParameters = [{ 'action' : @action }]
        @$element.trigger "#{eventName}.textFade#{capitalize(@action)}", extraParameters
        @$element.trigger "#{eventName}.textFade", extraParameters

Replace the character at the given index

      @_replace = (index) ->
        text     = @$element.text()
        prevChar = @begText.charAt index
        nextChar = @endText.charAt index

The replacement is skipped if the character is the same

        return if prevChar is nextChar

        @$element.text "#{text.substr 0, index}#{nextChar}#{text.substr index+nextChar.length}"

The function executed for each character replacement, until the sequence gets empty

      @_step = (sequence) ->
        times @options.steps.threads, () =>
          return if sequence.length is 0

          @_replace sequence.shift()

        if sequence.length is 0
          clearInterval @_interval
          @_trigger 'stop'

### Constructor

      @options = $.extend true, defaultOptions(), options

      text = @options.text ? @$element.text()

      if $.type(@options.sequence) is 'string'
        @options.sequence = SEQUENCES[@options.sequence] text
      else if $.isFunction @options.sequence
        @options.sequence = @options.sequence text
      # else assert @options.sequence to be an array; leave it unchanged

Use an `@options.sequence` clone in order to keep it unchanged

      sequenceClone = @options.sequence[0..]

Newlines are preserved in order to preserve the text structure

      blankText = text.replace BLANK_TEXT_REGEXP, ' '

The only difference between fade-in and fade-out is that on fade-in we start with a blank text and
finish with the submitted text, while on fade-out we start with the submitted text and finish with
a blank text

      switch @action
        when 'in'
          @begText = blankText
          @endText = text
        when 'out'
          @begText = text
          @endText = blankText

      @$element.text @begText

      @_trigger 'start'

      @_interval = setInterval =>
        @_step sequenceClone
      , @options.steps.duration

      @

### jQuery bindings

    $.fn.textFade = (action, options) ->
      @.each -> new TextFade $(@), action, options

    $.fn.textFadeIn = (options) ->
      @.textFade 'in', options

    $.fn.textFadeOut = (options) ->
      @.textFade 'out', options


Add delegatesFunctionsToTarget docs

Add delegatesFunctionsToTarget docs

# /api/Data Structures/Batman.Object/Batman.Proxy

`Batman.Proxy` extends `Batman.Object` but implements the default accessor to `get`, `set`, and `unset` on its `target`.

Any accessors without explicit definitions will be delegated to `target`:

    test "a Batman.Proxy delegates to its target", ->
      class CustomProxy extends Batman.Proxy
        @accessor 'customValue', -> "Custom Value!"

      targetObject = new Batman.Object({name: "Batman", favoriteColor: "#000"})
      proxy = new CustomProxy(targetObject)

      equal proxy.get('favoriteColor'), '#000', "Default accessor delegates to target"
      equal proxy.get('customValue'), "Custom Value!", "Custom accessors override delegated ones"

## ::constructor(target : Batman.Object) : Proxy

Returns a new `Batman.Proxy` delegating to `target`.

## ::.isProxy[=true] : Boolean

Returns `true`. Shows that the object is a proxy.

## ::%target : Object

Returns the object which the `Proxy` is delegating to.

## @delegatesFunctionsToTarget(names...)

Defines a whitelist of functions which the `Proxy` will delegate to its target object. Unlike accessors, functions are not automatically passed to the target. For example:

    class Batman.AssociationProxy
      ...
      @delegatesFunctionsToTarget('save', 'validate', 'destroy')
      ...

passes calls to `save`, `validate`, and `destroy` made on an `AssociationProxy` to the target `Batman.Model` where those functions are defined.