<commit_before>/**
 * module  DOM/event
 */

;(function(K){

function getWindow(element){
	// window
	return 'setInterval' in element ? element

		// document
		: 'getElementById' in element ? element.window
			: element.ownerDocument.window;
};

function getStorage(el){
	var id = SELECTOR.uid(el);

	return event_storage[id] || (event_storage[id] = {});
};

// from jQuery
function checkRelatedTarget(event){
	var related = event.relatedTarget,
		el = this;

	// Firefox sometimes assigns relatedTarget a XUL element
	// which we cannot access the parentNode property of
	try{
		// Chrome does something similar, the parentNode property
		// can be accessed but is null.
		if ( related && related !== document && !related.parentNode ) {
			return;
		}

		// Traverse up the tree
		while ( related && related !== el ) {
			related = related.parentNode;
		}

		if ( related !== el ) {
			// handle event if we actually just moused on to a non sub-element
			return true;
		}

	}catch(e){}

	return;
};

function removeDOMEvent(type, fn){
	var el = this,
		storage = getStorage(el),
		remove = removeDOMEventByType,
		s;

	if(!storage){
		return;
	}

	if(fn){
		var index;

		s = storage[type];
		index = s ? s.fns.indexOf(fn) : -1;
		index !== -1 && remove(el, type, s, index);

	}else{
		var types = type ?
				  storage[type] ? [type] : []
				: Object.keys(storage),

			len = types.length,
			t;

		while(len --){
			t = types[len]; 	// type
			s = storage[t];		// storage

			s.fns.forEach(function(v, i){
				v && remove(el, t, s, i);
			})

			s.fns.length = s.vals.length = 0;
			delete storage[t];
		}
	}
};

function removeDOMEventByType(el, type, storage, index){
	removeEvent(el, type, storage.vals[index]);
	delete storage.fns[index];
	delete storage.vals[index];
};

/**
 * @constructor
 */
function DOMEvent(event, win){
	if(event instanceof DOMEvent){
		return event;
	}

	win = win || K.__HOST;
	event = event || win.event;

	var self 	= this,
		type 	= self.type = event.type,
		target 	= self.type = event.target || event.srcElement,
		page 	= self.page = {},
		client 	= self.client = {},
		NULL	= null,
		related,
		doc,
		touch;

	self.event = event;
	K.mix(self, event, true, ['shiftKey', 'ctrlKey', 'altKey', 'metaKey']);

	while (target && target.nodeType == 3){
		target = target.parentNode;
	}

	if (type.indexOf('key') !== -1){
		// TODO:
		// test function keys, on macosx and win
		self.code = event.which || event.keyCode;

	} else if (type === 'click' || type === 'dblclick' || type === 'contextmenu' || !type.indexOf('mouse') ){
		doc = getCompactElement(win.document);

		page.x = event.pageX != NULL ? event.pageX : event.clientX + doc.scrollLeft;
		page.y = event.pageY != NULL ? event.pageY : event.clientY + doc.scrollTop;

		client.x = event.pageX != NULL ? event.pageX - win.pageXOffset : event.clientX;
		client.y = event.pageY != NULL ? event.pageY - win.pageYOffset : event.clientY;

		if (type === 'DOMMouseScroll' || type === 'mousewheel'){
			self.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : - (event.detail || 0) / 3;
		}

		self.rightClick = (event.which == 3) || (event.button == 2);

		if (type == 'mouseover' || type == 'mouseout'){
			related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];

			while (related && related.nodeType == 3){
				related = related.parentNode;
			}

			self.relatedTarget = related;
		}

	} else if ((/^(?:gesture|touch)/i).test(type)){
		K.mix(self, event, true, ['rotation', 'scale', 'targetTouches', 'changedTouches', 'touches']);

		touch = self.touches && self.touches[0];

		if (touch){
			page.x = touch.pageX;
			page.y = touch.pageY;
			client.x = touch.clientX;
			client.y = touch.clientY;
		}
	}
};

DOMEvent.prototype = {
	stop: function(){
		return this.stopBubble().prevent();
	},

	stopBubble: function(){
		var e = this.event, m = 'stopPropagation';
		e && ( e[m] ? e[m]() : (e.cancelBubble = true) );

		return this;
	},

	prevent: function(){
		var e = this.event, m = 'preventDefault';
		e && ( e[m] ? e[m]() : (e.returnValue = false) );

		return this;
	}
};

var DOM = K.DOM,
	SELECTOR = DOM.SELECTOR,
	storage = DOM.__storage,
	feature = DOM.feature,

	event_storage = (storage.events = {}),

	getCompactElement = feature.compactEl,
	addEvent = feature.addEvent,
	removeEvent = feature.removeEvent,

	TRUE = true,

	Events = {
		mouseenter: {
			base: 'mouseover',
			condition: checkRelatedTarget
		},

		mouseleave: {
			base: 'mouseout',
			condition: checkRelatedTarget
		},

		mousewheel: {
			base: K.UA.mozilla ? 'DOMMouseScroll' : 'mousewheel'
		}
	},

	NO_EVENTS = {
		unload: TRUE,
		beforeunload: TRUE,
		resize: TRUE,
		move: TRUE,
		DOMContentLoaded: TRUE,
		readystatechange: TRUE,
		error: TRUE,
		abort: TRUE,
		scroll: TRUE
	};

// cleaner
event_storage._clean = function(id){
	var storage = event_storage[id];

	if(storage){
		K.each(storage, function(v, key){
			v.fns.length = v.vals.length = 0;
			delete this[key];
		});
	}
};

DOM.extend({

	/**
	 * inspired by: Dean Edwards's addEvent lib
	 * bind an event
	 * @param {string} type
	 * @param {function()} fn
	 * @param {useOrigin}
	 */
	on: K._overloadSetter(function(type, fn){
		var el = this,
			storage = getStorage(el),
			fns;

		if(!storage[type]){
			storage[type] = {

				// store the original fn use passed in
				fns: [],

				// store the wrapped function
				vals: []
			};
		}

		fns = storage[type].fns;

		if(fns.indexOf(fn) !== -1){
			return;
		}
		fns.push(fn);

		var real_type = type,
			custom = Events[type],
			condition = fn,
			eventFn;

		if(custom){
			if(custom.condition){
				condition = function(event){
					return custom.condition.call(this, event) ? fn.call(this, event) : true;
				};
			}

			real_type = custom.base || real_type;
		}

		console.log('real_type', real_type, 'element', $(el).attr('data-depth'));

		eventFn = NO_EVENTS[real_type] ?
			function(){
				return fn.call(el);
			} :

			function(event){ console.log('event trying to fire')
				event = new DOMEvent(event, getWindow(el)); // TODO: getWindow
				if (condition.call(el, event) === false){
					event.stop();
				}
			};

		storage[type].vals.push(eventFn);
		addEvent(el, real_type, eventFn);
	}),

	/**
	 * .detach()								-> remove all
	 * .detach('click')							-> remove all click
	 * .detach('click', fn)						-> remove click method fn
	 * .detach({ click: fn, mouseenter: fn2 })	-> remove several events
	 */
	detach: K._overloadSetter(removeDOMEvent),

	/**
	 * fire an event
	 */
	fire: function(type){
		var el = this,
			storage = getStorage(el);

		if(storage[type]){
			storage[type].vals.forEach(function(fn){
				fn();
			});
		}
	}

}, 'iterator');

DOM.Event = DOMEvent;
DOM.Events = Events;

})(KM);

/**
 change log:

 2011-10-11  Kael:
 - improve stability when there's no event object
 - fix a bug about no-event object events
 - add method .fire()

 2011-10-06  Kael:
 TODO:
 - A. refractor event module

 2011-09-10  Kael:
 - basic functionalities

 TODO:
 A. fix onchange event of input elements

 */<commit_msg>dom/event: remove debug lines<commit_after>/**
 * module  DOM/event
 */

