<commit_before>var dispatcher = require( 'dispatchy' );
var extend = require( 'extend' );
var os = require( 'os' );
var compileLess = require( './lib/compile-less' );
var write = require( 'write' ).sync;
var Promise = require( 'es6-promise' ).Promise;
var path = require( 'path' );
var url = require( 'url' );
var format = require( 'stringformat' );
var fs = require( 'fs-extra' );
var autoPrefix = require( './lib/autoprefix' );

var isNull = function ( val ) {
  return typeof val === 'undefined' || val === null;
};

var trim = function ( str ) {
  return (str || '').trim();
};

var makeMinName = function ( fileName ) {
  var rgex = /(.+)\.(\w+)$/gi;
  return fileName.replace( rgex, '$1.min.$2' );
};

var addVersion = function ( fileName, version ) {
  if ( !version ) {
    return fileName;
  }
  var rgex = /(.+)\.(\w+)$/gi;
  return fileName.replace( rgex, '$1.' + version + '.$2' );
};

/**
 * check if this is a relative (to the document) url
 *
 * We need to rewrite if the url is relative. This function will return false if:
 * - starts with "/", cause it means it is relative to the main domain
 * - starts with "data:", cause it means is a data uri
 * - starts with a protocol
 *
 * in all other cases it will return true
 *
 * @param urlToCheck the url to test
 * @returns {boolean}
 */
var checkIfRelativePath = function ( urlToCheck ) {
  var DATA_URI_MATCHER = /^data:/gi, //regex to test for an url with a data uri
    PROTOCOL_MATCHER = /^http|^https:\/\//gi, //regex to test for an url with an absolute path
    RELATIVE_TO_HOST_MATCHER = /^\//g; //regex to test for an url relative to the host

  return urlToCheck.match( DATA_URI_MATCHER ) ? false : urlToCheck.match( RELATIVE_TO_HOST_MATCHER ) ? false : !urlToCheck.match( PROTOCOL_MATCHER );
};

var md5 = function ( str, encoding ) {
  var crypto = require( 'crypto' );
  return crypto
    .createHash( 'md5' )
    .update( str + '' )
    .digest( encoding || 'hex' );
};

