<commit_before>/*jshint laxcomma: true, smarttabs: true, node: true, unused: true */
'use strict';
/**
 * A resource instance using rethinkdb via thinky as a data source
 * @module tastypie/lib/resource/rethink
 * @author Eric Satterwhite
 * @since 0.3.2
 * @requires util
 * @requires joi
 * @requires debug
 * @requires mout/lang/isNumber
 * @requires mout/lang/toArray
 * @requires mout/lang/merge
 * @requires tastypie/lib/class
 * @requires tastypie/lib/options
 * @requires tastypie/lib/http
 * @requires tastypie/lib/resource
 */

var isNumber      = require('mout/lang/isNumber')
  , isString      = require('mout/lang/isString')
  , toArray       = require('mout/lang/toArray')
  , Boom          = require( 'boom' )
  , async         = require('async')
  , typecast      = require('mout/string/typecast')
  , Class         = require('tastypie/lib/class')
  , Options       = require('tastypie/lib/class/options')
  , Resource      = require('tastypie/lib/resource')
  , Paginator     = require('tastypie/lib/paginator')
  , http          = require('tastypie/lib/http')
  , constants     = require('tastypie/lib/constants')
  , debug         = require( 'debug' )('tastypie:resource:rethink')
  , filters       = require('./filters')
  , SEP           = '__'
  , orderExp      = /^(\-)?([\w]+)/
  , RethinkResource
  ;

/**
 * @alias module:tastypie/lib/resource/rethink
 * @constructor
 * @param {Object} options
 * @param {String} [options.pk=id] property to be considered the primary key field of the associated model
 * @extends module:tastypie/lib/resource
 * @example
var SampleResource = new Class({
	inherits:RethinkResource
	,options:{
		queryset: Sample.filter({})
	}
	,fields:{
		age:{type:'integer', null:true, attribute:'age'}
	}
});
 */
module.exports = RethinkResource = new Class({
	inherits:Resource
	,mixin:[Options]
	,options:{
		queryset:null
		,pk:'id'
		,objectTpl:null
		,paginator: Paginator.Remote
		,max:1000
	}

	,constructor: function( options ){

		this.parent( 'constructor', options );

		this.options.objectTpl = this.options.objectTpl || this.options.queryset._model;
		var paths = Object.keys( this.fields || this.options.queryset._model._schema._schema );
		this.allowablepaths = paths.filter(function(p){
			return p !== 'id';
		});

		paths = null;
	}

	, get_list: function get_list( bundle ){
		var query = this.options.queryset.filter({})
		  , that = this
		  , filters
		  ;

		try{
			filters = this.buildFilters( bundle.req.query );
		} catch( err ){
			err.req = bundle.req;
			err.res = bundle.res;
			return this.emit('error', err);
		}

		query = query.filter( filters );
		query.count().execute( function( err, count ){

			var paginator
			  , to_be_serialized
			  ;

			try{
				query = this.sort( query, bundle.req.query );
				query = this.offset( query, bundle );
				query = this.limit( query, bundle );
			} catch( err ){
				err.req = bundle.req;
				err.res = bundle.res;
				return that.emit('error', err );
			}
			query.run( function( err, objects ){
				objects = objects || [];
				if(err){
					err.req=bundle.req;
					err.res=bundle.res;
					return that.emit('error', err );
				}
				paginator = new that.options.paginator({
					limit:bundle.req.query.limit
					,req:bundle.req
					,res:bundle.res
					,collectionName:that.options.collection
					,objects:objects
					,count: count
					,offset: bundle.req.query.offset || 0
				});

				to_be_serialized = paginator.page();
				async.map( to_be_serialized[ that.options.collection ], function(item, done){
					return that.full_dehydrate( item, bundle, done );
				}, function(err, results ){
					to_be_serialized[ that.options.collection ] = results;
					bundle.data = to_be_serialized;
					paginator = to_be_serialized = null;
					return that.respond( bundle );
				});
			});
		}.bind( this ));
	}

	, delete_detail: function delete_detail( bundle ){
		var that = this;
		this.get_object(bundle, function( err, instance ){
			if( err ){
				err.req = bundle.req;
				err.res = bundle.res;
				return that.emit('error', err  );
			}

			if( !instance ){
				bundle.data = {message:'not found',code:404};
				return that.respond(bundle,http.notFound );
			}

			if(!that.options.returnData ){
				bundle.data = null;
				var response = http.noContent;
				return that.respond( bundle, response );
			}

			bundle.object = instance;
			that.full_dehydrate( bundle.object, bundle, function( err, data ){
				bundle.data = data;
				that.options.cache.set(bundle.toKey( 'detail') , null );
				instance.delete().then(function(){
					return that.respond( bundle );
				});
			});
		});
	}

	, create_object: function create_object( bundle, callback ){
		var format = this.format( bundle, this.options.serializer.types )
		  , that = this
		  ;

		this.deserialize( bundle.data, format, function( err, data ){
			bundle = that.bundle(bundle.req, bundle.res, data );
			bundle.object = new that.options.queryset._model( data );
			that.full_hydrate( bundle, function( err, bndl ){
				bndl.object.saveAll( function( err ){
					return callback && callback( err, bndl );
				});
			});
		});
	}

	, get_object: function( bundle, callback ){
		var filter = {};
		filter[ this.options.pk ] = bundle.req.params.pk;

		this.options
			.queryset
			._model
			.filter( filter )
			.run( function( err, results ){
				return callback && callback( err, results[0]);
			} );

		filter = null;
		return this;
	}

	, update_object: function( bundle, callback ){
		debug('update_object');
		var format = this.format( bundle, this.options.serializer.types );
		var that = this;
		this.get_object( bundle, function( err, obj ){

			if( err || !obj ){
				if( err ){
					err.req = bundle.req;
					err.res = bundle.res;
					return this.emit('error',err);
				}

				bundle.data = {message:'not found',code:404};
				return that.respond(bundle,http.notFound );
			}

			this.deserialize( bundle.data, format, function( err, data ){
				bundle.data   = data;
				bundle.object = obj;
				that.full_hydrate( bundle, function( err, bndl ){
					bndl.object.saveAll(function(err){
						return callback && callback( err, bndl );
					});
				});
			});
		}.bind( this ) );
	}

	, replace_object: function( bundle, callback ){
		var that = this
		  , format = this.format( bundle, this.options.serializer.types )
	  	  , Model = this.options.queryset._model
	  	  ;

		this.deserialize( bundle.data, format, function( err, data ){
			var pk = bundle.req.params.pk;
			bundle = that.bundle( bundle.req, bundle.res, data );
			bundle.object = {id:pk};
			that.full_hydrate( bundle, function( err, bndl ){
				Model.get( pk )
					.replace( bndl.object )
					.run(function( err ){
						return callback && callback( err, bndl );
					});
			});
		});
	}
	, buildFilters: function buildFilters( qs ){
		var remaining = null
		  , filters = this.options.filtering || {}
		  , fieldmap = this.fields
		  , r = this.options.queryset._r
		  ;

		for( var key in qs ){
			var bits = key.split(  SEP  )
 			  , filtername = 'exact'
 			  , bitlength
 			  , value
 			  , filter
 			  , fieldname
 			  , filtertype
 			  , attr
 			  ;

			value      = qs[key];
			fieldname  = bits.shift();
			bitlength  = bits.length - 1;
			filtername = bits[ bitlength ] || filtername;
			filtertype = filters[ filtername ] ? filters[bits.pop()] : filtername;
			var e;
			// exact isn't really a filter...
			if( filters[fieldname] === constants.ALL || !fieldmap[fieldname] ) {
				// pass
			} else if( !filters[ fieldname ] ){
				e  = Boom.create(400, "filtering on " + fieldname + " is not allowed");
				throw e;
			} else if( ( filters[fieldname] || []).indexOf( filtername ) === -1 ){
				e   = Boom.create(400,filtername + " filter is not allowed on field " + fieldname );
				throw e;
			}

			// should be defined on resource instance
			attr      = fieldmap[ fieldname ] ? fieldmap[fieldname].options.attribute || fieldname : fieldname;
			if( this.allowablepaths.indexOf( fieldname ) >=0 ){
				fieldname = bits.unshift( attr ) && bits.join( SEP );
				filter = filtertype( r, fieldname, typecast( value )  );
				remaining = remaining ? remaining.and( filter ) : filter;
			}
		}
		return remaining || {};
	}

	, offset: function offset( query, bundle ){
		debug('offset', bundle.req.query.offset);
		return query.skip( ~~(bundle.req.query.offset || 0 ));
	}

	, limit: function offset( query, bundle ){
		var qs = bundle.req.query
		  , lmt
		  ;

		qs.limit = qs.hasOwnProperty( 'limit' )  ? parseInt( qs.limit, 10) : qs.limit;
		lmt = isNumber( qs.limit ) ? qs.limit ? qs.limit : this.options.max : this.options.limit ? this.options.limit : 25;
		lmt = Math.min( lmt, this.options.max );
		return query.limit( lmt );
	}

	, sort: function offset( mquery, rquery ){
		var r = this.options.queryset._r;
		var allowed = this.options.ordering || [];
		var that = this;
		toArray( rquery.orderby ).forEach( function( param ){
			var bits = orderExp.exec( param )
			  , dir
			  ;

			if( !bits ){
				return;
			}else if( ~~bits[2] === 1 || allowed.indexOf( bits[2] ) === -1 ){
				return that.emit('error', Boom.create(400, "Invalid sort parameter: " + bits[2]) );
			}

			dir = bits[1] ? 'desc':'asc';
			debug('ordering %s - %s', bits[2], dir );
			mquery = mquery.orderBy( r[ dir ]( bits[2] ) );
		});
		return mquery;
	}
});

RethinkResource.extend = function( proto ){
	proto.inherits = RethinkResource;
	return new Class( proto );
};

RethinkResource.filter = function( name, fn ){
	Object.defineProperty(filters, name, {
		writable: false
	})
}
<commit_msg>overload filter function<commit_after>/*jshint laxcomma: true, smarttabs: true, node: true, unused: true */
'use strict';
/**
 * A resource instance using rethinkdb via thinky as a data source
 * @module tastypie/lib/resource/rethink
 * @author Eric Satterwhite
 * @since 0.3.2
 * @requires util
 * @requires joi
 * @requires debug
 * @requires mout/lang/isNumber
 * @requires mout/lang/toArray
 * @requires mout/lang/merge
 * @requires tastypie/lib/class
 * @requires tastypie/lib/options
 * @requires tastypie/lib/http
 * @requires tastypie/lib/resource
 */

var isNumber      = require('mout/lang/isNumber')
  , isString      = require('mout/lang/isString')
  , toArray       = require('mout/lang/toArray')
  , Boom          = require( 'boom' )
  , async         = require('async')
  , typecast      = require('mout/string/typecast')
  , Class         = require('tastypie/lib/class')
  , Options       = require('tastypie/lib/class/options')
  , Resource      = require('tastypie/lib/resource')
  , Paginator     = require('tastypie/lib/paginator')
  , http          = require('tastypie/lib/http')
  , constants     = require('tastypie/lib/constants')
  , debug         = require( 'debug' )('tastypie:resource:rethink')
  , filters       = require('./filters')
  , SEP           = '__'
  , orderExp      = /^(\-)?([\w]+)/
  , RethinkResource
  ;

  /**
   * Returns a function that allow for afunction to accept either a (key, value )signature or a ({key1:value1, key2:value2}) signature
   * @paran {Function} fn the function to overload
   * @return {Function} a function wrapper around the original function
   */