;(function(K){

function getWindow(element){
	// window
	return 'setInterval' in element ? element

		// document
		: 'getElementById' in element ? element.window
			: element.ownerDocument.window;
};

function getStorage(el){
	var id = SELECTOR.uid(el);

	return event_storage[id] || (event_storage[id] = {});
};

// from jQuery
function checkRelatedTarget(event){
	var related = event.relatedTarget,
		el = this;

	// Firefox sometimes assigns relatedTarget a XUL element
	// which we cannot access the parentNode property of
	try{
		// Chrome does something similar, the parentNode property
		// can be accessed but is null.
		if ( related && related !== document && !related.parentNode ) {
			return;
		}

		// Traverse up the tree
		while ( related && related !== el ) {
			related = related.parentNode;
		}

		if ( related !== el ) {
			// handle event if we actually just moused on to a non sub-element
			return true;
		}

	}catch(e){}

	return;
};

function removeDOMEvent(type, fn){
	var el = this,
		storage = getStorage(el),
		remove = removeDOMEventByType,
		s;

	if(!storage){
		return;
	}

	if(fn){
		var index;

		s = storage[type];
		index = s ? s.fns.indexOf(fn) : -1;
		index !== -1 && remove(el, type, s, index);

	}else{
		var types = type ?
				  storage[type] ? [type] : []
				: Object.keys(storage),

			len = types.length,
			t;

		while(len --){
			t = types[len]; 	// type
			s = storage[t];		// storage

			s.fns.forEach(function(v, i){
				v && remove(el, t, s, i);
			})

			s.fns.length = s.vals.length = 0;
			delete storage[t];
		}
	}
};

function removeDOMEventByType(el, type, storage, index){
	removeEvent(el, type, storage.vals[index]);
	delete storage.fns[index];
	delete storage.vals[index];
};

/**
 * @constructor
 */
function DOMEvent(event, win){
	if(event instanceof DOMEvent){
		return event;
	}

	win = win || K.__HOST;
	event = event || win.event;

	var self 	= this,
		type 	= self.type = event.type,
		target 	= self.type = event.target || event.srcElement,
		page 	= self.page = {},
		client 	= self.client = {},
		NULL	= null,
		related,
		doc,
		touch;

	self.event = event;
	K.mix(self, event, true, ['shiftKey', 'ctrlKey', 'altKey', 'metaKey']);

	while (target && target.nodeType == 3){
		target = target.parentNode;
	}

	if (type.indexOf('key') !== -1){
		// TODO:
		// test function keys, on macosx and win
		self.code = event.which || event.keyCode;

	} else if (type === 'click' || type === 'dblclick' || type === 'contextmenu' || !type.indexOf('mouse') ){
		doc = getCompactElement(win.document);

		page.x = event.pageX != NULL ? event.pageX : event.clientX + doc.scrollLeft;
		page.y = event.pageY != NULL ? event.pageY : event.clientY + doc.scrollTop;

		client.x = event.pageX != NULL ? event.pageX - win.pageXOffset : event.clientX;
		client.y = event.pageY != NULL ? event.pageY - win.pageYOffset : event.clientY;

		if (type === 'DOMMouseScroll' || type === 'mousewheel'){
			self.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : - (event.detail || 0) / 3;
		}

		self.rightClick = (event.which == 3) || (event.button == 2);

		if (type == 'mouseover' || type == 'mouseout'){
			related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];

			while (related && related.nodeType == 3){
				related = related.parentNode;
			}

			self.relatedTarget = related;
		}

	} else if ((/^(?:gesture|touch)/i).test(type)){
		K.mix(self, event, true, ['rotation', 'scale', 'targetTouches', 'changedTouches', 'touches']);

		touch = self.touches && self.touches[0];

		if (touch){
			page.x = touch.pageX;
			page.y = touch.pageY;
			client.x = touch.clientX;
			client.y = touch.clientY;
		}
	}
};

DOMEvent.prototype = {
	stop: function(){
		return this.stopBubble().prevent();
	},

	stopBubble: function(){
		var e = this.event, m = 'stopPropagation';
		e && ( e[m] ? e[m]() : (e.cancelBubble = true) );

		return this;
	},

	prevent: function(){
		var e = this.event, m = 'preventDefault';
		e && ( e[m] ? e[m]() : (e.returnValue = false) );

		return this;
	}
};

var DOM = K.DOM,
	SELECTOR = DOM.SELECTOR,
	storage = DOM.__storage,
	feature = DOM.feature,

	event_storage = (storage.events = {}),

	getCompactElement = feature.compactEl,
	addEvent = feature.addEvent,
	removeEvent = feature.removeEvent,

	TRUE = true,

	Events = {
		mouseenter: {
			base: 'mouseover',
			condition: checkRelatedTarget
		},

		mouseleave: {
			base: 'mouseout',
			condition: checkRelatedTarget
		},

		mousewheel: {
			base: K.UA.mozilla ? 'DOMMouseScroll' : 'mousewheel'
		}
	},

	NO_EVENTS = {
		unload: TRUE,
		beforeunload: TRUE,
		resize: TRUE,
		move: TRUE,
		DOMContentLoaded: TRUE,
		readystatechange: TRUE,
		error: TRUE,
		abort: TRUE,
		scroll: TRUE
	};

// cleaner
event_storage._clean = function(id){
	var storage = event_storage[id];

	if(storage){
		K.each(storage, function(v, key){
			v.fns.length = v.vals.length = 0;
			delete this[key];
		});
	}
};

DOM.extend({

	/**
	 * inspired by: Dean Edwards's addEvent lib
	 * bind an event
	 * @param {string} type
	 * @param {function()} fn
	 * @param {useOrigin}
	 */
	on: K._overloadSetter(function(type, fn){
		var el = this,
			storage = getStorage(el),
			fns;

		if(!storage[type]){
			storage[type] = {

				// store the original fn use passed in
				fns: [],

				// store the wrapped function
				vals: []
			};
		}

		fns = storage[type].fns;

		if(fns.indexOf(fn) !== -1){
			return;
		}
		fns.push(fn);

		var real_type = type,
			custom = Events[type],
			condition = fn,
			eventFn;

		if(custom){
			if(custom.condition){
				condition = function(event){
					return custom.condition.call(this, event) ? fn.call(this, event) : true;
				};
			}

			real_type = custom.base || real_type;
		}

		eventFn = NO_EVENTS[real_type] ?
			function(){
				return fn.call(el);
			} :

			function(event){
				event = new DOMEvent(event, getWindow(el)); // TODO: getWindow
				if (condition.call(el, event) === false){
					event.stop();
				}
			};

		storage[type].vals.push(eventFn);
		addEvent(el, real_type, eventFn);
	}),

	/**
	 * .detach()								-> remove all
	 * .detach('click')							-> remove all click
	 * .detach('click', fn)						-> remove click method fn
	 * .detach({ click: fn, mouseenter: fn2 })	-> remove several events
	 */
	detach: K._overloadSetter(removeDOMEvent),

	/**
	 * fire an event
	 */
	fire: function(type){
		var el = this,
			storage = getStorage(el);

		if(storage[type]){
			storage[type].vals.forEach(function(fn){
				fn();
			});
		}
	}

}, 'iterator');

DOM.Event = DOMEvent;
DOM.Events = Events;

})(KM);

/**
 change log:

 2011-10-11  Kael:
 - improve stability when there's no event object
 - fix a bug about no-event object events
 - add method .fire()

 2011-10-06  Kael:
 TODO:
 - A. refractor event module

 2011-09-10  Kael:
 - basic functionalities

 TODO:
 A. fix onchange event of input elements

 */<|endoftext|>


<commit_before>/**
 * Module Dependencies
 */

var Class = require('sand').Class;
var EventEmitter = require('events').EventEmitter;
var only = require('only');
var _ = require('lodash');
var fs = require('fs');

try {
  //console.log('logger: ', module.require.resolve('sand'));
  var Logger = require('sand').Logger;
} catch (e) {
  // Since Sand isn't loaded, lets load the fake logger
  Logger = require('./FakeLogger');
}

/**
 * Initialize a new `SandGrain`.
 *
 * @api public
 */
exports = module.exports = Class.extend(EventEmitter, {

  isSandGrain: true, // artificial duck typing to satisfy Sand.js

  construct: function() {
    this.name = this.name || 'SandGrain';
    this.env = !_.isUndefined(global.sand) ? global.sand.env : (process.env.NODE_ENV || 'development');
    this.configName = this.name;
    this.config = this.config || {};
    this.defaultConfig = this.defaultConfig || {};
    this.log = (new Logger(this.name)).log;

    try {
      this.version = this.version || require('../package').version;
    } catch(e) {
      this.version = 'unknown';
    }
  },

  inspect: toJSON,

  init: function(config, done) {
    var passedInConfig;
    if (typeof config === 'object') {
      passedInConfig = config;
    } else if (typeof config === 'string') {
      // Must be a path
      passedInConfig = require(config);
    }

    if (passedInConfig) {
      if (!this.validateConfig(passedInConfig)) {
        this.log('Missing env ' +  this.env  + ' or all on the config object');
        process.exit(1);
      }

      this.config = this.getConfig(passedInConfig);
    }

    if (_.isFunction(done)) {
      done();
    }

    return this;
  },

  shutdown: function(done) {
    if (_.isFunction(done)) {
      done();
    }
  },

  validateConfig: function(config) {
    // Default we check that it has environment or all
    return _.isPlainObject(config[this.env]) || _.isPlainObject(config['all']);
  },

  getConfig: function(config) {
    var env = config[this.env] || {};
    var all = config['all'] || {};

    return _.defaults(env, all, this.defaultConfig);
  }
});

function toJSON() {
  "use strict";
  return only(this, [
    'name',
    'version'
  ]);
}<commit_msg>added deep merge support<commit_after>/**
 * Module Dependencies
 */

var Class = require('sand').Class;
var EventEmitter = require('events').EventEmitter;
var only = require('only');
var _ = require('lodash');
var fs = require('fs');

try {
  //console.log('logger: ', module.require.resolve('sand'));
  var Logger = require('sand').Logger;
} catch (e) {
  // Since Sand isn't loaded, lets load the fake logger
  Logger = require('./FakeLogger');
}

/**
 * Initialize a new `SandGrain`.
 *
 * @api public
 */
exports = module.exports = Class.extend(EventEmitter, {

  isSandGrain: true, // artificial duck typing to satisfy Sand.js

  construct: function() {
    this.name = this.name || 'SandGrain';
    this.env = !_.isUndefined(global.sand) ? global.sand.env : (process.env.NODE_ENV || 'development');
    this.configName = this.name;
    this.config = this.config || {};
    this.defaultConfig = this.defaultConfig || {};
    this.log = (new Logger(this.name)).log;

    try {
      this.version = this.version || require('../package').version;
    } catch(e) {
      this.version = 'unknown';
    }
  },

  inspect: toJSON,

  init: function(config, done) {
    var passedInConfig;
    if (typeof config === 'object') {
      passedInConfig = config;
    } else if (typeof config === 'string') {
      // Must be a path
      passedInConfig = require(config);
    }

    if (passedInConfig) {
      if (!this.validateConfig(passedInConfig)) {
        this.log('Missing env ' +  this.env  + ' or all on the config object');
        process.exit(1);
      }

      this.config = this.getConfig(passedInConfig);
    }

    if (_.isFunction(done)) {
      done();
    }

    return this;
  },

  shutdown: function(done) {
    if (_.isFunction(done)) {
      done();
    }
  },

  validateConfig: function(config) {
    // Default we check that it has environment or all
    return _.isPlainObject(config[this.env]) || _.isPlainObject(config['all']);
  },

  getConfig: function(config) {
    var env = config[this.env] || {};
    var all = config['all'] || {};

    return _.merge({}, this.defaultConfig, all, env);
  }
});