module.exports = {
  create: function ( descriptor, options ) {
    var fileCache = { };

    var opts = extend( true, {
      banner: '',
      copyAssetsToDestFolder: true,
      revision: '',
      minimize: false,
      assetsPathFormat: 'assets/{REVISION}_{GUID}_{FNAME}',
      autoprefixer: {
        browsers: [
          'last 2 versions'
        ]
      },
      lessOptions: {
        paths: [],
        relativeUrls: true,
        compress: false,
        dumpLineNumbers: 'comments'
      },
      userFns: {},
      cssoOptions: {
        structureModifications: false
      }
    }, options );

    return extend( dispatcher.create(), {
      getId: function ( pathToFile ) {
        var id = fileCache[ pathToFile ] = fileCache[ pathToFile ] || md5( pathToFile );
        return id;
      },
      rewriteURLS: function ( ctn, src, destDir ) {
        var me = this;
        var URL_MATCHER = /url\(\s*[\'"]?\/?(.+?)[\'"]?\s*\)/gi; //regex used to match the urls inside the less or css files

        var version = opts.revision;
        var rewritePathTemplate = opts.assetsPathFormat;
        var referencedFiles = [ ];

        if ( !isNull( ctn ) ) {
          ctn = ctn.replace( URL_MATCHER, function ( match, foundURL ) {
            foundURL = trim( foundURL );
            var needRewrite = checkIfRelativePath( foundURL );

            if ( needRewrite ) {
              var rewriteDescriptor = me.copyFileToNewLocation( src, destDir, foundURL, version, rewritePathTemplate );
              if ( rewriteDescriptor.copied ) {
                var pathToFile = rewriteDescriptor.to;
                referencedFiles.push( rewriteDescriptor.from );

                var outputPath = format( 'url({0})', pathToFile );
                //verbose.writeln( format( '===> This url will be transformed : {0} ==> {1}', url, outputPath ) );
                me.fire( 'url:transformed', {
                  from: foundURL,
                  to: outputPath
                } );

                return outputPath;
              }
            }

            return match;
          } );
        }

        return { ctn: ctn, referencedFiles: referencedFiles };
      },
      copyFileToNewLocation: function ( src, destDir, relativePathToFile, version, rewritePathTemplate ) {
        rewritePathTemplate = rewritePathTemplate || '';

        var me = this;
        var dirOfFile = path.dirname( src );

        var urlObj = url.parse( relativePathToFile );
        var relativePath = trim( urlObj.pathname );
        var lastPart = trim( urlObj.search ) + trim( urlObj.hash );

        if ( relativePath === '' ) {
          throw new Error( 'Not a valid url' );
        }

        var absolutePathToResource = path.normalize( path.resolve( dirOfFile, relativePath ) );

        var fileId = me.getId( absolutePathToResource ); //md5( absolutePathToResource );

        var fName = format( '{0}', path.basename( relativePath ) );

        var relativeOutputFn = rewritePathTemplate.replace( /\{REVISION\}/g, version ) // fileId, fName );
          .replace( /\{GUID\}/g, fileId )
          .replace( /\{FNAME\}/g, fName );

        var newPath = path.normalize( path.join( destDir, relativeOutputFn ) );

        if ( opts.copyAssetsToDestFolder ) {
          fs.copySync( absolutePathToResource, newPath );
        }

        me.fire( 'resource:copied', {
          from: absolutePathToResource,
          to: newPath
        } );

        var outName = relativeOutputFn + lastPart;

        me.fire( 'url:replaced', {
          from: relativePathToFile,
          to: outName
        } );

        return {
          to: outName,
          copied: opts.copyAssetsToDestFolder,
          from: absolutePathToResource
        };
      },
      process: function () {
        var me = this;

        var src = Array.isArray( descriptor.src ) ? descriptor.src : [
          descriptor.src
        ];
        var dest = descriptor.dest;

        dest = addVersion( dest, opts.revision );

        me.fire( 'compile:start', {
          descriptor: descriptor,
          modifiedDest: dest,
          options: opts
        } );

        // we should be able to use Promise.all
        // but for some reason, if the compileLess process
        // is run in parallel will have some troubles and will
        // stop.
        //
        // So in this case we're just making sure that everything
        // is done in sequence and the results of the operations
        // are stored in this promise variable
        var promises = [ ];

        return src.reduce( function ( seq, file ) {
          return seq.then( function () {
            me.fire( 'compile:file', { file: file } );
            return compileLess( file, opts.lessOptions, opts.userFns ).then( function ( params ) {
              var result = params.css;

              var rewriteDescriptor = me.rewriteURLS( result, file, path.dirname( dest ) );

              result = rewriteDescriptor.ctn;

              return autoPrefix( result, {
                file: file,
                dest: dest,
                autoprefixer: opts.autoprefixer
              } ).then( function ( prefixedCSS ) {
                promises.push( {
                  prefixed: prefixedCSS,
                  meta: {
                    dest: dest,
                    referencedFiles: rewriteDescriptor.referencedFiles,
                    imports: params.imports || [ ],
                    src: file
                  }
                } );
              } );
            }, function ( err ) {
              setTimeout( function () {
                throw err;
              }, 0 );
            } );
          } );
        }, Promise.resolve() ).then( function () {
          return Promise.all( promises ).then( function ( params ) {
            var results = [ ];
            //var meta = [ ];
            var files = [ ];

            params.forEach( function ( entry ) {
              results.push( entry.prefixed );
              var meta = entry.meta;
              //console.log( entry.prefixed );

              files = files.concat( meta.src )
                .concat( meta.imports )
                .concat( meta.referencedFiles );
            } );

            //results = results || [];
            var args = { referencedFiles: files };

            me.fire( 'compile:end', args );

            me.fire( 'before:write', extend( args, { dest: dest } ) );

            if ( args.cancel ) {
              return;
            }

            var result = results.join( os.EOL );

            var banner = opts.banner ? opts.banner + os.EOL : '';

            write( dest, (banner + result) );

            me.fire( 'write:file', args );

            if ( opts.minimize ) {
              var csso = require( 'csso' );
              var cssoOptions = opts.cssoOptions || { };
              var minimized = csso.justDoIt( result, !!cssoOptions.structureModifications );
              var minimizedDest = makeMinName( dest );

              write( minimizedDest, (banner + minimized) );

              me.fire( 'write:minimized', extend( { }, args, {
                dest: minimizedDest
              } ) );
            }

          } ).catch( function ( err ) {
            //console.log(err);
            me.fire( 'error', err );
          //throw err;
          } );
        } );
      }
    } );
  }
};
<commit_msg>ENH: Do not break the tasks if an error happen in one target<commit_after>var dispatcher = require( 'dispatchy' );
var extend = require( 'extend' );
var os = require( 'os' );
var compileLess = require( './lib/compile-less' );
var write = require( 'write' ).sync;
var Promise = require( 'es6-promise' ).Promise;
var path = require( 'path' );
var url = require( 'url' );
var format = require( 'stringformat' );
var fs = require( 'fs-extra' );
var autoPrefix = require( './lib/autoprefix' );

var isNull = function ( val ) {
  return typeof val === 'undefined' || val === null;
};

var trim = function ( str ) {
  return (str || '').trim();
};

var makeMinName = function ( fileName ) {
  var rgex = /(.+)\.(\w+)$/gi;
  return fileName.replace( rgex, '$1.min.$2' );
};

var addVersion = function ( fileName, version ) {
  if ( !version ) {
    return fileName;
  }
  var rgex = /(.+)\.(\w+)$/gi;
  return fileName.replace( rgex, '$1.' + version + '.$2' );
};

/**
 * check if this is a relative (to the document) url
 *
 * We need to rewrite if the url is relative. This function will return false if:
 * - starts with "/", cause it means it is relative to the main domain
 * - starts with "data:", cause it means is a data uri
 * - starts with a protocol
 *
 * in all other cases it will return true
 *
 * @param urlToCheck the url to test
 * @returns {boolean}
 */
var checkIfRelativePath = function ( urlToCheck ) {
  var DATA_URI_MATCHER = /^data:/gi, //regex to test for an url with a data uri
    PROTOCOL_MATCHER = /^http|^https:\/\//gi, //regex to test for an url with an absolute path
    RELATIVE_TO_HOST_MATCHER = /^\//g; //regex to test for an url relative to the host

  return urlToCheck.match( DATA_URI_MATCHER ) ? false : urlToCheck.match( RELATIVE_TO_HOST_MATCHER ) ? false : !urlToCheck.match( PROTOCOL_MATCHER );
};

var md5 = function ( str, encoding ) {
  var crypto = require( 'crypto' );
  return crypto
    .createHash( 'md5' )
    .update( str + '' )
    .digest( encoding || 'hex' );
};

module.exports = {
  create: function ( descriptor, options ) {
    var fileCache = { };

    var opts = extend( true, {
      banner: '',
      copyAssetsToDestFolder: true,
      revision: '',
      minimize: false,
      assetsPathFormat: 'assets/{REVISION}_{GUID}_{FNAME}',
      autoprefixer: {
        browsers: [
          'last 2 versions'
        ]
      },
      lessOptions: {
        paths: [],
        relativeUrls: true,
        compress: false,
        dumpLineNumbers: 'comments'
      },
      userFns: {},
      cssoOptions: {
        structureModifications: false
      }
    }, options );

    return extend( dispatcher.create(), {
      getId: function ( pathToFile ) {
        var id = fileCache[ pathToFile ] = fileCache[ pathToFile ] || md5( pathToFile );
        return id;
      },
      rewriteURLS: function ( ctn, src, destDir ) {
        var me = this;
        var URL_MATCHER = /url\(\s*[\'"]?\/?(.+?)[\'"]?\s*\)/gi; //regex used to match the urls inside the less or css files

        var version = opts.revision;
        var rewritePathTemplate = opts.assetsPathFormat;
        var referencedFiles = [ ];

        if ( !isNull( ctn ) ) {
          ctn = ctn.replace( URL_MATCHER, function ( match, foundURL ) {
            foundURL = trim( foundURL );
            var needRewrite = checkIfRelativePath( foundURL );

            if ( needRewrite ) {
              var rewriteDescriptor = me.copyFileToNewLocation( src, destDir, foundURL, version, rewritePathTemplate );
              if ( rewriteDescriptor.copied ) {
                var pathToFile = rewriteDescriptor.to;
                referencedFiles.push( rewriteDescriptor.from );

                var outputPath = format( 'url({0})', pathToFile );
                //verbose.writeln( format( '===> This url will be transformed : {0} ==> {1}', url, outputPath ) );
                me.fire( 'url:transformed', {
                  from: foundURL,
                  to: outputPath
                } );

                return outputPath;
              }
            }

            return match;
          } );
        }

        return { ctn: ctn, referencedFiles: referencedFiles };
      },
      copyFileToNewLocation: function ( src, destDir, relativePathToFile, version, rewritePathTemplate ) {
        rewritePathTemplate = rewritePathTemplate || '';

        var me = this;
        var dirOfFile = path.dirname( src );

        var urlObj = url.parse( relativePathToFile );
        var relativePath = trim( urlObj.pathname );
        var lastPart = trim( urlObj.search ) + trim( urlObj.hash );

        if ( relativePath === '' ) {
          throw new Error( 'Not a valid url' );
        }

        var absolutePathToResource = path.normalize( path.resolve( dirOfFile, relativePath ) );

        var fileId = me.getId( absolutePathToResource ); //md5( absolutePathToResource );

        var fName = format( '{0}', path.basename( relativePath ) );

        var relativeOutputFn = rewritePathTemplate.replace( /\{REVISION\}/g, version ) // fileId, fName );
          .replace( /\{GUID\}/g, fileId )
          .replace( /\{FNAME\}/g, fName );

        var newPath = path.normalize( path.join( destDir, relativeOutputFn ) );

        if ( opts.copyAssetsToDestFolder ) {
          fs.copySync( absolutePathToResource, newPath );
        }

        me.fire( 'resource:copied', {
          from: absolutePathToResource,
          to: newPath
        } );

        var outName = relativeOutputFn + lastPart;

        me.fire( 'url:replaced', {
          from: relativePathToFile,
          to: outName
        } );

        return {
          to: outName,
          copied: opts.copyAssetsToDestFolder,
          from: absolutePathToResource
        };
      },
      process: function () {
        var me = this;

        var src = Array.isArray( descriptor.src ) ? descriptor.src : [
          descriptor.src
        ];
        var dest = descriptor.dest;

        dest = addVersion( dest, opts.revision );

        me.fire( 'compile:start', {
          descriptor: descriptor,
          modifiedDest: dest,
          options: opts
        } );

        // we should be able to use Promise.all
        // but for some reason, if the compileLess process
        // is run in parallel will have some troubles and will
        // stop.
        //
        // So in this case we're just making sure that everything
        // is done in sequence and the results of the operations
        // are stored in this promise variable
        var promises = [ ];

        return src.reduce( function ( seq, file ) {
          return seq.then( function () {
            me.fire( 'compile:file', { file: file } );
            return compileLess( file, opts.lessOptions, opts.userFns ).then( function ( params ) {
              var result = params.css;

              var rewriteDescriptor = me.rewriteURLS( result, file, path.dirname( dest ) );

              result = rewriteDescriptor.ctn;

              return autoPrefix( result, {
                file: file,
                dest: dest,
                autoprefixer: opts.autoprefixer
              } ).then( function ( prefixedCSS ) {
                promises.push( {
                  prefixed: prefixedCSS,
                  meta: {
                    dest: dest,
                    referencedFiles: rewriteDescriptor.referencedFiles,
                    imports: params.imports || [ ],
                    src: file
                  }
                } );
              } );
            }, function ( err ) {
              me.fire( 'error', err );
            } );
          } );
        }, Promise.resolve() ).then( function () {
          return Promise.all( promises ).then( function ( params ) {
            var results = [ ];
            //var meta = [ ];
            var files = [ ];

            params.forEach( function ( entry ) {
              results.push( entry.prefixed );
              var meta = entry.meta;
              //console.log( entry.prefixed );

              files = files.concat( meta.src )
                .concat( meta.imports )
                .concat( meta.referencedFiles );
            } );

            //results = results || [];
            var args = { referencedFiles: files };

            me.fire( 'compile:end', args );

            me.fire( 'before:write', extend( args, { dest: dest } ) );

            if ( args.cancel ) {
              return;
            }

            var result = results.join( os.EOL );

            var banner = opts.banner ? opts.banner + os.EOL : '';

            write( dest, (banner + result) );

            me.fire( 'write:file', args );

            if ( opts.minimize ) {
              var csso = require( 'csso' );
              var cssoOptions = opts.cssoOptions || { };
              var minimized = csso.justDoIt( result, !!cssoOptions.structureModifications );
              var minimizedDest = makeMinName( dest );

              write( minimizedDest, (banner + minimized) );

              me.fire( 'write:minimized', extend( { }, args, {
                dest: minimizedDest
              } ) );
            }

          } ).catch( function ( err ) {
            //console.log(err);
            me.fire( 'error', err );
          //throw err;
          } );
        } );
      }
    } );
  }
};
<|endoftext|>


<commit_before>Array.of = module.exports = Array.of || function () {
  var array = new Array(arguments.length)
  for (n = 0; n < arguments.length; n++){
    array[n] = arguments[n];
  }
  return array;
};<commit_msg>changed to += op instead of ++<commit_after>Array.of = module.exports = Array.of || function () {
  var array = new Array(arguments.length)
  for (n = 0; n < arguments.length; n += 1){
    array[n] = arguments[n];
  }
  return array;
};<|endoftext|>


<commit_before>var parsers = require('./parsers')
var url = require('url')
var CONTENT_TYPE_MAP = {
  'object': 'application/json',
  'string': 'text/plain'
}

function request (protocol, options, callback) {
  function done () {
    if (callback) callback()
    callback = undefined
  }

  // don't mutate
  options = Object.assign({}, options)

  if (options.url) {
    Object.assign(options, url.parse(options.url))
  }

  if (options.body !== undefined) {
    var typeOf = typeof options.body

    options.headers = options.headers || {}
    if (!options.headers['content-type']) {
      // don't mutate
      options.headers = Object.assign({}, options.headers)
      options.headers['content-type'] = CONTENT_TYPE_MAP[typeOf]
    }

    if (typeOf !== 'string') {
      options.body = JSON.stringify(options.body)
    }
  }

  var timeout
  var request = protocol.request(options, function (response) {
    var length = response.headers['content-length']
    if (options.limit && length > options.limit) return done(new Error('Content-Length exceeded limit'))

    function handle (err, body) {
      if (err) return done(err)

      var result = {
        statusCode: response.statusCode,
        headers: response.headers,
        body: body
      }

      if (timeout) {
        clearTimeout(timeout)
      }

      done(null, result)
    }

    var contentType = response.headers['content-type']
    if (contentType) {
      if (/application\/json/.test(contentType)) return parsers.json(response, length, handle)
      if (/text\/plain/.test(contentType)) return parsers.text(response, length, handle)
      if (/application\/octet-stream/.test(contentType)) return parsers.raw(response, length, handle)
    }

    handle()
  })

  request.on('error', done)

  if (options.timeout) {
    timeout = setTimeout(function () {
      request.abort()

      done(new Error('ETIMEDOUT'))
    }, options.timeout)
  }

  request.end(options.body)
}

module.exports = request
<commit_msg>add missing err/res arguments<commit_after>var parsers = require('./parsers')
var url = require('url')
var CONTENT_TYPE_MAP = {
  'object': 'application/json',
  'string': 'text/plain'
}

function request (protocol, options, callback) {
  function done (err, res) {
    if (callback) callback(err, res)
    callback = undefined
  }

  // don't mutate
  options = Object.assign({}, options)

  if (options.url) {
    Object.assign(options, url.parse(options.url))
  }

  if (options.body !== undefined) {
    var typeOf = typeof options.body

    options.headers = options.headers || {}
    if (!options.headers['content-type']) {
      // don't mutate
      options.headers = Object.assign({}, options.headers)
      options.headers['content-type'] = CONTENT_TYPE_MAP[typeOf]
    }

    if (typeOf !== 'string') {
      options.body = JSON.stringify(options.body)
    }
  }

  var timeout
  var request = protocol.request(options, function (response) {
    var length = response.headers['content-length']
    if (options.limit && length > options.limit) return done(new Error('Content-Length exceeded limit'))

    function handle (err, body) {
      if (err) return done(err)

      var result = {
        statusCode: response.statusCode,
        headers: response.headers,
        body: body
      }

      if (timeout) {
        clearTimeout(timeout)
      }

      done(null, result)
    }

    var contentType = response.headers['content-type']
    if (contentType) {
      if (/application\/json/.test(contentType)) return parsers.json(response, length, handle)
      if (/text\/plain/.test(contentType)) return parsers.text(response, length, handle)
      if (/application\/octet-stream/.test(contentType)) return parsers.raw(response, length, handle)
    }

    handle()
  })

  request.on('error', done)

  if (options.timeout) {
    timeout = setTimeout(function () {
      request.abort()

      done(new Error('ETIMEDOUT'))
    }, options.timeout)
  }

  request.end(options.body)
}

module.exports = request
<|endoftext|>


<commit_before>var kse=require("ksana-search");
var kde=require("ksana-database");
var bsearch=kde.bsearch;

var next=function(opts,cb,context) {
	kse.search(opts.db,opts.q,function(err,res){
		var db=res.engine;
		if (err) {
			cb(err);
			return;
		}
		var out=[];
		var next=opts.uti;
		var count=opts.count||10;
		for (var i=0;i<count;i++) {
			var next=db.nextTxtid(next);
			if (!next) break;
			out.push(next);
		}
		opts.uti=out;
		fetch(opts,cb,context);
	});
}
var prev=function(opts,cb,context) {
}

var toc=function(opts,cb,context) {
	var that=this;
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
		} else {
			var tocname=res.engine.get("meta").toc;
			res.engine.getTOC({tocname:tocname},function(data){
				cb(0,{name:tocname,toc:data,hits:res.rawresult});
			});
		}
	});
}

var txtids2key=function(txtids) {
	if (typeof txtids!="object") {
		txtids=[txtids];
	}
	var out=[];
	for (var i=0;i<txtids.length;i++) {
		var fseg=this.txtid2fileSeg(txtids[i]);
		out.push(["filecontents",fseg.file,fseg.seg]);
	}
	return out;
}

var hits2markup=function( Q,file,seg, text){
	var seg1=this.fileSegToAbsSeg(file,seg);
	var vpos=this.absSegToVpos(seg1-1);
	var vpos2=this.absSegToVpos(seg1);
	//console.log("rawresult",Q.rawresult,vpos,vpos2)
	var hits=kse.excerpt.realHitInRange(Q,vpos,vpos2,text);
	for (var i=0;i<hits.length;i++) {
		hits[i][2]="HL"+hits[i][2];
	}
	return hits;
}
var fetch=function(opts,cb,context) {
	var that=this;
	if (!opts.uti && !opts.vpos) {
		cb("missing uti or vpos");
		return;
	}
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
		} else {
			var uti=opts.uti;
			if (!uti) {
				uti=[];
				var vpos=opts.vpos;
				if (typeof vpos!="object") vpos=[vpos];
				for (var i=0;i<vpos.length;i++) {
					uti.push(res.engine.vpos2txtid(vpos[i]));
				}
			}
			var keys=txtids2key.call(res.engine,uti);
			if (typeof keys[0][1]=="undefined") {
				cb("uti not found: "+uti+" in "+opts.db);
				return;
			}

			res.engine.get(keys,function(data){
				var out=[];
				for (var i=0;i<uti.length;i++) {
					var hits=hits2markup.call(res.engine,res,keys[i][1],keys[i][2],data[i]);
					var vpos=res.engine.txtid2vpos(uti[i]);
					out.push({uti:uti[i],text:data[i],hits:hits,vpos:vpos});
				}
				cb(0,out);
			});
		}
	});
}