function overload( fn ){

	return function overloadedSetter( keyOrObj, value ){

		if( typeof keyOrObj !== 'string' ){
			for( var key in keyOrObj ){
				fn.call( this, key, keyOrObj[key ]);
			}
		}else{
			fn.call(this, keyOrObj, value );
		}
		return this;
	};
};
/**
 * @alias module:tastypie/lib/resource/rethink
 * @constructor
 * @param {Object} options
 * @param {String} [options.pk=id] property to be considered the primary key field of the associated model
 * @extends module:tastypie/lib/resource
 * @example
var SampleResource = new Class({
	inherits:RethinkResource
	,options:{
		queryset: Sample.filter({})
	}
	,fields:{
		age:{type:'integer', null:true, attribute:'age'}
	}
});
 */
module.exports = RethinkResource = new Class({
	inherits:Resource
	,mixin:[Options]
	,options:{
		queryset:null
		,pk:'id'
		,objectTpl:null
		,paginator: Paginator.Remote
		,max:1000
	}

	,constructor: function( options ){

		this.parent( 'constructor', options );

		this.options.objectTpl = this.options.objectTpl || this.options.queryset._model;
		var paths = Object.keys( this.fields || this.options.queryset._model._schema._schema );
		this.allowablepaths = paths.filter(function(p){
			return p !== 'id';
		});

		paths = null;
	}

	, get_list: function get_list( bundle ){
		var query = this.options.queryset.filter({})
		  , that = this
		  , filters
		  ;

		try{
			filters = this.buildFilters( bundle.req.query );
		} catch( err ){
			err.req = bundle.req;
			err.res = bundle.res;
			return this.emit('error', err);
		}

		query = query.filter( filters );
		query.count().execute( function( err, count ){

			var paginator
			  , to_be_serialized
			  ;

			try{
				query = this.sort( query, bundle.req.query );
				query = this.offset( query, bundle );
				query = this.limit( query, bundle );
			} catch( err ){
				err.req = bundle.req;
				err.res = bundle.res;
				return that.emit('error', err );
			}
			query.run( function( err, objects ){
				objects = objects || [];
				if(err){
					err.req=bundle.req;
					err.res=bundle.res;
					return that.emit('error', err );
				}
				paginator = new that.options.paginator({
					limit:bundle.req.query.limit
					,req:bundle.req
					,res:bundle.res
					,collectionName:that.options.collection
					,objects:objects
					,count: count
					,offset: bundle.req.query.offset || 0
				});

				to_be_serialized = paginator.page();
				async.map( to_be_serialized[ that.options.collection ], function(item, done){
					return that.full_dehydrate( item, bundle, done );
				}, function(err, results ){
					to_be_serialized[ that.options.collection ] = results;
					bundle.data = to_be_serialized;
					paginator = to_be_serialized = null;
					return that.respond( bundle );
				});
			});
		}.bind( this ));
	}

	, delete_detail: function delete_detail( bundle ){
		var that = this;
		this.get_object(bundle, function( err, instance ){
			if( err ){
				err.req = bundle.req;
				err.res = bundle.res;
				return that.emit('error', err  );
			}

			if( !instance ){
				bundle.data = {message:'not found',code:404};
				return that.respond(bundle,http.notFound );
			}

			if(!that.options.returnData ){
				bundle.data = null;
				var response = http.noContent;
				return that.respond( bundle, response );
			}

			bundle.object = instance;
			that.full_dehydrate( bundle.object, bundle, function( err, data ){
				bundle.data = data;
				that.options.cache.set(bundle.toKey( 'detail') , null );
				instance.delete().then(function(){
					return that.respond( bundle );
				});
			});
		});
	}

	, create_object: function create_object( bundle, callback ){
		var format = this.format( bundle, this.options.serializer.types )
		  , that = this
		  ;

		this.deserialize( bundle.data, format, function( err, data ){
			bundle = that.bundle(bundle.req, bundle.res, data );
			bundle.object = new that.options.queryset._model( data );
			that.full_hydrate( bundle, function( err, bndl ){
				bndl.object.saveAll( function( err ){
					return callback && callback( err, bndl );
				});
			});
		});
	}

	, get_object: function( bundle, callback ){
		var filter = {};
		filter[ this.options.pk ] = bundle.req.params.pk;

		this.options
			.queryset
			._model
			.filter( filter )
			.run( function( err, results ){
				return callback && callback( err, results[0]);
			} );

		filter = null;
		return this;
	}

	, update_object: function( bundle, callback ){
		debug('update_object');
		var format = this.format( bundle, this.options.serializer.types );
		var that = this;
		this.get_object( bundle, function( err, obj ){

			if( err || !obj ){
				if( err ){
					err.req = bundle.req;
					err.res = bundle.res;
					return this.emit('error',err);
				}

				bundle.data = {message:'not found',code:404};
				return that.respond(bundle,http.notFound );
			}

			this.deserialize( bundle.data, format, function( err, data ){
				bundle.data   = data;
				bundle.object = obj;
				that.full_hydrate( bundle, function( err, bndl ){
					bndl.object.saveAll(function(err){
						return callback && callback( err, bndl );
					});
				});
			});
		}.bind( this ) );
	}

	, replace_object: function( bundle, callback ){
		var that = this
		  , format = this.format( bundle, this.options.serializer.types )
	  	  , Model = this.options.queryset._model
	  	  ;

		this.deserialize( bundle.data, format, function( err, data ){
			var pk = bundle.req.params.pk;
			bundle = that.bundle( bundle.req, bundle.res, data );
			bundle.object = {id:pk};
			that.full_hydrate( bundle, function( err, bndl ){
				Model.get( pk )
					.replace( bndl.object )
					.run(function( err ){
						return callback && callback( err, bndl );
					});
			});
		});
	}
	, buildFilters: function buildFilters( qs ){
		var remaining = null
		  , filters = this.options.filtering || {}
		  , fieldmap = this.fields
		  , r = this.options.queryset._r
		  ;

		for( var key in qs ){
			var bits = key.split(  SEP  )
 			  , filtername = 'exact'
 			  , bitlength
 			  , value
 			  , filter
 			  , fieldname
 			  , filtertype
 			  , attr
 			  ;

			value      = qs[key];
			fieldname  = bits.shift();
			bitlength  = bits.length - 1;
			filtername = bits[ bitlength ] || filtername;
			filtertype = filters[ filtername ] ? filters[bits.pop()] : filtername;
			var e;
			// exact isn't really a filter...
			if( filters[fieldname] === constants.ALL || !fieldmap[fieldname] ) {
				// pass
			} else if( !filters[ fieldname ] ){
				e  = Boom.create(400, "filtering on " + fieldname + " is not allowed");
				throw e;
			} else if( ( filters[fieldname] || []).indexOf( filtername ) === -1 ){
				e   = Boom.create(400,filtername + " filter is not allowed on field " + fieldname );
				throw e;
			}

			// should be defined on resource instance
			attr      = fieldmap[ fieldname ] ? fieldmap[fieldname].options.attribute || fieldname : fieldname;
			if( this.allowablepaths.indexOf( fieldname ) >=0 ){
				fieldname = bits.unshift( attr ) && bits.join( SEP );
				filter = filtertype( r, fieldname, typecast( value )  );
				remaining = remaining ? remaining.and( filter ) : filter;
			}
		}
		return remaining || {};
	}

	, offset: function offset( query, bundle ){
		debug('offset', bundle.req.query.offset);
		return query.skip( ~~(bundle.req.query.offset || 0 ));
	}

	, limit: function offset( query, bundle ){
		var qs = bundle.req.query
		  , lmt
		  ;

		qs.limit = qs.hasOwnProperty( 'limit' )  ? parseInt( qs.limit, 10) : qs.limit;
		lmt = isNumber( qs.limit ) ? qs.limit ? qs.limit : this.options.max : this.options.limit ? this.options.limit : 25;
		lmt = Math.min( lmt, this.options.max );
		return query.limit( lmt );
	}

	, sort: function offset( mquery, rquery ){
		var r = this.options.queryset._r;
		var allowed = this.options.ordering || [];
		var that = this;
		toArray( rquery.orderby ).forEach( function( param ){
			var bits = orderExp.exec( param )
			  , dir
			  ;

			if( !bits ){
				return;
			}else if( ~~bits[2] === 1 || allowed.indexOf( bits[2] ) === -1 ){
				return that.emit('error', Boom.create(400, "Invalid sort parameter: " + bits[2]) );
			}

			dir = bits[1] ? 'desc':'asc';
			debug('ordering %s - %s', bits[2], dir );
			mquery = mquery.orderBy( r[ dir ]( bits[2] ) );
		});
		return mquery;
	}
});

RethinkResource.extend = function( proto ){
	proto.inherits = RethinkResource;
	return new Class( proto );
};

RethinkResource.filter = overload(function( name, fn ){
	Object.defineProperty(filters, name, {
		writable: false
	})
})
<|endoftext|>


<commit_before>var EventEmitter = require('events');
var util = require('util');

module.exports = ResourceLoader;

// TODO: Implement custom class for objects as they are much more complex.
var IMAGE_FIELDS = {
  '.material': ['frames', 'platformImage', 'stairImage'],
  '.matmod': ['frames']
};

var IMAGE_FIELD_SUFFIX = '__image';

function ResourceLoader(assetsManager, extension) {
  EventEmitter.call(this);

  this.assets = assetsManager;
  this.extension = extension;

  this.index = null;
  this.images = null;

  this._loadingIndex = false;
  this._pending = [];
  this._emitting = false;
}
util.inherits(ResourceLoader, EventEmitter);

ResourceLoader.prototype.get = function (id) {
  if (!this.index) return null;
  return this.index[id] || null;
};

ResourceLoader.prototype.getImage = function (idOrResource, fieldName) {
  var resource = typeof idOrResource == 'string' ? this.get(idOrResource) : idOrResource;
  if (!resource) return null;

  return resource[fieldName + IMAGE_FIELD_SUFFIX] || null;
};

ResourceLoader.prototype.loadImages = function (ids) {
  var fields = IMAGE_FIELDS[this.extension];
  if (!fields) return;

  if (this._pending) {
    // Ensure that we're loading the index.
    this.loadIndex();

    // Queue the requested ids for later.
    Array.prototype.push.apply(this._pending, ids);

    return;
  }

  for (var i = 0; i < ids.length; i++) {
    var resource = this.index[ids[i]];
    for (var j = 0; j < fields.length; j++) {
      this._loadImage(resource, fields[j]);
    }
  }
};

ResourceLoader.prototype.loadIndex = function () {
  if (this._loadingIndex) return;
  this._loadingIndex = true;

  // TODO: Fat arrows.
  var self = this;
  this.assets.loadResources(this.extension, function (err, index) {
    self._loadingIndex = false;
    self.index = index;

    var pending = self._pending;
    self._pending = null;
    self.loadImages(pending);
  });
};

ResourceLoader.prototype._loadImage = function (resource, field) {
  if (!(field in resource)) return;

  var imageField = field + IMAGE_FIELD_SUFFIX;

  // If the image is already loading, do nothing.
  if (imageField in resource) return;
  resource[imageField] = null;

  // Get an absolute path to the image.
  var path = resource[field];
  if (path[0] != '/') {
    var base = resource.__path__;
    path = base.substr(0, base.lastIndexOf('/') + 1) + path;
  }

  var self = this;
  this.assets.getBlobURL(path, function (err, url) {
    var image = new Image();
    image.src = url;
    image.onload = function () {
      resource[imageField] = image;
      if (!self._emitting) {
        self._emitting = true;
        process.nextTick(function () {
          self.emit('images');
          self._emitting = false;
        });
      }
    };
  });
};
<commit_msg>Warn if resources are missing<commit_after>var EventEmitter = require('events');
var util = require('util');