function toJSON() {
  "use strict";
  return only(this, [
    'name',
    'version'
  ]);
}<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright ( c ) 2015 Teem2 LLC

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.
*/
(function(global) {
  // Utility Functions
  var loadScript = function(src) {
      // Use document.write rather than dom insertion since we actually do
      // want to prevent the body from rendering until all scripts are
      // loaded since dreem rewrites the dom so things will look ugly in
      // the page until dreem executes.
      document.write('<script src="' + src + '"></'+'script>');
    },
    writeCSS = function(rules) {
      var s = document.createElement('style');
      s.type = 'text/css';

      var i = rules.length, rule;
      while (i) {
        rule = rules[--i];
        if (rule.length > 1) {
          rule[i] = rule.shift() + '{' + rule.join(';') + '}';
        } else {
          rule[i] = '';
        }
      }

      s.innerHTML = rules.join('');
      document.getElementsByTagName('head')[0].appendChild(s);
    },
    extend = function(targetObj, sourceObj) {
      var iterable = targetObj,
        result = iterable,
        args = arguments, argsLength = args.length, argsIndex = 0,
        key, ownIndex, ownKeys, length;
      if (iterable) {
        while (++argsIndex < argsLength) {
          iterable = args[argsIndex];
          if (iterable) {
            ownIndex = -1;
            ownKeys = Object.keys(iterable);
            length = ownKeys ? ownKeys.length : 0;
            while (++ownIndex < length) {
              key = ownKeys[ownIndex];
              result[key] = iterable[key];
            }
          }
        }
      }
      return result
    };

  // Defaults
  var opts = {
    baseUrl:'../',
    type:'example'
  };
  extend(opts, global.BOILERPLATE_OPTS || {});
  var isSmoke = opts.type === 'smoke';

  DREEM_ROOT = opts.baseUrl;
  if (document.currentScript) {
    var script_src = document.currentScript.src;
    if (script_src) {
      var found = script_src.match(/^(.*)boilerplate.js.*/);
      if (found.length > 1) {
        DREEM_ROOT = found[1];
      }
    }
  }

  DREEM_SERVER_AVAILABLE = false;
  DREEM_VERSION = "1.0";
  var request = new XMLHttpRequest();
  request.open('GET', DREEM_ROOT + 'version', false);
  request.onreadystatechange = function(){
    if (request.readyState === 4){
      if (request.status === 200) {
        DREEM_VERSION = request.responseText;
        //xxx check version against expected version
        DREEM_SERVER_AVAILABLE = true;
      }
    }
  };
  request.send();

  // Parse Query
  var query = (function(pairs) {
      var params = {};
      if (Array.isArray(pairs)) {
        var i = pairs.length, param;
        while (i) {
          param = pairs[--i].split('=', 2);
          params[param[0]] = (param.length === 1) ? "" : decodeURIComponent(param[1].replace(/\+/g, " "));
        }
      }
      return params;
    })(window.location.search.substr(1).split('&')),
    debug = query.debug,
    runtime = query.runtime,
    minify = query.minify;

  // Config
  var layoutQuery = [];
  //if (debug === 'true') layoutQuery.push('debug=true'); // FIXME: uncomment this when the assembler supports conditional debug code.
  if (runtime) layoutQuery.push('runtime=' + runtime);
  layoutQuery = (layoutQuery.length > 0) ? '?' + layoutQuery.join('&') : '';

  var layoutScript = '/layout' + (minify === 'true' ? '.min' : '') + '.js' + layoutQuery;
  if (!DREEM_SERVER_AVAILABLE) {
    console.log('Dreem server unavailable, defaulting to cache');
    layoutScript = '/dist' + layoutScript;
  }
  layoutScript = 'core' + layoutScript;

  var scriptsToLoad = [
      'lib/jquery-1.9.1.js',
      'lib/acorn.js',
      'lib/coffee-script.js',
      layoutScript,
      isSmoke ? 'lib/chai.js' : '',
      isSmoke ? 'lib/smoke_helper.js' : '',
    ],
    cssRules = [
      ['html,body',
        'height:100%',
        'margin:0px',
        'padding:0px',
        'border:0px none'
      ],
      ['body',
        'font-family:Arial, Helvetica, sans-serif',
        'font-size:14px'
      ]
    ];

  // Execution
  writeCSS(cssRules);
  var i = 0, len = scriptsToLoad.length, scriptUrl;
  for (; len > i;) {
    scriptUrl = scriptsToLoad[i++];
    if (scriptUrl) loadScript(DREEM_ROOT + scriptUrl);
  }
})(this);<commit_msg>check server version before defaulting to cached js<commit_after>/*
The MIT License (MIT)

Copyright ( c ) 2015 Teem2 LLC

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.
*/
(function(global) {
  // Utility Functions
  var loadScript = function(src) {
      // Use document.write rather than dom insertion since we actually do
      // want to prevent the body from rendering until all scripts are
      // loaded since dreem rewrites the dom so things will look ugly in
      // the page until dreem executes.
      document.write('<script src="' + src + '"></'+'script>');
    },
    writeCSS = function(rules) {
      var s = document.createElement('style');
      s.type = 'text/css';

      var i = rules.length, rule;
      while (i) {
        rule = rules[--i];
        if (rule.length > 1) {
          rule[i] = rule.shift() + '{' + rule.join(';') + '}';
        } else {
          rule[i] = '';
        }
      }

      s.innerHTML = rules.join('');
      document.getElementsByTagName('head')[0].appendChild(s);
    },
    extend = function(targetObj, sourceObj) {
      var iterable = targetObj,
        result = iterable,
        args = arguments, argsLength = args.length, argsIndex = 0,
        key, ownIndex, ownKeys, length;
      if (iterable) {
        while (++argsIndex < argsLength) {
          iterable = args[argsIndex];
          if (iterable) {
            ownIndex = -1;
            ownKeys = Object.keys(iterable);
            length = ownKeys ? ownKeys.length : 0;
            while (++ownIndex < length) {
              key = ownKeys[ownIndex];
              result[key] = iterable[key];
            }
          }
        }
      }
      return result
    };

  // Defaults
  var opts = {
    baseUrl:'../',
    type:'example'
  };
  extend(opts, global.BOILERPLATE_OPTS || {});
  var isSmoke = opts.type === 'smoke';

  DREEM_ROOT = opts.baseUrl;
  if (document.currentScript) {
    var script_src = document.currentScript.src;
    if (script_src) {
      var found = script_src.match(/^(.*)boilerplate.js.*/);
      if (found.length > 1) {
        DREEM_ROOT = found[1];
      }
    }
  }

  DREEM_SERVER_AVAILABLE = false;
  var compatibleServerVersions = ["1.0.0"];
  var request = new XMLHttpRequest();
  request.open('GET', DREEM_ROOT + 'version', false);
  request.onreadystatechange = function() {
    if (request.readyState === 4){
      if (request.status === 200) {
        var info = JSON.parse(request.responseText);
        DREEM_SERVER_AVAILABLE = ~compatibleServerVersions.indexOf(info.version);
      }
    }
  };
  request.send();

  // Parse Query
  var query = (function(pairs) {
      var params = {};
      if (Array.isArray(pairs)) {
        var i = pairs.length, param;
        while (i) {
          param = pairs[--i].split('=', 2);
          params[param[0]] = (param.length === 1) ? "" : decodeURIComponent(param[1].replace(/\+/g, " "));
        }
      }
      return params;
    })(window.location.search.substr(1).split('&')),
    debug = query.debug,
    runtime = query.runtime,
    minify = query.minify;

  // Config
  var layoutQuery = [];
  //if (debug === 'true') layoutQuery.push('debug=true'); // FIXME: uncomment this when the assembler supports conditional debug code.
  if (runtime) layoutQuery.push('runtime=' + runtime);
  layoutQuery = (layoutQuery.length > 0) ? '?' + layoutQuery.join('&') : '';

  var layoutScript = '/layout' + (minify === 'true' ? '.min' : '') + '.js' + layoutQuery;
  if (!DREEM_SERVER_AVAILABLE) {
    console.log('Compatible Dreem server unavailable, defaulting to cached javascript');
    layoutScript = '/dist' + layoutScript;
  }
  layoutScript = 'core' + layoutScript;

  var scriptsToLoad = [
      'lib/jquery-1.9.1.js',
      'lib/acorn.js',
      'lib/coffee-script.js',
      layoutScript,
      isSmoke ? 'lib/chai.js' : '',
      isSmoke ? 'lib/smoke_helper.js' : '',
    ],
    cssRules = [
      ['html,body',
        'height:100%',
        'margin:0px',
        'padding:0px',
        'border:0px none'
      ],
      ['body',
        'font-family:Arial, Helvetica, sans-serif',
        'font-size:14px'
      ]
    ];

  // Execution
  writeCSS(cssRules);
  var i = 0, len = scriptsToLoad.length, scriptUrl;
  for (; len > i;) {
    scriptUrl = scriptsToLoad[i++];
    if (scriptUrl) loadScript(DREEM_ROOT + scriptUrl);
  }
})(this);<|endoftext|>


<commit_before>const now = require("performance-now");
const isBoolean = require('lodash.isboolean');
const isEmpty = require('lodash.isempty');
const uuid = require('uuid/v4');
const format = require('string-template');

const STATES = {
    INIT: 'init',
    RUNNING: 'running',
    STOPPED: 'stopped',
    SPLIT: 'split'
};

function Stopwatch(name, autostart) {
    const self = this;

    if (isBoolean(name)) {
        autostart = name;
        name = null;
    }

    if (isEmpty(name)) {
        name = uuid();
    }

    self._name = name;

    self.reset();

    if (autostart) this.start();
}

Stopwatch.prototype.STATES = STATES;

Stopwatch.prototype.name = function () {
    const self = this;
    return self._name;
};

Stopwatch.prototype.start = function () {
    const self = this;

    if (self.state() !== STATES.STOPPED && self.state() !== STATES.INIT) {
        throw new Error('Cannot start a stopwatch that is currently running (' + self.state() + ')');
    }

    self._state = STATES.RUNNING;
    self.startTime = now();
};

Stopwatch.prototype.stop = function () {
    const self = this;
    self.stopTime = now();
    self._state = STATES.STOPPED;
    return this.read();
};

Stopwatch.prototype.split = function () {
    const self = this;

    if (self.state() !== STATES.RUNNING) {
        throw new Error('Cannot split time on a stopwatch that is not currently running');
    }

    self.stopTime = now();
    self._state = STATES.SPLIT;
    return this.read();
};

Stopwatch.prototype.unsplit = function () {
    const self = this;

    if (self.state() !== STATES.SPLIT) {
        throw new Error('Cannot unsplit time on a stopwatch that is not currently split');
    }

    self.stopTime = null;
    self._state = STATES.RUNNING;
    return this.read();
};

Stopwatch.prototype.state = function () {
    return this._state;
};

Stopwatch.prototype.reset = function () {
    const self = this;
    self._state = STATES.INIT;
    self.startTime = null;
    self.stopTime = null;
};

Stopwatch.prototype.splitTime = function () {
    const self = this;

    if (self.state() !== STATES.SPLIT) {
        throw new Error('Cannot get split time on a stopwatch that is not currently split');
    }

    const startTime = self.startTime;
    const stopTime = self.stopTime;
    const delta = calculateDelta(startTime, stopTime);
    return delta;

    function calculateDelta(start, end) {
        return end - start;
    }
};

Stopwatch.prototype.read = Stopwatch.prototype.time = function () {
    function calculateDelta(start, end) {
        return end - start;
    }

    const self = this;
    const startTime = self.startTime;
    let nowTime = undefined;
    let delta = undefined;

    if (startTime) {
        if (self.stopTime) {
            nowTime = self.stopTime;
        } else {
            nowTime = now();
        }

        delta = calculateDelta(startTime, nowTime);
    } else {
        nowTime = undefined;
        delta = NaN;
    }

    return delta;
};