var excerpt2defaultoutput=function(excerpt) {
	var out=[];
	for (var i=0;i<excerpt.length;i++) {
		var ex=excerpt[i];
		var vpos=this.fileSegToVpos(ex.file,ex.seg);
		var txtid=this.vpos2txtid(vpos);
		out.push({uti:txtid,text:ex.text,hits:ex.realHits});
	}
	return out;
}
//use startfrom to specifiy starting posting
var excerpt=function(opts,cb,context) {
	var that=this;
	if (!opts.q) {
		cb("missing q");
		return;
	}
	kse.search(opts.db,opts.q,{nohighlight:true,range:{from:opts.from}},
		function(err,res){
		if (err) {
			cb(err);
		} else {
			//console.log(res.rawresult)
			cb(0,excerpt2defaultoutput.call(res.engine,res.excerpt));
		}
	});
}

var beginWith=function(s,txtids) {
	var out=[];
	for (var i=1;i<s.length;i++) {
		tofind=s.substr(0,i);
		var idx=bsearch(txtids,tofind);
		if (idx>-1) out.push(txtids[idx]);
	}
	return out;
}
var scan=function(opts,cb,context) {
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
			return;
		}
		var db=res.engine;
		var out=[];
		var txtid=db.get("txtid");
		for (var i=0;i<opts.sentence.length;i++) {
			var q=opts.sentence.substr(i);
			out=out.concat(beginWith(q,txtid));
		}
		cb(0,out);
	});
}

var filterField=function(items,regex) {
	var reg=new RegExp(regex);
	var out=[];
	for (var i=0;i<items.length;i++) {
		var item=items[i];
		if (item.match(reg)) {
			out.push(item);
		}
	}
	return out;
}

var filter=function(opts,cb,context) {
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
			return;
		}
		var db=res.engine;
		var out=[];

		if (opts.field) {
			values=db.get(["fields",opts.field],function(data){
				var matches=filterField(data,opts.regex);
				cb(0,matches);
			});
		} else {//use uti
			var values=db.get("txtid");
			var matches=filterField(values,opts.regex);
			cb(0,matches);
		}
	});
}

var API={
	next:next,
	prev:prev,
	toc:toc,
	fetch:fetch,
	excerpt:excerpt,
	scan:scan,
	filter:filter
}
module.exports=API;<commit_msg>add prevUti,nextUti<commit_after>var kse=require("ksana-search");
var kde=require("ksana-database");
var bsearch=kde.bsearch;

//make sure db is opened
var nextUti=function(opts,cb){
	kde.open(opts.db,function(err,db){
		if (err) cb(err);
		else cb(0,db.nextTxtid(opts.uti));
	});
}
//make sure db is opened
var prevUti=function(opts,cb){
	kde.open(opts.db,function(err,db){
		if (err) cb(err);
		else cb(0,db.prevTxtid(opts.uti));
	});
}

var next=function(opts,cb,context) {
	kse.search(opts.db,opts.q,function(err,res){
		var db=res.engine;
		if (err) {
			cb(err);
			return;
		}
		var out=[];
		var next=opts.uti;
		var count=opts.count||10;
		for (var i=0;i<count;i++) {
			var next=db.nextTxtid(next);
			if (!next) break;
			out.push(next);
		}
		opts.uti=out;
		fetch(opts,cb,context);
	});
}
var prev=function(opts,cb,context) {
}

var toc=function(opts,cb,context) {
	var that=this;
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
		} else {
			var tocname=res.engine.get("meta").toc;
			res.engine.getTOC({tocname:tocname},function(data){
				cb(0,{name:tocname,toc:data,hits:res.rawresult,tocname:tocname});
			});
		}
	});
}

var txtids2key=function(txtids) {
	if (typeof txtids!="object") {
		txtids=[txtids];
	}
	var out=[];
	for (var i=0;i<txtids.length;i++) {
		var fseg=this.txtid2fileSeg(txtids[i]);
		out.push(["filecontents",fseg.file,fseg.seg]);
	}
	return out;
}

var hits2markup=function( Q,file,seg, text){
	var seg1=this.fileSegToAbsSeg(file,seg);
	var vpos=this.absSegToVpos(seg1);
	var vpos2=this.absSegToVpos(seg1+1);
	var hits=kse.excerpt.realHitInRange(Q,vpos,vpos2,text);
	return hits;
}
var fetch=function(opts,cb,context) {
	var that=this;
	if (!opts.uti && !opts.vpos) {
		cb("missing uti or vpos");
		return;
	}
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
		} else {
			var uti=opts.uti;
			if (!uti) {
				uti=[];
				var vpos=opts.vpos;
				if (typeof vpos!="object") vpos=[vpos];
				for (var i=0;i<vpos.length;i++) {
					uti.push(res.engine.vpos2txtid(vpos[i]));
				}
			}
			var keys=txtids2key.call(res.engine,uti);
			if (typeof keys[0][1]=="undefined") {
				cb("uti not found: "+uti+" in "+opts.db);
				return;
			}

			res.engine.get(keys,function(data){
				var out=[];
				for (var i=0;i<keys.length;i++) {
					var hits=hits2markup.call(res.engine,res,keys[i][1],keys[i][2],data[i]);
					var vpos=res.engine.txtid2vpos(uti[i]);
					out.push({uti:uti[i],text:data[i],hits:hits,vpos:vpos});
				}
				cb(0,out);
			});
		}
	});
}

var excerpt2defaultoutput=function(excerpt) {
	var out=[];
	for (var i=0;i<excerpt.length;i++) {
		var ex=excerpt[i];
		var vpos=this.fileSegToVpos(ex.file,ex.seg);
		var txtid=this.vpos2txtid(vpos);
		out.push({uti:txtid,text:ex.text,hits:ex.realHits});
	}
	return out;
}
//use startfrom to specifiy starting posting
var excerpt=function(opts,cb,context) {
	var that=this;
	if (!opts.q) {
		cb("missing q");
		return;
	}
	kse.search(opts.db,opts.q,{nohighlight:true,range:{from:opts.from}},
		function(err,res){
		if (err) {
			cb(err);
		} else {
			//console.log(res.rawresult)
			cb(0,excerpt2defaultoutput.call(res.engine,res.excerpt));
		}
	});
}

var beginWith=function(s,txtids) {
	var out=[];
	for (var i=1;i<s.length;i++) {
		tofind=s.substr(0,i);
		var idx=bsearch(txtids,tofind);
		if (idx>-1) out.push(txtids[idx]);
	}
	return out;
}
var scan=function(opts,cb,context) {
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
			return;
		}
		var db=res.engine;
		var out=[];
		var txtid=db.get("txtid");
		for (var i=0;i<opts.sentence.length;i++) {
			var q=opts.sentence.substr(i);
			out=out.concat(beginWith(q,txtid));
		}
		cb(0,out);
	});
}

var filterField=function(items,regex) {
	var reg=new RegExp(regex);
	var out=[];
	for (var i=0;i<items.length;i++) {
		var item=items[i];
		if (item.match(reg)) {
			out.push(item);
		}
	}
	return out;
}

var filter=function(opts,cb,context) {
	kse.search(opts.db,opts.q,{},function(err,res){
		if (err) {
			cb(err);
			return;
		}
		var db=res.engine;
		var out=[];

		if (opts.field) {
			values=db.get(["fields",opts.field],function(data){
				var matches=filterField(data,opts.regex);
				cb(0,matches);
			});
		} else {//use uti
			var values=db.get("txtid");
			var matches=filterField(values,opts.regex);
			cb(0,matches);
		}
	});
}
var listkdb=kde.listkdb;

var fillHits=function(searchable,tofind,cb) {
	var taskqueue=[],out=[];
	for (var i=0;i<searchable.length;i++) {
		(function(dbname){
			taskqueue.push(function(err,data){
				if (typeof data=='object' && data.__empty) {
					//not pushing the first call
				} else {
					searchable.map(function(db){
						if (db.shortname===data.dbname) {
							db.hits=data.rawresult.length;
						}
					})
				}
				kse.search(dbname,tofind,taskqueue.shift(0,data));
			});;
		})(searchable[i].fullname)
	};

	taskqueue.push(function(err,data){

		searchable.sort(function(a,b){
			return b.hits-a.hits;
		});

		cb(searchable);
	});
	taskqueue.shift()(0,{__empty:true});
}

var API={
	next:next,
	prev:prev,
	nextUti:nextUti,
	prevUti:prevUti,
	toc:toc,
	fetch:fetch,
	excerpt:excerpt,
	scan:scan,
	filter:filter,
	listkdb:listkdb,
	fillHits:fillHits
}
module.exports=API;<|endoftext|>


<commit_before>'use strict';

/** @ignore */
let utils = require('./lib/utils');

module.exports.EmbedEngine = require('./lib/classes/EmbedEngine');
module.exports.URLEmbedProvider = require('./lib/classes/URLEmbedProvider');
module.exports.OEmbedProvider = require('./lib/classes/OEmbedProvider');
module.exports.defaultProviderClasses = {};
module.exports.errorClasses = {};

let providerList = utils.loadClassesFromDirectory(__dirname + '/lib/classes/default_providers');

for (let i = 0; i < providerList.length; i++) {
  let Provider = providerList[i];
  module.exports.defaultProviderClasses[Provider.name] = Provider;
}

let errorList = utils.loadClassesFromDirectory(__dirname + '/lib/classes/errors');

for (let i = 0; i < errorList.length; i++) {
  let ErrorClass = errorList[i];
  let errorInstance = new ErrorClass();
  module.exports.errorClasses[typeof errorInstance] = ErrorClass;
}<commit_msg>Added reference to the Embed class<commit_after>'use strict';

/** @ignore */
let utils = require('./lib/utils');

module.exports.EmbedEngine = require('./lib/classes/EmbedEngine');
module.exports.URLEmbedProvider = require('./lib/classes/URLEmbedProvider');
module.exports.OEmbedProvider = require('./lib/classes/OEmbedProvider');
module.exports.Embed = require('./lib/classes/Embed');
module.exports.defaultProviderClasses = {};
module.exports.errorClasses = {};

let providerList = utils.loadClassesFromDirectory(__dirname + '/lib/classes/default_providers');

for (let i = 0; i < providerList.length; i++) {
  let Provider = providerList[i];
  module.exports.defaultProviderClasses[Provider.name] = Provider;
}

let errorList = utils.loadClassesFromDirectory(__dirname + '/lib/classes/errors');

for (let i = 0; i < errorList.length; i++) {
  let ErrorClass = errorList[i];
  let errorInstance = new ErrorClass();
  module.exports.errorClasses[typeof errorInstance] = ErrorClass;
}<|endoftext|>


<commit_before>var jade  = require('jade');
var coffee = require('./coffee');
//process.env.DEBUG = 'derby-jade';
var debug = require('debug')('derby-jade');
var options;
var defaultIndent = 2;

module.exports = function (app, opts) {
  options = opts || {};
  app.viewExtensions.push('.jade');
  app.compilers['.jade'] = compiler;
};

function addindent(source, count) {
  if (count === undefined) count = defaultIndent;
  var indentation = '';
  for (var i = 0; i < count; i++) {
    indentation += ' ';
  }
  return indentation + source;
}