module.exports = ResourceLoader;

// TODO: Implement custom class for objects as they are much more complex.
var IMAGE_FIELDS = {
  '.material': ['frames', 'platformImage', 'stairImage'],
  '.matmod': ['frames']
};

var IMAGE_FIELD_SUFFIX = '__image';

function ResourceLoader(assetsManager, extension) {
  EventEmitter.call(this);

  this.assets = assetsManager;
  this.extension = extension;

  this.index = null;
  this.images = null;

  this._loadingIndex = false;
  this._pending = [];
  this._emitting = false;
}
util.inherits(ResourceLoader, EventEmitter);

ResourceLoader.prototype.get = function (id) {
  if (!this.index) return null;
  return this.index[id] || null;
};

ResourceLoader.prototype.getImage = function (idOrResource, fieldName) {
  var resource = typeof idOrResource == 'string' ? this.get(idOrResource) : idOrResource;
  if (!resource) return null;

  return resource[fieldName + IMAGE_FIELD_SUFFIX] || null;
};

ResourceLoader.prototype.loadImages = function (ids) {
  var fields = IMAGE_FIELDS[this.extension];
  if (!fields) return;

  if (this._pending) {
    // Ensure that we're loading the index.
    this.loadIndex();

    // Queue the requested ids for later.
    Array.prototype.push.apply(this._pending, ids);

    return;
  }

  for (var i = 0; i < ids.length; i++) {
    var resource = this.index[ids[i]];
    if (!resource) {
      console.warn('Missing ' + this.extension.substr(1) + ' with id ' + ids[i]);
      continue;
    }

    for (var j = 0; j < fields.length; j++) {
      this._loadImage(resource, fields[j]);
    }
  }
};

ResourceLoader.prototype.loadIndex = function () {
  if (this._loadingIndex) return;
  this._loadingIndex = true;

  // TODO: Fat arrows.
  var self = this;
  this.assets.loadResources(this.extension, function (err, index) {
    self._loadingIndex = false;
    self.index = index;

    var pending = self._pending;
    self._pending = null;
    self.loadImages(pending);
  });
};

ResourceLoader.prototype._loadImage = function (resource, field) {
  if (!(field in resource)) return;

  var imageField = field + IMAGE_FIELD_SUFFIX;

  // If the image is already loading, do nothing.
  if (imageField in resource) return;
  resource[imageField] = null;

  // Get an absolute path to the image.
  var path = resource[field];
  if (path[0] != '/') {
    var base = resource.__path__;
    path = base.substr(0, base.lastIndexOf('/') + 1) + path;
  }

  var self = this;
  this.assets.getBlobURL(path, function (err, url) {
    var image = new Image();
    image.src = url;
    image.onload = function () {
      resource[imageField] = image;
      if (!self._emitting) {
        self._emitting = true;
        process.nextTick(function () {
          self.emit('images');
          self._emitting = false;
        });
      }
    };
  });
};
<|endoftext|>


<commit_before>var State = require('ampersand-state');
var callerId = require('caller-id');
var TrackerCollection = require('../models/tracker-collection');
var _ = require('lodash');
var format = require('util').format;

var debug = require('debug')('mongodb-js-metrics:resources:base');

module.exports = State.extend({
  idAttribute: 'id',
  id: 'Base',
  collections: {
    trackers: TrackerCollection
  },
  initialize: function() {
    this.on('change', this._update_trackers.bind(this));
    this.listenTo(this.trackers, 'add reset', this._update_trackers.bind(this));
  },
  /**
   * Either the trackers or the properties of this resource have changed. In
   * any case, pass own properties to the trackers.
   */
  _update_trackers: function() {
    debug('tracker or properties have changed, updating trackers.', this.serialize());
    this.trackers.each(function(tracker) {
      tracker.set(this.serialize());
    }.bind(this));
  },
  /**
   * send any GA hit. This is the only actual call to GA.
   *
   * @param {Object} options   options to send
   * @api private
   */
  _send_ga: function(options, callback) {
    var tracker = this.trackers.get('ga');
    if (tracker) {
      return tracker.send(options, callback);
    }
    callback(new Error('Google Analytics tracker not set up.'));
  },
  /**
   * prepare GA hit with a `event` hitType. Category and action
   * are set automatically if not provided.
   *
   * @param {Object} options  options can contain eventCategory, eventAction,
   *                          eventLabel, eventValue.
   * @api private
   */
  _send_ga_event: function(options, callback) {
    var resource = options.resource || this.id;
    var action = options.action || callerId.getData().methodName;

    options = _.defaults(options || {}, {
      hitType: 'event',
      eventCategory: resource,
      eventAction: action
    });
    // debug('_send_ga_event, adding hitType, eventCategory, eventAction', options);
    this._send_ga(options, callback);
  },
  /**
   * send an intercom event. This is the only actual call to the intercom tracker.
   *
   * @param {String} eventName   eventName to send
   * @param {Object} metadata    attached metadata (5 keys max!)
   * @api private
   */
  _send_intercom: function(eventName, metadata, callback) {
    var tracker = this.trackers.get('intercom');
    if (tracker) {
      return tracker.send(eventName, metadata, callback);
    }
    if (callback) {
      return callback(new Error('Intercom tracker not set up.'));
    }
  },
  /**
   * prepare sending an event to intercom. Re-format resource and action into
   * `<Resource> <action>` string, attach all other relevant information
   * as metadata.
   *
   * @param {Object} options    options containing metadata to be sent
   * @api private
   */
  _send_intercom_event: function(options, callback) {
    var resource = options.resource || this.id;
    var action = options.action || callerId.getData().methodName;

    var eventName = format('%s %s', resource, action);
    // debug('_send_intercom_event %s with metadata %j', eventName, options);
    this._send_intercom(eventName, options, callback);
  },
  _send_bugsnag: function(error, metadata) {
    var severity = metadata.severity || callerId.getData().methodName;
    var tracker = this.trackers.get('bugsnag');
    if (tracker) {
      tracker.send(error, metadata || {}, severity);
    }
  }
});
<commit_msg>delete "rename" metadata keys.<commit_after>var State = require('ampersand-state');
var callerId = require('caller-id');
var TrackerCollection = require('../models/tracker-collection');
var _ = require('lodash');
var format = require('util').format;

var debug = require('debug')('mongodb-js-metrics:resources:base');

module.exports = State.extend({
  idAttribute: 'id',
  id: 'Base',
  collections: {
    trackers: TrackerCollection
  },
  initialize: function() {
    this.on('change', this._update_trackers.bind(this));
    this.listenTo(this.trackers, 'add reset', this._update_trackers.bind(this));
  },
  /**
   * Either the trackers or the properties of this resource have changed. In
   * any case, pass own properties to the trackers.
   */
  _update_trackers: function() {
    debug('tracker or properties have changed, updating trackers.', this.serialize());
    this.trackers.each(function(tracker) {
      tracker.set(this.serialize());
    }.bind(this));
  },
  /**
   * send any GA hit. This is the only actual call to GA.
   *
   * @param {Object} options   options to send
   * @api private
   */
  _send_ga: function(options, callback) {
    var tracker = this.trackers.get('ga');
    if (tracker) {
      return tracker.send(options, callback);
    }
    callback(new Error('Google Analytics tracker not set up.'));
  },
  /**
   * prepare GA hit with a `event` hitType. Category and action
   * are set automatically if not provided.
   *
   * @param {Object} options  options can contain eventCategory, eventAction,
   *                          eventLabel, eventValue.
   * @api private
   */
  _send_ga_event: function(options, callback) {
    var resource = options.resource || this.id;
    var action = options.action || callerId.getData().methodName;
    delete options.action;
    delete options.resource;

    options = _.defaults(options || {}, {
      hitType: 'event',
      eventCategory: resource,
      eventAction: action
    });
    // debug('_send_ga_event, adding hitType, eventCategory, eventAction', options);
    this._send_ga(options, callback);
  },
  /**
   * send an intercom event. This is the only actual call to the intercom tracker.
   *
   * @param {String} eventName   eventName to send
   * @param {Object} metadata    attached metadata (5 keys max!)
   * @api private
   */
  _send_intercom: function(eventName, metadata, callback) {
    var tracker = this.trackers.get('intercom');
    if (tracker) {
      return tracker.send(eventName, metadata, callback);
    }
    if (callback) {
      return callback(new Error('Intercom tracker not set up.'));
    }
  },
  /**
   * prepare sending an event to intercom. Re-format resource and action into
   * `<Resource> <action>` string, attach all other relevant information
   * as metadata.
   *
   * @param {Object} options    options containing metadata to be sent
   * @api private
   */
  _send_intercom_event: function(options, callback) {
    var resource = options.resource || this.id;
    var action = options.action || callerId.getData().methodName;
    delete options.resource;
    delete options.action;

    var eventName = format('%s %s', resource, action);
    // debug('_send_intercom_event %s with metadata %j', eventName, options);
    this._send_intercom(eventName, options, callback);
  },
  _send_bugsnag: function(error, metadata) {
    var severity = metadata.severity || callerId.getData().methodName;
    delete metadata.severity;

    var tracker = this.trackers.get('bugsnag');
    if (tracker) {
      tracker.send(error, metadata || {}, severity);
    }
  }
});
<|endoftext|>


<commit_before>
"use strict";

var express   = require('express'),
    router    = express.Router(),
    model     = require('../model/db'),
    Promise   = require('bluebird'),
    moment    = require('moment'),
    _         = require('underscore'),
    get_and_validate_leave_params = require('./validator/leave_request'),
    CalendarMonth                 = require('../model/calendar_month');

router.post('/bookleave/', function(req, res){

    Promise.join (
        req.user.promise_users_I_can_manage(),
        req.user.get_company_with_all_leave_types(),
        Promise.try( function(){return get_and_validate_leave_params({req : req}) }),
        function(users, company, valide_attributes){
            // TODO make sure that indexes submitted map to existing objects
            var employee = users[valide_attributes.user || req.user],
                leave_type = company.leave_types[valide_attributes.leave_type];

            if (!employee) {
                req.session.flash_error('Incorrect employee');
                throw new Error( 'Got validation errors' );
            }

            if (!leave_type) {
                req.session.flash_error('Incorrect leave type');
                throw new Error( 'Got validation errors' );
            }

            return employee.promise_superviser()

            .then(function(superviser){
                return model.Leave.create({
                    UserId           : employee.id,
                    leaveTypeId      : leave_type.id,
                    status           : 1,
                    ApproverId       : superviser.id,
                    employee_comment : valide_attributes.reason,
                });
            });
        }
    )

    .then(function(valide_attributes){
        // TODO
        // check that current user can book a holiday for the user submitted in
        // a form
        //
        // Add the leave request into the system
        //
        req.session.flash_message('New leave request was added');
        res.redirect_with_session('../');
    })

    .catch(function(error){
        console.error(
            'An error occured when user '+req.user.id+
            ' try to create a leave request: '+error
        );
        req.session.flash_error('Failed to create a leave request');
        res.redirect_with_session('../');
    });

});

router.get('/', function(req, res) {

    res.locals.custom_java_script.push(
        '/js/bootstrap-datepicker.js'
    );
    res.locals.custom_css.push(
        '/css/bootstrap-datepicker3.standalone.css'
    );

    Promise.join(
        req.user.promise_calendar(),
        req.user.get_company_with_all_leave_types(),
        req.user.promise_users_I_can_manage(),
        function(calendar, company, employees){
            res.render('calendar', {
                calendar      : calendar,
                company       : company,
                employees     : employees,
                booking_start : moment(),
                booking_end   : moment(),
            });
        }
    );

});

