text: (function() {
  
    var _ = require('underscore');
  
    function existy(x) { return x != null }
    exports.existy = existy;
  
    function cat() {
      var head = _.first(arguments);
      if (existy(head))
        return head.concat.apply(head, _.rest(arguments));
      else
        return [];
    }
    exports.cat = cat;
  
    function construct(head, tail) {
      return cat([head], _.toArray(tail));
    }
    exports.construct = construct;
  
    exports.partial1 = function partial1(fun, arg1) {
      return function(/* args */) {
        var args = construct(arg1, arguments);
        return fun.apply(fun, args);
      };
    };
  
    exports.partial2 = function _partial2(fun, arg1, arg2) {
      return function(/* args */) {
        var args = exports.cat([arg1, arg2], arguments);
        return fun.apply(fun, args);
      };
    };
  
    exports.partial3 = function _partial3(fun, arg1, arg2, arg3) {
      return function(/* args */) {
        var args = exports.cat([arg1, arg2, arg3], arguments);
        return fun.apply(fun, args);
      };
    };
  
    exports.pipeline = function pipeline(seed /*, args */) {
      return _.reduce(_.rest(arguments),
                      function (l, r) { return r(l); },
                      seed);
    };
  
    exports.curry3 = function curry3(fun) {
      return function(thirdArg) {
        return function (secondArg) {
          return function (firstArg) {
            return fun(firstArg, secondArg, thirdArg);
          };
        };
      };
    };
  
    exports.curry2 = function curry2(fun) {
      return function(secondArg) {
        return function(firstArg) {
          return fun(firstArg, secondArg);
        };
      };
    };
  
    exports.greaterThan = exports.curry2(function (lhs, rhs) { return lhs > rhs });
    exports.lessThan = exports.curry2(function (lhs, rhs) { return lhs < rhs });
  
    exports.lift = function lift(answerFun, stateFun) {
      return function(/* args */) {
        var args = _.toArray(arguments);
  
        return function(state) {
          var ans = answerFun.apply(null, exports.construct(state, args));
          var s = stateFun ? stateFun(state) : ans;
  
          return {answer: ans, state: s};
        };
      };
    };
  
    // TODO: Optimizations opportunity: actually, just use pipelining for this!
    // If needed, provide actions that do not produce intermediate results to
    // reduce cost of method. This would work potentially in the buffer + offset
    // case, by directly updating the offset instead of returning the new offset.
  
    exports.actions = function actions(acts, done) {
      return function (seed) {
        var init = { values: [], state: seed };
  
        var intermediate = _.reduce(acts, function (stateObj, action) {
          var result = action(stateObj.state);
          var values = exports.cat(stateObj.values, [result.answer]);
          return {values: values, state: result.state};
        }, init);
  
        var keep = _.filter(intermediate.values, existy);
  
        return done(keep, intermediate.state);
      };
    };
  
    function mapcat(fun, coll) {
      return cat.apply(null, _.map(coll, fun));
    }
  
    exports.condition1 = function condition1(/* validators */) {
      var validators = _.toArray(arguments);
  
      return function(fun, arg) {
        var errors = mapcat(function(isValid) {
          return isValid(arg) ? []
            : [_.isFunction(isValid.message) ? isValid.message.apply(arg) : isValid.message];
        }, validators);
  
        if (!_.isEmpty(errors))
          throw new Error(errors.join(', '));
  
        return fun(arg);
      };
    };
  
    exports.validator = function validator(message, fun) {
      var f = function(/* args */) {
        return fun.apply(fun, arguments);
      };
  
      f['message'] = message;
      return f;
    };
  
    exports.truthy = truthy;
    function truthy(x) { return (x !== false) && existy(x) }
  
    function doWhen(cond, action) {
      if(truthy(cond))
        return action();
      else
        return undefined;
    }
  
    exports.invoker = function invoker (NAME, METHOD) {
      return function(target /* args ... */) {
        if (!existy(target)) throw new Error('Must provide a target');
  
        var targetMethod = target[NAME];
        var args = _.rest(arguments);
  
        return doWhen((existy(targetMethod) && METHOD === targetMethod), function() {
          return targetMethod.apply(target, args);
        });
      };
    };
  
    // Merge converts _.extend into a pure function. Instead of using the first
    // argument as the target object, it instead sticks a local empty object
    // into the front of _.extend’s arguments and mutate that instead.
    exports.merge = function(/*args*/) {
      return _.extend.apply(null, construct({}, arguments));
    };
  
    exports.dispatch = function(/* funs */) {
      var funs = _.toArray(arguments);
      var size = funs.length;
  
      return function(target /*, args */) {
        var ret;
        var args = _.rest(arguments);
  
        for (var funIndex = 0; funIndex < size; funIndex++) {
          var fun = funs[funIndex];
          ret = fun.apply(fun, construct(target, args));
  
          if (existy(ret)) return ret;
        }
  
        return ret;
      };
    };
  
    exports.isa = function(type, action) {
      return function(obj) {
        if (type === obj)
          return action(obj);
      }
    }
  
  }.call(this));
  