function preprocess(source) {
  return source
    // Replace if, else, each, etc statements to __derby-statement(type="if", value="expression")
    // we cheat Jade, because it has it`s own statements
    .replace(/^([ \t]+)(if|else(?:[ \t]+if)?|unless|each|with|bound|unbound|on)((?:[ \t]|\().+)?$/gm,
      function (statement, indentation, type, expression) {
        if (options.coffee) {
          expression = ' ' + coffee(expression);
        }
        return indentation + '__derby-statement(type=\"' + type + '\"' +
          (expression ? ' value=\"' + escape(expression) + '\"' : '') + ')';
    })
    // This is needed for coffee
    // find all statements in {{..}}
    .replace(/{{([^\/].*?)}}/g, function(statement, expression) {
      var block = '';
      if (blockCaptures = /^((?:unescaped|if|else if|unless|each|with|bound|unbound|on)\*?) *([^\n]*)/.exec(expression)) {
        block = blockCaptures[1] + ' ';
        expression = blockCaptures[2];
      } else if (expression === 'else') {
        block = expression;
        expression = '';
      }
      if (options.coffee) expression = coffee(expression);
      return '{{' + block + expression + '}}';
    })
    // Make Derby attribues unescaped
    .replace(/on-(.*?)=(['"])(.*?)\2/gm, function(statement, type, quote, expression) {
      if (options.coffee) expression = coffee(expression);
      return 'on-' + type + '!=\"' + expression + '\"';
    });
}

function postprocess(html) {
  return html
    // Clean redundant Derby statements
    .replace(/[ \t]*<\/__derby-statement>\n?(?=\s+<__derby-statement type="else([ \t]+if)?")/g, '')
    // Replace Derby statements back
    .replace(/<__derby-statement type="([^"]+)"(?: value="([^"]+)")?>/gm, function (statement, type, value) {
      if (value === '%20') value = '';
      return '{{' + type + (value ? unescape(value) : '') + '}}';
    })
    // Closing Derby statements
    .replace(/<\/__derby-statement>/g, '{{/}}');
}

function compiler(file, fileName) {
  var out = [];
  var lines = file.split('\n');
  var lastComment = Infinity;
  var lastScript = Infinity;
  var script = [];
  var scripts = [];
  var block = [];
  var debugString;

  function renderBlock() {
    if (block.length) {
      debugString += ', block end';
      var source = preprocess(block.join('\n'));
      block = [];
      var jadeOptions = {
        filename: fileName,
        pretty: true
      }
      jade.render(source, jadeOptions, function (error, html) {
        if (error) throw error;
        html = html
          // Remove underscores
          .replace(/<_derby_/g, '<')
          .replace(/<\/_derby_/g, '<\/')
          // Add colons
          .replace(/^\s*(<([\w-:]+))((?:\b[^>]+)?>)\n?([\s\S]*?)\n?<\/\2>$/, function (template, left, name, right, content) {
            return left + ':' + right + (content ? '\n' + content : '');
          })
          // Add scripts
          .replace(/<script(\d*)><\/script\1>/g, function(statement, index) {
            return scripts[index];
          });
        out.push(postprocess(html));
      });
    }
  }

  function closeScript() {
    if (script.length) {
      var source = script.join('\n');
      if (options.coffee) source = coffee(source);
      script = [];
      var scriptSource = '<script>';
      source.split('\n').forEach(function (scriptLine) {
        scriptLine = scriptLine.replace(/^\s*/g, '');
        scriptSource += '\n' + addindent(scriptLine, lastScript + defaultIndent);
      });
      scriptSource += '\n' + addindent('</script>', lastScript);
      scripts.push(scriptSource);
      block.push(addindent('script' + (scripts.length - 1), lastScript));
    }
  }

  for (var i = 0; i < lines.length; i++) {
    var line = lines[i];

    var res = /^(\s*)(.*?)$/g.exec(line);
    var spaces = res[1];
    var statement = res[2];
    var indent = spaces.length;
    debugString = addindent(statement, indent) + ' | ' + indent;

    // Comment
    if (lastComment !== Infinity) {
      if (indent > lastComment) {
        debug(debugString + ', comment');
        continue;
      } else {
        debugString += ', comment end';
        lastComment = Infinity;
      }
    }
    if (statement.indexOf('//') === 0) {
      lastComment = indent;
      debug(debugString + ', comment start');
      continue;
    }
    // Script
    if (lastScript !== Infinity) {
      if (indent > lastScript) {
        script.push(addindent(statement, indent));
        debug(debugString + ', script');
        continue;
      } else {
        debugString += ', script end';
        closeScript();
        lastScript = Infinity;
      }
    }
    if (statement.indexOf('script.') === 0) {
      // Script block
      lastScript = indent;
      debug(debugString + ', script.start');
      continue;
    }
    if (statement.indexOf('script ') === 0) {
      // Script line
      if (options.coffee) statement = 'script ' + coffee(statement.slice(7));
      block.push(addindent(statement, indent));
      debug(debugString + ', script line');
      continue;
    }
    // Empty line
    if (!statement.length) {
      block.push('');
      debug(debugString + ', empty');
      continue;
    }

    if (indent === 0) {
      // Derby tag
      // It means that we are going to start another block,
      // so we should render last one first
      renderBlock();
      // Remove colons after Derby tags
      // it makes colons optional
      statement = statement.replace(/:([\n\s(])/, function(statement, symbol) {
        return symbol;
      });
      statement = statement.replace(/:$/, '');
      // We add underscore to avoid problems when Derby tag name
      // is same as non closing tags
      statement = '_derby_' + statement;
      debugString += ', block start';
      block.push(statement);
    } else {
      debugString += ', block';
      block.push(line);
    }
    debug(debugString);
  }
  // Close script if exist and render block
  closeScript();
  renderBlock();

  return out.join('\n');
}<commit_msg>windows line ending support<commit_after>var jade  = require('jade');
var coffee = require('./coffee');
//process.env.DEBUG = 'derby-jade';
var debug = require('debug')('derby-jade');
var options;
var defaultIndent = 2;
//process.platform = 'win32';
var newLine = process.platform === 'win32' ? '\r\n' : '\n';
var regNewLine = process.platform === 'win32' ? '\\r\\n' : '\\n';

function r(pattern, modifiers) {
  return new RegExp(pattern, modifiers);
}

module.exports = function (app, opts) {
  options = opts || {};
  app.viewExtensions.push('.jade');
  app.compilers['.jade'] = compiler;
};

function addindent(source, count) {
  if (count === undefined) count = defaultIndent;
  var indentation = '';
  for (var i = 0; i < count; i++) {
    indentation += ' ';
  }
  return indentation + source;
}

function preprocess(source) {
  return source
    // Replace if, else, each, etc statements to __derby-statement(type="if", value="expression")
    // we cheat Jade, because it has it`s own statements
    .replace(/^([ \t]+)(if|else(?:[ \t]+if)?|unless|each|with|bound|unbound|on)((?:[ \t]|\().+)?$/gm,
      function (statement, indentation, type, expression) {
        if (options.coffee) {
          expression = ' ' + coffee(expression);
        }
        return indentation + '__derby-statement(type=\"' + type + '\"' +
          (expression ? ' value=\"' + escape(expression) + '\"' : '') + ')';
    })
    // This is needed for coffee
    // find all statements in {{..}}
    .replace(/{{([^\/].*?)}}/g, function(statement, expression) {
      var block = '';
      if (blockCaptures = /^((?:unescaped|if|else if|unless|each|with|bound|unbound|on)\*?) *([^\n]*)/.exec(expression)) {
        block = blockCaptures[1] + ' ';
        expression = blockCaptures[2];
      } else if (expression === 'else') {
        block = expression;
        expression = '';
      }
      if (options.coffee) expression = coffee(expression);
      return '{{' + block + expression + '}}';
    })
    // Make Derby attribues unescaped
    .replace(/on-(.*?)=(['"])(.*?)\2/gm, function(statement, type, quote, expression) {
      if (options.coffee) expression = coffee(expression);
      return 'on-' + type + '!=\"' + expression + '\"';
    });
}

function postprocess(html) {
  return html
    // Clean redundant Derby statements
    //.replace(/[ \t]*<\/__derby-statement>\n?(?=\s+<__derby-statement type="else([ \t]+if)?")/g, '')
    .replace(r('[ \\t]*<\\/__derby-statement>' + regNewLine + '?(?=\\s+<__derby-statement type="else([ \\t]+if)?")', 'g'), '')
    // Replace Derby statements back
    .replace(/<__derby-statement type="([^"]+)"(?: value="([^"]+)")?>/gm, function (statement, type, value) {
      if (value === '%20') value = '';
      return '{{' + type + (value ? unescape(value) : '') + '}}';
    })
    // Closing Derby statements
    .replace(/<\/__derby-statement>/g, '{{/}}');
}

function compiler(file, fileName) {
  var out = [];
  var lines = file.split(newLine);
  var lastComment = Infinity;
  var lastScript = Infinity;
  var script = [];
  var scripts = [];
  var block = [];
  var debugString;

  function renderBlock() {
    if (block.length) {
      debugString += ', block end';
      var source = preprocess(block.join(newLine));
      block = [];
      var jadeOptions = {
        filename: fileName,
        pretty: true
      }
      jade.render(source, jadeOptions, function (error, html) {
        if (error) throw error;
        html = html
          .replace(/\n/g, newLine)
          // Remove underscores
          .replace(/<_derby_/g, '<')
          .replace(/<\/_derby_/g, '<\/')
          // Add colons
          //.replace(/^\s*(<([\w-:]+))((?:\b[^>]+)?>)\n?([\s\S]*?)\n?<\/\2>$/, function (template, left, name, right, content) {
          //  return left + ':' + right + (content ? newLine + content : '');
          //})
          .replace(r('^\\s*(<([\\w-:]+))((?:\\b[^>]+)?>)(?:' + regNewLine + ')?([\\s\\S]*?)(?:' + regNewLine + ')?<\\/\\2>$'), function (template, left, name, right, content) {
            return left + ':' + right + (content ? newLine + content : '');
          })
          // Add scripts
          .replace(/<script(\d*)><\/script\1>/g, function(statement, index) {
            return scripts[index];
          })
          .replace(/\r$/g, '');
        out.push(postprocess(html));
      });
    }
  }

  function closeScript() {
    if (script.length) {
      var source = script.join(newLine);
      if (options.coffee) source = coffee(source);
      script = [];
      var scriptSource = '<script>';
      source.split(newLine).forEach(function (scriptLine) {
        scriptLine = scriptLine.replace(/^\s*/g, '');
        scriptSource += newLine + addindent(scriptLine, lastScript + defaultIndent);
      });
      scriptSource += newLine + addindent('</script>', lastScript);
      scripts.push(scriptSource);
      block.push(addindent('script' + (scripts.length - 1), lastScript));
    }
  }

  for (var i = 0; i < lines.length; i++) {
    var line = lines[i];

    var res = /^(\s*)(.*?)$/g.exec(line);
    var spaces = res[1];
    var statement = res[2];
    var indent = spaces.length;
    debugString = addindent(statement, indent) + ' | ' + indent;

    // Comment
    if (lastComment !== Infinity) {
      if (indent > lastComment) {
        debug(debugString + ', comment');
        continue;
      } else {
        debugString += ', comment end';
        lastComment = Infinity;
      }
    }
    if (statement.indexOf('//') === 0) {
      lastComment = indent;
      debug(debugString + ', comment start');
      continue;
    }
    // Script
    if (lastScript !== Infinity) {
      if (indent > lastScript) {
        script.push(addindent(statement, indent));
        debug(debugString + ', script');
        continue;
      } else {
        debugString += ', script end';
        closeScript();
        lastScript = Infinity;
      }
    }
    if (statement.indexOf('script.') === 0) {
      // Script block
      lastScript = indent;
      debug(debugString + ', script.start');
      continue;
    }
    if (statement.indexOf('script ') === 0) {
      // Script line
      if (options.coffee) statement = 'script ' + coffee(statement.slice(7));
      block.push(addindent(statement, indent));
      debug(debugString + ', script line');
      continue;
    }
    // Empty line
    if (!statement.length) {
      block.push('');
      debug(debugString + ', empty');
      continue;
    }

    if (indent === 0) {
      // Derby tag
      // It means that we are going to start another block,
      // so we should render last one first
      renderBlock();
      // Remove colons after Derby tags
      // it makes colons optional
      statement = statement.replace(/:([\n\s(])/, function(statement, symbol) {
        return symbol;
      });
      statement = statement.replace(/:$/, '');
      // We add underscore to avoid problems when Derby tag name
      // is same as non closing tags
      statement = '_derby_' + statement;
      debugString += ', block start';
      block.push(statement);
    } else {
      debugString += ', block';
      block.push(line);
    }
    debug(debugString);
  }
  // Close script if exist and render block
  closeScript();
  renderBlock();

  return out.join(newLine);
}<|endoftext|>


<commit_before>var express = require('express'),
  router = express.Router(),
  mongoose = require('mongoose'),
  Schema = mongoose.Schema,
  _ = require('underscore'),
  debug = require('debug')('mera'),
  ejs = require('ejs');

function mongooseRoute(model, options) {
  var router = express.Router();

  function error(method, err, statusCode) {
    var msg = 'Failed to ' + method + ' ' + model.modelName + ' : ' + err;
    var retErr = new Error(msg);
    err.statusCode = statusCode || 500;
    debug('err: %j', retErr);
    return retErr;
  }

  function convert(data) {
    data = _.pick(data, props);
    _.each(_.keys(propsMapping), k => {
      if (data[k] && propsMapping[k] != k) {
        data[propsMapping[k]] = data[k];
        delete data[k];
      }
    });
    return data;
  }

  function output(item) {
    var output = {};
    props.forEach(p => { output[p] = item[p] }); // item can have virtual props so they need to be assigned one by one.
    return output;
  }

  var options = options || {},
    props = options.props || _.keys(model.schema.tree).filter(e => !/^_/.test(e)),
    propsMapping = _.extend({ 'id': '_id' }, options.propsMapping);

  // protect the method if defined in protects
  router.use('/', function(req, rest, next) {
    var protects = options.protects || {};
    var protect = req.method === 'GET' ? (req.url === '/' ? protects.LIST : protects.GET) : protects[req.method];
    if (protect) {
      protect(req, next);
    } else {
      next();
    }
  });

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

    // filter buildup
    var filter = null;
    // regard _filter in query firstly
    if (req.query._filters) {
      try {
        filter = _.pick(JSON.parse(req.query._filters), props);
      } catch (e) {
        debug('not valid _filter although present: %j', req.query._filter);
      }
    }
    // if _filter not present, look for all direct props, which not starting with _
    if (!filter) {
      filter = _.pick(req.query, props);
    }
    filter = _.extend(convert(filter), options.baseFilter);
    debug('List %s by filter %j', model.modelName, filter);

    // listOptions buildup
    var lo = {
      limit: parseInt(req.query._perPage) || 0
    };
    lo.skip = Math.max((req.query._page || 1) - 1, 0) * lo.limit;
    if (req.query._sortField && req.query._sortDir) {
      lo.sort = {};
      lo.sort[req.query._sortField.replace(/^id/, '_id')] = req.query._sortDir.toUpperCase() == 'ASC' ? 1 : -1;
    } else {
      lo.sort = options.defaultSort;
    }
    debug('get list options from request: %j', lo);

    // list model
    model.count(filter, function(err, num) {
      if (err) {
        return next(error('LIST', err));
      }
      model.find(filter).skip(lo.skip).limit(lo.limit).sort(lo.sort).exec(function(err2, items) {
        if (err2) {
          return next(error('LIST', err2));
        }
        res.set('X-Total-Count', num).json(items.map(output));
      });
    });
  });

  router.post('/', function(req, res, next) {
    var data = convert(req.body);
    debug('Post to model %s by data %j', model.modelName, data);

    model.create(data, function(err, item) {
      if (err) {
        return next(error('POST', err));
      }
      res.json(output(item));
    });
  });

  router.get('/:id', function(req, res, next) {
    debug('Get model %s by id %s', model.modelName, req.params.id);
    model.findOne({
      _id: req.params.id
    }).exec(function(err, item) {
      if (err) {
        return next(error('GET', err));
      }
      if (!item) {
        return next();
      }
      res.json(output(item));
    });
  });

  router.put('/:id', function(req, res, next) {
    var data = convert(req.body);
    debug('Put to model %s, id %s by data %j', model.modelName, req.params.id, data);

    model.findOne({
      _id: req.params.id
    }).exec(function(err, item) {
      if (err) {
        return next(error('PUT', err));
      }
      if (!item) {
        return next();
      }
      _.extend(item, data);
      item.save(function(err) {
        if (err) {
          return next(error('PUT', err));
        }
        res.json(output(item));
      });
    });
  });

  router.delete('/:id', function(req, res, next) {
    debug('delete model %s by id %s', model.modelName, req.params.id);

    model.remove({
      _id: req.params['id']
    }).exec(function(err, item) {
      if (err) {
        return next(error('DELETE', err));
      }
      res.json({});
    });
  });

  // var ngaBaseTemplate = fs.readFileSync(path.join(__dirname, './templates/nga-base.ejs'));
  // router.get('/nga-base.js', function(req, res, next) {
  //   var content = ejs.render(ngaBaseTemplate, {
  //     appName: options.appName || (model.modelName + 'App'),
  //     title: options.title || model.modelName,
  //     baseApiUrl: req.baseUrl.split('/').slice(0,-1).join('/')
  //   });
  //   res.set('content-type', 'text/javascript').end(content);
  // });

  // var ngaBaseTemplate = fs.readFileSync(path.join(__dirname, './templates/nga-entity.ejs'));
  // router.get('/nga-entity.js', function(req, res, next) {

  // });

  return router;
}

module.exports = mongooseRoute;
<commit_msg>add support for timeFilter<commit_after>var express = require('express'),
  router = express.Router(),
  mongoose = require('mongoose'),
  Schema = mongoose.Schema,
  _ = require('underscore'),
  debug = require('debug')('mera');

function mongooseRoute(model, options) {
  var router = express.Router();

  var options = options || {},
    props = options.props || _.keys(model.schema.tree).filter(e => !/^_/.test(e)),
    propsMapping = _.extend({ 'id': '_id' }, options.propsMapping);

  function error(method, err, statusCode) {
    var msg = 'Failed to ' + method + ' ' + model.modelName + ' : ' + err;
    var retErr = new Error(msg);
    err.statusCode = statusCode || 500;
    debug('err: %j', retErr);
    return retErr;
  }

  function convert(data) {
    data = _.pick(data, props);
    _.each(_.keys(propsMapping), k => {
      if (data[k] && propsMapping[k] != k) {
        data[propsMapping[k]] = data[k];
        delete data[k];
      }
    });
    return data;
  }

  function output(item) {
    var output = {};
    props.forEach(p => { output[p] = item[p] }); // item can have virtual props so they need to be assigned one by one.
    return output;
  }

  // time filter works in such a way:
  // if start is given, only look at end, and start/end are parsed literally by moment.js, gte start, and lt end
  // otherwise look at start_time and then end_time
  // so if given start and end_time, only start takes effects
  // a special handle on end_time is if YYYY-MM-DD is given, we regard it as a full day included
  function getTimeFilter(rawFilter) {
    if (!options.timeFilter) {
      return null;
    }
    var f = {};
    if (rawFilter.start) {
      f.$gte = moment(rawFilter.start).toDate();
      if (rawFilter.end) {
        f.$lt = moment(rawFilter.end).toDate();
      }
    } else if (rawFilter.start_time) {
      f.$gte = moment(rawFilter.start_time).toDate();
      if (rawFilter.end_time) {
        if (/[0-9]{4,4}-[0-9]{2,2}-[0-9]{2,2}/.test(rawFilter.end_time)) {
          f.$lt = moment(rawFilter.end_time).add(1, 'day').startOf('day').toDate();
        } else {
          f.$lt = moment(rawFilter.end_time).toDate();
        }
      }
    }
    if (_.isEmpty(f)) {
      return null;
    }
    var timeFilter = {};
    timeFilter[options.timeFilter] = f;
    return timeFilter;
  }

  // protect the method if defined in protects
  router.use('/', function(req, rest, next) {
    var protects = options.protects || {};
    var protect = req.method === 'GET' ? (req.url === '/' ? protects.LIST : protects.GET) : protects[req.method];
    if (protect) {
      protect(req, next);
    } else {
      next();
    }
  });

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

    // filter buildup
    var filter = null;

    // regard _filter in query firstly
    if (req.query._filters) {
      try {
        filter = _.pick(JSON.parse(req.query._filters), props);
        _.extend(filter, getTimeFilter(req.query._filter));
      } catch (e) {
        debug('not valid _filter although present: %j', req.query._filter);
      }
    }
    // if _filter not present, look for all direct props, which not starting with _
    if (!filter) {
      filter = _.pick(req.query, props);
      _.extend(filter, getTimeFilter(req.query));
    }

    filter = _.extend(convert(filter), options.baseFilter);
    debug('List %s by filter %j', model.modelName, filter);

    // listOptions buildup
    var lo = {
      limit: parseInt(req.query._perPage) || 0
    };
    lo.skip = Math.max((req.query._page || 1) - 1, 0) * lo.limit;
    if (req.query._sortField && req.query._sortDir) {
      lo.sort = {};
      lo.sort[req.query._sortField.replace(/^id/, '_id')] = req.query._sortDir.toUpperCase() == 'ASC' ? 1 : -1;
    } else {
      lo.sort = options.defaultSort;
    }
    debug('get list options from request: %j', lo);

    // list model
    model.count(filter, function(err, num) {
      if (err) {
        return next(error('LIST', err));
      }
      model.find(filter).skip(lo.skip).limit(lo.limit).sort(lo.sort).exec(function(err2, items) {
        if (err2) {
          return next(error('LIST', err2));
        }
        res.set('X-Total-Count', num).json(items.map(output));
      });
    });
  });

  router.post('/', function(req, res, next) {
    var data = convert(req.body);
    debug('Post to model %s by data %j', model.modelName, data);

    model.create(data, function(err, item) {
      if (err) {
        return next(error('POST', err));
      }
      res.json(output(item));
    });
  });

  router.get('/:id', function(req, res, next) {
    debug('Get model %s by id %s', model.modelName, req.params.id);
    model.findOne({
      _id: req.params.id
    }).exec(function(err, item) {
      if (err) {
        return next(error('GET', err));
      }
      if (!item) {
        return next();
      }
      res.json(output(item));
    });
  });

  router.put('/:id', function(req, res, next) {
    var data = convert(req.body);
    debug('Put to model %s, id %s by data %j', model.modelName, req.params.id, data);

    model.findOne({
      _id: req.params.id
    }).exec(function(err, item) {
      if (err) {
        return next(error('PUT', err));
      }
      if (!item) {
        return next();
      }
      _.extend(item, data);
      item.save(function(err) {
        if (err) {
          return next(error('PUT', err));
        }
        res.json(output(item));
      });
    });
  });

  router.delete('/:id', function(req, res, next) {
    debug('delete model %s by id %s', model.modelName, req.params.id);

    model.remove({
      _id: req.params['id']
    }).exec(function(err, item) {
      if (err) {
        return next(error('DELETE', err));
      }
      res.json({});
    });
  });

  return router;
}