module.exports = router;
<commit_msg>Some more changes for adding new booking<commit_after>
"use strict";

var express   = require('express'),
    router    = express.Router(),
    model     = require('../model/db'),
    Promise   = require('bluebird'),
    moment    = require('moment'),
    _         = require('underscore'),
    get_and_validate_leave_params = require('./validator/leave_request'),
    CalendarMonth                 = require('../model/calendar_month');

router.post('/bookleave/', function(req, res){

    Promise.join (
        req.user.promise_users_I_can_manage(),
        req.user.get_company_with_all_leave_types(),
        Promise.try( function(){return get_and_validate_leave_params({req : req})}),
        function(users, company, valide_attributes){
            // Make sure that indexes submitted map to existing objects
            var employee = users[valide_attributes.user || req.user],
                leave_type = company.leave_types[valide_attributes.leave_type];

            if (!employee) {
                req.session.flash_error('Incorrect employee');
                throw new Error( 'Got validation errors' );
            }

            if (!leave_type) {
                req.session.flash_error('Incorrect leave type');
                throw new Error( 'Got validation errors' );
            }

            // TODO Make sure new booking does not overlap with existing ones

            // TODO Following lines is better to mmove somewhere into its own
            // method so it is reusable
            return employee.promise_superviser()

            .then(function(superviser){
                return model.Leave.create({
                    UserId           : employee.id,
                    leaveTypeId      : leave_type.id,
                    status           : 1,
                    ApproverId       : superviser.id,
                    employee_comment : valide_attributes.reason,
                })
                .then(function(leave){
                    return model.LeaveDay.bulkCreate([{
                        date     : moment(valide_attributes.from_date).format('yyyy-mm-dd'),
                        day_part : 1,
                        LeaveId  : leave.id,
                    }]);
                });
            });
        }
    )

    .then(function(valide_attributes){
        // TODO
        // check that current user can book a holiday for the user submitted in
        // a form
        //
        // Add the leave request into the system
        //
        req.session.flash_message('New leave request was added');
        res.redirect_with_session('../');
    })

    .catch(function(error){
        console.error(
            'An error occured when user '+req.user.id+
            ' try to create a leave request: '+error
        );
        req.session.flash_error('Failed to create a leave request');
        res.redirect_with_session('../');
    });

});

router.get('/', function(req, res) {

    res.locals.custom_java_script.push(
        '/js/bootstrap-datepicker.js'
    );
    res.locals.custom_css.push(
        '/css/bootstrap-datepicker3.standalone.css'
    );

    Promise.join(
        req.user.promise_calendar(),
        req.user.get_company_with_all_leave_types(),
        req.user.promise_users_I_can_manage(),
        function(calendar, company, employees){
            res.render('calendar', {
                calendar      : calendar,
                company       : company,
                employees     : employees,
                booking_start : moment(),
                booking_end   : moment(),
            });
        }
    );

});

module.exports = router;
<|endoftext|>


<commit_before>var Ship = function(map, path, marker, nodeProvider) {
  this.map_ = map;
  this.path_ = path;
  this.marker_ = marker;
  this.nodeProvider_ = nodeProvider;
  this.lastNode_ = this.nodeProvider_();
  this.nextNode_ = this.nodeProvider_(this.lastNode_.index);

  this.path_.push(this.lastNode_.latLng);
  this.path_.push(this.nextNode_.latLng);

  this.speed_ = Ship.lerp(Ship.MIN_RATE, Ship.MAX_RATE, Math.random());
  this.t_ = (Math.random() * Ship.MAX_INITIAL_DISTANCE) / this.speed_;
};

Ship.MAX_INITIAL_DISTANCE = 50;
Ship.MIN_RATE = 0.025;
Ship.MAX_RATE = 0.07;

Ship.lerp = function(a, b, t) {
  return a + t * (b - a);
};

Ship.dist = function(pointA, pointB) {
  var xDist = pointA.x - pointB.x;
  var yDist = pointA.y - pointB.y;
  return Math.sqrt(xDist*xDist + yDist*yDist);
};

Ship.correctForAntimeridian = function(from, to) {
  var xDist = to.x - from.x;
  if (Math.abs(xDist + 256) < Math.abs(xDist)) {
    to.x += 256;
  } else if (Math.abs(xDist - 256) < Math.abs(xDist)) {
    to.x -= 256;
  }
};

Ship.prototype.update = function(dt) {
  this.t_ += Math.max(0, dt);
  var toTravel = this.t_ * this.speed_;

  var proj = this.map_.getProjection();
  var lastPoint = proj.fromLatLngToPoint(this.lastNode_.latLng);
  var nextPoint = proj.fromLatLngToPoint(this.nextNode_.latLng);
  Ship.correctForAntimeridian(lastPoint, nextPoint);
  var dist = Ship.dist(lastPoint, nextPoint);

  // add new legs until distance to go is less than length of next leg
  while (toTravel - dist > 0) {
    toTravel -= dist;

    // get new next point
    this.path_.setAt(this.path_.length - 1, this.nextNode_.latLng);
    this.lastNode_ = this.nextNode_;
    this.nextNode_ = this.nodeProvider_(this.lastNode_.index);
    this.path_.push(this.nextNode_);

    // update distance for next leg
    lastPoint = nextPoint;
    nextPoint = proj.fromLatLngToPoint(this.nextNode_.latLng);
    Ship.correctForAntimeridian(lastPoint, nextPoint);
    dist = Ship.dist(lastPoint, nextPoint);

    if (nextPoint.x < lastPoint.x) {
      this.marker_.setIcon({
        url: 'pirate_marker_64_west.png',
        scaledSize: new google.maps.Size(32, 32)
      });
    } else {
      this.marker_.setIcon({
        url: 'pirate_marker_64.png',
        scaledSize: new google.maps.Size(32, 32)
      });
    }
  }
  this.t_ = toTravel / this.speed_;

  nextPoint.x = Ship.lerp(lastPoint.x, nextPoint.x, toTravel / dist);
  nextPoint.y = Ship.lerp(lastPoint.y, nextPoint.y, toTravel / dist);
  var currentLatLng = proj.fromPointToLatLng(nextPoint);
  this.path_.setAt(this.path_.length - 1, currentLatLng);
  this.marker_.setPosition(currentLatLng);
};
<commit_msg>Updated ship.js for pirates demo.<commit_after>var Ship = function(map, path, marker, nodeProvider) {
  this.map_ = map;
  this.path_ = path;
  this.marker_ = marker;
  this.nodeProvider_ = nodeProvider;
  this.lastNode_ = this.nodeProvider_();
  this.nextNode_ = this.nodeProvider_(this.lastNode_.index);

  this.path_.push(this.lastNode_.latLng);
  this.path_.push(this.nextNode_.latLng);

  this.speed_ = Ship.lerp(Ship.MIN_RATE, Ship.MAX_RATE, Math.random());
  this.t_ = (Math.random() * Ship.MAX_INITIAL_DISTANCE) / this.speed_;
  this.directionInitted_ = false;
};

Ship.MAX_INITIAL_DISTANCE = 50;
Ship.MIN_RATE = 0.025;
Ship.MAX_RATE = 0.07;

Ship.lerp = function(a, b, t) {
  return a + t * (b - a);
};

Ship.dist = function(pointA, pointB) {
  var xDist = pointA.x - pointB.x;
  var yDist = pointA.y - pointB.y;
  return Math.sqrt(xDist*xDist + yDist*yDist);
};

Ship.correctForAntimeridian = function(from, to) {
  var xDist = to.x - from.x;
  if (Math.abs(xDist + 256) < Math.abs(xDist)) {
    to.x += 256;
  } else if (Math.abs(xDist - 256) < Math.abs(xDist)) {
    to.x -= 256;
  }
};

Ship.prototype.update = function(dt) {
  this.t_ += Math.max(0, dt);
  var toTravel = this.t_ * this.speed_;

  var proj = this.map_.getProjection();
  var lastPoint = proj.fromLatLngToPoint(this.lastNode_.latLng);
  var nextPoint = proj.fromLatLngToPoint(this.nextNode_.latLng);
  Ship.correctForAntimeridian(lastPoint, nextPoint);
  var dist = Ship.dist(lastPoint, nextPoint);

  var westward = nextPoint.x < lastPoint.x;

  // add new legs until distance to go is less than length of next leg
  while (toTravel - dist > 0) {
    toTravel -= dist;

    // get new next point
    this.path_.setAt(this.path_.length - 1, this.nextNode_.latLng);
    this.lastNode_ = this.nextNode_;
    this.nextNode_ = this.nodeProvider_(this.lastNode_.index);
    this.path_.push(this.nextNode_);

    // update distance for next leg
    lastPoint = nextPoint;
    nextPoint = proj.fromLatLngToPoint(this.nextNode_.latLng);
    Ship.correctForAntimeridian(lastPoint, nextPoint);
    dist = Ship.dist(lastPoint, nextPoint);
  }
  this.t_ = toTravel / this.speed_;

  var newWestward = nextPoint.x < lastPoint.x;
  if (newWestward !== westward || !this.directionInitted_) {
    this.marker_.setIcon({
      url: 'pirate_marker_64' + (newWestward ? '_west' : '') + '.png',
      scaledSize: new google.maps.Size(32, 32)
    });
    this.directionInitted_ = true;
  }

  nextPoint.x = Ship.lerp(lastPoint.x, nextPoint.x, toTravel / dist);
  nextPoint.y = Ship.lerp(lastPoint.y, nextPoint.y, toTravel / dist);
  var currentLatLng = proj.fromPointToLatLng(nextPoint);
  this.path_.setAt(this.path_.length - 1, currentLatLng);
  this.marker_.setPosition(currentLatLng);
};
<|endoftext|>


<commit_before>var UnauthorizedError = require('../util/errors/unauthorized');
var InvalidRequestError = require('../util/errors/invalid-request');
var UnknownResourceError = require('../util/errors/unknown-resource');
var check = require('validator').check;
var Record = require('../models/record');
var ops = require('../util/ops');

module.exports = exports = function(app, api) {

	app.get('/records', function(req, res, next) {
		var user = req.user;
		var skip = req.param('skip') || 0;
		var limit = req.param('limit') || 0;
		var search = req.param('search');

		try {
			skip && check(+skip, 'skip parameter must be a positive integer.').isNumeric().min(0);
			limit && check(+limit, 'limit parameter must be a positive integer.').isNumeric().min(0);
		} catch(err) {
			return next(err);
		}

		var isAllowed = user.hasPermission(ops.READ, {type: 'Record'});
		if(isAllowed) {
			var q = Record.find()
			skip && q.skip(skip);
			limit && q.limit(limit);
			if(search) {
				var tokens = ""
			}
			q.exec(function(err, records) {
				if(err) return next(err);
				return res.send(records.filter(function(r) {
					return user.hasPermission(ops.READ, r)
				}));
			});
		} else return next(new UnauthorizedError());

	});

	app.post('/records', function(req, res, next) {
		var user = req.user;
		var data = req.body;
		if(data) {
			var isAllowed = user.hasPermission(ops.CREATE, data);
			if(isAllowed) {
				var rec = new Record(data);
				rec.creator = user._id;
				rec.save(function(err, record) {
					if(err) return next(err);
					res.send(record.decrypt());
				});
			} else return next(new UnauthorizedError());
		} else return next(new InvalidRequestError());
	});

	app.put('/records/:recordId', function(req, res, next) {
		var recordId;
		var user = req.user;
		var newRecord = req.body;
		var recordId = req.params.recordId;
		if(newRecord && recordId) {
			Record.findById(recordId, function(err, record){
				if(err) return next(err);
				if(record) {
					var isAllowed = user.hasPermission(ops.UPDATE, record);
					if(isAllowed) {
						record.label = newRecord.label;
						record.text = newRecord.text;
						record.tags = newRecord.tags;
						record.save(function(err, record) {
							if(err) return next(err);
							res.send(200, record.decrypt());
						});
					} else return next(new UnauthorizedError());
				} else return next(new UnknownResourceError());
			})
		} else return next(new InvalidRequestError());
	});

	app.get('/records/:recordId', function(req, res, next) {
		var user = req.user;
		var recordId = req.params.recordId;
		Record.findOne({_id: recordId}, function(err, record){
			if(err) return next(err);
			if(record) {
				var isAllowed = user.hasPermission(ops.READ, record);
				if(isAllowed) {
					return res.send(record);
				} else return next(new UnauthorizedError());
			} else return next(new UnknownResourceError());
		});
	});

};<commit_msg>Search filter GET /records<commit_after>var UnauthorizedError = require('../util/errors/unauthorized');
var InvalidRequestError = require('../util/errors/invalid-request');
var UnknownResourceError = require('../util/errors/unknown-resource');
var check = require('validator').check;
var Record = require('../models/record');
var ops = require('../util/ops');