Stopwatch.prototype.toString = function () {
    const self = this;
    const template = '[{name} => state:{state}; value:{value}]';
    return format(template, {name: self.name(), state: self.state(), value: self.read().toFixed(2)});
};

module.exports = Stopwatch;<commit_msg>resolving code review issue with var/let<commit_after>const now = require("performance-now");
const isBoolean = require('lodash.isboolean');
const isEmpty = require('lodash.isempty');
const uuid = require('uuid/v4');
const format = require('string-template');

const STATES = {
    INIT: 'init',
    RUNNING: 'running',
    STOPPED: 'stopped',
    SPLIT: 'split'
};

function Stopwatch(name, autostart) {
    const self = this;

    if (isBoolean(name)) {
        autostart = name;
        name = null;
    }

    if (isEmpty(name)) {
        name = uuid();
    }

    self._name = name;

    self.reset();

    if (autostart) this.start();
}

Stopwatch.prototype.STATES = STATES;

Stopwatch.prototype.name = function () {
    const self = this;
    return self._name;
};

Stopwatch.prototype.start = function () {
    const self = this;

    if (self.state() !== STATES.STOPPED && self.state() !== STATES.INIT) {
        throw new Error('Cannot start a stopwatch that is currently running (' + self.state() + ')');
    }

    self._state = STATES.RUNNING;
    self.startTime = now();
};

Stopwatch.prototype.stop = function () {
    const self = this;
    self.stopTime = now();
    self._state = STATES.STOPPED;
    return this.read();
};

Stopwatch.prototype.split = function () {
    const self = this;

    if (self.state() !== STATES.RUNNING) {
        throw new Error('Cannot split time on a stopwatch that is not currently running');
    }

    self.stopTime = now();
    self._state = STATES.SPLIT;
    return this.read();
};

Stopwatch.prototype.unsplit = function () {
    const self = this;

    if (self.state() !== STATES.SPLIT) {
        throw new Error('Cannot unsplit time on a stopwatch that is not currently split');
    }

    self.stopTime = null;
    self._state = STATES.RUNNING;
    return this.read();
};

Stopwatch.prototype.state = function () {
    return this._state;
};

Stopwatch.prototype.reset = function () {
    const self = this;
    self._state = STATES.INIT;
    self.startTime = null;
    self.stopTime = null;
};

Stopwatch.prototype.splitTime = function () {
    const self = this;

    if (self.state() !== STATES.SPLIT) {
        throw new Error('Cannot get split time on a stopwatch that is not currently split');
    }

    const startTime = self.startTime;
    const stopTime = self.stopTime;
    const delta = calculateDelta(startTime, stopTime);
    return delta;

    function calculateDelta(start, end) {
        return end - start;
    }
};

Stopwatch.prototype.read = Stopwatch.prototype.time = function () {
    function calculateDelta(start, end) {
        return end - start;
    }

    const self = this;
    const startTime = self.startTime;
    var nowTime ;
    var  delta ;

    if (startTime) {
        if (self.stopTime) {
            nowTime = self.stopTime;
        } else {
            nowTime = now();
        }

        delta = calculateDelta(startTime, nowTime);
    } else {
        nowTime = undefined;
        delta = NaN;
    }

    return delta;
};

Stopwatch.prototype.toString = function () {
    const self = this;
    const template = '[{name} => state:{state}; value:{value}]';
    return format(template, {name: self.name(), state: self.state(), value: self.read().toFixed(2)});
};

module.exports = Stopwatch;<|endoftext|>


<commit_before>javascript:
/**
 * TAMES Case Number Search Bookmarklet
 * (c) 2014 Ed Cottrell
 *
 * Licensed under the MIT License
 *
 * 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.
 */

var url = 'http://www.search.txcourts.gov/CaseSearch.aspx?coa=cossup', /* Initialize the URL to use if we can't do a search */
	gs = window.getSelection(); /* Get the user's selection */

/* See if the user has actually selected anything */ if(gs.type != "None") {
	var caseNoContainer = gs.getRangeAt(0), /* Get the selected range */
		sc = caseNoContainer.startContainer; /* Get the data container for the user's selection */
	if(typeof(sc.data) != 'undefined') {
		/* Get the raw selection */
		var caseNo = sc.data.substr(caseNoContainer.startOffset, caseNoContainer.endOffset - caseNoContainer.startOffset);

		/* Replace en-dashes with hyphens and strip any leading or trailing characters */
		caseNo = caseNo.replace(/\u2013/g, '-').replace(/^[^\d]+|[^CRV\d]+$/g, '');

		/* If the case is a -CR or -CV case, make sure the numeric parts are appropriately padded with leading zeroes */
		if(caseNo.match(/C[RV]$/)) {
			caseNoParts = caseNo.split('-');
			caseNoParts[0] = ("00"+caseNoParts[0]).slice(-2);
			caseNoParts[1] = ("00"+caseNoParts[1]).slice(-2);
			caseNoParts[2] = ("00000"+caseNoParts[2]).slice(-5);
			caseNo = caseNoParts.join('-');
		}

		/* If the case number is non-empty, get the URL for the search page. */
		if(caseNo != '') {
			var url = 'http://www.search.txcourts.gov/Case.aspx?cn='+caseNo;
		}
	}
}
/* Open the search window */
window.open(url);
<commit_msg>Update bookmarklet.js<commit_after>javascript:
/**
 * TAMES Case Number Search Bookmarklet
 * (c) 2014 Ed Cottrell
 *
 * Licensed under the MIT License
 *
 * 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.
 */

var url = 'http://www.search.txcourts.gov/CaseSearch.aspx?coa=cossup', /* Initialize the URL to use if we can't do a search */
	gs = window.getSelection(); /* Get the user's selection */

/* See if the user has actually selected anything */
if(gs.type != "None") {
	var caseNoContainer = gs.getRangeAt(0), /* Get the selected range */
		sc = caseNoContainer.startContainer; /* Get the data container for the user's selection */
	if(typeof(sc.data) != 'undefined') {
		/* Get the raw selection */
		var caseNo = sc.data.substr(caseNoContainer.startOffset, caseNoContainer.endOffset - caseNoContainer.startOffset);

		/* Replace en-dashes with hyphens and strip any leading or trailing characters */
		caseNo = caseNo.replace(/\u2013/g, '-').replace(/^[^\d]+|[^CRV\d]+$/g, '');

		/* If the case is a -CR or -CV case, make sure the numeric parts are appropriately padded with leading zeroes */
		if(caseNo.match(/C[RV]$/)) {
			caseNoParts = caseNo.split('-');
			caseNoParts[0] = ("00"+caseNoParts[0]).slice(-2);
			caseNoParts[1] = ("00"+caseNoParts[1]).slice(-2);
			caseNoParts[2] = ("00000"+caseNoParts[2]).slice(-5);
			caseNo = caseNoParts.join('-');
		}

		/* If the case number is non-empty, get the URL for the search page. */
		if(caseNo != '') {
			var url = 'http://www.search.txcourts.gov/Case.aspx?cn='+caseNo;
		}
	}
}
/* Open the search window */
window.open(url);
<|endoftext|>


<commit_before>'use strict';

var verb = require('..');
verb.data('package.json');

verb.task('default', function() {
  verb.src('.verb*.md')
    .pipe(verb.dest('./'));
});
<commit_msg>add comments to default verbfile<commit_after>'use strict';

var verb = require('..');

/**
 * This is the default verbfile used if one isn't found
 * in the root of a project.
 */

verb.task('default', function() {
  verb.src('.verb*.md')
    .pipe(verb.dest('./'));
});
<|endoftext|>


<commit_before>//
//  Author: Vlad Seryakov vseryakov@gmail.com
//  backendjs 2018
//

const path = require('path');
const util = require('util');
const fs = require('fs');
const core = require(__dirname + '/core');
const lib = require(__dirname + '/lib');
const api = require(__dirname + '/api');
const logger = require(__dirname + '/logger');
const mime = require("mime");

// Returns absolute file url if it is configured with any prefix or S3 bucket, otherwise returns empty string
api.fileUrl = function(file, options)
{
    if (file) {
        options = options || lib.empty;
        var s3url = options.filesS3 || this.filesS3;
        var s3opts = options.filesS3Options || this.filesS3Options;
        if (s3url && s3opts) {
            s3opts.url = true;
            file = core.modules.aws.signS3("GET", s3url, path.normalize(file), "", s3opts);
        } else {
            var filesUrl = options.filesUrl || this.filesUrl;
            var filesRaw = options.filesRaw || this.filesRaw;
            if (filesUrl && filesRaw) {
                file = filesUrl + path.normalize(file);
            }
        }
    }
    return file || "";
}

// Send a file to the client
api.getFile = function(req, file, options)
{
    if (!options) options = lib.empty;
    logger.debug('sendFile:', file, options);

    if (options.filesS3 || this.filesS3) {
        core.modules.aws.s3Proxy(req.res, options.filesS3 || this.filesS3, path.normalize(file), options);
    } else {
        this.sendFile(req, path.join(options.filesPath || core.path.files, path.normalize(file)));
    }
}

// Returns contents of a file, all specific parameters are passed as is, the contents of the file is returned to the callback,
// see `lib.readFile` or `aws.s3GetFile` for specific options.
api.readFile = function(file, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = lib.empty;
    logger.debug('readFile:', file, options);

    if (options.filesS3 || this.filesS3) {
        file = path.join(options.filesS3 || this.filesS3, path.normalize(file));
        core.modules.aws.s3GetFile(file, options, (err, params) => {
            if (params.status == 200) {
                if (options.json) params.data = lib.jsonParse(params.data, options); else
                if (options.xml) params.data = lib.xmlParse(params.data, options); else
                if (options.list) params.data = lib.strSplit(params.data, options.list);
            }
            lib.tryCall(callback, err, params.data);
        });
    } else {
        file = path.join(options.filesPath || core.path.files, path.normalize(file));
        lib.readFile(file, options, callback);
    }
}