module.exports = mongooseRoute;
<|endoftext|>


<commit_before>'use strict'
const immer = require('immer')
const produce = immer.default

const { Subject } = require('rxjs')

const {debounceTime, filter, takeWhile, map, share, mergeMap, groupBy, startWith} = require('rxjs/operators')

const _set = require('lodash.set')
const _get = require('lodash.get')

const utils = require('./utils')
const getMainKey = utils.getMainKey
const splitLastKey = utils.splitLastKey

function Justore (initData, storeName) {
  let self = this
  self.name = storeName || 'Anonymous Store'
  self.debugOn = []

  self.bufferWrite = true

  function isIndebug (key) {
    return self.debugOn && self.debugOn.indexOf && self.debugOn.indexOf(key) >= 0
  }

  self.onError = function () {}

  /** @protected */
  self._getErrorMsg = function (msg) {
    return '[Store ' + self.name + '] ' + msg
  }

  var data = initData || {}
  var previousData = data

  function dataSetter (path, payload) {
    let newData = produce(data, function (draft) {
      _set(draft, path, payload)
    })
    updatePreviousData()
    data = newData
    return {newData: data, previousData: previousData}
  }
  function batchSetter (manipulateFunction) {
    let newData = produce(data, manipulateFunction)
    updatePreviousData()
    data = newData
    return {newData: data, previousData: previousData}
  }

  function dataDeleter (path) {
    let newData = produce(data, function (draft) {
      let pathPair = splitLastKey(path)
      if (pathPair[1]) {
        delete _get(draft, pathPair[1])[pathPair[0]]
      } else {
        delete draft[pathPair[0]]
      }
    })
    updatePreviousData()
    data = newData
    return {newData: data, previousData: previousData}
  }

  function dataGetter (path, isPre) {
    var source = isPre ? previousData : data
    return _get(source, path)
  }

  function updatePreviousData () {
    previousData = data
  }

  /** @protected */
  this.writeSubject = new Subject()

  /**
   * Write data to the store, return store
   * @param {String} updatePath - Update path
   * @param {Object} value - The value
   * @param {Object} [opt] - Options
   * @param {Boolean} [opt.mute=false] - Mute the change events
   * @return {Object} self - Justore instance
   * */
  this.write = function (updatePath, value, opt) {
    let conf = {
      key: getMainKey(updatePath),
      path: updatePath,
      d: value,
      opt: opt || {}
    }

    if (isIndebug(conf.key)) { debugger }
    let updateResult = dataSetter(conf.path, conf.d)
    conf.newData = updateResult.newData
    conf.previousData = updateResult.previousData
    self.writeSubject.next(conf)
    return self
  }

  this.delete = function (updatePath, opt) {
    let conf = {
      key: getMainKey(updatePath),
      path: updatePath,
      opt: opt || {}
    }
    if (isIndebug(conf.key)) { debugger }
    let updateResult = dataDeleter(conf.path)
    conf.newData = updateResult.newData
    conf.previousData = updateResult.previousData
    self.writeSubject.next(conf)
    return self
  }

  this.batchWrite = function (updatePaths, manipulateFunction, opt) {
    let updateResult = batchSetter(manipulateFunction)
    let paths = (updatePaths || [])
    if (!Array.isArray(paths)) {
      throw TypeError('updatePaths should be an Array of update paths')
    }
    paths.forEach(function (updatePath) {
      let conf = {
        key: getMainKey(updatePath),
        path: updatePath,
        d: _get(updateResult.newData, updatePath),
        opt: opt || {}
      }
      conf.newData = updateResult.newData
      conf.previousData = updateResult.previousData
      self.writeSubject.next(conf)
    })
    return self
  }

  function onReject (reson) {
    self.onError(reson)
    console.warn('Justore write ' + self.name + ' Error: ', reson)
  }

  this.writing$ = this.writeSubject
    .pipe(
      groupBy(function (conf) { return conf.path }),
      mergeMap(function (g) {
        var ob = self.bufferWrite ? g.pipe(debounceTime(0)) : g
        return ob
      }),
      share()
    )

  this.writing$.subscribe(function (info) {
    updatePreviousData()
    return info
  }, onReject)

  /**
   * Read the value from store
   * @param {String} key - Store key
   */
  self.read = function (key) {
    return key === '*' ? data : dataGetter(key)
  }

  /**
   * Subscribe to the writing$
   * @param {String} path - Subscribe update path
   * @param {Function} [onchange] - onNextHandler
   * @param {Boolean} [immediate] - use 'startWith' operator
   * @return {Subscription} subscription - subscription
   */
  self.sub = function (path, onchange, immediate) {
    var stream = self.writing$
      .pipe(
        takeWhile(function (info) {
          let keyPairs = splitLastKey(path)
          const inData = function (d, pairs) { return pairs[1] ? pairs[0] in (_get(d, pairs[1]) || {}) : pairs[0] in d }

          // Must from have -> don't have
          if (inData(info.newData, keyPairs)) {
            return true
          } else if (inData(info.previousData, keyPairs)) {
            return false
          } else {
            return true
          }
        }),
        filter(function (info) {
          if (info.opt.mute) {
            return false
          }
          return _get(info.newData, path) !== _get(info.previousData, path)
        })
      )

    function genPair (info) {
      return [_get(info.newData, path), _get(info.previousData, path)]
    }

    if (immediate) {
      stream = stream
        .pipe(
          map(genPair),
          startWith(
            [dataGetter(path), dataGetter(path, true)]
          )
        )
    } else {
      stream = stream
        .pipe(map(genPair))
    }

    if (onchange) {
      let subscription = stream
        .subscribe(function (arg) {
          onchange.apply(self, arg)
        }, onReject)

      return subscription
    } else {
      return stream
    }
  }
};