module.exports = exports = function(app, api) {

	app.get('/records', function(req, res, next) {
		var user = req.user;
		var skip = req.param('skip') || 0;
		var limit = req.param('limit') || 0;
		var search = req.param('search');

		try {
			skip && check(+skip, 'skip parameter must be a positive integer.').isNumeric().min(0);
			limit && check(+limit, 'limit parameter must be a positive integer.').isNumeric().min(0);
			search && check(search, 'search parameter must be an alphanumeric text.').is(/[^\*\(\)\{\}]/i);
		} catch(err) {
			return next(err);
		}

		var isAllowed = user.hasPermission(ops.READ, {type: 'Record'});
		if(isAllowed) {
			var q = Record.find()
			skip && q.skip(skip);
			limit && q.limit(limit);
			if(search) {
				var or = [];
				var tokens = search.split(' ');
				if(tokens.length) {
					or.push({
						label: new RegExp(tokens.join('|'), 'i')
					});
					or.push({
						tags: {'$in': tokens}
					});
				}
				q.or(or);
			}
			q.exec(function(err, records) {
				if(err) return next(err);
				return res.send(records.filter(function(r) {
					return user.hasPermission(ops.READ, r)
				}));
			});
		} else return next(new UnauthorizedError());

	});

	app.post('/records', function(req, res, next) {
		var user = req.user;
		var data = req.body;
		if(data) {
			var isAllowed = user.hasPermission(ops.CREATE, data);
			if(isAllowed) {
				var rec = new Record(data);
				rec.creator = user._id;
				rec.save(function(err, record) {
					if(err) return next(err);
					res.send(record.decrypt());
				});
			} else return next(new UnauthorizedError());
		} else return next(new InvalidRequestError());
	});

	app.put('/records/:recordId', function(req, res, next) {
		var recordId;
		var user = req.user;
		var newRecord = req.body;
		var recordId = req.params.recordId;
		if(newRecord && recordId) {
			Record.findById(recordId, function(err, record){
				if(err) return next(err);
				if(record) {
					var isAllowed = user.hasPermission(ops.UPDATE, record);
					if(isAllowed) {
						record.label = newRecord.label;
						record.text = newRecord.text;
						record.tags = newRecord.tags;
						record.save(function(err, record) {
							if(err) return next(err);
							res.send(200, record.decrypt());
						});
					} else return next(new UnauthorizedError());
				} else return next(new UnknownResourceError());
			})
		} else return next(new InvalidRequestError());
	});

	app.get('/records/:recordId', function(req, res, next) {
		var user = req.user;
		var recordId = req.params.recordId;
		Record.findOne({_id: recordId}, function(err, record){
			if(err) return next(err);
			if(record) {
				var isAllowed = user.hasPermission(ops.READ, record);
				if(isAllowed) {
					return res.send(record);
				} else return next(new UnauthorizedError());
			} else return next(new UnknownResourceError());
		});
	});

};<|endoftext|>


<commit_before>/**
 * @fileoverview Validation rules with bem-naming tech from Yandex
 * @author Ivan Sobolev
 */

"use strict";

var lodash = require("lodash"),
    bemNaming = require("bem-naming"),
    allRules = require("./rules");

function ruleValidator($, rule_id, options) {
    this.rule = allRules[rule_id];

    this.input = options.input;
    this.source = options.source;
    this.bemNaming = bemNaming({
                    elem:         options.elem,
                    mod:          options.mod,
                    wordPattern:  options.wordPattern
                });

    this.valid = true;
    if ( allRules[rule_id] && this.isRuleOptionsValid() ) {
        this.valid = allRules[rule_id].valid(this.bemNaming, this.input, this.source, $);
    }

    console.log(this.valid, rule_id);

};

ruleValidator.prototype = {
    constructor: ruleValidator,

    isRuleOptionsValid: function() {
        if (    this.rule.isBlock && this.bemNaming.isBlock(this.input)        ||
                this.rule.isElem && this.bemNaming.isElem(this.input)          ||
                this.rule.isBlockMod && this.bemNaming.isBlockMod(this.input)  ||
                this.rule.isElemMod && this.bemNaming.isElemMod(this.input) )  {

            return true;
        }

        return false;
    }
};

module.exports = ruleValidator;
<commit_msg>minor fix<commit_after>/**
 * @fileoverview Validation rules with bem-naming tech from Yandex
 * @author Ivan Sobolev
 */

"use strict";

var lodash = require("lodash"),
    bemNaming = require("bem-naming"),
    allRules = require("./rules");

function ruleValidator($, rule_id, options) {
    this.rule = allRules[rule_id];

    this.input = options.input;
    this.source = options.source;
    this.bemNaming = bemNaming({
                    elem:         options.elem,
                    mod:          options.mod,
                    wordPattern:  options.wordPattern
                });

    this.valid = true;
    if ( allRules[rule_id] && this.isRuleOptionsValid() ) {
        this.valid = allRules[rule_id].valid(this.bemNaming, this.input, this.source, $);
    }
};

ruleValidator.prototype = {
    constructor: ruleValidator,

    isRuleOptionsValid: function() {
        if (    this.rule.isBlock && this.bemNaming.isBlock(this.input)        ||
                this.rule.isElem && this.bemNaming.isElem(this.input)          ||
                this.rule.isBlockMod && this.bemNaming.isBlockMod(this.input)  ||
                this.rule.isElemMod && this.bemNaming.isElemMod(this.input) )  {

            return true;
        }

        return false;
    }
};

module.exports = ruleValidator;
<|endoftext|>


<commit_before>// Copyright 2011 Marcel Laverdet (code partially borrowed from original streamline fibers runtime)
"use strict";

var Fiber = require('fibers');
var util = require('./util');

var g = util.getGlobals('fibers');

exports.await = function(object, property, index1, index2, returnArray) {
	if (returnArray) console.error("GOT RETURNARRAY");
	var bound = typeof property !== "function";
	var fn = bound ? object[property] : property;
	if (typeof fn !== "function") throw util.typeError("cannot call", "function", fn);
	var key = 'awaitWrapper-' + index1 + '-' + index2 + '-' + returnArray;
	var wrapper = fn[key];
	if (wrapper) return bound ? wrapper.bind(object) : wrapper;

	wrapper = function() {
		var that = bound ? object : this;
		var args = Array.prototype.slice.call(arguments),
			arg = args[index1];
		if (typeof arg !== 'boolean') throw util.argError(fn.name, index1, 'boolean', arg);
		var cx = g.context;

		var fiber = Fiber.current;
		var err, val, yielded = false;
		var callback = function(e, v) {
			if (returnArray && !e) {
				v = Array.prototype.slice.call(arguments, 1);
			}
			if (!yielded) {
				yielded = true;
				err = e;
				val = v;
			} else {
				var oldContext = g.context;
				g.context = cx;
				try {
					if (e) {
						fiber.throwInto(e);
					} else {
						fiber.run(v);
					}
				} finally {
					g.context = oldContext;
				}
			}
		};
		if (index2 != null) {
			args[index1] = function(r) { callback(null, r); }
			args[index2] = function(e) { callback(e); }
		} else {
			args[index1] = callback;
		}

		// Invoke the function and yield
		fn.apply(that, args);
		if (yielded) {
			if (err) {
				throw err;
			}
			return val;
		}
		yielded = true;
		cx = g.context;
		try {
			return Fiber.yield();
		} catch (e) {
			throw e;
		}
	};
	if (!bound) {
		fn[key] = wrapper;
		wrapper['asyncWrapper-' + index1] = fn;
	}
	return wrapper;
};

exports.async = function(fn, index) {
	if (typeof fn !== "function") throw util.typeError("cannot wrap function", "function", fn);
	var key = 'asyncWrapper-' + index;
	var wrapper = fn[key];
	if (wrapper) return wrapper;
	wrapper = function() {
		var that = this;
		var args = Array.prototype.slice.call(arguments);
		var cb = args[index];
		if (typeof cb !== "function") {
			// if cb is false, return a future
			if (cb === false) return future(null, wrapper.bind(self), args);
			throw util.argError(fn.name, index, "function", typeof cb);
		}
		// Start a new fiber
		var cx = g.context;
		Fiber(function __streamline$run() {
			// copy variables from outer scope into locals and reset them
			// this avoids a serious memory leak.
			var largs = args;
			args = null;
			var lcb = cb;
			cb = null;
			var lthat = that;
			that = null;

			var val, err = null;
			var oldContext = g.context;
			g.context = cx;
			cx = null;
			try {
				val = fn.apply(lthat, largs);
			} catch (e) {
				err = e;
			} finally {
				lcb(err, val);
				g.context = oldContext;
			}
		}).run();
	};
	wrapper['awaitWrapper-' + index + '-null-false'] = fn;
	fn[key] = wrapper;
	return wrapper;
}

exports.new = function(constructor, index) {
	if (typeof constructor !== "function") throw util.typeError("cannot instantiate", "function", constructor);
	return function() {
		var that = Object.create(constructor.prototype);
		arguments[index] = true;
		exports.await(null, constructor, index, null, false).apply(that, arguments);
		return that;
	};
}

exports.future = require('./future');<commit_msg>fixed arity count on wrapped functions + direct calls<commit_after>// Copyright 2011 Marcel Laverdet (code partially borrowed from original streamline fibers runtime)
"use strict";

var Fiber = require('fibers');
var util = require('./util');

var g = util.getGlobals('fibers');

var counters = {
	slowAwait: 0,
	fastAwait: 0,
	slowAsync: 0,
	fastAsync: 0,
};

