summaryrefslogtreecommitdiffstats
path: root/dgbuilder/dgeflows/node_modules/express/lib/router
diff options
context:
space:
mode:
authorTimoney, Daniel (dt5972) <dtimoney@att.com>2017-02-15 10:37:53 -0500
committerTimoney, Daniel (dt5972) <dtimoney@att.com>2017-02-15 10:40:37 -0500
commit324ee36fe31763e507b422ab0a88e4230045e205 (patch)
treed0b04520f6657601c918ce63fd27575977624187 /dgbuilder/dgeflows/node_modules/express/lib/router
parentf0c97e8db427481e28c0a16b789bc73801b35e47 (diff)
Initial commit for OpenECOMP SDN-C OA&M
Change-Id: I7ab579fd0d206bf356f36d52dcdf4f71f1fa2680 Signed-off-by: Timoney, Daniel (dt5972) <dtimoney@att.com> Former-commit-id: 2a9f0edd09581f907e62ec4689b5ac94dd5382ba
Diffstat (limited to 'dgbuilder/dgeflows/node_modules/express/lib/router')
-rw-r--r--dgbuilder/dgeflows/node_modules/express/lib/router/index.js630
-rw-r--r--dgbuilder/dgeflows/node_modules/express/lib/router/layer.js166
-rw-r--r--dgbuilder/dgeflows/node_modules/express/lib/router/route.js183
3 files changed, 979 insertions, 0 deletions
diff --git a/dgbuilder/dgeflows/node_modules/express/lib/router/index.js b/dgbuilder/dgeflows/node_modules/express/lib/router/index.js
new file mode 100644
index 00000000..209f881b
--- /dev/null
+++ b/dgbuilder/dgeflows/node_modules/express/lib/router/index.js
@@ -0,0 +1,630 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Route = require('./route');
+var Layer = require('./layer');
+var methods = require('methods');
+var mixin = require('utils-merge');
+var debug = require('debug')('express:router');
+var deprecate = require('depd')('express');
+var parseUrl = require('parseurl');
+var utils = require('../utils');
+
+/**
+ * Module variables.
+ */
+
+var objectRegExp = /^\[object (\S+)\]$/;
+var slice = Array.prototype.slice;
+var toString = Object.prototype.toString;
+
+/**
+ * Initialize a new `Router` with the given `options`.
+ *
+ * @param {Object} options
+ * @return {Router} which is an callable function
+ * @api public
+ */
+
+var proto = module.exports = function(options) {
+ options = options || {};
+
+ function router(req, res, next) {
+ router.handle(req, res, next);
+ }
+
+ // mixin Router class functions
+ router.__proto__ = proto;
+
+ router.params = {};
+ router._params = [];
+ router.caseSensitive = options.caseSensitive;
+ router.mergeParams = options.mergeParams;
+ router.strict = options.strict;
+ router.stack = [];
+
+ return router;
+};
+
+/**
+ * Map the given param placeholder `name`(s) to the given callback.
+ *
+ * Parameter mapping is used to provide pre-conditions to routes
+ * which use normalized placeholders. For example a _:user_id_ parameter
+ * could automatically load a user's information from the database without
+ * any additional code,
+ *
+ * The callback uses the same signature as middleware, the only difference
+ * being that the value of the placeholder is passed, in this case the _id_
+ * of the user. Once the `next()` function is invoked, just like middleware
+ * it will continue on to execute the route, or subsequent parameter functions.
+ *
+ * Just like in middleware, you must either respond to the request or call next
+ * to avoid stalling the request.
+ *
+ * app.param('user_id', function(req, res, next, id){
+ * User.find(id, function(err, user){
+ * if (err) {
+ * return next(err);
+ * } else if (!user) {
+ * return next(new Error('failed to load user'));
+ * }
+ * req.user = user;
+ * next();
+ * });
+ * });
+ *
+ * @param {String} name
+ * @param {Function} fn
+ * @return {app} for chaining
+ * @api public
+ */
+
+proto.param = function param(name, fn) {
+ // param logic
+ if (typeof name === 'function') {
+ deprecate('router.param(fn): Refactor to use path params');
+ this._params.push(name);
+ return;
+ }
+
+ // apply param functions
+ var params = this._params;
+ var len = params.length;
+ var ret;
+
+ if (name[0] === ':') {
+ deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.substr(1)) + ', fn) instead');
+ name = name.substr(1);
+ }
+
+ for (var i = 0; i < len; ++i) {
+ if (ret = params[i](name, fn)) {
+ fn = ret;
+ }
+ }
+
+ // ensure we end up with a
+ // middleware function
+ if ('function' != typeof fn) {
+ throw new Error('invalid param() call for ' + name + ', got ' + fn);
+ }
+
+ (this.params[name] = this.params[name] || []).push(fn);
+ return this;
+};
+
+/**
+ * Dispatch a req, res into the router.
+ *
+ * @api private
+ */
+
+proto.handle = function(req, res, done) {
+ var self = this;
+
+ debug('dispatching %s %s', req.method, req.url);
+
+ var search = 1 + req.url.indexOf('?');
+ var pathlength = search ? search - 1 : req.url.length;
+ var fqdn = req.url[0] !== '/' && 1 + req.url.substr(0, pathlength).indexOf('://');
+ var protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : '';
+ var idx = 0;
+ var removed = '';
+ var slashAdded = false;
+ var paramcalled = {};
+
+ // store options for OPTIONS request
+ // only used if OPTIONS request
+ var options = [];
+
+ // middleware and routes
+ var stack = self.stack;
+
+ // manage inter-router variables
+ var parentParams = req.params;
+ var parentUrl = req.baseUrl || '';
+ done = restore(done, req, 'baseUrl', 'next', 'params');
+
+ // setup next layer
+ req.next = next;
+
+ // for options requests, respond with a default if nothing else responds
+ if (req.method === 'OPTIONS') {
+ done = wrap(done, function(old, err) {
+ if (err || options.length === 0) return old(err);
+ sendOptionsResponse(res, options, old);
+ });
+ }
+
+ // setup basic req values
+ req.baseUrl = parentUrl;
+ req.originalUrl = req.originalUrl || req.url;
+
+ next();
+
+ function next(err) {
+ var layerError = err === 'route'
+ ? null
+ : err;
+
+ // remove added slash
+ if (slashAdded) {
+ req.url = req.url.substr(1);
+ slashAdded = false;
+ }
+
+ // restore altered req.url
+ if (removed.length !== 0) {
+ req.baseUrl = parentUrl;
+ req.url = protohost + removed + req.url.substr(protohost.length);
+ removed = '';
+ }
+
+ // no more matching layers
+ if (idx >= stack.length) {
+ setImmediate(done, layerError);
+ return;
+ }
+
+ // get pathname of request
+ var path = getPathname(req);
+
+ if (path == null) {
+ return done(layerError);
+ }
+
+ // find next matching layer
+ var layer;
+ var match;
+ var route;
+
+ while (match !== true && idx < stack.length) {
+ layer = stack[idx++];
+ match = matchLayer(layer, path);
+ route = layer.route;
+
+ if (typeof match !== 'boolean') {
+ // hold on to layerError
+ layerError = layerError || match;
+ }
+
+ if (match !== true) {
+ continue;
+ }
+
+ if (!route) {
+ // process non-route handlers normally
+ continue;
+ }
+
+ if (layerError) {
+ // routes do not match with a pending error
+ match = false;
+ continue;
+ }
+
+ var method = req.method;
+ var has_method = route._handles_method(method);
+
+ // build up automatic options response
+ if (!has_method && method === 'OPTIONS') {
+ appendMethods(options, route._options());
+ }
+
+ // don't even bother matching route
+ if (!has_method && method !== 'HEAD') {
+ match = false;
+ continue;
+ }
+ }
+
+ // no match
+ if (match !== true) {
+ return done(layerError);
+ }
+
+ // store route for dispatch on change
+ if (route) {
+ req.route = route;
+ }
+
+ // Capture one-time layer values
+ req.params = self.mergeParams
+ ? mergeParams(layer.params, parentParams)
+ : layer.params;
+ var layerPath = layer.path;
+
+ // this should be done for the layer
+ self.process_params(layer, paramcalled, req, res, function (err) {
+ if (err) {
+ return next(layerError || err);
+ }
+
+ if (route) {
+ return layer.handle_request(req, res, next);
+ }
+
+ trim_prefix(layer, layerError, layerPath, path);
+ });
+ }
+
+ function trim_prefix(layer, layerError, layerPath, path) {
+ var c = path[layerPath.length];
+ if (c && '/' !== c && '.' !== c) return next(layerError);
+
+ // Trim off the part of the url that matches the route
+ // middleware (.use stuff) needs to have the path stripped
+ if (layerPath.length !== 0) {
+ debug('trim prefix (%s) from url %s', layerPath, req.url);
+ removed = layerPath;
+ req.url = protohost + req.url.substr(protohost.length + removed.length);
+
+ // Ensure leading slash
+ if (!fqdn && req.url[0] !== '/') {
+ req.url = '/' + req.url;
+ slashAdded = true;
+ }
+
+ // Setup base URL (no trailing slash)
+ req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
+ ? removed.substring(0, removed.length - 1)
+ : removed);
+ }
+
+ debug('%s %s : %s', layer.name, layerPath, req.originalUrl);
+
+ if (layerError) {
+ layer.handle_error(layerError, req, res, next);
+ } else {
+ layer.handle_request(req, res, next);
+ }
+ }
+};
+
+/**
+ * Process any parameters for the layer.
+ *
+ * @api private
+ */
+
+proto.process_params = function(layer, called, req, res, done) {
+ var params = this.params;
+
+ // captured parameters from the layer, keys and values
+ var keys = layer.keys;
+
+ // fast track
+ if (!keys || keys.length === 0) {
+ return done();
+ }
+
+ var i = 0;
+ var name;
+ var paramIndex = 0;
+ var key;
+ var paramVal;
+ var paramCallbacks;
+ var paramCalled;
+
+ // process params in order
+ // param callbacks can be async
+ function param(err) {
+ if (err) {
+ return done(err);
+ }
+
+ if (i >= keys.length ) {
+ return done();
+ }
+
+ paramIndex = 0;
+ key = keys[i++];
+
+ if (!key) {
+ return done();
+ }
+
+ name = key.name;
+ paramVal = req.params[name];
+ paramCallbacks = params[name];
+ paramCalled = called[name];
+
+ if (paramVal === undefined || !paramCallbacks) {
+ return param();
+ }
+
+ // param previously called with same value or error occurred
+ if (paramCalled && (paramCalled.error || paramCalled.match === paramVal)) {
+ // restore value
+ req.params[name] = paramCalled.value;
+
+ // next param
+ return param(paramCalled.error);
+ }
+
+ called[name] = paramCalled = {
+ error: null,
+ match: paramVal,
+ value: paramVal
+ };
+
+ paramCallback();
+ }
+
+ // single param callbacks
+ function paramCallback(err) {
+ var fn = paramCallbacks[paramIndex++];
+
+ // store updated value
+ paramCalled.value = req.params[key.name];
+
+ if (err) {
+ // store error
+ paramCalled.error = err;
+ param(err);
+ return;
+ }
+
+ if (!fn) return param();
+
+ try {
+ fn(req, res, paramCallback, paramVal, key.name);
+ } catch (e) {
+ paramCallback(e);
+ }
+ }
+
+ param();
+};
+
+/**
+ * Use the given middleware function, with optional path, defaulting to "/".
+ *
+ * Use (like `.all`) will run for any http METHOD, but it will not add
+ * handlers for those methods so OPTIONS requests will not consider `.use`
+ * functions even if they could respond.
+ *
+ * The other difference is that _route_ path is stripped and not visible
+ * to the handler function. The main effect of this feature is that mounted
+ * handlers can operate without any code changes regardless of the "prefix"
+ * pathname.
+ *
+ * @api public
+ */
+
+proto.use = function use(fn) {
+ var offset = 0;
+ var path = '/';
+
+ // default path to '/'
+ // disambiguate router.use([fn])
+ if (typeof fn !== 'function') {
+ var arg = fn;
+
+ while (Array.isArray(arg) && arg.length !== 0) {
+ arg = arg[0];
+ }
+
+ // first arg is the path
+ if (typeof arg !== 'function') {
+ offset = 1;
+ path = fn;
+ }
+ }
+
+ var callbacks = utils.flatten(slice.call(arguments, offset));
+
+ if (callbacks.length === 0) {
+ throw new TypeError('Router.use() requires middleware functions');
+ }
+
+ callbacks.forEach(function (fn) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('Router.use() requires middleware function but got a ' + gettype(fn));
+ }
+
+ // add the middleware
+ debug('use %s %s', path, fn.name || '<anonymous>');
+
+ var layer = new Layer(path, {
+ sensitive: this.caseSensitive,
+ strict: false,
+ end: false
+ }, fn);
+
+ layer.route = undefined;
+
+ this.stack.push(layer);
+ }, this);
+
+ return this;
+};
+
+/**
+ * Create a new Route for the given path.
+ *
+ * Each route contains a separate middleware stack and VERB handlers.
+ *
+ * See the Route api documentation for details on adding handlers
+ * and middleware to routes.
+ *
+ * @param {String} path
+ * @return {Route}
+ * @api public
+ */
+
+proto.route = function(path){
+ var route = new Route(path);
+
+ var layer = new Layer(path, {
+ sensitive: this.caseSensitive,
+ strict: this.strict,
+ end: true
+ }, route.dispatch.bind(route));
+
+ layer.route = route;
+
+ this.stack.push(layer);
+ return route;
+};
+
+// create Router#VERB functions
+methods.concat('all').forEach(function(method){
+ proto[method] = function(path){
+ var route = this.route(path)
+ route[method].apply(route, slice.call(arguments, 1));
+ return this;
+ };
+});
+
+// append methods to a list of methods
+function appendMethods(list, addition) {
+ for (var i = 0; i < addition.length; i++) {
+ var method = addition[i];
+ if (list.indexOf(method) === -1) {
+ list.push(method);
+ }
+ }
+}
+
+// get pathname of request
+function getPathname(req) {
+ try {
+ return parseUrl(req).pathname;
+ } catch (err) {
+ return undefined;
+ }
+}
+
+// get type for error message
+function gettype(obj) {
+ var type = typeof obj;
+
+ if (type !== 'object') {
+ return type;
+ }
+
+ // inspect [[Class]] for objects
+ return toString.call(obj)
+ .replace(objectRegExp, '$1');
+}
+
+/**
+ * Match path to a layer.
+ *
+ * @param {Layer} layer
+ * @param {string} path
+ * @private
+ */
+
+function matchLayer(layer, path) {
+ try {
+ return layer.match(path);
+ } catch (err) {
+ return err;
+ }
+}
+
+// merge params with parent params
+function mergeParams(params, parent) {
+ if (typeof parent !== 'object' || !parent) {
+ return params;
+ }
+
+ // make copy of parent for base
+ var obj = mixin({}, parent);
+
+ // simple non-numeric merging
+ if (!(0 in params) || !(0 in parent)) {
+ return mixin(obj, params);
+ }
+
+ var i = 0;
+ var o = 0;
+
+ // determine numeric gaps
+ while (i === o || o in parent) {
+ if (i in params) i++;
+ if (o in parent) o++;
+ }
+
+ // offset numeric indices in params before merge
+ for (i--; i >= 0; i--) {
+ params[i + o] = params[i];
+
+ // create holes for the merge when necessary
+ if (i < o) {
+ delete params[i];
+ }
+ }
+
+ return mixin(parent, params);
+}
+
+// restore obj props after function
+function restore(fn, obj) {
+ var props = new Array(arguments.length - 2);
+ var vals = new Array(arguments.length - 2);
+
+ for (var i = 0; i < props.length; i++) {
+ props[i] = arguments[i + 2];
+ vals[i] = obj[props[i]];
+ }
+
+ return function(err){
+ // restore vals
+ for (var i = 0; i < props.length; i++) {
+ obj[props[i]] = vals[i];
+ }
+
+ return fn.apply(this, arguments);
+ };
+}
+
+// send an OPTIONS response
+function sendOptionsResponse(res, options, next) {
+ try {
+ var body = options.join(',');
+ res.set('Allow', body);
+ res.send(body);
+ } catch (err) {
+ next(err);
+ }
+}
+
+// wrap a function
+function wrap(old, fn) {
+ return function proxy() {
+ var args = new Array(arguments.length + 1);
+
+ args[0] = old;
+ for (var i = 0, len = arguments.length; i < len; i++) {
+ args[i + 1] = arguments[i];
+ }
+
+ fn.apply(this, args);
+ };
+}
diff --git a/dgbuilder/dgeflows/node_modules/express/lib/router/layer.js b/dgbuilder/dgeflows/node_modules/express/lib/router/layer.js
new file mode 100644
index 00000000..88ebd396
--- /dev/null
+++ b/dgbuilder/dgeflows/node_modules/express/lib/router/layer.js
@@ -0,0 +1,166 @@
+/**
+ * Module dependencies.
+ */
+
+var pathRegexp = require('path-to-regexp');
+var debug = require('debug')('express:router:layer');
+
+/**
+ * Module variables.
+ */
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+/**
+ * Expose `Layer`.
+ */
+
+module.exports = Layer;
+
+function Layer(path, options, fn) {
+ if (!(this instanceof Layer)) {
+ return new Layer(path, options, fn);
+ }
+
+ debug('new %s', path);
+ options = options || {};
+
+ this.handle = fn;
+ this.name = fn.name || '<anonymous>';
+ this.params = undefined;
+ this.path = undefined;
+ this.regexp = pathRegexp(path, this.keys = [], options);
+
+ if (path === '/' && options.end === false) {
+ this.regexp.fast_slash = true;
+ }
+}
+
+/**
+ * Handle the error for the layer.
+ *
+ * @param {Error} error
+ * @param {Request} req
+ * @param {Response} res
+ * @param {function} next
+ * @api private
+ */
+
+Layer.prototype.handle_error = function handle_error(error, req, res, next) {
+ var fn = this.handle;
+
+ if (fn.length !== 4) {
+ // not a standard error handler
+ return next(error);
+ }
+
+ try {
+ fn(error, req, res, next);
+ } catch (err) {
+ next(err);
+ }
+};
+
+/**
+ * Handle the request for the layer.
+ *
+ * @param {Request} req
+ * @param {Response} res
+ * @param {function} next
+ * @api private
+ */
+
+Layer.prototype.handle_request = function handle(req, res, next) {
+ var fn = this.handle;
+
+ if (fn.length > 3) {
+ // not a standard request handler
+ return next();
+ }
+
+ try {
+ fn(req, res, next);
+ } catch (err) {
+ next(err);
+ }
+};
+
+/**
+ * Check if this route matches `path`, if so
+ * populate `.params`.
+ *
+ * @param {String} path
+ * @return {Boolean}
+ * @api private
+ */
+
+Layer.prototype.match = function match(path) {
+ if (path == null) {
+ // no path, nothing matches
+ this.params = undefined;
+ this.path = undefined;
+ return false;
+ }
+
+ if (this.regexp.fast_slash) {
+ // fast path non-ending match for / (everything matches)
+ this.params = {};
+ this.path = '';
+ return true;
+ }
+
+ var m = this.regexp.exec(path);
+
+ if (!m) {
+ this.params = undefined;
+ this.path = undefined;
+ return false;
+ }
+
+ // store values
+ this.params = {};
+ this.path = m[0];
+
+ var keys = this.keys;
+ var params = this.params;
+ var prop;
+ var n = 0;
+ var key;
+ var val;
+
+ for (var i = 1, len = m.length; i < len; ++i) {
+ key = keys[i - 1];
+ prop = key
+ ? key.name
+ : n++;
+ val = decode_param(m[i]);
+
+ if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
+ params[prop] = val;
+ }
+ }
+
+ return true;
+};
+
+/**
+ * Decode param value.
+ *
+ * @param {string} val
+ * @return {string}
+ * @api private
+ */
+
+function decode_param(val){
+ if (typeof val !== 'string') {
+ return val;
+ }
+
+ try {
+ return decodeURIComponent(val);
+ } catch (e) {
+ var err = new TypeError("Failed to decode param '" + val + "'");
+ err.status = 400;
+ throw err;
+ }
+}
diff --git a/dgbuilder/dgeflows/node_modules/express/lib/router/route.js b/dgbuilder/dgeflows/node_modules/express/lib/router/route.js
new file mode 100644
index 00000000..6213b821
--- /dev/null
+++ b/dgbuilder/dgeflows/node_modules/express/lib/router/route.js
@@ -0,0 +1,183 @@
+/**
+ * Module dependencies.
+ */
+
+var debug = require('debug')('express:router:route');
+var Layer = require('./layer');
+var methods = require('methods');
+var utils = require('../utils');
+
+/**
+ * Expose `Route`.
+ */
+
+module.exports = Route;
+
+/**
+ * Initialize `Route` with the given `path`,
+ *
+ * @param {String} path
+ * @api private
+ */
+
+function Route(path) {
+ debug('new %s', path);
+ this.path = path;
+ this.stack = [];
+
+ // route handlers for various http methods
+ this.methods = {};
+}
+
+/**
+ * @api private
+ */
+
+Route.prototype._handles_method = function _handles_method(method) {
+ if (this.methods._all) {
+ return true;
+ }
+
+ method = method.toLowerCase();
+
+ if (method === 'head' && !this.methods['head']) {
+ method = 'get';
+ }
+
+ return Boolean(this.methods[method]);
+};
+
+/**
+ * @return {Array} supported HTTP methods
+ * @api private
+ */
+
+Route.prototype._options = function _options() {
+ var methods = Object.keys(this.methods);
+
+ // append automatic head
+ if (this.methods.get && !this.methods.head) {
+ methods.push('head');
+ }
+
+ for (var i = 0; i < methods.length; i++) {
+ // make upper case
+ methods[i] = methods[i].toUpperCase();
+ }
+
+ return methods;
+};
+
+/**
+ * dispatch req, res into this route
+ *
+ * @api private
+ */
+
+Route.prototype.dispatch = function(req, res, done){
+ var idx = 0;
+ var stack = this.stack;
+ if (stack.length === 0) {
+ return done();
+ }
+
+ var method = req.method.toLowerCase();
+ if (method === 'head' && !this.methods['head']) {
+ method = 'get';
+ }
+
+ req.route = this;
+
+ next();
+
+ function next(err) {
+ if (err && err === 'route') {
+ return done();
+ }
+
+ var layer = stack[idx++];
+ if (!layer) {
+ return done(err);
+ }
+
+ if (layer.method && layer.method !== method) {
+ return next(err);
+ }
+
+ if (err) {
+ layer.handle_error(err, req, res, next);
+ } else {
+ layer.handle_request(req, res, next);
+ }
+ }
+};
+
+/**
+ * Add a handler for all HTTP verbs to this route.
+ *
+ * Behaves just like middleware and can respond or call `next`
+ * to continue processing.
+ *
+ * You can use multiple `.all` call to add multiple handlers.
+ *
+ * function check_something(req, res, next){
+ * next();
+ * };
+ *
+ * function validate_user(req, res, next){
+ * next();
+ * };
+ *
+ * route
+ * .all(validate_user)
+ * .all(check_something)
+ * .get(function(req, res, next){
+ * res.send('hello world');
+ * });
+ *
+ * @param {function} handler
+ * @return {Route} for chaining
+ * @api public
+ */
+
+Route.prototype.all = function(){
+ var callbacks = utils.flatten([].slice.call(arguments));
+ callbacks.forEach(function(fn) {
+ if (typeof fn !== 'function') {
+ var type = {}.toString.call(fn);
+ var msg = 'Route.all() requires callback functions but got a ' + type;
+ throw new Error(msg);
+ }
+
+ var layer = Layer('/', {}, fn);
+ layer.method = undefined;
+
+ this.methods._all = true;
+ this.stack.push(layer);
+ }, this);
+
+ return this;
+};
+
+methods.forEach(function(method){
+ Route.prototype[method] = function(){
+ var callbacks = utils.flatten([].slice.call(arguments));
+
+ callbacks.forEach(function(fn) {
+ if (typeof fn !== 'function') {
+ var type = {}.toString.call(fn);
+ var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
+ throw new Error(msg);
+ }
+
+ debug('%s %s', method, this.path);
+
+ var layer = Layer('/', {}, fn);
+ layer.method = method;
+
+ this.methods[method] = true;
+ this.stack.push(layer);
+ }, this);
+ return this;
+ };
+});