Justore.prototype.createReactMixin = function (key) {
  var self = this
  let subscriptions
  return {
    componentWillMount: function () {
      subscriptions = self.sub(key, this.onStoreChange)
    },
    componentWillUnmount: function () {
      if (subscriptions && subscriptions.unsubscribe) {
        subscriptions.unsubscribe()
      }
    }
  }
}

Justore.prototype.report = function () {
  return this.read('*')
}

module.exports = Justore
<commit_msg>Smaller rx<commit_after>'use strict'
const immer = require('immer')
const produce = immer.default

const Subject = require('rxjs/Subject').Subject
const debounceTime = require('rxjs/operators/debounceTime').debounceTime
const filter = require('rxjs/operators/filter').filter
const takeWhile = require('rxjs/operators/takeWhile').takeWhile
const map = require('rxjs/operators/map').map
const share = require('rxjs/operators/share').share
const mergeMap = require('rxjs/operators/mergeMap').mergeMap
const groupBy = require('rxjs/operators/groupBy').groupBy
const startWith = require('rxjs/operators/startWith').startWith

const _set = require('lodash.set')
const _get = require('lodash.get')

const utils = require('./utils')
const getMainKey = utils.getMainKey
const splitLastKey = utils.splitLastKey

function Justore (initData, storeName) {
  let self = this
  self.name = storeName || 'Anonymous Store'
  self.debugOn = []

  self.bufferWrite = true

  function isIndebug (key) {
    return self.debugOn && self.debugOn.indexOf && self.debugOn.indexOf(key) >= 0
  }

  self.onError = function () {}

  /** @protected */
  self._getErrorMsg = function (msg) {
    return '[Store ' + self.name + '] ' + msg
  }

  var data = initData || {}
  var previousData = data

  function dataSetter (path, payload) {
    let newData = produce(data, function (draft) {
      _set(draft, path, payload)
    })
    updatePreviousData()
    data = newData
    return {newData: data, previousData: previousData}
  }
  function batchSetter (manipulateFunction) {
    let newData = produce(data, manipulateFunction)
    updatePreviousData()
    data = newData
    return {newData: data, previousData: previousData}
  }

  function dataDeleter (path) {
    let newData = produce(data, function (draft) {
      let pathPair = splitLastKey(path)
      if (pathPair[1]) {
        delete _get(draft, pathPair[1])[pathPair[0]]
      } else {
        delete draft[pathPair[0]]
      }
    })
    updatePreviousData()
    data = newData
    return {newData: data, previousData: previousData}
  }

  function dataGetter (path, isPre) {
    var source = isPre ? previousData : data
    return _get(source, path)
  }

  function updatePreviousData () {
    previousData = data
  }

  /** @protected */
  this.writeSubject = new Subject()

  /**
   * Write data to the store, return store
   * @param {String} updatePath - Update path
   * @param {Object} value - The value
   * @param {Object} [opt] - Options
   * @param {Boolean} [opt.mute=false] - Mute the change events
   * @return {Object} self - Justore instance
   * */
  this.write = function (updatePath, value, opt) {
    let conf = {
      key: getMainKey(updatePath),
      path: updatePath,
      d: value,
      opt: opt || {}
    }

    if (isIndebug(conf.key)) { debugger }
    let updateResult = dataSetter(conf.path, conf.d)
    conf.newData = updateResult.newData
    conf.previousData = updateResult.previousData
    self.writeSubject.next(conf)
    return self
  }

  this.delete = function (updatePath, opt) {
    let conf = {
      key: getMainKey(updatePath),
      path: updatePath,
      opt: opt || {}
    }
    if (isIndebug(conf.key)) { debugger }
    let updateResult = dataDeleter(conf.path)
    conf.newData = updateResult.newData
    conf.previousData = updateResult.previousData
    self.writeSubject.next(conf)
    return self
  }

  this.batchWrite = function (updatePaths, manipulateFunction, opt) {
    let updateResult = batchSetter(manipulateFunction)
    let paths = (updatePaths || [])
    if (!Array.isArray(paths)) {
      throw TypeError('updatePaths should be an Array of update paths')
    }
    paths.forEach(function (updatePath) {
      let conf = {
        key: getMainKey(updatePath),
        path: updatePath,
        d: _get(updateResult.newData, updatePath),
        opt: opt || {}
      }
      conf.newData = updateResult.newData
      conf.previousData = updateResult.previousData
      self.writeSubject.next(conf)
    })
    return self
  }

  function onReject (reson) {
    self.onError(reson)
    console.warn('Justore write ' + self.name + ' Error: ', reson)
  }

  this.writing$ = this.writeSubject
    .pipe(
      groupBy(function (conf) { return conf.path }),
      mergeMap(function (g) {
        var ob = self.bufferWrite ? g.pipe(debounceTime(0)) : g
        return ob
      }),
      share()
    )

  this.writing$.subscribe(function (info) {
    updatePreviousData()
    return info
  }, onReject)

  /**
   * Read the value from store
   * @param {String} key - Store key
   */
  self.read = function (key) {
    return key === '*' ? data : dataGetter(key)
  }

  /**
   * Subscribe to the writing$
   * @param {String} path - Subscribe update path
   * @param {Function} [onchange] - onNextHandler
   * @param {Boolean} [immediate] - use 'startWith' operator
   * @return {Subscription} subscription - subscription
   */
  self.sub = function (path, onchange, immediate) {
    var stream = self.writing$
      .pipe(
        takeWhile(function (info) {
          let keyPairs = splitLastKey(path)
          const inData = function (d, pairs) { return pairs[1] ? pairs[0] in (_get(d, pairs[1]) || {}) : pairs[0] in d }

          // Must from have -> don't have
          if (inData(info.newData, keyPairs)) {
            return true
          } else if (inData(info.previousData, keyPairs)) {
            return false
          } else {
            return true
          }
        }),
        filter(function (info) {
          if (info.opt.mute) {
            return false
          }
          return _get(info.newData, path) !== _get(info.previousData, path)
        })
      )

    function genPair (info) {
      return [_get(info.newData, path), _get(info.previousData, path)]
    }

    if (immediate) {
      stream = stream
        .pipe(
          map(genPair),
          startWith(
            [dataGetter(path), dataGetter(path, true)]
          )
        )
    } else {
      stream = stream
        .pipe(map(genPair))
    }

    if (onchange) {
      let subscription = stream
        .subscribe(function (arg) {
          onchange.apply(self, arg)
        }, onReject)

      return subscription
    } else {
      return stream
    }
  }
};

Justore.prototype.createReactMixin = function (key) {
  var self = this
  let subscriptions
  return {
    componentWillMount: function () {
      subscriptions = self.sub(key, this.onStoreChange)
    },
    componentWillUnmount: function () {
      if (subscriptions && subscriptions.unsubscribe) {
        subscriptions.unsubscribe()
      }
    }
  }
}

Justore.prototype.report = function () {
  return this.read('*')
}

module.exports = Justore
<|endoftext|>


<commit_before>/**
 * Activates typeahead behavior for given element.
 * @param element (required) The DOM element to infect.
 * @param source (optional) The custom data source.
 */
Meteor.typeahead = function(element, source) {
	var $e = $(element);
	var datasets = resolve_datasets($e, source);

	$e.typeahead('destroy');

	var opts = $e.data('options') || {};
	if (typeof opts != 'object') {
		opts = {};
	}

	// other known options passed via data attributes
	var highlight = Boolean($e.data('highlight')) || false;
	var hint = Boolean($e.data('hint')) || false;
	var minLength = parseInt($e.data('min-length')) || 1;

	if($e.data('autocompleted')) {
		var autocompleted = resolve_template_function($e[0], $e.data('autocompleted'));
	}
	if($e.data('selected')) {
		var selected = resolve_template_function($e[0], $e.data('selected'));
	}

	var options = $.extend(opts, {
		highlight: highlight,
		hint: hint,
		minLength: minLength
	});

	var instance;
	if (Array.isArray(datasets)) {
		instance = $e.typeahead.apply($e, [options].concat(datasets));
	} else {
		instance = $e.typeahead(options, datasets);
	}

	// event handlers (PR #18)
	if (typeof selected == 'function') {
		instance.on('typeahead:selected', selected);
	}
	if (typeof autocompleted == 'function') {
		instance.on('typeahead:autocompleted', autocompleted);
	}

	// fix to apply bootstrap form-control to tt-hint
	// TODO support other classes if needed
	if ($e.hasClass('form-control')) {
		$e.parent('.twitter-typeahead').find('.tt-hint').addClass('form-control');
	}
};

/**
 * Activates all typeahead elements.
 * @param selector (optional) selector to find typeahead elements to be activated
 */
Meteor.typeahead.inject = function(selector) {
	if (!selector) {
		selector = '.typeahead';
	}
	$(selector).each(function(i,e) {
		try {
			Meteor.typeahead(e);
		} catch (err) {
			console.log(err);
		}
	});
};