exports.await = function(object, property, index1, index2, returnArray) {
	var bound = typeof property !== "function";
	var fn = bound ? object[property] : property;
	if (typeof fn !== "function") throw util.typeError("cannot call", "function", fn);
	var key = 'awaitWrapper-' + index1 + '-' + index2 + '-' + returnArray;
	var wrapper = fn[key];
	if (wrapper) {
		counters.fastAwait++;
		return bound ? wrapper.bind(object) : wrapper;
	}
	counters.slowAwait++;
	if (counters.slowAwait % 100000 === 0) console.error(counters);
	var that = bound ? object : this;

	wrapper = function() {
		var args = Array.prototype.slice.call(arguments),
			arg = args[index1];
		if (typeof arg !== 'boolean') throw util.argError(fn.name, index1, 'boolean', arg);
		var cx = g.context;

		var fiber = Fiber.current;
		var err, val, yielded = false;
		var callback = function(e, v) {
				if (returnArray && !e) {
					v = Array.prototype.slice.call(arguments, 1);
				}
				if (!yielded) {
					yielded = true;
					err = e;
					val = v;
				} else {
					var oldContext = g.context;
					g.context = cx;
					try {
						if (e) {
							fiber.throwInto(e);
						} else {
							fiber.run(v);
						}
					} finally {
						g.context = oldContext;
					}
				}
			};
		if (index2 != null) {
			args[index1] = function(r) {
				callback(null, r);
			}
			args[index2] = function(e) {
				callback(e);
			}
		} else {
			args[index1] = callback;
		}

		// Invoke the function and yield
		fn.apply(that, args);
		if (yielded) {
			if (err) throw err;
			return val;
		}
		yielded = true;
		cx = g.context;
		try {
			return Fiber.yield();
		} catch (e) {
			throw e;
		}

	}

	if (!bound) {
		fn[key] = wrapper;
		wrapper['asyncWrapper-' + index1] = fn;
	}
	return wrapper;
};

function arityWrapper(template) {
	var body = template.toString();
	body = body.substring(body.indexOf('{'));
	var cache = [];
	function makeArgs(i) {
		if (i <= 0) return "";
		return i > 1 ? makeArgs(i - 1) + ', a' + i : "a1";
	}
	function makeTransform(i) {
		return eval("(function(fn, index)" + body.replace(/function\s*\(\)/, "function(" + makeArgs(i) + ")") + ")");
	}
	return function(i) {
		return cache[i] || (cache[i] = makeTransform(i));
	}
}

var asyncTemplate = arityWrapper(function(fn, index) {
	var key = 'asyncWrapper-' + index;
	var wrapper = fn[key];
	if (wrapper) {
		counters.fastAsync++;
		return wrapper;
	}
	counters.slowAsync++;
	wrapper = function() {
		var that = this;
		var args = Array.prototype.slice.call(arguments);
		var cb = args[index];
		if (typeof cb !== "function") {
			// if cb is false, return a future
			if (cb === false) return future(null, wrapper.bind(self), args);
			throw util.argError(fn.name, index, "function", typeof cb);
		}
		// Start a new fiber
		var cx = g.context;
		Fiber(function __streamline$run() {
			// copy variables from outer scope into locals and reset them
			// this avoids a serious memory leak.
			var largs = args;
			args = null;
			var lcb = cb;
			cb = null;
			var lthat = that;
			that = null;

			var val, err = null;
			var oldContext = g.context;
			g.context = cx;
			cx = null;
			try {
				val = fn.apply(lthat, largs);
			} catch (e) {
				err = e;
			} finally {
				lcb(err, val);
				g.context = oldContext;
			}
		}).run();
	}
	wrapper['awaitWrapper-' + index + '-null-false'] = fn;
	fn[key] = wrapper;
	return wrapper;
});

exports.async = function(fn, index) {
	if (typeof fn !== "function") throw util.typeError("cannot wrap function", "function", fn);
	return asyncTemplate(fn.length)(fn, index);
}

exports.new = function(constructor, index) {
	if (typeof constructor !== "function") throw util.typeError("cannot instantiate", "function", constructor);
	return function() {
		var that = Object.create(constructor.prototype);
		arguments[index] = true;
		exports.await(null, constructor, index, null, false).apply(that, arguments);
		return that;
	};
}

exports.future = require('./future');<|endoftext|>


<commit_before>var fs = require('fs'),
    Q = require('q'),
    path = require('path');

module.exports = function(dirsConfig, basedir) {
  // TODO: Make this asynchronous
  var jsFiles = [];
  dirsConfig.forEach(function(dirConfig) {
    var dirPath = path.join(basedir, dirConfig.dir);
    var files = fs.readdirSync(dirPath);
    files.forEach(function(file) {
      var fullFilePath = path.join(dirPath, file)
      jsFiles.push(path.relative(basedir, fullFilePath));
    });
  });

  jsFiles = jsFiles.map(function(filepath) {
    return filepath.split(path.sep).join('/');
  });

  return jsFiles;
};<commit_msg>JS scanner now handles ordering rules and exclusions<commit_after>var fs = require('fs'),
    Q = require('q'),
    path = require('path');

module.exports = function(dirsConfig, basedir) {
  // TODO: Make this asynchronous
  // TODO: Make this recursive
  var jsFiles = [];
  dirsConfig.forEach(function(dirConfig) {
    var dirPath = path.join(basedir, dirConfig.dir);
    var files = fs.readdirSync(dirPath);

    var firstFiles = dirConfig.first.map(function(filename) {
      return dirConfig.dir + '/' + filename;
    });
    var dirFiles = [];
    var lastFiles = dirConfig.last.map(function(filename) {
      return dirConfig.dir + '/' + filename;
    });

    files.forEach(function(file) {
      if (path.extname(file) === '.js') {
        var fullFilePath = path.join(dirPath, file);
        var filepath = path.relative(basedir, fullFilePath);
        var relativeFilepath = path.relative(dirConfig.dir, filepath);
        filepath = filepath.split(path.sep).join('/');
        if (dirConfig.exclude.indexOf(relativeFilepath) === -1 &&
          dirConfig.first.indexOf(relativeFilepath) === -1 &&
          dirConfig.last.indexOf(relativeFilepath) === -1) {
          dirFiles.push(filepath);
        }
      }
    });

    dirFiles.sort();

    jsFiles = jsFiles.concat(firstFiles, dirFiles, lastFiles);
  });

  return jsFiles;
};<|endoftext|>