// Upload file and store in the filesystem or S3, try to find the file in multipart form, in the body or query by the given name
// - name is the name property to look for in the multipart body or in the request body or query
// - callback will be called with err and actual filename saved
//
// Output file name is built according to the following options properties:
// - name - defines the output name for the file, if not given same name as property will be used
// - prefix - the folder prefix where the file will be uploaded, all leading folders will be created automatically
// - ext - what file extention to use, appended to the name, if no ext is given the extension from the uploaded file will be used or no extention if could not determine one.
// - extkeep - keep actual extention from the uploaded file, ignore the ext parameter
// - extmap - an object which extensions must be replaced
// - namekeep - keep the name of the uploaded file if present in the multipart form
// - encoding - encoding of the body, default is base64
// - allow - a Regexp with allowed MIME types, this will use detectFile method to discover file type by the contents
//
// On return the options may have the following properties set:
// - filesize - size of the file in bytes if available
// - mimetype - file mime type if detected
api.putFile = function(req, name, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = {};

    var btype = lib.typeName(req.body);
    var ext = options.ext ? (options.ext[0] == '.' ? "" : ".") + options.ext : "";
    var outfile = path.join(path.normalize(options.prefix || ""), path.basename(options.name || name) + ext);

    logger.debug("putFile:", name, outfile, options);

    if (req.files && req.files[name]) {
        if (options.namekeep && req.files[name].name) {
            outfile = path.join(path.dirname(outfile), path.basename(req.files[name].name));
        } else
        if (options.extkeep) {
            ext = path.extname(req.files[name].name || req.files[name].path);
            if (ext) {
                const d = path.parse(outfile);
                d.ext = ext;
                outfile = path.format(d);
            }
        }
        options.filesize = req.files[name].size;
        this.detectStoreFile(req.files[name].path, outfile, options, callback);
    } else
    // JSON object submitted with .name property with the icon contents
    if (btype == "object" && req.body[name]) {
        var data = Buffer.isBuffer(req.body[name]) ? req.body[name] : Buffer.from(req.body[name], options.encoding || "base64");
        this.detectStoreFile(data, outfile, options, callback);
    } else
    // Save a buffer as is
    if (btype == "buffer") {
        this.detectStoreFile(req.body, outfile, options, callback);
    } else
    // Query base64 encoded parameter
    if (req.query[name]) {
        var data = Buffer.isBuffer(req.query[name]) ? req.query[name] : Buffer.from(req.query[name], options.encoding || "base64");
        this.detectStoreFile(data, outfile, options, callback);
    } else {
        lib.tryCall(callback);
    }
}

api.detectStoreFile = function(file, outfile, options, callback)
{
    if (util.isRegExp(options.allow)) {
        this.detectFile(file, function(err, type, ext) {
            logger.debug("detectStoreFile:", file, outfile, type, ext, "allow:", options.allow);
            if (err || !options.allow.test(type)) return lib.tryCall(callback, err);
            options.mimetype = type;
            if (ext) {
                options.ext = ext;
                outfile = path.join(path.dirname(outfile), path.basename(outfile, path.extname(outfile)) + "." + ext);
            }
            api.storeFile(file, outfile, options, callback);
        });
    } else {
        this.storeFile(file, outfile, options, callback);
    }
}

// Place the uploaded tmpfile to the destination pointed by outfile
api.storeFile = function(tmpfile, outfile, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = {};

    if (options.extmap) {
        var ext = path.extname(outfile);
        var ext2 = options.extmap[ext] || options.extmap[ext.substr(1)];
        if (ext2) {
            options.ext = (ext2[0] == "." ? "" : ".") + ext2;
            outfile = path.join(path.dirname(outfile), path.basename(outfile, path.extname(outfile)) + options.ext);
        }
    }
    logger.debug("storeFile:", outfile, options);

    if (options.filesS3 || this.filesS3) {
        outfile = "s3://" + (options.filesS3 || this.filesS3) + "/" + path.normalize(outfile);
        core.modules.aws.s3PutFile(outfile, tmpfile, { postsize: options.filesize }, function(err, params) {
            if (!err) return lib.tryCall(callback, err, outfile, params);
            logger.error('storeFile:', outfile, err, params.data, options);
            lib.tryCall(callback, err);
        });
    } else {
        outfile = path.normalize(path.join(options.filesPath || core.path.files, outfile));
        lib.makePath(path.dirname(outfile), function(err) {
            if (err) return lib.tryCall(callback, err);
            if (Buffer.isBuffer(tmpfile)) {
                fs.writeFile(outfile, tmpfile, function(err) {
                    if (!err) return lib.tryCall(callback, err, outfile);
                    logger.error('storeFile:', outfile, err, options);
                    lib.tryCall(callback, err);
                });
            } else {
                lib.moveFile(tmpfile, outfile, true, function(err) {
                    if (!err) return lib.tryCall(callback, err, outfile);
                    logger.error('storeFile:', outfile, err, options);
                    lib.tryCall(callback, err);
                });
            }
        });
    }
}

// Delete file by name from the local filesystem or S3 drive if filesS3 is defined in api or options objects
api.delFile = function(file, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = {};

    file = path.normalize(file);
    if (options.filesS3 || this.filesS3) {
        var aws = core.modules.aws;
        aws.queryS3(options.filesS3 || this.filesS3, file, { method: "DELETE" }, callback);
    } else {
        fs.unlink(path.join(options.filesPath || core.path.files, file), function(err) {
            if (err) logger.error('delFile:', file, err);
            lib.tryCall(callback, err);
        })
    }
}

// Returns detected mime type and ext for a file
api.detectFile = function(file, callback)
{
    try {
        var magic = require("mmmagic");
        var m = new magic.Magic(magic.MAGIC_MIME_TYPE);
        m[Buffer.isBuffer(file) ? "detect" : "detectFile"](file, function(err, type) {
            lib.tryCall(callback, err, type, mime.getExtension(type));
        });
    } catch(err) {
        if (err) logger.error("detectFile:", file, err);
        lib.tryCall(callback, err);
    }
}
<commit_msg>return mimetype for uploads<commit_after>//
//  Author: Vlad Seryakov vseryakov@gmail.com
//  backendjs 2018
//

const path = require('path');
const util = require('util');
const fs = require('fs');
const core = require(__dirname + '/core');
const lib = require(__dirname + '/lib');
const api = require(__dirname + '/api');
const logger = require(__dirname + '/logger');
const mime = require("mime");

// Returns absolute file url if it is configured with any prefix or S3 bucket, otherwise returns empty string
api.fileUrl = function(file, options)
{
    if (file) {
        options = options || lib.empty;
        var s3url = options.filesS3 || this.filesS3;
        var s3opts = options.filesS3Options || this.filesS3Options;
        if (s3url && s3opts) {
            s3opts.url = true;
            file = core.modules.aws.signS3("GET", s3url, path.normalize(file), "", s3opts);
        } else {
            var filesUrl = options.filesUrl || this.filesUrl;
            var filesRaw = options.filesRaw || this.filesRaw;
            if (filesUrl && filesRaw) {
                file = filesUrl + path.normalize(file);
            }
        }
    }
    return file || "";
}

// Send a file to the client
api.getFile = function(req, file, options)
{
    if (!options) options = lib.empty;
    logger.debug('sendFile:', file, options);

    if (options.filesS3 || this.filesS3) {
        core.modules.aws.s3Proxy(req.res, options.filesS3 || this.filesS3, path.normalize(file), options);
    } else {
        this.sendFile(req, path.join(options.filesPath || core.path.files, path.normalize(file)));
    }
}

// Returns contents of a file, all specific parameters are passed as is, the contents of the file is returned to the callback,
// see `lib.readFile` or `aws.s3GetFile` for specific options.
api.readFile = function(file, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = lib.empty;
    logger.debug('readFile:', file, options);

    if (options.filesS3 || this.filesS3) {
        file = path.join(options.filesS3 || this.filesS3, path.normalize(file));
        core.modules.aws.s3GetFile(file, options, (err, params) => {
            if (params.status == 200) {
                if (options.json) params.data = lib.jsonParse(params.data, options); else
                if (options.xml) params.data = lib.xmlParse(params.data, options); else
                if (options.list) params.data = lib.strSplit(params.data, options.list);
            }
            lib.tryCall(callback, err, params.data);
        });
    } else {
        file = path.join(options.filesPath || core.path.files, path.normalize(file));
        lib.readFile(file, options, callback);
    }
}

// Upload file and store in the filesystem or S3, try to find the file in multipart form, in the body or query by the given name
// - name is the name property to look for in the multipart body or in the request body or query
// - callback will be called with err and actual filename saved
//
// Output file name is built according to the following options properties:
// - name - defines the output name for the file, if not given same name as property will be used
// - prefix - the folder prefix where the file will be uploaded, all leading folders will be created automatically
// - ext - what file extention to use, appended to the name, if no ext is given the extension from the uploaded file will be used or no extention if could not determine one.
// - extkeep - keep actual extention from the uploaded file, ignore the ext parameter
// - extmap - an object which extensions must be replaced
// - namekeep - keep the name of the uploaded file if present in the multipart form
// - encoding - encoding of the body, default is base64
// - allow - a Regexp with allowed MIME types, this will use detectFile method to discover file type by the contents
//
// On return the options may have the following properties set:
// - filesize - size of the file in bytes if available
// - mimetype - file mime type if detected
api.putFile = function(req, name, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = {};

    var btype = lib.typeName(req.body);
    var ext = options.ext ? (options.ext[0] == '.' ? "" : ".") + options.ext : "";
    var outfile = path.join(path.normalize(options.prefix || ""), path.basename(options.name || name) + ext);

    logger.debug("putFile:", name, outfile, options);

    if (req.files && req.files[name]) {
        if (options.namekeep && req.files[name].name) {
            outfile = path.join(path.dirname(outfile), path.basename(req.files[name].name));
        } else
        if (options.extkeep) {
            ext = path.extname(req.files[name].name || req.files[name].path);
            if (ext) {
                const d = path.parse(outfile);
                d.ext = ext;
                outfile = path.format(d);
            }
        }
        options.filesize = req.files[name].size;
        this.detectStoreFile(req.files[name].path, outfile, options, callback);
    } else
    // JSON object submitted with .name property with the icon contents
    if (btype == "object" && req.body[name]) {
        var data = Buffer.isBuffer(req.body[name]) ? req.body[name] : Buffer.from(req.body[name], options.encoding || "base64");
        this.detectStoreFile(data, outfile, options, callback);
    } else
    // Save a buffer as is
    if (btype == "buffer") {
        this.detectStoreFile(req.body, outfile, options, callback);
    } else
    // Query base64 encoded parameter
    if (req.query[name]) {
        var data = Buffer.isBuffer(req.query[name]) ? req.query[name] : Buffer.from(req.query[name], options.encoding || "base64");
        this.detectStoreFile(data, outfile, options, callback);
    } else {
        lib.tryCall(callback);
    }
}