function resolve_datasets($e, source) {
	var element = $e[0];
	var datasets = $e.data('sets');
	if (datasets) {
		if (typeof datasets == 'string') {
			datasets = resolve_template_function(element, datasets);
		}
		if (typeof datasets == 'function') {
			datasets = datasets() || [];
		}
		return datasets.map(function(ds) {
			return make_bloodhound(ds);
		});
	}

	var name = $e.attr('name') || $e.attr('id') || 'dataset';
	var limit = $e.data('limit');
	var templateName = $e.data('template'); // specifies name of custom template
	var valueKey = $e.data('value-key');

	if (!source) {
		source = $e.data('source') || [];
	}

	if (typeof source === 'string') {
		source = resolve_template_function(element, source);
	}

	var dataset = {
		name: name,
		valueKey: valueKey,
		displayKey: valueKey
	};

	if (limit) {
		dataset.limit = limit;
	}

	// support for custom templates
	if (templateName) {
		dataset.template = templateName;
	}

	if (Array.isArray(source) || (typeof source == 'function' && source.length === 0)) {
		dataset.local = source;
		return make_bloodhound(dataset);
	}

	dataset.source = source;
	dataset.templates = make_templates(dataset);

	return dataset;
}

function resolve_template_function(element, name) {
	var view = Blaze.getElementView(element);
	if (!view) {
		return [];
	}
	var fn = view.template && view.template[name];
	if (typeof fn != 'function') {
		console.log("Unable to resolve data source function '%s'.", name);
		return [];
	}
	return fn;
}

function make_template_function(templateName) {
	if (!templateName) {
		throw new Error("templateName is not specified");
	}

	var tmpl = Template[templateName];
	if (!tmpl) {
		throw new Error("Template '" + templateName  + "' is not defined");
	}

	return function(context) {
		var div = $("<div/>");
		var range = UI.renderWithData(tmpl, context);
		UI.insert(range, div[0]);
		return div.html();
	};
}

function make_templates(dataset) {
	var templates = {};
	if (dataset.header) {
		templates.header = dataset.header;
	}
	if (dataset.template) {
		var templateFn = typeof dataset.template == 'string' ?
			make_template_function(dataset.template)
			: dataset.template;
		if (typeof templateFn == 'function') {
			templates.suggestion = templateFn;
		}
	}
	return templates;
}

// creates Bloodhound suggestion engine based on given dataset
function make_bloodhound(dataset) {

	function wrap_value(value) {
          if (typeof value == 'object') {
                return value;
          } else {
		return {value: value};
          }
	}

	if (!dataset.template) {
		if (Array.isArray(dataset.local)) {
			dataset.local = dataset.local.map(wrap_value);
		} else if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			var localFn = dataset.local;
			dataset.local = function() {
				return (localFn() || []).map(wrap_value);
			};
		}
	}

	var need_bloodhound = Array.isArray(dataset.local) ||
		typeof dataset.local == 'function' && dataset.local.length === 0;

	var engine;
	var valueKey = dataset.valueKey || 'value';

	if (need_bloodhound) {
		var options = $.extend({}, dataset, {
			// TODO support custom tokenizers
			datumTokenizer: Bloodhound.tokenizers.obj.whitespace(valueKey),
			queryTokenizer: Bloodhound.tokenizers.whitespace
		});

		engine = new Bloodhound(options);
		engine.initialize();

		if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			// update data source on changing deps of local function
			// TODO find better (functional) way to do that
			Deps.autorun(function() {
				engine = new Bloodhound(options);
				engine.initialize();
			});
		}
	}

	function bloodhound_source(query, cb) {
		var fn = engine.ttAdapter();
		return fn(query, cb);
	}

	return {
		displayKey: valueKey,
		source: need_bloodhound ? bloodhound_source : dataset.local,
		templates: make_templates(dataset)
	};
}
<commit_msg>fixed jshint errors<commit_after>/**
 * Activates typeahead behavior for given element.
 * @param element (required) The DOM element to infect.
 * @param source (optional) The custom data source.
 */
Meteor.typeahead = function(element, source) {
	var $e = $(element);
	var datasets = resolve_datasets($e, source);

	$e.typeahead('destroy');

	var opts = $e.data('options') || {};
	if (typeof opts != 'object') {
		opts = {};
	}

	// other known options passed via data attributes
	var highlight = Boolean($e.data('highlight')) || false;
	var hint = Boolean($e.data('hint')) || false;
	var minLength = parseInt($e.data('min-length')) || 1;
	var autocompleted = null, selected = null;

	if ($e.data('autocompleted')) {
		autocompleted = resolve_template_function($e[0], $e.data('autocompleted'));
	}
	if ($e.data('selected')) {
		selected = resolve_template_function($e[0], $e.data('selected'));
	}

	var options = $.extend(opts, {
		highlight: highlight,
		hint: hint,
		minLength: minLength
	});

	var instance;
	if (Array.isArray(datasets)) {
		instance = $e.typeahead.apply($e, [options].concat(datasets));
	} else {
		instance = $e.typeahead(options, datasets);
	}

	// event handlers (PR #18)
	if (typeof selected == 'function') {
		instance.on('typeahead:selected', selected);
	}
	if (typeof autocompleted == 'function') {
		instance.on('typeahead:autocompleted', autocompleted);
	}

	// fix to apply bootstrap form-control to tt-hint
	// TODO support other classes if needed
	if ($e.hasClass('form-control')) {
		$e.parent('.twitter-typeahead').find('.tt-hint').addClass('form-control');
	}
};

/**
 * Activates all typeahead elements.
 * @param selector (optional) selector to find typeahead elements to be activated
 */
Meteor.typeahead.inject = function(selector) {
	if (!selector) {
		selector = '.typeahead';
	}
	$(selector).each(function(i,e) {
		try {
			Meteor.typeahead(e);
		} catch (err) {
			console.log(err);
		}
	});
};

function resolve_datasets($e, source) {
	var element = $e[0];
	var datasets = $e.data('sets');
	if (datasets) {
		if (typeof datasets == 'string') {
			datasets = resolve_template_function(element, datasets);
		}
		if (typeof datasets == 'function') {
			datasets = datasets() || [];
		}
		return datasets.map(function(ds) {
			return make_bloodhound(ds);
		});
	}

	var name = $e.attr('name') || $e.attr('id') || 'dataset';
	var limit = $e.data('limit');
	var templateName = $e.data('template'); // specifies name of custom template
	var valueKey = $e.data('value-key');

	if (!source) {
		source = $e.data('source') || [];
	}

	if (typeof source === 'string') {
		source = resolve_template_function(element, source);
	}

	var dataset = {
		name: name,
		valueKey: valueKey,
		displayKey: valueKey
	};

	if (limit) {
		dataset.limit = limit;
	}

	// support for custom templates
	if (templateName) {
		dataset.template = templateName;
	}

	if (Array.isArray(source) || (typeof source == 'function' && source.length === 0)) {
		dataset.local = source;
		return make_bloodhound(dataset);
	}

	dataset.source = source;
	dataset.templates = make_templates(dataset);

	return dataset;
}

function resolve_template_function(element, name) {
	var view = Blaze.getElementView(element);
	if (!view) {
		return [];
	}
	var fn = view.template && view.template[name];
	if (typeof fn != 'function') {
		console.log("Unable to resolve data source function '%s'.", name);
		return [];
	}
	return fn;
}

function make_template_function(templateName) {
	if (!templateName) {
		throw new Error("templateName is not specified");
	}

	var tmpl = Template[templateName];
	if (!tmpl) {
		throw new Error("Template '" + templateName  + "' is not defined");
	}

	return function(context) {
		var div = $("<div/>");
		var range = UI.renderWithData(tmpl, context);
		UI.insert(range, div[0]);
		return div.html();
	};
}

function make_templates(dataset) {
	var templates = {};
	if (dataset.header) {
		templates.header = dataset.header;
	}
	if (dataset.template) {
		var templateFn = typeof dataset.template == 'string' ?
			make_template_function(dataset.template)
			: dataset.template;
		if (typeof templateFn == 'function') {
			templates.suggestion = templateFn;
		}
	}
	return templates;
}

// creates Bloodhound suggestion engine based on given dataset
function make_bloodhound(dataset) {

	function wrap_value(value) {
          if (typeof value == 'object') {
                return value;
          } else {
		return {value: value};
          }
	}

	if (!dataset.template) {
		if (Array.isArray(dataset.local)) {
			dataset.local = dataset.local.map(wrap_value);
		} else if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			var localFn = dataset.local;
			dataset.local = function() {
				return (localFn() || []).map(wrap_value);
			};
		}
	}

	var need_bloodhound = Array.isArray(dataset.local) ||
		typeof dataset.local == 'function' && dataset.local.length === 0;

	var engine;
	var valueKey = dataset.valueKey || 'value';

	if (need_bloodhound) {
		var options = $.extend({}, dataset, {
			// TODO support custom tokenizers
			datumTokenizer: Bloodhound.tokenizers.obj.whitespace(valueKey),
			queryTokenizer: Bloodhound.tokenizers.whitespace
		});

		engine = new Bloodhound(options);
		engine.initialize();

		if (typeof dataset.local == 'function' && dataset.local.length === 0) {
			// update data source on changing deps of local function
			// TODO find better (functional) way to do that
			Deps.autorun(function() {
				engine = new Bloodhound(options);
				engine.initialize();
			});
		}
	}

	function bloodhound_source(query, cb) {
		var fn = engine.ttAdapter();
		return fn(query, cb);
	}

	return {
		displayKey: valueKey,
		source: need_bloodhound ? bloodhound_source : dataset.local,
		templates: make_templates(dataset)
	};
}
<|endoftext|>


<commit_before>'use strict';

require('es6-promise').polyfill();

var Response = require('node-fetch/lib/response');
var Headers = require('node-fetch/lib/headers');
var sinon = require('sinon');
var stream = require('stream');

function mockResponse (url, config) {
	if (config.throws) {
		return Promise.reject(config.throws);
	}
	opts = config.opts || {};
	opts.url = url;
	opts.status = opts.status || 200;
	opts.headers = opts.headers ? new Headers(opts.headers) : new Headers();

	var s = new stream.Readable();
	if (config.body != null) {
		var body = config.body;
		if (typeof body === 'object') {
			body = JSON.stringify(body);
		}
		s.push(body);
	}

	s.push(null);

	return Promise.resolve(new Response(s, opts));
}

function compileRoute (route) {
	if (typeof route.matcher === 'string') {
		var expectedUrl = route.matcher
		route.matcher = function (url) {
			return url === expectedUrl;
		}
	} else if (route.matcher instanceof RegExp) {
		var urlRX = route.matcher
		route.matcher = function (url) {
			return urlRX.test(url);
		}
	}
	return route;
}

var FetchMock = function () {
	this.routes = [];
	this._calls = {};
};

FetchMock.prototype.registerRoute = function (name, matcher, response) {
	var routes;
	if (name instanceof Array) {
		routes = name;
	} else {
		routes = [{
			name: name,
			matcher: matcher,
			response: response
		}]
	}
	this.routes = this.routes.concat(routes.map(compileRoute));
};