<commit_before>(function() {
    'use strict';

    var DIR_SERVER      = './',

        path            = require('path'),
        child_process   = require('child_process'),
        exec            = child_process.exec,
        spawn           = child_process.spawn,

        Util            = require('util-io'),

        win             = require('win32'),
        socket          = require(DIR_SERVER    + 'socket'),

        equalPart       = Util.isContainStrAtBegin,

        ClientFuncs     = [],
        ClientDirs      = [],
        Clients         = [],
        WIN             = process.platform === 'win32',

        addNewLine      = function (text) {
            var newLine    = '',
                n           = text && text.length;

            if(n && text[n-1] !== '\n')
                newLine = '\n';

            return text + newLine;
        },

        rmNewLine       = function (text) {
            var strs    = ['\n', '\r'],
                str     = Util.rmStr(text, strs);

            return str;
        },

        ConNum          = 0,

        CHANNEL         = 'console-data';

    /**
     * function listen on servers port
     * @pServer {Object} started server object
     */
    exports.init = function() {
        var ret;

        ret = socket.on('connection', function(clientSocket) {
            onConnection(clientSocket, function(json) {
                socket.emit(CHANNEL, json, clientSocket);
            });
        });

        return ret;
    };

    function onConnection(clientSocket, callback) {
        var msg, onDisconnect, onMessage;

        ++ConNum;

        if (!Clients[ConNum]) {
            msg = log(ConNum, 'console connected');

            callback({
                stdout  : addNewLine(msg),
                path    : process.cwd()
            });

            Clients[ConNum]             = true;

            onMessage                   = Util.exec.with(getOnMessage, ConNum, callback);
            onDisconnect                = function(conNum) {
                Clients[conNum]         =
                ClientFuncs[conNum]     = null;

                log(conNum, 'console disconnected');

                socket.removeListener(CHANNEL, onMessage, clientSocket);
                socket.removeListener('disconnect', onDisconnect, clientSocket);
            }.bind(null, ConNum);

            socket.on(CHANNEL, onMessage, clientSocket);
            socket.on('disconnect', onDisconnect, clientSocket);
        } else {
            msg = log(ConNum, ' in use. Reconnecting...\n');

            Util.exec(callback, {
                stdout: msg
            });

            socket.disconnect();
        }
    }

    /**
     * function gets onMessage function
     * that execute needed command
     *
     * @param pConnNum
     * @param callback
     */
    function getOnMessage(connNum, callback, command) {
        var funcExec, firstChar,
            connName, ret,

            isVolume    = win.isChangeVolume(command),
            isCD        = command.match(new RegExp('^cd ')),
            isCDWin     = command.match(new RegExp('^cd ', 'i')),

            symbolsExec = ['*', '&', '{', '}', '|', '\'', '"'],
            isSymbol    = Util.isContainStr(command, symbolsExec),

            CWD         = process.cwd(),
            dir         = ClientDirs[connNum],
            options     = {
                cwd:    dir || CWD
            };

        if (!dir)
            dir = ClientDirs[connNum] = CWD;

        connName = '#' + connNum + ': ';
        Util.log(connName + command);

        if (isCD || isCDWin && WIN || isVolume) {
            ret = true;

            onCD(command, dir, function(error, json) {
                var path  = '';

                if (!error) {
                    path                = json.path;
                    ClientDirs[connNum] = path;
                }

                callback(json);
            });
        }

        if (!ret) {
            if (WIN)
                command    = 'cmd /C ' + command;

            if (!ClientFuncs[connNum])
                ClientFuncs[connNum] = Util.exec.with(setExec, function(json, error, stderr) {
                    log(connNum, error, 'error');
                    log(connNum, stderr, 'stderror');

                    Util.exec(callback, json);
                });

            funcExec        = ClientFuncs[connNum];
            firstChar       = command[0];

            if (firstChar === '#') {
                command     = command.slice(1);
                command     = connName + command;
                command     = addNewLine(command);

                Util.exec(callback, {
                    stdout: command
                }, true);
            } else if (WIN || firstChar === ' ' || isSymbol)
                exec(command, options, funcExec);
            else
                setSpawn(command, options, callback);
        }
    }

    /**
     * function send result of command to client
     * @param callback
     */
    function setExec(callback, error, stdout, stderr) {
        var json,
            errorStr    = '';

        if (stderr)
            errorStr    = stderr;
        else if (error)
            errorStr    = error.message;

        json            = {
            stdout : stdout,
            stderr : errorStr
        };

        Util.exec(callback, json, error, stderr);
    }

    function setSpawn(сommand, options, callback) {
        var cmd, error,
            isSended    = false,
            args        = сommand.split(' '),
            send        = function(error, data) {
                isSended = true;

                callback({
                    stderr: error,
                    stdout: data
                });
            },
            sendError     = function(error) {
                isSended = true;

                send(error, null);
            };

        сommand    = args.shift();

        error       = Util.exec.tryLog(function() {
            cmd = spawn(сommand, args, options);
        });

        if (error) {
            sendError(error);
        } else {
            cmd.stderr.setEncoding('utf8');
            cmd.stdout.setEncoding('utf8');

            cmd.stdout.on('data', function(data) {
                send(null, data);
            });

            cmd.stderr.on('data', function(error) {
                sendError(error);
            });

            cmd.on('error', function(error) {
                var errorStr    = addNewLine(error + '');

                Util.log(error);
                sendError(errorStr);
            });

            cmd.on('close', function () {
                cmd = null;

                if (!isSended)
                    send(null, null);
            });
        }
    }

     function onCD(command, currDir, callback) {
        var isChangeVolume  = win.isChangeVolume(command),
            isVolume        = win.isVolume(command),
            paramDir        = Util.rmStr(command, 'cd '),
            isRootOrHome    = equalPart(paramDir, ['/', '~']),
            getDir          = WIN ? 'chdir' : 'pwd';

        if (!isRootOrHome && !isChangeVolume || isVolume)
            command     = 'cd ' + path.join(currDir, paramDir);

        exec(command + ' && ' + getDir, {cwd : currDir}, function (error, stdout, stderr) {
            var errorStr    = '';

            if (stderr)
                errorStr    = stderr;
            else if (error)
                errorStr    = error.message;

            callback(error || stderr, {
                stderr  : errorStr,
                path    : rmNewLine(stdout)
            });
        });
    }

    function log(connNum, str, typeParam) {
        var ret,
            type       = ' ';

        if (str) {

            if (typeParam)
                type  += typeParam + ':';

            ret        = 'client #' + connNum + type + str;

            Util.log(ret);
        }

        return ret;
    }
})();
<commit_msg>fix(console) change dir if current dir removed<commit_after>(function() {
    'use strict';

    var DIR_SERVER      = './',

        path            = require('path'),
        child_process   = require('child_process'),
        exec            = child_process.exec,
        spawn           = child_process.spawn,

        Util            = require('util-io'),

        win             = require('win32'),
        socket          = require(DIR_SERVER    + 'socket'),

        equalPart       = Util.isContainStrAtBegin,

        ClientFuncs     = [],
        ClientDirs      = [],
        Clients         = [],
        WIN             = process.platform === 'win32',

        addNewLine      = function (text) {
            var newLine    = '',
                n           = text && text.length;

            if(n && text[n-1] !== '\n')
                newLine = '\n';

            return text + newLine;
        },

        rmNewLine       = function (text) {
            var strs    = ['\n', '\r'],
                str     = Util.rmStr(text, strs);

            return str;
        },

        ConNum          = 0,

        CHANNEL         = 'console-data';

    /**
     * function listen on servers port
     * @pServer {Object} started server object
     */
    exports.init = function() {
        var ret;

        ret = socket.on('connection', function(clientSocket) {
            onConnection(clientSocket, function(json) {
                socket.emit(CHANNEL, json, clientSocket);
            });
        });

        return ret;
    };

    function onConnection(clientSocket, callback) {
        var msg, onDisconnect, onMessage;

        ++ConNum;

        if (!Clients[ConNum]) {
            msg = log(ConNum, 'console connected');

            callback({
                stdout  : addNewLine(msg),
                path    : process.cwd()
            });

            Clients[ConNum]             = true;

            onMessage                   = Util.exec.with(getOnMessage, ConNum, callback);
            onDisconnect                = function(conNum) {
                Clients[conNum]         =
                ClientFuncs[conNum]     = null;

                log(conNum, 'console disconnected');

                socket.removeListener(CHANNEL, onMessage, clientSocket);
                socket.removeListener('disconnect', onDisconnect, clientSocket);
            }.bind(null, ConNum);

            socket.on(CHANNEL, onMessage, clientSocket);
            socket.on('disconnect', onDisconnect, clientSocket);
        } else {
            msg = log(ConNum, ' in use. Reconnecting...\n');

            Util.exec(callback, {
                stdout: msg
            });

            socket.disconnect();
        }
    }

    /**
     * function gets onMessage function
     * that execute needed command
     *
     * @param pConnNum
     * @param callback
     */
    function getOnMessage(connNum, callback, command) {
        var funcExec, firstChar,
            connName, ret,

            isVolume    = win.isChangeVolume(command),
            isCD        = command.match(new RegExp('^cd ')),
            isCDWin     = command.match(new RegExp('^cd ', 'i')),

            symbolsExec = ['*', '&', '{', '}', '|', '\'', '"'],
            isSymbol    = Util.isContainStr(command, symbolsExec),

            CWD         = process.cwd(),
            dir         = ClientDirs[connNum],
            options     = {
                cwd:    dir || CWD
            };

        if (!dir)
            dir = ClientDirs[connNum] = CWD;

        connName = '#' + connNum + ': ';
        Util.log(connName + command);

        if (isCD || isCDWin && WIN || isVolume) {
            ret = true;

            onCD(command, dir, function(error, json) {
                var path  = '';

                if (!error) {
                    path                = json.path;
                    ClientDirs[connNum] = path;
                }

                callback(json);
            });
        }

        if (!ret) {
            if (WIN)
                command    = 'cmd /C ' + command;

            if (!ClientFuncs[connNum])
                ClientFuncs[connNum] = Util.exec.with(setExec, function(json, error, stderr) {
                    log(connNum, error, 'error');
                    log(connNum, stderr, 'stderror');

                    Util.exec(callback, json);
                });

            funcExec        = ClientFuncs[connNum];
            firstChar       = command[0];

            if (firstChar === '#') {
                command     = command.slice(1);
                command     = connName + command;
                command     = addNewLine(command);

                Util.exec(callback, {
                    stdout: command
                }, true);
            } else if (WIN || firstChar === ' ' || isSymbol)
                exec(command, options, funcExec);
            else
                setSpawn(command, options, callback);
        }
    }

    /**
     * function send result of command to client
     * @param callback
     */
    function setExec(callback, error, stdout, stderr) {
        var json,
            errorStr    = '';

        if (stderr)
            errorStr    = stderr;
        else if (error)
            errorStr    = error.message;

        json            = {
            stdout : stdout,
            stderr : errorStr
        };

        Util.exec(callback, json, error, stderr);
    }

    function setSpawn(сommand, options, callback) {
        var cmd, error,
            isSended    = false,
            args        = сommand.split(' '),
            send        = function(error, data) {
                isSended = true;

                callback({
                    stderr: error,
                    stdout: data
                });
            },
            sendError     = function(error) {
                isSended = true;

                send(error, null);
            };

        сommand    = args.shift();

        error       = Util.exec.tryLog(function() {
            cmd = spawn(сommand, args, options);
        });

        if (error) {
            sendError(error);
        } else {
            cmd.stderr.setEncoding('utf8');
            cmd.stdout.setEncoding('utf8');

            cmd.stdout.on('data', function(data) {
                send(null, data);
            });

            cmd.stderr.on('data', function(error) {
                sendError(error);
            });

            cmd.on('error', function(error) {
                var errorStr    = addNewLine(error + '');

                Util.log(error);
                sendError(errorStr);
            });

            cmd.on('close', function () {
                cmd = null;

                if (!isSended)
                    send(null, null);
            });
        }
    }

     function onCD(command, currDir, callback) {
        var isChangeVolume  = win.isChangeVolume(command),
            isVolume        = win.isVolume(command),
            paramDir        = Util.rmStr(command, 'cd '),
            isRootOrHome    = equalPart(paramDir, ['/', '~']),
            getDir          = WIN ? 'chdir' : 'pwd';

        if (!isRootOrHome && !isChangeVolume || isVolume) {
            paramDir    =  path.join(currDir, paramDir);
            command     = 'cd ' + paramDir;
        }

        exec(command + ' && ' + getDir, {cwd : paramDir}, function (error, stdout, stderr) {
            var errorStr    = '';

            if (stderr)
                errorStr    = stderr;
            else if (error)
                errorStr    = error.message;

            callback(error || stderr, {
                stderr  : addNewLine(errorStr),
                path    : rmNewLine(stdout)
            });
        });
    }

    function log(connNum, str, typeParam) {
        var ret,
            type       = ' ';

        if (str) {

            if (typeParam)
                type  += typeParam + ':';

            ret        = 'client #' + connNum + type + str;

            Util.log(ret);
        }

        return ret;
    }
})();
<|endoftext|>