api.detectStoreFile = function(file, outfile, options, callback)
{
    if (util.isRegExp(options.allow)) {
        this.detectFile(file, function(err, type, ext) {
            logger.debug("detectStoreFile:", file, outfile, type, ext, "allow:", options.allow);
            if (type) options.mimetype = type;
            if (err || !options.allow.test(type)) return lib.tryCall(callback, err);
            if (ext) {
                options.ext = ext;
                outfile = path.join(path.dirname(outfile), path.basename(outfile, path.extname(outfile)) + "." + ext);
            }
            api.storeFile(file, outfile, options, callback);
        });
    } else {
        this.storeFile(file, outfile, options, callback);
    }
}

// Place the uploaded tmpfile to the destination pointed by outfile
api.storeFile = function(tmpfile, outfile, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = {};

    if (options.extmap) {
        var ext = path.extname(outfile);
        var ext2 = options.extmap[ext] || options.extmap[ext.substr(1)];
        if (ext2) {
            options.ext = (ext2[0] == "." ? "" : ".") + ext2;
            outfile = path.join(path.dirname(outfile), path.basename(outfile, path.extname(outfile)) + options.ext);
        }
    }
    logger.debug("storeFile:", outfile, options);

    if (options.filesS3 || this.filesS3) {
        outfile = "s3://" + (options.filesS3 || this.filesS3) + "/" + path.normalize(outfile);
        core.modules.aws.s3PutFile(outfile, tmpfile, { postsize: options.filesize }, function(err, params) {
            if (!err) return lib.tryCall(callback, err, outfile, params);
            logger.error('storeFile:', outfile, err, params.data, options);
            lib.tryCall(callback, err);
        });
    } else {
        outfile = path.normalize(path.join(options.filesPath || core.path.files, outfile));
        lib.makePath(path.dirname(outfile), function(err) {
            if (err) return lib.tryCall(callback, err);
            if (Buffer.isBuffer(tmpfile)) {
                fs.writeFile(outfile, tmpfile, function(err) {
                    if (!err) return lib.tryCall(callback, err, outfile);
                    logger.error('storeFile:', outfile, err, options);
                    lib.tryCall(callback, err);
                });
            } else {
                lib.moveFile(tmpfile, outfile, true, function(err) {
                    if (!err) return lib.tryCall(callback, err, outfile);
                    logger.error('storeFile:', outfile, err, options);
                    lib.tryCall(callback, err);
                });
            }
        });
    }
}

// Delete file by name from the local filesystem or S3 drive if filesS3 is defined in api or options objects
api.delFile = function(file, options, callback)
{
    if (typeof options == "function") callback = options, options = null;
    if (!options) options = {};

    file = path.normalize(file);
    if (options.filesS3 || this.filesS3) {
        var aws = core.modules.aws;
        aws.queryS3(options.filesS3 || this.filesS3, file, { method: "DELETE" }, callback);
    } else {
        fs.unlink(path.join(options.filesPath || core.path.files, file), function(err) {
            if (err) logger.error('delFile:', file, err);
            lib.tryCall(callback, err);
        })
    }
}

// Returns detected mime type and ext for a file
api.detectFile = function(file, callback)
{
    try {
        var magic = require("mmmagic");
        var m = new magic.Magic(magic.MAGIC_MIME_TYPE);
        m[Buffer.isBuffer(file) ? "detect" : "detectFile"](file, function(err, type) {
            lib.tryCall(callback, err, type, mime.getExtension(type));
        });
    } catch(err) {
        if (err) logger.error("detectFile:", file, err);
        lib.tryCall(callback, err);
    }
}
<|endoftext|>


<commit_before>({
	baseUrl: ".",
	name: "index",
	out: "./../browser-build/index.js",
	deps:function(){
		console.log()
		var plugins = require.nodeRequire(__dirname + '/../../../lib/index').Config.coretags,
			files = [],
			plugin;
		for(var i = 0, l = plugins.length; i < l; i++){
			plugin = plugins[i];
			files.push('./../plugins/' + plugin + '/' + plugin + '.js');
			files.push('./../plugins/'+ plugin + '/' + plugin + '_globalization.js');
		}
		return files;
	}()
})<commit_msg>modified to handle index rename<commit_after>({
	baseUrl: ".",
	name: "noodles",
	out: "./../browser-build/noodles.js",
	deps:function(){
		console.log()
		var plugins = require.nodeRequire(__dirname + '/../../../lib/noodles').Config.coretags,
			files = [],
			plugin;
		for(var i = 0, l = plugins.length; i < l; i++){
			plugin = plugins[i];
			files.push('./../plugins/' + plugin + '/' + plugin + '.js');
			files.push('./../plugins/'+ plugin + '/' + plugin + '_globalization.js');
		}
		return files;
	}()
})<|endoftext|>