FetchMock.prototype.unregisterRoute = function (name) {
	var names;
	if (!name) {
		this.routes = [];
		return;
	if (name instanceof Array) {
		names = name;
	} else {
		names = [name];
	}

	this.routes = this.routes.filter(function (route) {
		return names.indexOf(route.name)  === -1;
	});

}

FetchMock.prototype.getRouter = function (config) {
	var routes;

	if (config.routes) {
		var preRegisteredRoutes = {};
		this.routes.forEach(function (route) {
			preRegisteredRoutes[route.name] = route;
		});

		routes = config.routes.map(function (route) {
			if (typeof route === 'string') {
				return preRegisteredRoutes[route];
			} else {
				return compileRoute(route);
			}
		});
	} else {
		routes = this.routes;
	}

	opts.responses = opts.responses || {};

	return function (url, opts) {
		var response;
		routes.some(function (route) {
			if (route.matcher(url, opts)) {
				this._calls[route.name] = this.calls[route.name] || [];
				this._calls[route.name].push([url, opts]);
				response = opts.responses || route.response;
				if (typeof response === 'function') {
					response = response(url, opts);
				}
				return true;
			}
		});
		return response;
	}
};

FetchMock.prototype.mock = function (config) {
	var defaultFetch = GLOBAL.fetch;
	var router = this.getRouter(config);
	config.greed = config.greed || 'none';
	sinon.stub(GLOBAL, 'fetch', function (url, opts) {
			var response = router(url, opts);
			if (response) {
				return mockResponse(url, response);
			} else if (config.greed === 'good') {
				return mockResponse(url, {body: 'unmocked url :' + url});
			} else if (config.greed === 'bad') {
				return mockResponse(url, {throws: 'unmocked url :' + url});
			} else {
				return defaultFetch(url, opts);
			}
	});
};

FetchMock.prototype.restore = function () {
	this.reset();
	GLOBAL.fetch.restore();
};

FetchMock.prototype.reset = function () {
	this.calls = {};
};

FetchMock.prototype.calls = function (name) {
	return this._calls[name];
};

module.exports = new FetchMock();
<commit_msg>added called method<commit_after>'use strict';

require('es6-promise').polyfill();

var Response = require('node-fetch/lib/response');
var Headers = require('node-fetch/lib/headers');
var sinon = require('sinon');
var stream = require('stream');

function mockResponse (url, config) {
	if (config.throws) {
		return Promise.reject(config.throws);
	}
	opts = config.opts || {};
	opts.url = url;
	opts.status = opts.status || 200;
	opts.headers = opts.headers ? new Headers(opts.headers) : new Headers();

	var s = new stream.Readable();
	if (config.body != null) {
		var body = config.body;
		if (typeof body === 'object') {
			body = JSON.stringify(body);
		}
		s.push(body);
	}

	s.push(null);

	return Promise.resolve(new Response(s, opts));
}

function compileRoute (route) {
	if (typeof route.matcher === 'string') {
		var expectedUrl = route.matcher
		route.matcher = function (url) {
			return url === expectedUrl;
		}
	} else if (route.matcher instanceof RegExp) {
		var urlRX = route.matcher
		route.matcher = function (url) {
			return urlRX.test(url);
		}
	}
	return route;
}

var FetchMock = function () {
	this.routes = [];
	this._calls = {};
};

FetchMock.prototype.registerRoute = function (name, matcher, response) {
	var routes;
	if (name instanceof Array) {
		routes = name;
	} else {
		routes = [{
			name: name,
			matcher: matcher,
			response: response
		}]
	}
	this.routes = this.routes.concat(routes.map(compileRoute));
};

FetchMock.prototype.unregisterRoute = function (name) {
	var names;
	if (!name) {
		this.routes = [];
		return;
	if (name instanceof Array) {
		names = name;
	} else {
		names = [name];
	}

	this.routes = this.routes.filter(function (route) {
		return names.indexOf(route.name)  === -1;
	});

}

FetchMock.prototype.getRouter = function (config) {
	var routes;

	if (config.routes) {
		var preRegisteredRoutes = {};
		this.routes.forEach(function (route) {
			preRegisteredRoutes[route.name] = route;
		});

		routes = config.routes.map(function (route) {
			if (typeof route === 'string') {
				return preRegisteredRoutes[route];
			} else {
				return compileRoute(route);
			}
		});
	} else {
		routes = this.routes;
	}

	opts.responses = opts.responses || {};

	return function (url, opts) {
		var response;
		routes.some(function (route) {
			if (route.matcher(url, opts)) {
				this._calls[route.name] = this.calls[route.name] || [];
				this._calls[route.name].push([url, opts]);
				response = opts.responses || route.response;
				if (typeof response === 'function') {
					response = response(url, opts);
				}
				return true;
			}
		});
		return response;
	}
};

FetchMock.prototype.mock = function (config) {
	var defaultFetch = GLOBAL.fetch;
	var router = this.getRouter(config);
	config.greed = config.greed || 'none';
	sinon.stub(GLOBAL, 'fetch', function (url, opts) {
			var response = router(url, opts);
			if (response) {
				return mockResponse(url, response);
			} else if (config.greed === 'good') {
				return mockResponse(url, {body: 'unmocked url :' + url});
			} else if (config.greed === 'bad') {
				return mockResponse(url, {throws: 'unmocked url :' + url});
			} else {
				return defaultFetch(url, opts);
			}
	});
};

FetchMock.prototype.restore = function () {
	this.reset();
	GLOBAL.fetch.restore();
};

FetchMock.prototype.reset = function () {
	this.calls = {};
};

FetchMock.prototype.calls = function (name) {
	return this._calls[name];
};

FetchMock.prototype.called = function (name) {
	return !!(this._calls[name] && this._calls[name].length);
};

module.exports = new FetchMock();
<|endoftext|>


<commit_before>'use strict'

const fs        = require('fs')
  ,   path      = require('path')
  ,   _         = require('lodash')
  ,   objHash   = require('object-hash')
  ,   case      = require('snake-case')
  ,   Promise   = require('bluebird')
  ,   Waterline = require('waterline')
  ,   peer      = require('codependency').register(module)
  ,   readdir   = Promise.promisify(fs.readdir)

const defaultConfig = {
    dir: null,
    target: global,
    adapters: {},
    connections: {}
}

const adapters = [
    'postgresql',
    'mysql',
    'mongo',
    'memory',
    'disk',
    'sqlserver',
    'redis',
    'riak',
    'irc',
    'twitter',
    'jsdom',
    'neo4j',
    'orientdb',
    'arangodb',
    'cassandra',
    'graphql',
    'solr'
]
.forEach((name) => {
    let adapter = peer('sails-' + name, { optional: true })
    if (adapter != null)
        defaultConfig.adapters[name] = adapter
})

const ormCache = {}

const buildConfig = function(_config) {
    if (_.isString(_config))
        _config = { dir: _config }

    if (!_config.dir) {
        throw TypeError('First argument must be the path to the models directory or an object with a dir attribute')

    let config = _.assign({}, defaultConfig, _config)

    if (config.connection) {
        if (config.connections.default)
            throw Error('connections.default and connection should not be both defined')
        config.connections.default = config.connection
        config.connection = undefined
    }

    if (_.isEmpty(config.connections)) {
        config.connections.default = { adapter: 'memory' }
    }

    _.values(config.connections).each((c) => {
        if (!c.adapter)
            throw TypeError('connection must contain an adapter field')
        if (!defaultConfig.adapters[c.adapter])
            throw Error('Default sails-memory adapter could\'t be loaded. Run "npm i sails-' + c.adapter + '"')
    })

    // config.orm is what will be passed to Waterline#initialize
    // so keep it clean
    config.orm = _.omit(config, [ 'dir', 'target', 'connection' ])

    return config
}

const WaterlineLighter = function(_config, cb) {

    let hash = objHash(_config)
    let cached = ormCache[hash]

    if (cached)
        return Promise.resolve(cached)

    let config = null;

    try {
        config = buildConfig(_config)
    } catch(err) {
        return Promise.reject(err)
    }

    let orm = new Waterline()
    let ormInitialize = Promise.promisify(orm.initialize, { context: orm })
    let dir = path.join(path.dirname(module.parent.filename), config.dir)

    return readdir(dir)
    .then((files) => {
        let p = files
        .filter((f) => (/\.js$/.test(f)))
        .map((f) => {
            let file = path.join(dir, f)
            let name = path.basename(file, '.js')
            let model = require(file)
            if (!model.connection)
                model.connection = 'default'
            if (!model.identity)
                model.identity = case(name)
            return model
        })
        .map((m) => (Waterline.Collection.extend(m)))
        .map((m) => (orm.loadCollection(m)))

        return Promise.all(p)
    })
    .then(() => (ormInitialize(config.orm)))
    .then((models) => {
        let result = _.assign({ orm, config }, models)

        if (config.target !== false) // Inject in the target if available
            _.assign(config.target, _.pick(result, [ 'models', 'connections' ]))

        ormCache[hash] = result

        if (_.isFunction(cb))
            return cb(null, result)
        else
            return result
    })
    .catch((error) => {
        if (_.isFunction(cb))
            return cb(error)
        else
            throw error
    })
}

WaterlineLighter.middleware = function(config) {
    return function(req, res, next) {
        let app = req.app
        if (!app.models && !app.connections) {
            WaterlineLighter(_.assign({}, config, { target: app }))
            .then(() => next)
            .catch(next)
        } else
            next()
    }
}

module.exports = WaterlineLighter
Waterline.Lighter = WaterlineLighter
Waterline.initialize = WaterlineLighter<commit_msg>Fix compile error... Of course case is a reserved word... -.-''<commit_after>'use strict'

const fs        = require('fs')
  ,   path      = require('path')
  ,   _         = require('lodash')
  ,   objHash   = require('object-hash')
  ,   sCase     = require('snake-case')
  ,   Promise   = require('bluebird')
  ,   Waterline = require('waterline')
  ,   peer      = require('codependency').register(module)
  ,   readdir   = Promise.promisify(fs.readdir)

const defaultConfig = {
    dir: null,
    target: global,
    adapters: {},
    connections: {}
}

const adapters = [
    'postgresql',
    'mysql',
    'mongo',
    'memory',
    'disk',
    'sqlserver',
    'redis',
    'riak',
    'irc',
    'twitter',
    'jsdom',
    'neo4j',
    'orientdb',
    'arangodb',
    'cassandra',
    'graphql',
    'solr'
]
.forEach((name) => {
    let adapter = peer('sails-' + name, { optional: true })
    if (adapter != null)
        defaultConfig.adapters[name] = adapter
})

const ormCache = {}

const buildConfig = function(_config) {
    if (_.isString(_config))
        _config = { dir: _config }

    if (!_config.dir) {
        throw TypeError('First argument must be the path to the models directory or an object with a dir attribute')

    let config = _.assign({}, defaultConfig, _config)

    if (config.connection) {
        if (config.connections.default)
            throw Error('connections.default and connection should not be both defined')
        config.connections.default = config.connection
        config.connection = undefined
    }

    if (_.isEmpty(config.connections)) {
        config.connections.default = { adapter: 'memory' }
    }

    _.values(config.connections).each((c) => {
        if (!c.adapter)
            throw TypeError('connection must contain an adapter field')
        if (!defaultConfig.adapters[c.adapter])
            throw Error('Default sails-memory adapter could\'t be loaded. Run "npm i sails-' + c.adapter + '"')
    })

    // config.orm is what will be passed to Waterline#initialize
    // so keep it clean
    config.orm = _.omit(config, [ 'dir', 'target', 'connection' ])

    return config
}

const WaterlineLighter = function(_config, cb) {

    let hash = objHash(_config)
    let cached = ormCache[hash]

    if (cached)
        return Promise.resolve(cached)

    let config = null;

    try {
        config = buildConfig(_config)
    } catch(err) {
        return Promise.reject(err)
    }

    let orm = new Waterline()
    let ormInitialize = Promise.promisify(orm.initialize, { context: orm })
    let dir = path.join(path.dirname(module.parent.filename), config.dir)

    return readdir(dir)
    .then((files) => {
        let p = files
        .filter((f) => (/\.js$/.test(f)))
        .map((f) => {
            let file = path.join(dir, f)
            let name = path.basename(file, '.js')
            let model = require(file)
            if (!model.connection)
                model.connection = 'default'
            if (!model.identity)
                model.identity = sCase(name)
            return model
        })
        .map((m) => (Waterline.Collection.extend(m)))
        .map((m) => (orm.loadCollection(m)))

        return Promise.all(p)
    })
    .then(() => (ormInitialize(config.orm)))
    .then((models) => {
        let result = _.assign({ orm, config }, models)

        if (config.target !== false) // Inject in the target if available
            _.assign(config.target, _.pick(result, [ 'models', 'connections' ]))

        ormCache[hash] = result

        if (_.isFunction(cb))
            return cb(null, result)
        else
            return result
    })
    .catch((error) => {
        if (_.isFunction(cb))
            return cb(error)
        else
            throw error
    })
}

WaterlineLighter.middleware = function(config) {
    return function(req, res, next) {
        let app = req.app
        if (!app.models && !app.connections) {
            WaterlineLighter(_.assign({}, config, { target: app }))
            .then(() => next)
            .catch(next)
        } else
            next()
    }
}

module.exports = WaterlineLighter
Waterline.Lighter = WaterlineLighter
Waterline.initialize = WaterlineLighter<|endoftext|>