<commit_before>(function() {
    'use strict';

    var main            = global.cloudcmd.main,

        socket          = main.socket,
        update          = main.srvrequire('update'),

        exec            = main.child_process.exec,
        spawn           = main.child_process.spawn,

        Util            = main.util,
        path            = main.path,
        CloudFunc       = main.cloudfunc,
        mainpackage     = main.mainpackage,
        equalPart       = Util.isContainStrAtBegin,
        CLOUDCMD        = mainpackage.name,
        ClientFuncs     = [],
        ClientDirs      = [],
        Clients         = [],
        WIN32           = main.WIN32,

        addNewLine      = CloudFunc.addNewLine,

        ConNum          = 0,

        CHANNEL         = CloudFunc.CHANNEL_CONSOLE,

        HELP            = {
            stdout  : CLOUDCMD + ' exit     \n' +
                      CLOUDCMD + ' update   \n',
        },

        /* windows commands thet require
         * unicode charset on locales
         * different then English
         */
        Win32Commands   = ['ASSOC', 'AT', 'ATTRIB', 'BREAK', 'CACLS', 'CALL',
                            'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', 'CLS',
                            'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY',
                            'DATE', 'DEL', 'DIR', 'DISKCOMP', 'DISKCOPY', 'DOSKEY',
                            'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC', 'FIND',
                            'FINDSTR', 'FOR', 'FORMAT', 'FTYPE', 'GOTO', 'GRAFTABL',
                            'HELP', 'IF', 'LABEL', 'MD', 'MKDIR', 'MODE', 'MORE',
                            'MOVE', 'PATH', 'PAUSE', 'POPD', 'PRINT', 'PROMPT',
                            'PUSHD', 'RD', 'RECOVER', 'REM', 'REN', 'RENAME',
                            'REPLACE', 'RMDIR', 'SET', 'SETLOCAL', 'SHIFT', 'SORT',
                            'START', 'SUBST', 'TIME', 'TITLE', 'TREE', 'TYPE',
                            'VER', 'VERIFY', 'VOL', 'XCOPY'];

    /**
     * function listen on servers port
     * @pServer {Object} started server object
     */
    exports.init = function() {
        var ret;

        ret = socket.on('connection', function(clientSocket) {
            onConnection(clientSocket, function(json, all) {
                socket.emit(CHANNEL, json, clientSocket, all);
            });
        });

        return ret;
    };

    function onConnection(clientSocket, callback) {
        var msg, onDisconnect, onMessage;

        ++ConNum;

        if (!Clients[ConNum]) {
            msg = log(ConNum, 'console connected');

            Util.exec(callback, {
                stdout : addNewLine(msg)
            });

            Clients[ConNum]             = true;

            onMessage                   = Util.exec.with(getOnMessage, ConNum, callback);
            onDisconnect                = function(conNum) {
                Clients[conNum]         =
                ClientFuncs[conNum]     = null;

                log(conNum, 'console disconnected');

                socket.removeListener(CHANNEL, onMessage, clientSocket);
                socket.removeListener('disconnect', onDisconnect, clientSocket);
            }.bind(null, ConNum);

            socket.on(CHANNEL, onMessage, clientSocket);
            socket.on('disconnect', onDisconnect, clientSocket);
        } else {
            msg = log(ConNum, ' in use. Reconnecting...\n');

            Util.exec(callback, {
                stdout: msg
            });

            socket.disconnect();
        }
    }

    /**
     * function gets onMessage function
     * that execute needed command
     *
     * @param pConnNum
     * @param callback
     */
    function getOnMessage(connNum, callback, command) {
        var winCommand, funcExec, firstChar,
            connName, ret, isContain,

            symbolsExec = ['*', '&', '{', '}', '|', '\'', '"'],
            CWD         = process.cwd(),
            dir         = ClientDirs[connNum],
            options     = {
                cwd:    dir || CWD
            };

        if (!dir)
            dir = ClientDirs[connNum] = CWD;

        connName = '#' + connNum + ': ';
        Util.log(connName + command);

        if (equalPart(command, CLOUDCMD))
            ret = onCloudCmd(command, callback);
        else if (equalPart(command, 'cd '))  {
            ret = true;

            onCD(command, dir, function(json) {
                var error   = json.stderr,
                    stdout  = json.stdout;

                if (error)
                    Util.exec(callback, json);
                else
                    ClientDirs[connNum] = stdout;
            });
        }

        if (!ret) {
            /* if we on windows and command is build in
             * change code page to unicode becouse
             * windows use unicode on non English versions
             */
            if (WIN32) {
                winCommand     = command.toUpperCase();

                if (Win32Commands.indexOf(winCommand) >= 0)
                    command    = 'chcp 65001 |' + command;
            }

            if (!ClientFuncs[connNum])
                ClientFuncs[connNum] = Util.exec.with(setExec, function(json, error, stderr) {
                    log(connNum, error, 'error');
                    log(connNum, stderr, 'stderror');

                    Util.exec(callback, json);
                });

            funcExec        = ClientFuncs[connNum];
            isContain       = Util.isContainStr(command, symbolsExec);
            firstChar       = command[0];

            if (firstChar === '#') {
                command     = command.slice(1);
                command     = connName + command;
                command     = addNewLine(command);

                Util.exec(callback, {
                    stdout: command
                }, true);
            } else if (WIN32 || firstChar === ' ' || isContain)
                exec(command, options, funcExec);
            else
                setSpawn(command, options, callback);
        }
    }

    /**
     * function send result of command to client
     * @param callback
     */
    function setExec(callback, error, stdout, stderr) {
            var json,
                errorStr    = stderr || error;

            if (errorStr)
                errorStr    = addNewLine(errorStr + '');

            json            = {
                stdout : stdout,
                stderr : errorStr
            };

            Util.exec(callback, json, error, stderr);
    }

    function setSpawn(сommand, options, callback) {
        var cmd, error,
            args        = сommand.split(' '),
            send        = function(error, data) {
                var exec    = {
                        stderr: error,
                        stdout: data
                    };

                Util.exec(callback, exec);
            },
            sendError     = function(error) {
                send(error + '', null);
            };

        сommand    = args.shift();

        error       = Util.exec.tryLog(function() {
            cmd = spawn(сommand, args, options);
        });

        if (error) {
            sendError(error);
        } else {
            cmd.stdout.on('data', function(data) {
                send(null, data + '');
            });

            cmd.stderr.on('data', sendError);
            cmd.on('error', function(error) {
                var errorStr    = addNewLine(error + '');

                Util.log(error);
                sendError(errorStr);
            });

            cmd.on('close', function () {
                cmd = null;
            });
        }
    }

    function onCloudCmd(command, callback) {
        var is;

        command = Util.rmStr(command, CLOUDCMD);
        is      = !equalPart(command, ' ');

        if (is) {
            Util.exec(callback, HELP);
        } else {
            command = Util.rmStr(command, ' ');
            is  = update && equalPart(command, 'update');

            if (is) {
                update.get();

                Util.exec(callback, {
                    stdout: addNewLine('update: ok')
                });
            }

            is = Util.strCmp(command, 'exit');

            if (is)
                process.exit();
        }

        return is;
    }

    function onCD(command, currDir, callback) {
        var dir,
            getDir      = WIN32 ? 'chdir' : 'pwd',
            paramDir    = Util.rmStr(command, 'cd ');

        if (equalPart(paramDir, ['/', '~']))
            dir = paramDir;
        else
            dir = path.join(currDir, paramDir);

        exec('cd ' + dir + ' && ' + getDir, function (error, stdout, stderr) {
            var errorStr    = '',
                errorData   = error || stderr;

            if (errorData)
                errorStr    = Util.stringifyJSON(errorData);

            Util.exec(callback, {
                stderr  : errorStr,
                stdout  : CloudFunc.rmNewLine(stdout)
            });
        });
    }

    function log(connNum, str, typeParam) {
        var ret,
            type       = ' ';

        if (str) {

            if (typeParam)
                type  += typeParam + ':';

            ret        = 'client #' + connNum + type + str;

            Util.log(ret);
        }

        return ret;
    }
})();
<commit_msg>refactor(console) setSpawn: "+ " -> setEncoding<commit_after>(function() {
    'use strict';

    var main            = global.cloudcmd.main,

        socket          = main.socket,
        update          = main.srvrequire('update'),

        exec            = main.child_process.exec,
        spawn           = main.child_process.spawn,

        Util            = main.util,
        path            = main.path,
        CloudFunc       = main.cloudfunc,
        mainpackage     = main.mainpackage,
        equalPart       = Util.isContainStrAtBegin,
        CLOUDCMD        = mainpackage.name,
        ClientFuncs     = [],
        ClientDirs      = [],
        Clients         = [],
        WIN32           = main.WIN32,

        addNewLine      = CloudFunc.addNewLine,

        ConNum          = 0,

        CHANNEL         = CloudFunc.CHANNEL_CONSOLE,

        HELP            = {
            stdout  : CLOUDCMD + ' exit     \n' +
                      CLOUDCMD + ' update   \n',
        },

        /* windows commands thet require
         * unicode charset on locales
         * different then English
         */
        Win32Commands   = ['ASSOC', 'AT', 'ATTRIB', 'BREAK', 'CACLS', 'CALL',
                            'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', 'CLS',
                            'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY',
                            'DATE', 'DEL', 'DIR', 'DISKCOMP', 'DISKCOPY', 'DOSKEY',
                            'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC', 'FIND',
                            'FINDSTR', 'FOR', 'FORMAT', 'FTYPE', 'GOTO', 'GRAFTABL',
                            'HELP', 'IF', 'LABEL', 'MD', 'MKDIR', 'MODE', 'MORE',
                            'MOVE', 'PATH', 'PAUSE', 'POPD', 'PRINT', 'PROMPT',
                            'PUSHD', 'RD', 'RECOVER', 'REM', 'REN', 'RENAME',
                            'REPLACE', 'RMDIR', 'SET', 'SETLOCAL', 'SHIFT', 'SORT',
                            'START', 'SUBST', 'TIME', 'TITLE', 'TREE', 'TYPE',
                            'VER', 'VERIFY', 'VOL', 'XCOPY'];

    /**
     * function listen on servers port
     * @pServer {Object} started server object
     */
    exports.init = function() {
        var ret;

        ret = socket.on('connection', function(clientSocket) {
            onConnection(clientSocket, function(json, all) {
                socket.emit(CHANNEL, json, clientSocket, all);
            });
        });

        return ret;
    };

    function onConnection(clientSocket, callback) {
        var msg, onDisconnect, onMessage;

        ++ConNum;

        if (!Clients[ConNum]) {
            msg = log(ConNum, 'console connected');

            Util.exec(callback, {
                stdout : addNewLine(msg)
            });

            Clients[ConNum]             = true;

            onMessage                   = Util.exec.with(getOnMessage, ConNum, callback);
            onDisconnect                = function(conNum) {
                Clients[conNum]         =
                ClientFuncs[conNum]     = null;

                log(conNum, 'console disconnected');

                socket.removeListener(CHANNEL, onMessage, clientSocket);
                socket.removeListener('disconnect', onDisconnect, clientSocket);
            }.bind(null, ConNum);

            socket.on(CHANNEL, onMessage, clientSocket);
            socket.on('disconnect', onDisconnect, clientSocket);
        } else {
            msg = log(ConNum, ' in use. Reconnecting...\n');

            Util.exec(callback, {
                stdout: msg
            });

            socket.disconnect();
        }
    }

    /**
     * function gets onMessage function
     * that execute needed command
     *
     * @param pConnNum
     * @param callback
     */
    function getOnMessage(connNum, callback, command) {
        var winCommand, funcExec, firstChar,
            connName, ret, isContain,

            symbolsExec = ['*', '&', '{', '}', '|', '\'', '"'],
            CWD         = process.cwd(),
            dir         = ClientDirs[connNum],
            options     = {
                cwd:    dir || CWD
            };

        if (!dir)
            dir = ClientDirs[connNum] = CWD;

        connName = '#' + connNum + ': ';
        Util.log(connName + command);

        if (equalPart(command, CLOUDCMD))
            ret = onCloudCmd(command, callback);
        else if (equalPart(command, 'cd '))  {
            ret = true;

            onCD(command, dir, function(json) {
                var error   = json.stderr,
                    stdout  = json.stdout;

                if (error)
                    Util.exec(callback, json);
                else
                    ClientDirs[connNum] = stdout;
            });
        }

        if (!ret) {
            /* if we on windows and command is build in
             * change code page to unicode becouse
             * windows use unicode on non English versions
             */
            if (WIN32) {
                winCommand     = command.toUpperCase();

                if (Win32Commands.indexOf(winCommand) >= 0)
                    command    = 'chcp 65001 |' + command;
            }

            if (!ClientFuncs[connNum])
                ClientFuncs[connNum] = Util.exec.with(setExec, function(json, error, stderr) {
                    log(connNum, error, 'error');
                    log(connNum, stderr, 'stderror');

                    Util.exec(callback, json);
                });

            funcExec        = ClientFuncs[connNum];
            isContain       = Util.isContainStr(command, symbolsExec);
            firstChar       = command[0];

            if (firstChar === '#') {
                command     = command.slice(1);
                command     = connName + command;
                command     = addNewLine(command);

                Util.exec(callback, {
                    stdout: command
                }, true);
            } else if (WIN32 || firstChar === ' ' || isContain)
                exec(command, options, funcExec);
            else
                setSpawn(command, options, callback);
        }
    }

    /**
     * function send result of command to client
     * @param callback
     */
    function setExec(callback, error, stdout, stderr) {
            var json,
                errorStr    = stderr || error;

            if (errorStr)
                errorStr    = addNewLine(errorStr + '');

            json            = {
                stdout : stdout,
                stderr : errorStr
            };

            Util.exec(callback, json, error, stderr);
    }

    function setSpawn(сommand, options, callback) {
        var cmd, error,
            args        = сommand.split(' '),
            send        = function(error, data) {
                var exec    = {
                        stderr: error,
                        stdout: data
                    };

                Util.exec(callback, exec);
            },
            sendError     = function(error) {
                send(error, null);
            };

        сommand    = args.shift();

        error       = Util.exec.tryLog(function() {
            cmd = spawn(сommand, args, options);
        });

        if (error) {
            sendError(error);
        } else {
            cmd.stderr.setEncoding('utf8');
            cmd.stdout.setEncoding('utf8');

            cmd.stdout.on('data', function(data) {
                send(null, data);
            });

            cmd.stderr.on('data', sendError);

            cmd.on('error', function(error) {
                var errorStr    = addNewLine(error + '');

                Util.log(error);
                sendError(errorStr);
            });

            cmd.on('close', function () {
                cmd = null;
            });
        }
    }

    function onCloudCmd(command, callback) {
        var is;

        command = Util.rmStr(command, CLOUDCMD);
        is      = !equalPart(command, ' ');

        if (is) {
            Util.exec(callback, HELP);
        } else {
            command = Util.rmStr(command, ' ');
            is  = update && equalPart(command, 'update');

            if (is) {
                update.get();

                Util.exec(callback, {
                    stdout: addNewLine('update: ok')
                });
            }

            is = Util.strCmp(command, 'exit');

            if (is)
                process.exit();
        }

        return is;
    }

    function onCD(command, currDir, callback) {
        var dir,
            getDir      = WIN32 ? 'chdir' : 'pwd',
            paramDir    = Util.rmStr(command, 'cd ');

        if (equalPart(paramDir, ['/', '~']))
            dir = paramDir;
        else
            dir = path.join(currDir, paramDir);

        exec('cd ' + dir + ' && ' + getDir, function (error, stdout, stderr) {
            var errorStr    = '',
                errorData   = error || stderr;

            if (errorData)
                errorStr    = Util.stringifyJSON(errorData);

            Util.exec(callback, {
                stderr  : errorStr,
                stdout  : CloudFunc.rmNewLine(stdout)
            });
        });
    }

    function log(connNum, str, typeParam) {
        var ret,
            type       = ' ';

        if (str) {

            if (typeParam)
                type  += typeParam + ':';

            ret        = 'client #' + connNum + type + str;

            Util.log(ret);
        }

        return ret;
    }
})();
<|endoftext|>