<commit_before>/*
 * Geddy JavaScript Web development framework
 * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

var domain = require('domain')
  , fs = require('fs')
  , path = require('path')
  , model = require('model')
  , controller = require('../controller')
  , utils = require('../utils')
  , cwd = process.cwd()
  , errors = require('../response/errors')
  , init = require('../init')
  , helpers = require('../template/helpers')
  , actionHelpers = require('../template/helpers/action')
  , ErrorController = require('../controller/error_controller').ErrorController
  , StaticFileController =
        require('../controller/static_file_controller').StaticFileController
  , controllerInit = require('../controller/init')
  , InFlight = require('../in_flight').InFlight
  , sessions = require('../sessions')
  , usingCoffee // Global variable for CoffeeScript
  , logging = require('./logging')
  , requestHelpers = require('./request_helpers');

// Set up a bunch of aliases
geddy.inFlight = new InFlight();
geddy.inflection = utils.inflection;
geddy.model = model;
geddy.controller = controller;
geddy.utils = utils;
geddy.errors = errors;
geddy.viewHelpers = {};

// Use Geddy logger as the utility logger
utils.log.registerLogger(geddy.log);

var App = function () {

  // Init core -- eventually all init should move here
  // ==================
      _baseInit = function (next) {
        init.init(this, next);
      }

  // Connect to session-store
  // ==================
    , _loadSessionStore = function (next) {
        sessionsConfig = geddy.config.sessions;
        if (sessionsConfig) {
          sessions.createStore(sessionsConfig.store, next);
        }
        else {
          next();
        }
      }

  // Register template-paths
  // ==================
    , _registerTemplatePaths = function (next) {
        var viewsPath = path.normalize('app/views')
          , geddyTemplatesPath = path.join(__dirname, '../template', 'templates');

        // If viewsPath doesn't exist they're running viewless
        if(!utils.file.existsSync(viewsPath)) {
          this.templateRegistry = {};
          next();
        } else {
          var files = utils.file.readdirR(viewsPath)
            , geddyTemplatesFiles = utils.file.readdirR(geddyTemplatesPath)
            , pat = /\.(ejs|jade|hbs|mustache|ms|mu|swig)$/
            , templates = {}
            , file
            , origFile
            , noExtFile
            , fileExt
            , fileBaseName
            , addTemplate
            , createTemplates;

          // Adds a template object to templates
          addTemplate = function (noExtFile, file, origFile, fileExt, fileBaseName) {
            if(!origFile) origFile = noExtFile;

            templates[origFile] = {
                file: file
              , ext: fileExt
              , baseName: fileBaseName
              , baseNamePath: noExtFile
            };
          };

          // Read dir list and create template objects from each file
          createTemplates = function (dir, isGeddy) {
            for (var i = 0; i < dir.length; i++) {
              file = dir[i];
              fileExt = path.extname(file);
              fileBaseName = path.basename(file, fileExt).replace(/\.html$/, '');

              if (isGeddy) {
                origFile = path.normalize('geddy/' + fileBaseName);
              }

              if (pat.test(file)) {
                // Strip .html and extension for easier detecting when rendering
                if (isGeddy) {
                  noExtFile = path.normalize('geddy/' + fileBaseName);
                } else noExtFile = file.replace(/\.html.*$/, '');

                addTemplate(noExtFile, file, origFile, fileExt, fileBaseName);
              }
            }
          };

          // Loop through template files and add it them to registry
          createTemplates(files);

          // Add custom templates from `lib/template/templates`
          createTemplates(geddyTemplatesFiles, true);

          this.templateRegistry = templates;
          next();
        }
      }

  // Run code in the app's config/after_start.js file
  // and run anything else that needs to be run after
  // the server has started listening for requests
  // ================================================
    , _afterStart = function (next) {
        geddy.server.listeners('request');

        // Load socket.io if it's enabled. This gets run after
        // the server starts listening for requests. Socket.io
        // won't work if we start it before.
        if (geddy.config.realtime) {
          geddy.io = utils.file.requireLocal('socket.io').listen(geddy.server, {'log level': 0});
          // add event listeners to all the models
          // set up socket.io emitters for each event

          var events = [
          , 'save'
          , 'update'
          , 'beforeRemove'
          ]

          , registerEventListener = function (model, event) {
            geddy.model[model].on(event, function (d) {
              var data = geddy.mixin({}, d)
                , id;

              event = event.replace('before','').toLowerCase();

              if (typeof data == 'object') {
                data.model = model;
                data.event = event;
                id = data.id;
              }
              else {
                id = data;
              }

              geddy.io.sockets.emit(model+':'+event, (typeof data['toObj'] === 'function' ) ? data.toObj() : data);
              geddy.io.sockets.emit(model+':'+event+':'+id, (typeof data['toObj'] === 'function' ) ? data.toObj() : data);
            });
          }

          for (var i in geddy.model.descriptionRegistry) {
            for (var e in events) {
              registerEventListener(i, events[e]);
            }
          }

        }

        try {
          require(path.join(cwd, 'config', 'after_start'));
        } catch (e) {}
      };

  this.router = null;
  this.modelRegistry = {};
  this.templateRegistry = {};
  this.controllerRegistry = {};

  this.init = function (callback) {
    var self = this
      , items
      , chain;

    items = [
      _baseInit
    // TODO: Migrate all these into _baseInit
    , _loadSessionStore
    , _registerTemplatePaths
    ];

    chain = new utils.async.SimpleAsyncChain(items, this);
    chain.last = function () {
      self.start(callback);
    };
    chain.run();
  };

  this.handleControllerAction = function (controllerInst, reqUrl, method,
          params, accessTime, reqObj, respObj) {
    var initKeys
      , initializer
      , cb;

    // Async setup steps to allow the controller to handle
    // the request
    initKeys = [
      'cookies'
    , 'i18n'
    , 'inFlight'
    , 'parseBody'
    , 'session'
    ];

    // Mix all the shits onto the controller instance
    utils.mixin(controllerInst, {
      app: this
    , url: reqUrl  // Can we dispense with this? It's in the params
    , method: method // And this?
    , params: params
    , accessTime: accessTime
    , request: reqObj
    , response: respObj
    , name: params.controller
    });

    reqObj.controller = controllerInst;
    respObj.controller = controllerInst;

    cb = function () {
      controllerInst._handleAction.call(controllerInst, params.action);
      // TODO Replace this with readable-stream module for 0.8 support
      if (reqObj.req && typeof reqObj.req.read != 'function') {
        reqObj.sync(); // Flush buffered events and begin emitting
      }
    };
    initializer = new utils.async.Initializer(initKeys, cb);

    // Run all the async setup steps
    initKeys.forEach(function (key) {
      controllerInit[key].call(controllerInst, function () {
        initializer.complete(key);
      });
    });
  };

  this.handleStaticFile = function (staticPath, params, reqUrl, reqObj, respObj) {
    var controllerInst;
    // May be a path to a directory, with or without a trailing
    // slash -- any trailing slash has already been stripped by
    // this point
    if (fs.statSync(staticPath).isDirectory()) {
      // TODO: Make the name of any index file configurable
      staticPath = path.join(staticPath, 'index.html');
      if (utils.file.existsSync(staticPath) && fs.statSync(staticPath).isFile()) {
        controllerInst = new StaticFileController(reqObj, respObj, params);
        controllerInst.respond({
          path: staticPath
        });
      }
      // Directory with no index file
      else {
        this.handleNotFound(reqUrl, params, reqObj, respObj);
      }
    }
    // Path to an actual file. Just serve it up
    else if (fs.statSync(staticPath).isFile()) {
      controllerInst = new StaticFileController(reqObj, respObj, params);
      controllerInst.respond({
        path: staticPath
      });
    }
  };

  this.handleMethodNotAllowed = function (method, reqUrl, params, reqObj, respObj,
      nonMethodRoutes) {
    // build a unique list of acceptable methods for this resource
    var acceptableMethods = {}
      , err
      , controllerInst;

    nonMethodRoutes.map(function (params) {
      acceptableMethods[params.method] = true;
    });
    acceptableMethods = Object.keys(acceptableMethods);

    // send a friendly error response
    throw new errors.MethodNotAllowedError(
      method + ' method not allowed. Please consider ' +
      acceptableMethods.join(', ').replace(/,\s(\w+)$/," or $1") +
      ' instead.');
  };

  this.handleNotFound = function (reqUrl, params, reqObj, respObj) {
    throw new errors.NotFoundError(reqUrl + ' not found.');
  };

  this.handleNoMatchedRoute = function (method, reqUrl, params, reqObj, respObj) {
    var staticPath
      , controllerInst
      , nonMethodRoutes;

    // Get the path to the file, decoding the request URI
    staticPath = geddy.config.staticFilePath + decodeURIComponent(reqUrl);
    // Ignore querystring
    staticPath = staticPath.split('?')[0];

    // Static?
    if (utils.file.existsSync(staticPath)) {
      this.handleStaticFile(staticPath, params, reqUrl, reqObj, respObj, params);
    }
    else {
      nonMethodRoutes = this.router.all(reqUrl);

      // Good route, wrong verb -- 405?
      if (nonMethodRoutes.length) {
        this.handleMethodNotAllowed(method, reqUrl, params, reqObj, respObj,
          nonMethodRoutes);
      }
      // Nada, 404
      else {
        this.handleNotFound(reqUrl, params, reqObj, respObj);
      }
    }
  };
  this.handleNoAction = function (params, reqObj, respObj) {
    throw new errors.InternalServerError('No ' + params.action +
        ' action on ' + params.controller + ' controller.');
  };

  this.handleNoController = function (params, reqObj, respObj) {
    throw new errors.InternalServerError('controller ' +
        params.controller + ' not found.');
  };

  this.start = function (callback) {
    var self = this
      , ctors = this.controllerRegistry
      , controllerActionTimers = {};

    // Handle the requests
    // ==================
    geddy.server.addListener('request', function (req, resp) {
      var dmn = domain.create()
        , caught = false
        , badRequestErr
        , controllerInst
        , reqObj
        , respObj;

      // Attempt a nice, high-fi customizable error
      // Only try this once -- if something fails during the
      // rendering process for the error, fall back to a low-fi
      // fool-proof error to display that
      dmn.on('error', function (err) {
        var serverErr
          , controllerInst;

        if (caught) {
          return errors.respond(err, respObj);
        }

        caught = true;

        if (err.statusCode) {
          serverErr = err;
        }
        else {
          serverErr = new errors.InternalServerError(err.message, err.stack);
        }

        try {
          controllerInst = new ErrorController(reqObj, respObj);
          controllerInst.respondWith(serverErr);
        }
        // Catch sync errors in the error-rendering process
        // Respond with a low-fi fool-proof err
        // Async ones will be handled by re-entering this domain
        // on-error handler
        catch(e) {
          errors.respond(e, respObj);
        }
      });

      dmn.add(req);
      dmn.add(resp);

      // Parsing URLs may result in a bad request -- if this happens,
      // throw the error inside the domain code, so we can get a nice,
      // customizable error message
      try {
        reqObj = requestHelpers.enhanceRequest(req);
        respObj = requestHelpers.enhanceResponse(resp);
      }
      catch (err) {
        req.url = '/';
        reqObj = requestHelpers.enhanceRequest(req);
        respObj = requestHelpers.enhanceResponse(resp);
        badRequestErr = new errors.BadRequestError(err.message, err.stack);
        controllerInst = new ErrorController(reqObj, respObj);
        return controllerInst.respondWith(badRequestErr);
      }

      dmn.add(reqObj);
      dmn.add(respObj);

      dmn.run(function () {
        var reqUrl
          , urlParams
          , method
          , accessTime
          , params
          , controllerInst;

        // Parse out some needed request properties
        reqUrl = requestHelpers.normalizeUrl(req);
        urlParams = requestHelpers.getUrlParams(reqUrl);
        method = requestHelpers.getMethod(reqUrl, urlParams, req);
        accessTime = requestHelpers.getAccessTime();

        // Now only for timeout, domains are handling errors
        requestHelpers.initInFlight(reqObj, respObj, method, accessTime);

        // TODO: Allow custom formats
        logging.initRequestLogger(reqUrl, reqObj, respObj, method, accessTime);

        params = requestHelpers.getParams(self.router, reqUrl, method);
        // Route/method combo give us something valid?
        if (params) {

          controllerInst = controller.create(params.controller);
          // Valid controller?
          if (controllerInst) {
            // Enhance the parsed params with URL params
            geddy.mixin(params, urlParams);

            // FIXME: Backward-compat shim for old action-name 'destroy'
            if (params.action == 'destroy' &&
                typeof controllerInst.destroy != 'function') {
              params.action = 'remove';
            }

            if (typeof controllerInst[params.action] == 'function') {
              self.handleControllerAction(controllerInst, reqUrl, method,
                      params, accessTime, reqObj, respObj);
            }
            // No action, 500 error
            else {
              self.handleNoAction(params, reqObj, respObj);
            }
          }
          // No controller, 500 error
          else {
            self.handleNoController(params, reqObj, respObj);
          }
        }
        // Either 405, static, or 404
        else {
          self.handleNoMatchedRoute(method, reqUrl, params, reqObj, respObj);
        }

      });
    });

    _afterStart();
    callback();
  };

};

module.exports.App = App;

<commit_msg>using toJSON instead of toObj now<commit_after>/*
 * Geddy JavaScript Web development framework
 * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

var domain = require('domain')
  , fs = require('fs')
  , path = require('path')
  , model = require('model')
  , controller = require('../controller')
  , utils = require('../utils')
  , cwd = process.cwd()
  , errors = require('../response/errors')
  , init = require('../init')
  , helpers = require('../template/helpers')
  , actionHelpers = require('../template/helpers/action')
  , ErrorController = require('../controller/error_controller').ErrorController
  , StaticFileController =
        require('../controller/static_file_controller').StaticFileController
  , controllerInit = require('../controller/init')
  , InFlight = require('../in_flight').InFlight
  , sessions = require('../sessions')
  , usingCoffee // Global variable for CoffeeScript
  , logging = require('./logging')
  , requestHelpers = require('./request_helpers');

// Set up a bunch of aliases
geddy.inFlight = new InFlight();
geddy.inflection = utils.inflection;
geddy.model = model;
geddy.controller = controller;
geddy.utils = utils;
geddy.errors = errors;
geddy.viewHelpers = {};

// Use Geddy logger as the utility logger
utils.log.registerLogger(geddy.log);

var App = function () {

  // Init core -- eventually all init should move here
  // ==================
      _baseInit = function (next) {
        init.init(this, next);
      }

  // Connect to session-store
  // ==================
    , _loadSessionStore = function (next) {
        sessionsConfig = geddy.config.sessions;
        if (sessionsConfig) {
          sessions.createStore(sessionsConfig.store, next);
        }
        else {
          next();
        }
      }

  // Register template-paths
  // ==================
    , _registerTemplatePaths = function (next) {
        var viewsPath = path.normalize('app/views')
          , geddyTemplatesPath = path.join(__dirname, '../template', 'templates');

        // If viewsPath doesn't exist they're running viewless
        if(!utils.file.existsSync(viewsPath)) {
          this.templateRegistry = {};
          next();
        } else {
          var files = utils.file.readdirR(viewsPath)
            , geddyTemplatesFiles = utils.file.readdirR(geddyTemplatesPath)
            , pat = /\.(ejs|jade|hbs|mustache|ms|mu|swig)$/
            , templates = {}
            , file
            , origFile
            , noExtFile
            , fileExt
            , fileBaseName
            , addTemplate
            , createTemplates;

          // Adds a template object to templates
          addTemplate = function (noExtFile, file, origFile, fileExt, fileBaseName) {
            if(!origFile) origFile = noExtFile;

            templates[origFile] = {
                file: file
              , ext: fileExt
              , baseName: fileBaseName
              , baseNamePath: noExtFile
            };
          };

          // Read dir list and create template objects from each file
          createTemplates = function (dir, isGeddy) {
            for (var i = 0; i < dir.length; i++) {
              file = dir[i];
              fileExt = path.extname(file);
              fileBaseName = path.basename(file, fileExt).replace(/\.html$/, '');

              if (isGeddy) {
                origFile = path.normalize('geddy/' + fileBaseName);
              }

              if (pat.test(file)) {
                // Strip .html and extension for easier detecting when rendering
                if (isGeddy) {
                  noExtFile = path.normalize('geddy/' + fileBaseName);
                } else noExtFile = file.replace(/\.html.*$/, '');

                addTemplate(noExtFile, file, origFile, fileExt, fileBaseName);
              }
            }
          };

          // Loop through template files and add it them to registry
          createTemplates(files);

          // Add custom templates from `lib/template/templates`
          createTemplates(geddyTemplatesFiles, true);

          this.templateRegistry = templates;
          next();
        }
      }

  // Run code in the app's config/after_start.js file
  // and run anything else that needs to be run after
  // the server has started listening for requests
  // ================================================
    , _afterStart = function (next) {
        geddy.server.listeners('request');

        // Load socket.io if it's enabled. This gets run after
        // the server starts listening for requests. Socket.io
        // won't work if we start it before.
        if (geddy.config.realtime) {
          geddy.io = utils.file.requireLocal('socket.io').listen(geddy.server, {'log level': 0});
          // add event listeners to all the models
          // set up socket.io emitters for each event

          var events = [
          , 'save'
          , 'update'
          , 'beforeRemove'
          ]

          , registerEventListener = function (model, event) {
            geddy.model[model].on(event, function (d) {
              var data = geddy.mixin({}, d)
                , id;

              event = event.replace('before','').toLowerCase();

              if (typeof data == 'object') {
                data.model = model;
                data.event = event;
                id = data.id;
              }
              else {
                id = data;
              }

              geddy.io.sockets.emit(model+':'+event, (typeof data['toJSON'] === 'function' ) ? data.toJSON() : data);
              geddy.io.sockets.emit(model+':'+event+':'+id, (typeof data['toJSON'] === 'function' ) ? data.toJSON() : data);
            });
          }

          for (var i in geddy.model.descriptionRegistry) {
            for (var e in events) {
              registerEventListener(i, events[e]);
            }
          }

        }

        try {
          require(path.join(cwd, 'config', 'after_start'));
        } catch (e) {}
      };

  this.router = null;
  this.modelRegistry = {};
  this.templateRegistry = {};
  this.controllerRegistry = {};

  this.init = function (callback) {
    var self = this
      , items
      , chain;

    items = [
      _baseInit
    // TODO: Migrate all these into _baseInit
    , _loadSessionStore
    , _registerTemplatePaths
    ];

    chain = new utils.async.SimpleAsyncChain(items, this);
    chain.last = function () {
      self.start(callback);
    };
    chain.run();
  };

  this.handleControllerAction = function (controllerInst, reqUrl, method,
          params, accessTime, reqObj, respObj) {
    var initKeys
      , initializer
      , cb;

    // Async setup steps to allow the controller to handle
    // the request
    initKeys = [
      'cookies'
    , 'i18n'
    , 'inFlight'
    , 'parseBody'
    , 'session'
    ];

    // Mix all the shits onto the controller instance
    utils.mixin(controllerInst, {
      app: this
    , url: reqUrl  // Can we dispense with this? It's in the params
    , method: method // And this?
    , params: params
    , accessTime: accessTime
    , request: reqObj
    , response: respObj
    , name: params.controller
    });

    reqObj.controller = controllerInst;
    respObj.controller = controllerInst;

    cb = function () {
      controllerInst._handleAction.call(controllerInst, params.action);
      // TODO Replace this with readable-stream module for 0.8 support
      if (reqObj.req && typeof reqObj.req.read != 'function') {
        reqObj.sync(); // Flush buffered events and begin emitting
      }
    };
    initializer = new utils.async.Initializer(initKeys, cb);

    // Run all the async setup steps
    initKeys.forEach(function (key) {
      controllerInit[key].call(controllerInst, function () {
        initializer.complete(key);
      });
    });
  };

  this.handleStaticFile = function (staticPath, params, reqUrl, reqObj, respObj) {
    var controllerInst;
    // May be a path to a directory, with or without a trailing
    // slash -- any trailing slash has already been stripped by
    // this point
    if (fs.statSync(staticPath).isDirectory()) {
      // TODO: Make the name of any index file configurable
      staticPath = path.join(staticPath, 'index.html');
      if (utils.file.existsSync(staticPath) && fs.statSync(staticPath).isFile()) {
        controllerInst = new StaticFileController(reqObj, respObj, params);
        controllerInst.respond({
          path: staticPath
        });
      }
      // Directory with no index file
      else {
        this.handleNotFound(reqUrl, params, reqObj, respObj);
      }
    }
    // Path to an actual file. Just serve it up
    else if (fs.statSync(staticPath).isFile()) {
      controllerInst = new StaticFileController(reqObj, respObj, params);
      controllerInst.respond({
        path: staticPath
      });
    }
  };

  this.handleMethodNotAllowed = function (method, reqUrl, params, reqObj, respObj,
      nonMethodRoutes) {
    // build a unique list of acceptable methods for this resource
    var acceptableMethods = {}
      , err
      , controllerInst;

    nonMethodRoutes.map(function (params) {
      acceptableMethods[params.method] = true;
    });
    acceptableMethods = Object.keys(acceptableMethods);

    // send a friendly error response
    throw new errors.MethodNotAllowedError(
      method + ' method not allowed. Please consider ' +
      acceptableMethods.join(', ').replace(/,\s(\w+)$/," or $1") +
      ' instead.');
  };

  this.handleNotFound = function (reqUrl, params, reqObj, respObj) {
    throw new errors.NotFoundError(reqUrl + ' not found.');
  };

  this.handleNoMatchedRoute = function (method, reqUrl, params, reqObj, respObj) {
    var staticPath
      , controllerInst
      , nonMethodRoutes;

    // Get the path to the file, decoding the request URI
    staticPath = geddy.config.staticFilePath + decodeURIComponent(reqUrl);
    // Ignore querystring
    staticPath = staticPath.split('?')[0];

    // Static?
    if (utils.file.existsSync(staticPath)) {
      this.handleStaticFile(staticPath, params, reqUrl, reqObj, respObj, params);
    }
    else {
      nonMethodRoutes = this.router.all(reqUrl);

      // Good route, wrong verb -- 405?
      if (nonMethodRoutes.length) {
        this.handleMethodNotAllowed(method, reqUrl, params, reqObj, respObj,
          nonMethodRoutes);
      }
      // Nada, 404
      else {
        this.handleNotFound(reqUrl, params, reqObj, respObj);
      }
    }
  };
  this.handleNoAction = function (params, reqObj, respObj) {
    throw new errors.InternalServerError('No ' + params.action +
        ' action on ' + params.controller + ' controller.');
  };

  this.handleNoController = function (params, reqObj, respObj) {
    throw new errors.InternalServerError('controller ' +
        params.controller + ' not found.');
  };

  this.start = function (callback) {
    var self = this
      , ctors = this.controllerRegistry
      , controllerActionTimers = {};

    // Handle the requests
    // ==================
    geddy.server.addListener('request', function (req, resp) {
      var dmn = domain.create()
        , caught = false
        , badRequestErr
        , controllerInst
        , reqObj
        , respObj;

      // Attempt a nice, high-fi customizable error
      // Only try this once -- if something fails during the
      // rendering process for the error, fall back to a low-fi
      // fool-proof error to display that
      dmn.on('error', function (err) {
        var serverErr
          , controllerInst;

        if (caught) {
          return errors.respond(err, respObj);
        }

        caught = true;

        if (err.statusCode) {
          serverErr = err;
        }
        else {
          serverErr = new errors.InternalServerError(err.message, err.stack);
        }

        try {
          controllerInst = new ErrorController(reqObj, respObj);
          controllerInst.respondWith(serverErr);
        }
        // Catch sync errors in the error-rendering process
        // Respond with a low-fi fool-proof err
        // Async ones will be handled by re-entering this domain
        // on-error handler
        catch(e) {
          errors.respond(e, respObj);
        }
      });

      dmn.add(req);
      dmn.add(resp);

      // Parsing URLs may result in a bad request -- if this happens,
      // throw the error inside the domain code, so we can get a nice,
      // customizable error message
      try {
        reqObj = requestHelpers.enhanceRequest(req);
        respObj = requestHelpers.enhanceResponse(resp);
      }
      catch (err) {
        req.url = '/';
        reqObj = requestHelpers.enhanceRequest(req);
        respObj = requestHelpers.enhanceResponse(resp);
        badRequestErr = new errors.BadRequestError(err.message, err.stack);
        controllerInst = new ErrorController(reqObj, respObj);
        return controllerInst.respondWith(badRequestErr);
      }

      dmn.add(reqObj);
      dmn.add(respObj);

      dmn.run(function () {
        var reqUrl
          , urlParams
          , method
          , accessTime
          , params
          , controllerInst;

        // Parse out some needed request properties
        reqUrl = requestHelpers.normalizeUrl(req);
        urlParams = requestHelpers.getUrlParams(reqUrl);
        method = requestHelpers.getMethod(reqUrl, urlParams, req);
        accessTime = requestHelpers.getAccessTime();

        // Now only for timeout, domains are handling errors
        requestHelpers.initInFlight(reqObj, respObj, method, accessTime);

        // TODO: Allow custom formats
        logging.initRequestLogger(reqUrl, reqObj, respObj, method, accessTime);

        params = requestHelpers.getParams(self.router, reqUrl, method);
        // Route/method combo give us something valid?
        if (params) {

          controllerInst = controller.create(params.controller);
          // Valid controller?
          if (controllerInst) {
            // Enhance the parsed params with URL params
            geddy.mixin(params, urlParams);

            // FIXME: Backward-compat shim for old action-name 'destroy'
            if (params.action == 'destroy' &&
                typeof controllerInst.destroy != 'function') {
              params.action = 'remove';
            }

            if (typeof controllerInst[params.action] == 'function') {
              self.handleControllerAction(controllerInst, reqUrl, method,
                      params, accessTime, reqObj, respObj);
            }
            // No action, 500 error
            else {
              self.handleNoAction(params, reqObj, respObj);
            }
          }
          // No controller, 500 error
          else {
            self.handleNoController(params, reqObj, respObj);
          }
        }
        // Either 405, static, or 404
        else {
          self.handleNoMatchedRoute(method, reqUrl, params, reqObj, respObj);
        }

      });
    });

    _afterStart();
    callback();
  };

};

module.exports.App = App;

<|endoftext|>