<commit_before>/*! collection- v0.0.0 - MIT license */

"use strict";

var poser = require( "poser" );
var Collection = poser.Array();
var fast = require( "./fast" )( Collection );

var cp = Collection.prototype;

function isCollection ( obj ) {
  return obj instanceof Collection;
}

function isFunction ( obj ) {
  return typeof obj === "function";
}

function isArrayish ( obj ) {
  return Object.prototype.toString.call( obj ) === "[object Array]";
}

function factory () {
  var len = arguments.length;
  var args;

  if ( len === 0 ) {
    return new Collection();
  }

  if ( len === 1 && isArrayish( arguments[0] ) ) {
    return new Collection().concat( arguments[0] );
  }

  if ( len === 1 && typeof arguments[0] === "number") {
    return new Collection( arguments[0] );
  }

  args = new Collection( len );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return factory( args );
}

function factoryOne () {
  return factory( arguments[0] );
}

function factoryDeep ( arr ) {
  return new Collection().concat( arr ).map( function ( item ) {
    return isArrayish( item ) ? factoryDeep( item ) : item;
  });
}

function extend ( target, source ) {
  return Object.keys( source ).reduce( function ( tgt, key ) {
    tgt[key] = source[key];
    return tgt;
  }, target );
}

function keys ( obj ) {
  return factory( Object.keys( obj ) );
}

function matches ( against, obj ) {
  return keys( against ).every( function ( key ) {
    return obj[key] === against[key];
  });
}

function flip ( fn ) {
  return function ( a, b ) {
    return fn.call( this, b, a );
  };
}

function get ( prop ) {
  return function ( obj ) {
    return obj[prop];
  };
}

function not ( fn ) {
  return function () {
    return !fn.apply( this, arguments );
  };
}

function contains ( obj, value ) {
  return cp.indexOf.call( obj, value ) > -1;
}

function identity ( value ) {
  return value;
}

function iterator( value ) {
  if ( value == null ) {
    return identity;
  } else if ( isFunction( value ) ) {
    return value;
  } else {
    return get( value );
  }
}

function flatten ( arr ) {
  return arr.reduce( function ( acc, item ) {
    return acc.chainPush.apply( acc, isArrayish( item ) ? flatten( item ) : [ item ] );
  }, new Collection() );
}

function invoke ( obj, fnOrMethod ) {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  args = args.slice( 2 );
  return ( isFunction( fnOrMethod ) ? fnOrMethod : obj[fnOrMethod] ).apply( obj, args );
}

function collectify ( headers, rows ) {
  return rows.map( function ( item ) {
    return item.reduce( function ( model, val, i ) {
      model[ headers[i] ] = val;
      return model;
    }, {} );
  });
}

var containsFlip = flip( contains );
var partial = fast.partial;

// create chainable versions of these native methods
[ "push", "pop", "shift", "unshift" ].forEach( function( method ) {
  // new methods will be named chainPush, chainPop, chainShift, chainUnshift
  var name = "chain" + method.charAt( 0 ).toUpperCase() + method.slice( 1 );
  var original = cp[method];
  cp[name] = function() {
    original.apply( this, arguments );
    return this;
  };
});

[ "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "indexOf", "lastIndexOf" ].forEach( function( method ) {
  var name = "native" + method.charAt( 0 ).toUpperCase()  + method.slice( 1 );
  var original = cp[method];
  delete cp[method];
  cp[name] = function() {
    return original.apply( this, arguments );
  };
});

// Methods that we're delegating to fast.js
cp.forEach = function( fn, thisArg ) {
  return fast.forEach( this, fn, thisArg );
};
cp.each = cp.forEach;

cp.map = function( fn, thisArg ) {
  return fast.map( this, fn, thisArg );
};
cp.collect = cp.map;

cp.reduce = function( fn, initialValue, thisArg ) {
  return fast.reduce( this, fn, initialValue, thisArg );
};

cp.reduceRight = function( fn, initialValue, thisArg ) {
  return fast.reduceRight( this, fn, initialValue, thisArg );
};

// Travis throws on functions implementing filter as fast.filter
// for an unknown reason.
cp.filter = function( fn, thisArg ) {
  // return fast.filter( this, fn, thisArg );
  return this.reduce( function ( acc, item, i, arr ) {
    if ( fn.call( thisArg, item, i, arr ) ) {
      acc.push( item );
    }
    return acc;
  }, new Collection() );
};
cp.select = cp.filter;

cp.indexOf = function( target ) {
  return fast.indexOf( this, target );
};

cp.lastIndexOf = function( target ) {
  return fast.lastIndexOf( this, target );
};

cp.some = function( fn, thisContext ) {
  return fast.some( this, fn, thisContext );
};

cp.every = function ( fn, thisContext ) {
  return fast.every( this, fn, thisContext );
};

cp.forEachRight = function ( fn ) {
  this.slice().reverse().each( fn );
};
cp.eachRight = cp.forEachRight;

cp.where = function ( obj ) {
  return this.filter( partial( matches, obj ) );
};

cp.whereNot = function ( obj ) {
  return this.filter( not( partial( matches, obj ) ) );
};

cp.find = function ( testFn ) {
  var result = null;
  this.some( function ( item, i, arr ) {
    var test = testFn( item, i, arr );
    if ( test ) {
      result = item;
      return true;
    }
  });
  return result;
};

cp.findNot = function ( testFn ) {
  return this.find( not( testFn ) );
};

cp.findWhere = function ( obj ) {
  return this.find( partial( matches, obj ) );
};

cp.findWhereNot = function ( obj ) {
  return this.find( not( partial( matches, obj ) ) );
};

cp.pluck = function ( prop ) {
  return this.map( get( prop ) );
};

cp.pick = function () {
  var props = new Collection( arguments.length );
  for ( var i = 0; i < props.length; i++ ) {
    props[i] = arguments[i];
  }
  return this.map( function ( el ) {
    var obj = {};
    props.each( function ( prop ) {
      obj[prop] = el[prop];
    });
    return obj;
  });
};

cp.reject = function ( testFn ) {
  return this.filter( not( testFn ) );
};

cp.invoke = function () {
  this.mapInvoke.apply( this, arguments );
  return this;
};

cp.mapInvoke = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.map( function ( item ) {
    return invoke.apply( null, [item].concat( args ) );
  });
};

cp.without = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.reject( partial( contains, args ) );
};
cp.remove = cp.without;

cp.contains = function ( obj ) {
  return contains( this, obj );
};

cp.tap = function ( fn ) {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  fn( this, args.slice( 1 ) );
  return this;
};

cp.clone = function () {
  return fast.clone( this );
};

cp.first = function ( num ) {
  if ( num == null ) {
    return this[0];
  }
  return this.slice( 0, num );
};
cp.head = cp.first;
cp.take = cp.first;

cp.initial = function ( num ) {
  if ( num == null ) {
    num = 1;
  }
  return this.slice( 0, this.length - num );
};

cp.last = function ( num ) {
  if ( num == null ) {
    return this[this.length - 1];
  }
  return this.slice( 0, -1 * num );
};

cp.rest = function ( num ) {
  if ( num == null ) {
    num = 1;
  }
  return this.slice( num );
};
cp.tail = cp.rest;
cp.drop = cp.rest;

cp.compact = function () {
  return this.filter( identity );
};

cp.flatten = function () {
  return flatten( this );
};

cp.partition = function ( testFn ) {
  return this.reduce( function ( acc, item, i, arr ) {
    ( testFn( item, i, arr ) ? acc[0] : acc[1] ).push( item );
    return acc;
  }, factory( factory(), factory() ) );
};

cp.union = function () {
  return cp.concat.apply( this, arguments ).unique();
};

cp.intersection = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.filter( function ( el ) {
    return args.every( partial( containsFlip, el ) );
  });
};

cp.difference = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.filter( function ( el ) {
    return args.every( not( partial( containsFlip, el ) ) );
  });
};

cp.unique = function () {
  return this.reduce( function ( acc, item ) {
    if ( !acc.contains( item ) ) {
      return acc.chainPush( item );
    }
    return acc;
  }, new Collection() );
};
cp.uniq = cp.unique;

// ripped off from Underscore
cp.sortBy = function ( fn, thisArg ) {
  fn = iterator( fn );
  return cp.pluck.call(
    this.map( function ( val, i, obj ) {
      return {
        val: val,
        i: i,
        param: fn.call( thisArg, val, i, obj )
      };
    }).sort( function ( left, right ) {
      var a = left.param;
      var b = right.param;
      if ( a !== b ) {
        if ( a > b || a === undefined ) {
          return 1;
        }
        if ( a < b || b === undefined ) {
          return -1;
        }
      }
      return left.i - right.i;
    }), "val" );
};

cp.zip = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return args
    .chainUnshift( this )
    .map( factoryOne )
    .sortBy( "length" )
    .last()
    .map( function ( item, i ) {
      return args.map( get( i ) );
    });
};

cp.min = function ( prop ) {
  if ( prop ) {
    return cp.min.call( this.pluck( prop ) );
  }
  return Math.min.apply( Math, this );
};

cp.max = function ( prop ) {
  if ( prop ) {
    return cp.max.call( this.pluck( prop ) );
  }
  return Math.max.apply( Math, this );
};

cp.extent = function ( prop ) {
  return [ this.min( prop ), this.max( prop ) ];
};

cp.toArray = function () {
  return [].concat( this );
  // return Array.prototype.slice.call( this );
};

cp.toArrayDeep = function () {
  return this.toArray().map( function ( item ) {
    if ( isCollection( item ) ) {
      item = item.toArrayDeep();
    }
    return item;
  });
};

cp.asRowsOf = function ( headers ) {
  return collectify( headers, this );
};

cp.asHeadersOf = function ( rows ) {
  if ( !( rows instanceof Collection ) ) {
    rows = factory( rows );
  }
  return collectify( this, rows );
};

factory.ctor = Collection;
factory.proto = cp;

factory.extend = extend.bind( null, cp );

factory.isCollection = isCollection;
factory.isArrayish = isArrayish;

factory.one = factoryOne;
factory.deep = factoryDeep;

module.exports = factory;
<commit_msg>Use native Array.isArray() where possible.<commit_after>/*! collection- v0.0.0 - MIT license */

"use strict";

var poser = require( "poser" );
var Collection = poser.Array();
var fast = require( "./fast" )( Collection );

var cp = Collection.prototype;

function isCollection ( obj ) {
  return obj instanceof Collection;
}

function isFunction ( obj ) {
  return typeof obj === "function";
}

if (typeof Array.isArray === "function" && Array.isArray(cp)) {
  var isArrayish = Array.isArray;
}
else {
  var isArrayish = function ( obj ) {
    return Object.prototype.toString.call( obj ) === "[object Array]";
  };
}

function factory () {
  var len = arguments.length;
  var args;

  if ( len === 0 ) {
    return new Collection();
  }

  if ( len === 1 && isArrayish( arguments[0] ) ) {
    return new Collection().concat( arguments[0] );
  }

  if ( len === 1 && typeof arguments[0] === "number") {
    return new Collection( arguments[0] );
  }

  args = new Collection( len );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return factory( args );
}

function factoryOne () {
  return factory( arguments[0] );
}

function factoryDeep ( arr ) {
  return new Collection().concat( arr ).map( function ( item ) {
    return isArrayish( item ) ? factoryDeep( item ) : item;
  });
}

function extend ( target, source ) {
  return Object.keys( source ).reduce( function ( tgt, key ) {
    tgt[key] = source[key];
    return tgt;
  }, target );
}

function keys ( obj ) {
  return factory( Object.keys( obj ) );
}

function matches ( against, obj ) {
  return keys( against ).every( function ( key ) {
    return obj[key] === against[key];
  });
}

function flip ( fn ) {
  return function ( a, b ) {
    return fn.call( this, b, a );
  };
}

function get ( prop ) {
  return function ( obj ) {
    return obj[prop];
  };
}

function not ( fn ) {
  return function () {
    return !fn.apply( this, arguments );
  };
}

function contains ( obj, value ) {
  return cp.indexOf.call( obj, value ) > -1;
}

function identity ( value ) {
  return value;
}

function iterator( value ) {
  if ( value == null ) {
    return identity;
  } else if ( isFunction( value ) ) {
    return value;
  } else {
    return get( value );
  }
}

function flatten ( arr ) {
  return arr.reduce( function ( acc, item ) {
    return acc.chainPush.apply( acc, isArrayish( item ) ? flatten( item ) : [ item ] );
  }, new Collection() );
}

function invoke ( obj, fnOrMethod ) {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  args = args.slice( 2 );
  return ( isFunction( fnOrMethod ) ? fnOrMethod : obj[fnOrMethod] ).apply( obj, args );
}

function collectify ( headers, rows ) {
  return rows.map( function ( item ) {
    return item.reduce( function ( model, val, i ) {
      model[ headers[i] ] = val;
      return model;
    }, {} );
  });
}

var containsFlip = flip( contains );
var partial = fast.partial;

// create chainable versions of these native methods
[ "push", "pop", "shift", "unshift" ].forEach( function( method ) {
  // new methods will be named chainPush, chainPop, chainShift, chainUnshift
  var name = "chain" + method.charAt( 0 ).toUpperCase() + method.slice( 1 );
  var original = cp[method];
  cp[name] = function() {
    original.apply( this, arguments );
    return this;
  };
});

[ "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "indexOf", "lastIndexOf" ].forEach( function( method ) {
  var name = "native" + method.charAt( 0 ).toUpperCase()  + method.slice( 1 );
  var original = cp[method];
  delete cp[method];
  cp[name] = function() {
    return original.apply( this, arguments );
  };
});

// Methods that we're delegating to fast.js
cp.forEach = function( fn, thisArg ) {
  return fast.forEach( this, fn, thisArg );
};
cp.each = cp.forEach;

cp.map = function( fn, thisArg ) {
  return fast.map( this, fn, thisArg );
};
cp.collect = cp.map;

cp.reduce = function( fn, initialValue, thisArg ) {
  return fast.reduce( this, fn, initialValue, thisArg );
};

cp.reduceRight = function( fn, initialValue, thisArg ) {
  return fast.reduceRight( this, fn, initialValue, thisArg );
};

// Travis throws on functions implementing filter as fast.filter
// for an unknown reason.
cp.filter = function( fn, thisArg ) {
  // return fast.filter( this, fn, thisArg );
  return this.reduce( function ( acc, item, i, arr ) {
    if ( fn.call( thisArg, item, i, arr ) ) {
      acc.push( item );
    }
    return acc;
  }, new Collection() );
};
cp.select = cp.filter;

cp.indexOf = function( target ) {
  return fast.indexOf( this, target );
};

cp.lastIndexOf = function( target ) {
  return fast.lastIndexOf( this, target );
};

cp.some = function( fn, thisContext ) {
  return fast.some( this, fn, thisContext );
};

cp.every = function ( fn, thisContext ) {
  return fast.every( this, fn, thisContext );
};

cp.forEachRight = function ( fn ) {
  this.slice().reverse().each( fn );
};
cp.eachRight = cp.forEachRight;

cp.where = function ( obj ) {
  return this.filter( partial( matches, obj ) );
};

cp.whereNot = function ( obj ) {
  return this.filter( not( partial( matches, obj ) ) );
};

cp.find = function ( testFn ) {
  var result = null;
  this.some( function ( item, i, arr ) {
    var test = testFn( item, i, arr );
    if ( test ) {
      result = item;
      return true;
    }
  });
  return result;
};

cp.findNot = function ( testFn ) {
  return this.find( not( testFn ) );
};

cp.findWhere = function ( obj ) {
  return this.find( partial( matches, obj ) );
};

cp.findWhereNot = function ( obj ) {
  return this.find( not( partial( matches, obj ) ) );
};

cp.pluck = function ( prop ) {
  return this.map( get( prop ) );
};

cp.pick = function () {
  var props = new Collection( arguments.length );
  for ( var i = 0; i < props.length; i++ ) {
    props[i] = arguments[i];
  }
  return this.map( function ( el ) {
    var obj = {};
    props.each( function ( prop ) {
      obj[prop] = el[prop];
    });
    return obj;
  });
};

cp.reject = function ( testFn ) {
  return this.filter( not( testFn ) );
};

cp.invoke = function () {
  this.mapInvoke.apply( this, arguments );
  return this;
};

cp.mapInvoke = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.map( function ( item ) {
    return invoke.apply( null, [item].concat( args ) );
  });
};

cp.without = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.reject( partial( contains, args ) );
};
cp.remove = cp.without;

cp.contains = function ( obj ) {
  return contains( this, obj );
};

cp.tap = function ( fn ) {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  fn( this, args.slice( 1 ) );
  return this;
};

cp.clone = function () {
  return fast.clone( this );
};

cp.first = function ( num ) {
  if ( num == null ) {
    return this[0];
  }
  return this.slice( 0, num );
};
cp.head = cp.first;
cp.take = cp.first;

cp.initial = function ( num ) {
  if ( num == null ) {
    num = 1;
  }
  return this.slice( 0, this.length - num );
};

cp.last = function ( num ) {
  if ( num == null ) {
    return this[this.length - 1];
  }
  return this.slice( 0, -1 * num );
};

cp.rest = function ( num ) {
  if ( num == null ) {
    num = 1;
  }
  return this.slice( num );
};
cp.tail = cp.rest;
cp.drop = cp.rest;

cp.compact = function () {
  return this.filter( identity );
};

cp.flatten = function () {
  return flatten( this );
};

cp.partition = function ( testFn ) {
  return this.reduce( function ( acc, item, i, arr ) {
    ( testFn( item, i, arr ) ? acc[0] : acc[1] ).push( item );
    return acc;
  }, factory( factory(), factory() ) );
};

cp.union = function () {
  return cp.concat.apply( this, arguments ).unique();
};

cp.intersection = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.filter( function ( el ) {
    return args.every( partial( containsFlip, el ) );
  });
};

cp.difference = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return this.filter( function ( el ) {
    return args.every( not( partial( containsFlip, el ) ) );
  });
};

cp.unique = function () {
  return this.reduce( function ( acc, item ) {
    if ( !acc.contains( item ) ) {
      return acc.chainPush( item );
    }
    return acc;
  }, new Collection() );
};
cp.uniq = cp.unique;

// ripped off from Underscore
cp.sortBy = function ( fn, thisArg ) {
  fn = iterator( fn );
  return cp.pluck.call(
    this.map( function ( val, i, obj ) {
      return {
        val: val,
        i: i,
        param: fn.call( thisArg, val, i, obj )
      };
    }).sort( function ( left, right ) {
      var a = left.param;
      var b = right.param;
      if ( a !== b ) {
        if ( a > b || a === undefined ) {
          return 1;
        }
        if ( a < b || b === undefined ) {
          return -1;
        }
      }
      return left.i - right.i;
    }), "val" );
};

cp.zip = function () {
  var args = new Collection( arguments.length );
  for ( var i = 0; i < args.length; i++ ) {
    args[i] = arguments[i];
  }
  return args
    .chainUnshift( this )
    .map( factoryOne )
    .sortBy( "length" )
    .last()
    .map( function ( item, i ) {
      return args.map( get( i ) );
    });
};

cp.min = function ( prop ) {
  if ( prop ) {
    return cp.min.call( this.pluck( prop ) );
  }
  return Math.min.apply( Math, this );
};

cp.max = function ( prop ) {
  if ( prop ) {
    return cp.max.call( this.pluck( prop ) );
  }
  return Math.max.apply( Math, this );
};

cp.extent = function ( prop ) {
  return [ this.min( prop ), this.max( prop ) ];
};

cp.toArray = function () {
  return [].concat( this );
  // return Array.prototype.slice.call( this );
};

cp.toArrayDeep = function () {
  return this.toArray().map( function ( item ) {
    if ( isCollection( item ) ) {
      item = item.toArrayDeep();
    }
    return item;
  });
};

cp.asRowsOf = function ( headers ) {
  return collectify( headers, this );
};

cp.asHeadersOf = function ( rows ) {
  if ( !( rows instanceof Collection ) ) {
    rows = factory( rows );
  }
  return collectify( this, rows );
};

factory.ctor = Collection;
factory.proto = cp;

factory.extend = extend.bind( null, cp );

factory.isCollection = isCollection;
factory.isArrayish = isArrayish;

factory.one = factoryOne;
factory.deep = factoryDeep;

module.exports = factory;
<|endoftext|>


<commit_before>var redis = require('redis');

var internals = {};

internals.defaults = {
  global:{limit: -1 , bucketLength: 1},
  routes: {},
  redis:{}
};

exports.register = function(plugin, options, next) {
  var settings = plugin.hapi.utils.applyToDefaults(internals.defaults, options);
  var redisClient  = redis.createClient(options.redis.port, options.redis.host, options.redis.options);
  plugin.state('cl-hapi-rate',{});
  plugin.ext('onRequest', function(request, callback) {
    var ipts = request.info.remoteAddress+':'+Math.floor((new Date()).getTime()/1000)
    redisClient.get(ipts,function(err, token){
      if(token && token > 1) {
        return request.reply(429);
      }else{
        rediClient.multi([['INCR',ipts],['EXPIRE', 120]]).exec(function(err) {
          return next();
        });
      }
    });
  });
};
<commit_msg>rediSclient<commit_after>var redis = require('redis');

var internals = {};

internals.defaults = {
  global:{limit: -1 , bucketLength: 1},
  routes: {},
  redis:{}
};

exports.register = function(plugin, options, next) {
  var settings = plugin.hapi.utils.applyToDefaults(internals.defaults, options);
  var redisClient  = redis.createClient(options.redis.port, options.redis.host, options.redis.options);
  plugin.state('cl-hapi-rate',{});
  plugin.ext('onRequest', function(request, callback) {
    var ipts = request.info.remoteAddress+':'+Math.floor((new Date()).getTime()/1000)
    redisClient.get(ipts,function(err, token){
      if(token && token > 1) {
        return request.reply(429);
      }else{
        rediClient.multi([['INCR',ipts],['EXPIRE', 120]]).exec(function(err) {
          return callback();
        });
      }
    });
  });
  next();
};
<|endoftext|>


<commit_before>// Load modules

var Fs = require('fs');

// Declare internals

var internals = {};

// Clone object or array

exports.clone = function (obj) {

    if (obj != null && typeof obj != 'undefined') {
        return exports.extend({}, obj);
    }
    return null;
};

exports.extend = function (target, source) {

    var newObj = (source instanceof Array) ? [] : {};
    if (Object.keys(target).length > 0) {
        newObj = exports.clone(target);
    }

    Object.keys(source).forEach(function (key) {

        var descriptor = Object.getOwnPropertyDescriptor(source, key);
        var orig = descriptor.value;

        if (orig instanceof Date) {
            descriptor.value = new Date(orig.getTime());
        }
        else if (orig instanceof RegExp) {
            var flags = '' + (orig.global ? 'g' : '') + (orig.ignoreCase ? 'i' : '') + (orig.multiline ? 'm' : ''); // y is a firefox only thing + (orig.sticky ? 'y' : '');
            descriptor.value = new RegExp(orig.source, flags);
        }
        else if (orig instanceof Array) {
            descriptor.value = orig.slice();
        }
        else if (typeof orig == 'object') {
            if (source == orig) {
                // console.log('cyclic detected')
            }
            else {
                descriptor.value = exports.extend({}, orig);
            }
        }
        else {
            // Should just be ignorable immutables here (String, Number, Boolean...)
        }

        Object.defineProperty(newObj, key, descriptor);
    });

    return newObj;
};

// Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied

exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {

    exports.assert(target && typeof target == 'object', 'Invalid target value: must be an object');
    exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');

    if (!source) {
        return target;
    }

    if (source instanceof Array) {
        exports.assert(target instanceof Array, 'Cannot merge array onto an object');
        if (isMergeArrays === false) {                                                  // isMergeArrays defaults to true
            target.length = 0;                                                          // Must not change target assignment
        }

        source.forEach(function (item) {

            target.push(item);
        });

        return target;
    }

    Object.keys(source).forEach(function (key) {

        var value = source[key];
        if (value &&
            typeof value === 'object') {

            if (!target[key] ||
                typeof target[key] !== 'object') {

                target[key] = exports.clone(value);
            }
            else {
                exports.merge(target[key], source[key], isNullOverride, isMergeArrays);
            }
        }
        else {
            if (value !== null && value !== undefined) {            // Explicit to preserve empty strings
                target[key] = value;
            }
            else if (isNullOverride !== false) {                    // Defaults to true
                target[key] = value;
            }
        }
    });

    return target;
};

// Apply options to a copy of the defaults

exports.applyToDefaults = function (defaults, options) {

    exports.assert(defaults && typeof defaults == 'object', 'Invalid defaults value: must be an object');
    exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');

    if (!options) {                                                 // If no options, return null
        return null;
    }

    var copy = exports.clone(defaults);

    if (options === true) {                                         // If options is set to true, use defaults
        return copy;
    }

    return exports.merge(copy, options, false, false);
};

// Remove duplicate items from array

exports.unique = function (array, key) {

    var index = {};
    var result = [];

    for (var i = 0, il = array.length; i < il; ++i) {
        var id = (key ? array[i][key] : array[i]);
        if (index[id] !== true) {

            result.push(array[i]);
            index[id] = true;
        }
    }

    return result;
};

// Convert array into object

exports.mapToObject = function (array, key) {

    if (!array) {
        return null;
    }

    var obj = {};
    for (var i = 0, il = array.length; i < il; ++i) {
        if (key) {
            if (array[i][key]) {
                obj[array[i][key]] = true;
            }
        }
        else {
            obj[array[i]] = true;
        }
    }

    return obj;
};

// Find the common unique items in two arrays

exports.intersect = function (array1, array2) {

    if (!array1 || !array2) {
        return [];
    }

    var common = [];
    var hash = exports.mapToObject(array1);
    var found = {};
    for (var i = 0, il = array2.length; i < il; ++i) {
        if (hash[array2[i]] && !found[array2[i]]) {
            common.push(array2[i]);
            found[array2[i]] = true;
        }
    }

    return common;
};

// Find which keys are present

exports.matchKeys = function (obj, keys) {

    var matched = [];
    for (var i = 0, il = keys.length; i < il; ++i) {
        if (obj.hasOwnProperty(keys[i])) {
            matched.push(keys[i]);
        }
    }
    return matched;
};

// Flatten array

exports.flatten = function (array, target) {

    var result = target || [];

    for (var i = 0, il = array.length; i < il; ++i) {
        if (Array.isArray(array[i])) {
            exports.flatten(array[i], result);
        }
        else {
            result.push(array[i]);
        }
    }

    return result;
};

// Remove keys

exports.removeKeys = function (object, keys) {

    for (var i = 0, il = keys.length; i < il; i++) {
        delete object[keys[i]];
    }
};

// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])

exports.reach = function (obj, chain) {

    var path = chain.split('.');
    var ref = obj;
    path.forEach(function (level) {

        if (ref) {
            ref = ref[level];
        }
    });

    return ref;
};

// Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors

exports.inheritAsync = function (self, obj, keys) {

    keys = keys || null;

    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            if (keys instanceof Array &&
                keys.indexOf(i) < 0) {

                continue;
            }

            self.prototype[i] = (function (fn) {

                return function (callback) {

                    var result = null;
                    try {
                        result = fn();
                    }
                    catch (err) {
                        return callback(err);
                    }

                    return callback(null, result);
                };
            })(obj[i]);
        }
    }
};

exports.callStack = function (slice) {

    // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi

    var v8 = Error.prepareStackTrace;
    Error.prepareStackTrace = function (err, stack) {

        return stack;
    };

    var capture = {};
    Error.captureStackTrace(capture, arguments.callee);
    var stack = capture.stack;

    Error.prepareStackTrace = v8;

    var trace = [];
    stack.forEach(function (item) {

        trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
    });

    if (slice) {
        return trace.slice(slice);
    }

    return trace;
};

exports.displayStack = function (slice) {

    var trace = exports.callStack(slice === undefined ? 1 : slice + 1);
    var display = [];
    trace.forEach(function (row) {

        display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
    });

    return display;
};

exports.abortThrow = false;

exports.abort = function (message, hideStack) {

    if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
        throw new Error(message || 'Unknown error');
    }

    var stack = '';
    if (!hideStack) {
        stack = exports.displayStack(1).join('\n\t');
    }
    console.log('ABORT: ' + message + '\n\t' + stack);
    process.exit(1);
};

exports.assert = function (condition, message) {

    if (!condition) {
        throw new Error(message || 'Unknown error');
    }
};

exports.loadDirModules = function (path, excludeFiles, target) {      // target(filename, name, capName)

    var exclude = {};
    for (var i = 0, il = excludeFiles.length; i < il; ++i) {
        exclude[excludeFiles[i] + '.js'] = true;
    }

    Fs.readdirSync(path).forEach(function (filename) {

        if (/\.js$/.test(filename) &&
            !exclude[filename]) {

            var name = filename.substr(0, filename.lastIndexOf('.'));
            var capName = name.charAt(0).toUpperCase() + name.substr(1).toLowerCase();

            if (typeof target !== 'function') {
                target[capName] = require(path + '/' + name);
            }
            else {
                target(path + '/' + name, name, capName);
            }
        }
    });
};

exports.rename = function (obj, from, to) {

    obj[to] = obj[from];
    delete obj[from];
};

exports.Timer = function () {

    this.reset();
};

exports.Timer.prototype.reset = function () {

    this.ts = Date.now();
};

exports.Timer.prototype.elapsed = function () {

    return Date.now() - this.ts;
};

// Load and parse package.json process root or given directory

exports.loadPackage = function (dir) {

    var result = {};
    var filepath = (dir || process.env.PWD) + '/package.json';
    if (Fs.existsSync(filepath)) {
        try {
            result = JSON.parse(Fs.readFileSync(filepath));
        }
        catch (e) { }
    }

    return result;
};

// Escape string for Regex construction

exports.escapeRegex = function (string) {

    // Escape ^$.*+-?=!:|\/()[]{},
    return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
};

// Return an error as first argument of a callback

exports.toss = function (condition /*, [message], callback */) {

    var message = (arguments.length === 3 ? arguments[1] : '');
    var callback = (arguments.length === 3 ? arguments[2] : arguments[1]);

    var err = (message instanceof Error ? message : (message ? new Error(message) : (condition instanceof Error ? condition : new Error())));

    if (condition instanceof Error ||
        !condition) {

        return callback(err);
    }
};

// Base64url (RFC 4648) encode

exports.base64urlEncode = function (value) {

    return (new Buffer(value, 'binary')).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
};

// Base64url (RFC 4648) decode

exports.base64urlDecode = function (encoded) {

    if (encoded &&
        !encoded.match(/^[\w\-]*$/)) {

        return new Error('Invalid character');
    }

    try {
        return (new Buffer(encoded.replace(/-/g, '+').replace(/:/g, '/'), 'base64')).toString('binary');
    }
    catch (err) {
        return err;
    }
};

// Escape attribute value for use in HTTP header

exports.escapeHeaderAttribute = function (attribute) {

    return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');
};

// Escape string for inclusion in HTML

internals.htmlEscaped = {
    '&': '&',
    '<': '<',
    '>': '>',
    '"': '"',
    "'": ''',
    '`': '`'
};

exports.escapeHtml = function (string) {

    if (!string) {
        return '';
    }

    if (/[&<>"'`]/.test(string) === false) {
        return string;
    }

    return string.replace(/[&<>"'`]/g, function (chr) {

        return internals.htmlEscaped[chr];
    });
};

/*
var event = {
    timestamp: now.getTime(),
    tags: ['tag'],
    data: { some: 'data' }
};
*/

exports.consoleFunc = console.log;

exports.printEvent = function (event) {

    var pad = function (value) {

        return (value < 10 ? '0' : '') + value;
    };

    var now = new Date(event.timestamp);
    var timestring = (now.getYear() - 100).toString() +
        pad(now.getMonth() + 1) +
        pad(now.getDate()) +
        '/' +
        pad(now.getHours()) +
        pad(now.getMinutes()) +
        pad(now.getSeconds()) +
        '.' +
        now.getMilliseconds();

    var data = event.data;
    if (typeof event.data !== 'string') {
        try {
            data = JSON.stringify(event.data);
        }
        catch (e) {
            data = 'JSON Error: ' + e.message;
        }
    }

    var output = timestring + ', ' + event.tags[0] + ', ' + data;
    exports.consoleFunc(output);
};
<commit_msg>generalized cyclic detection<commit_after>// Load modules

var Fs = require('fs');

// Declare internals

var internals = {};

// Clone object or array

exports.clone = function (obj) {

    if (obj != null && typeof obj != 'undefined') {
        return exports.extend({}, obj);
    }
    return null;
};

exports.extend = function (target, source, seen) {

    var newObj = (source instanceof Array) ? [] : {};
    seen = seen || [source];

    if (Object.keys(target).length > 0) {
        newObj = exports.clone(target);
    }

    Object.keys(source).forEach(function (key) {

        var descriptor = Object.getOwnPropertyDescriptor(source, key);
        var orig = descriptor.value;

        if (orig instanceof Date) {
            descriptor.value = new Date(orig.getTime());
        }
        else if (orig instanceof RegExp) {
            var flags = '' + (orig.global ? 'g' : '') + (orig.ignoreCase ? 'i' : '') + (orig.multiline ? 'm' : ''); // y is a firefox only thing + (orig.sticky ? 'y' : '');
            descriptor.value = new RegExp(orig.source, flags);
        }
        else if (orig instanceof Array) {
            descriptor.value = orig.slice();
        }
        else if (typeof orig == 'object') {
            if (seen.indexOf(orig) >= 0) {
                // console.log('cyclic detected')
            }
            else {
                descriptor.value = exports.extend({}, orig, seen);
                seen.push(descriptor.value)
            }
        }
        else {
            // Should just be ignorable immutables here (String, Number, Boolean...)
        }

        Object.defineProperty(newObj, key, descriptor);
    });

    return newObj;
};

// Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied

exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {

    exports.assert(target && typeof target == 'object', 'Invalid target value: must be an object');
    exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');

    if (!source) {
        return target;
    }

    if (source instanceof Array) {
        exports.assert(target instanceof Array, 'Cannot merge array onto an object');
        if (isMergeArrays === false) {                                                  // isMergeArrays defaults to true
            target.length = 0;                                                          // Must not change target assignment
        }

        source.forEach(function (item) {

            target.push(item);
        });

        return target;
    }

    Object.keys(source).forEach(function (key) {

        var value = source[key];
        if (value &&
            typeof value === 'object') {

            if (!target[key] ||
                typeof target[key] !== 'object') {

                target[key] = exports.clone(value);
            }
            else {
                exports.merge(target[key], source[key], isNullOverride, isMergeArrays);
            }
        }
        else {
            if (value !== null && value !== undefined) {            // Explicit to preserve empty strings
                target[key] = value;
            }
            else if (isNullOverride !== false) {                    // Defaults to true
                target[key] = value;
            }
        }
    });

    return target;
};

// Apply options to a copy of the defaults

exports.applyToDefaults = function (defaults, options) {

    exports.assert(defaults && typeof defaults == 'object', 'Invalid defaults value: must be an object');
    exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');

    if (!options) {                                                 // If no options, return null
        return null;
    }

    var copy = exports.clone(defaults);

    if (options === true) {                                         // If options is set to true, use defaults
        return copy;
    }

    return exports.merge(copy, options, false, false);
};

// Remove duplicate items from array

exports.unique = function (array, key) {

    var index = {};
    var result = [];

    for (var i = 0, il = array.length; i < il; ++i) {
        var id = (key ? array[i][key] : array[i]);
        if (index[id] !== true) {

            result.push(array[i]);
            index[id] = true;
        }
    }

    return result;
};

// Convert array into object

exports.mapToObject = function (array, key) {

    if (!array) {
        return null;
    }

    var obj = {};
    for (var i = 0, il = array.length; i < il; ++i) {
        if (key) {
            if (array[i][key]) {
                obj[array[i][key]] = true;
            }
        }
        else {
            obj[array[i]] = true;
        }
    }

    return obj;
};

// Find the common unique items in two arrays

exports.intersect = function (array1, array2) {

    if (!array1 || !array2) {
        return [];
    }

    var common = [];
    var hash = exports.mapToObject(array1);
    var found = {};
    for (var i = 0, il = array2.length; i < il; ++i) {
        if (hash[array2[i]] && !found[array2[i]]) {
            common.push(array2[i]);
            found[array2[i]] = true;
        }
    }

    return common;
};

// Find which keys are present

exports.matchKeys = function (obj, keys) {

    var matched = [];
    for (var i = 0, il = keys.length; i < il; ++i) {
        if (obj.hasOwnProperty(keys[i])) {
            matched.push(keys[i]);
        }
    }
    return matched;
};

// Flatten array

exports.flatten = function (array, target) {

    var result = target || [];

    for (var i = 0, il = array.length; i < il; ++i) {
        if (Array.isArray(array[i])) {
            exports.flatten(array[i], result);
        }
        else {
            result.push(array[i]);
        }
    }

    return result;
};

// Remove keys

exports.removeKeys = function (object, keys) {

    for (var i = 0, il = keys.length; i < il; i++) {
        delete object[keys[i]];
    }
};

// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])

exports.reach = function (obj, chain) {

    var path = chain.split('.');
    var ref = obj;
    path.forEach(function (level) {

        if (ref) {
            ref = ref[level];
        }
    });

    return ref;
};

// Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors

exports.inheritAsync = function (self, obj, keys) {

    keys = keys || null;

    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            if (keys instanceof Array &&
                keys.indexOf(i) < 0) {

                continue;
            }

            self.prototype[i] = (function (fn) {

                return function (callback) {

                    var result = null;
                    try {
                        result = fn();
                    }
                    catch (err) {
                        return callback(err);
                    }

                    return callback(null, result);
                };
            })(obj[i]);
        }
    }
};

exports.callStack = function (slice) {

    // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi

    var v8 = Error.prepareStackTrace;
    Error.prepareStackTrace = function (err, stack) {

        return stack;
    };

    var capture = {};
    Error.captureStackTrace(capture, arguments.callee);
    var stack = capture.stack;

    Error.prepareStackTrace = v8;

    var trace = [];
    stack.forEach(function (item) {

        trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
    });

    if (slice) {
        return trace.slice(slice);
    }

    return trace;
};

exports.displayStack = function (slice) {

    var trace = exports.callStack(slice === undefined ? 1 : slice + 1);
    var display = [];
    trace.forEach(function (row) {

        display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
    });

    return display;
};

exports.abortThrow = false;

exports.abort = function (message, hideStack) {

    if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
        throw new Error(message || 'Unknown error');
    }

    var stack = '';
    if (!hideStack) {
        stack = exports.displayStack(1).join('\n\t');
    }
    console.log('ABORT: ' + message + '\n\t' + stack);
    process.exit(1);
};

exports.assert = function (condition, message) {

    if (!condition) {
        throw new Error(message || 'Unknown error');
    }
};

exports.loadDirModules = function (path, excludeFiles, target) {      // target(filename, name, capName)

    var exclude = {};
    for (var i = 0, il = excludeFiles.length; i < il; ++i) {
        exclude[excludeFiles[i] + '.js'] = true;
    }

    Fs.readdirSync(path).forEach(function (filename) {

        if (/\.js$/.test(filename) &&
            !exclude[filename]) {

            var name = filename.substr(0, filename.lastIndexOf('.'));
            var capName = name.charAt(0).toUpperCase() + name.substr(1).toLowerCase();

            if (typeof target !== 'function') {
                target[capName] = require(path + '/' + name);
            }
            else {
                target(path + '/' + name, name, capName);
            }
        }
    });
};

exports.rename = function (obj, from, to) {

    obj[to] = obj[from];
    delete obj[from];
};

exports.Timer = function () {

    this.reset();
};

exports.Timer.prototype.reset = function () {

    this.ts = Date.now();
};

exports.Timer.prototype.elapsed = function () {

    return Date.now() - this.ts;
};

// Load and parse package.json process root or given directory

exports.loadPackage = function (dir) {

    var result = {};
    var filepath = (dir || process.env.PWD) + '/package.json';
    if (Fs.existsSync(filepath)) {
        try {
            result = JSON.parse(Fs.readFileSync(filepath));
        }
        catch (e) { }
    }

    return result;
};

// Escape string for Regex construction

exports.escapeRegex = function (string) {

    // Escape ^$.*+-?=!:|\/()[]{},
    return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
};

// Return an error as first argument of a callback

exports.toss = function (condition /*, [message], callback */) {

    var message = (arguments.length === 3 ? arguments[1] : '');
    var callback = (arguments.length === 3 ? arguments[2] : arguments[1]);

    var err = (message instanceof Error ? message : (message ? new Error(message) : (condition instanceof Error ? condition : new Error())));

    if (condition instanceof Error ||
        !condition) {

        return callback(err);
    }
};

// Base64url (RFC 4648) encode

exports.base64urlEncode = function (value) {

    return (new Buffer(value, 'binary')).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
};

// Base64url (RFC 4648) decode

exports.base64urlDecode = function (encoded) {

    if (encoded &&
        !encoded.match(/^[\w\-]*$/)) {

        return new Error('Invalid character');
    }

    try {
        return (new Buffer(encoded.replace(/-/g, '+').replace(/:/g, '/'), 'base64')).toString('binary');
    }
    catch (err) {
        return err;
    }
};

// Escape attribute value for use in HTTP header

exports.escapeHeaderAttribute = function (attribute) {

    return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');
};

// Escape string for inclusion in HTML

internals.htmlEscaped = {
    '&': '&',
    '<': '<',
    '>': '>',
    '"': '"',
    "'": ''',
    '`': '`'
};

exports.escapeHtml = function (string) {

    if (!string) {
        return '';
    }

    if (/[&<>"'`]/.test(string) === false) {
        return string;
    }

    return string.replace(/[&<>"'`]/g, function (chr) {

        return internals.htmlEscaped[chr];
    });
};

/*
var event = {
    timestamp: now.getTime(),
    tags: ['tag'],
    data: { some: 'data' }
};
*/

exports.consoleFunc = console.log;

exports.printEvent = function (event) {

    var pad = function (value) {

        return (value < 10 ? '0' : '') + value;
    };

    var now = new Date(event.timestamp);
    var timestring = (now.getYear() - 100).toString() +
        pad(now.getMonth() + 1) +
        pad(now.getDate()) +
        '/' +
        pad(now.getHours()) +
        pad(now.getMinutes()) +
        pad(now.getSeconds()) +
        '.' +
        now.getMilliseconds();

    var data = event.data;
    if (typeof event.data !== 'string') {
        try {
            data = JSON.stringify(event.data);
        }
        catch (e) {
            data = 'JSON Error: ' + e.message;
        }
    }

    var output = timestring + ', ' + event.tags[0] + ', ' + data;
    exports.consoleFunc(output);
};
<|endoftext|>


<commit_before>var centerLatlng = new L.LatLng(center.lat, center.lng);
var map;
var defaultZoom = 8;
function initialize() {
    map = new L.Map('map_canvas');
    var cloudmadeTileLayer = new L.TileLayer('http://{s}.tile.cloudmade.com/b1e5699de0e74928959c89bf0f777a5b/997/256/{z}/{x}/{y}.png', {
        attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
        maxZoom: 18
    });
    map.setView(centerLatlng, defaultZoom).addLayer(cloudmadeTileLayer);
    var latLngArray = new Array();
    for (var i=0; i<points.length; i=i+1) {
        // use a self executing function to create a new scope in each
        // iteration of the loop.
        latLngArray.push((function(){
            // create a marker on the map for this point
            var point = new L.LatLng(points[i].lat, points[i].lng);
            var marker = new L.CircleMarker(point, {
                'radius': 8
            });
            var instance = points[i].instance;

            // TODO: remove hard coded url
            var url = "/odk_viewer/survey/" + instance.toString() + "/";
            // open a loading popup so the user knows something is happening
            //a = marker.bindPopup('Loading...');//.openPopup();

            // bind open popup to marker's click event
            marker.on('click', function(e){
                var targetMarker = e.target;
                var popup = new L.Popup({
                    'maxWidth': 500,
                });
                latlng = e.latlng;
                latlng.lat += 1;
                popup.setLatLng(latlng);
                $.get(url).done(function(data){
                    popup.setContent(data);
                    map.openPopup(popup);
                });
            });

            map.addLayer(marker);
            return point;
        })());
    }
    // fitting to bounds with one point will zoom too far
    if (latLngArray.length > 1) {
        var latlngbounds = new L.LatLngBounds(latLngArray);
        map.fitBounds(latlngbounds);
   }
}
<commit_msg>used the Popups offset option to position the popup properly.<commit_after>var centerLatlng = new L.LatLng(center.lat, center.lng);
var map;
var defaultZoom = 8;
function initialize() {
    map = new L.Map('map_canvas');
    var cloudmadeTileLayer = new L.TileLayer('http://{s}.tile.cloudmade.com/b1e5699de0e74928959c89bf0f777a5b/997/256/{z}/{x}/{y}.png', {
        attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
        maxZoom: 18
    });
    map.setView(centerLatlng, defaultZoom).addLayer(cloudmadeTileLayer);
    var latLngArray = new Array();
    for (var i=0; i<points.length; i=i+1) {
        // use a self executing function to create a new scope in each
        // iteration of the loop.
        latLngArray.push((function(){
            // create a marker on the map for this point
            var point = new L.LatLng(points[i].lat, points[i].lng);
            var marker = new L.CircleMarker(point, {
                'radius': 8
            });
            var instance = points[i].instance;

            // TODO: remove hard coded url
            var url = "/odk_viewer/survey/" + instance.toString() + "/";
            // open a loading popup so the user knows something is happening
            //a = marker.bindPopup('Loading...');//.openPopup();

            // bind open popup to marker's click event
            marker.on('click', function(e){
                var targetMarker = e.target;
                var popup = new L.Popup({
                    'maxWidth': 500,
                    'offset': new L.Point(0,-50)
                });
                latlng = e.latlng;
                popup.setLatLng(latlng);
                $.get(url).done(function(data){
                    popup.setContent(data);
                    map.openPopup(popup);
                });
            });

            map.addLayer(marker);
            return point;
        })());
    }
    // fitting to bounds with one point will zoom too far
    if (latLngArray.length > 1) {
        var latlngbounds = new L.LatLngBounds(latLngArray);
        map.fitBounds(latlngbounds);
   }
}
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash')
  , Q = require('q')
  , errors = require('./errors')
  , yaml = require('yamljs')
  , EasyXml = require('easyxml')
  , Promise = require('promise')
  , xmldefaults = {
        singularizeChildren: true,
        allowAttributes: true,
        manifest: true
    }
  , errorpathelement = '_errors'
  , extensionmappings = {
        json: 'json',
        xml: 'xml',
        yml: 'text/x-yaml'
    };

/**
 * creates an express router middleware that
 * serves every sequelize resource in `models`
 * as a rest service at `/:resource` (relative
 * to the mount point of the router)
 *
 * for examples in this class, assume it is
 * mounted at '/api'
 */
module.exports = function(models) {
    /**
     * creates the {{pseudo-mime}} => {{serialization}}
     * mappings required by the res.format of express
     */
    function format(xml, res, object) {
        return {
            xml: function() {
                res.set('Content-Type', 'application/xml').send(xml.render(object));
            },
            json: function() {
                res.json(object);
            },
            'text/x-yaml': function() {
                res.set('Content-Type', 'text/x-yaml').send(yaml.stringify(object));
            },
            default: function() {
                res.send(object);
            }
        };
    }

    /**
     * turns a list of sequelize items to plain javascript objects
     * @see #cleanitem(item)
     */
    function cleanitems(items) {
            return _.chain(items)
                .map(function(item) { return cleanitem(item); })
                .value();
    }
    /**
     * turns sequelize item to plain javascript object,
     * omits `createdAt` and `updatedAt` values
     */
    function cleanitem(item) {
        return _.omit(item.dataValues, 'createdAt', 'updatedAt');
    }

    /**
     * creates an xml renderer based on EasyXml
     * given a root element (normally model.getTableName())
     */
    function xmlbuilder(root) {
        return new EasyXml(_.extend({
            rootElement: root
        }, xmldefaults));
    }

    function errorbuilder(req, err) {
        return _.extend({
            url: req.baseUrl + '/' + errorpathelement + '/' + err.slug
        }, err.error);
    }

    var api = require('express').Router();

    /**
     * lists urls to all resource types, e.g.
     *
     * ```
     * ['/api/foo', '/api/bar']
     * ```
     */
    api.get('/', function(req, res, next) {
        res.format(format(
            xmlbuilder('endpoints'),
            res,
            _.map(models, function(model) {
                return [req.baseUrl, model.getTableName()].join('/');
            })
        ));
        next();
    });

    _.each(_.values(errors), function(err) {
        api.get('/' + errorpathelement + '/' + err.slug, function(req, res, next) {
            res.format(format(
                xmlbuilder('error'),
                res,
                err.description
            ));
            next();
        });
    });

    /**
     * for examples, let `model` be `foo`
     */
    _.each(models, function(model) {
        function resourceurl(req, id) {
            return req.baseUrl + collection + '/' + id;
        }

        function getcollection(req) {
            return new Promise(function(resolve) {
                if (req.query.include_docs) {
                    model.findAll().then(function(results) {
                        resolve(cleanitems(results));
                    });
                } else {
                    model.findAll({
                        attributes: ['id']
                    }).then(function(results) {
                        resolve(_.map(results, function(result) {
                            return resourceurl(req, result.id);
                        }));
                    });
                }
            });
        }

        function getresource(req) {
            return new Promise(function(resolve, reject) {
                model.findOne(req.params.id.replace(/\.[^\.]+$/g, '')).then(function(result) {
                    resolve(cleanitem(result));
                }, reject);
            });
        }

        var collection = '/' + model.getTableName()
          , resource = collection + '/:id'
          , xml = xmlbuilder(model.getTableName());

        /**
         * lists urls to all resources specified by `model`, e.g.
         *
         * ```
         * ['/api/foo/1', '/api/foo/2']
         * ```
         *
         * if called with ?include_docs=true, returns the docs instead, e.g.
         *
         * ```
         * [{id: 1, name: goo}, {id: 2, name: gle}]
         * ```
         */
        api.get(collection, function(req, res, next) {
            getcollection(req).then(function(items) {
                res.format(format(xml, res, items));
                next();
            });
        });

        api.get(collection + '.:ext', function(req, res, next) {
            if (req.params.ext in extensionmappings) {
                getcollection(req).then(function(items) {
                    format(xml, res, items)[extensionmappings[req.params.ext]]();
                    next();
                });
            } else {
                res
                    .status(400)
                    .format(format(xml, res, errorbuilder(req, errors.UNKNOWN_TYPE)));
                next();
            }
        });

        api.post(collection, function(req, res, next) {
            model.create(req.body).then(function(resource) {
                res.format(format(
                    xml,
                    res,
                    resourceurl(req, resource.dataValues.id)
                ));
                next();
            });
        });

        api.put(collection, function(req, res, next) {
            Q.all(_.map(req.body, function(item) {
                return model.upsert(item);
            })).then(function() {
                res.sendStatus(200);
                next();
            });
        });

        api.delete(collection, function(req, res, next) {
            model.destroy({where: {id: {gt: 0}}}).then(function() {
                res.sendStatus(200);
                next();
            });
        });

        /**
         * gets the single resource at '/:resource/:id', e.g.
         *
         * {id: 1, name: 'goo'}
         */
        api.get(resource, function(req, res, next) {
            // /:id matches /:id.:ext as well -> next() in that case
            if (/\.[^\.]+$/.test(req.params.id)) {
                next();
            } else {
                getresource(req).then(function(item) {
                    res.format(format(xml, res, item));
                    next();
                });
            }
        });

        api.get(resource + '.:ext', function(req, res, next) {
            if (req.params.ext in extensionmappings) {
                getresource(req).then(function(item) {
                    format(xml, res, item)[extensionmappings[req.params.ext]]();
                    next();
                });
            } else {
                res
                    .status(400)
                    .format(format(xml, res, errorbuilder(req, errors.UNKNOWN_TYPE)));
                next();
            }
        });

        api.post(resource, function(req, res, next) {
            res
                .status(400)
                .format(format(xml, res, errorbuilder(req, errors.POST_RESOURCE)));
            next();
        });

        api.put(resource, function(req, res, next) {
            model.update(req.body, {where: {id: req.params.id}}).then(function() {
                res.format(format(xml, res, resourceurl(req, req.params.id)));
                next();
            });
        });

        api.delete(resource, function(req, res, next) {
            model.destroy({where: {id: req.params.id}}).then(function() {
                res.format(format(xml, res, req.baseUrl + collection));
                next();
            });
        });
    });

    return api;
};<commit_msg>removed default entry from res.format as there is no way to get it executed (missing Accept: header yields text/xml representation)<commit_after>'use strict';

var _ = require('lodash')
  , Q = require('q')
  , errors = require('./errors')
  , yaml = require('yamljs')
  , EasyXml = require('easyxml')
  , Promise = require('promise')
  , xmldefaults = {
        singularizeChildren: true,
        allowAttributes: true,
        manifest: true
    }
  , errorpathelement = '_errors'
  , extensionmappings = {
        json: 'json',
        xml: 'xml',
        yml: 'text/x-yaml'
    };

/**
 * creates an express router middleware that
 * serves every sequelize resource in `models`
 * as a rest service at `/:resource` (relative
 * to the mount point of the router)
 *
 * for examples in this class, assume it is
 * mounted at '/api'
 */
module.exports = function(models) {
    /**
     * creates the {{pseudo-mime}} => {{serialization}}
     * mappings required by the res.format of express
     */
    function format(xml, res, object) {
        return {
            xml: function() {
                res
                    .set('Content-Type', 'application/xml')
                    .send(xml.render(object));
            },
            json: function() {
                res
                    .json(object);
            },
            'text/x-yaml': function() {
                res
                    .set('Content-Type', 'text/x-yaml')
                    .send(yaml.stringify(object));
            }
        };
    }

    /**
     * turns a list of sequelize items to plain javascript objects
     * @see #cleanitem(item)
     */
    function cleanitems(items) {
            return _.chain(items)
                .map(function(item) { return cleanitem(item); })
                .value();
    }
    /**
     * turns sequelize item to plain javascript object,
     * omits `createdAt` and `updatedAt` values
     */
    function cleanitem(item) {
        return _.omit(item.dataValues, 'createdAt', 'updatedAt');
    }

    /**
     * creates an xml renderer based on EasyXml
     * given a root element (normally model.getTableName())
     */
    function xmlbuilder(root) {
        return new EasyXml(_.extend({
            rootElement: root
        }, xmldefaults));
    }

    function errorbuilder(req, err) {
        return _.extend({
            url: req.baseUrl + '/' + errorpathelement + '/' + err.slug
        }, err.error);
    }

    var api = require('express').Router();

    /**
     * lists urls to all resource types, e.g.
     *
     * ```
     * ['/api/foo', '/api/bar']
     * ```
     */
    api.get('/', function(req, res, next) {
        res.format(format(
            xmlbuilder('endpoints'),
            res,
            _.map(models, function(model) {
                return [req.baseUrl, model.getTableName()].join('/');
            })
        ));
        next();
    });

    _.each(_.values(errors), function(err) {
        api.get('/' + errorpathelement + '/' + err.slug, function(req, res, next) {
            res.format(format(
                xmlbuilder('error'),
                res,
                err.description
            ));
            next();
        });
    });

    /**
     * for examples, let `model` be `foo`
     */
    _.each(models, function(model) {
        function resourceurl(req, id) {
            return req.baseUrl + collection + '/' + id;
        }

        function getcollection(req) {
            return new Promise(function(resolve) {
                if (req.query.include_docs) {
                    model.findAll().then(function(results) {
                        resolve(cleanitems(results));
                    });
                } else {
                    model.findAll({
                        attributes: ['id']
                    }).then(function(results) {
                        resolve(_.map(results, function(result) {
                            return resourceurl(req, result.id);
                        }));
                    });
                }
            });
        }

        function getresource(req) {
            return new Promise(function(resolve, reject) {
                model.findOne(req.params.id.replace(/\.[^\.]+$/g, '')).then(function(result) {
                    resolve(cleanitem(result));
                }, reject);
            });
        }

        var collection = '/' + model.getTableName()
          , resource = collection + '/:id'
          , xml = xmlbuilder(model.getTableName());

        /**
         * lists urls to all resources specified by `model`, e.g.
         *
         * ```
         * ['/api/foo/1', '/api/foo/2']
         * ```
         *
         * if called with ?include_docs=true, returns the docs instead, e.g.
         *
         * ```
         * [{id: 1, name: goo}, {id: 2, name: gle}]
         * ```
         */
        api.get(collection, function(req, res, next) {
            getcollection(req).then(function(items) {
                res.format(format(xml, res, items));
                next();
            });
        });

        api.get(collection + '.:ext', function(req, res, next) {
            if (req.params.ext in extensionmappings) {
                getcollection(req).then(function(items) {
                    format(xml, res, items)[extensionmappings[req.params.ext]]();
                    next();
                });
            } else {
                res
                    .status(400)
                    .format(format(xml, res, errorbuilder(req, errors.UNKNOWN_TYPE)));
                next();
            }
        });

        api.post(collection, function(req, res, next) {
            model.create(req.body).then(function(resource) {
                res.format(format(
                    xml,
                    res,
                    resourceurl(req, resource.dataValues.id)
                ));
                next();
            });
        });

        api.put(collection, function(req, res, next) {
            Q.all(_.map(req.body, function(item) {
                return model.upsert(item);
            })).then(function() {
                res.sendStatus(200);
                next();
            });
        });

        api.delete(collection, function(req, res, next) {
            model.destroy({where: {id: {gt: 0}}}).then(function() {
                res.sendStatus(200);
                next();
            });
        });

        /**
         * gets the single resource at '/:resource/:id', e.g.
         *
         * {id: 1, name: 'goo'}
         */
        api.get(resource, function(req, res, next) {
            // /:id matches /:id.:ext as well -> next() in that case
            if (/\.[^\.]+$/.test(req.params.id)) {
                next();
            } else {
                getresource(req).then(function(item) {
                    res.format(format(xml, res, item));
                    next();
                });
            }
        });

        api.get(resource + '.:ext', function(req, res, next) {
            if (req.params.ext in extensionmappings) {
                getresource(req).then(function(item) {
                    format(xml, res, item)[extensionmappings[req.params.ext]]();
                    next();
                });
            } else {
                res
                    .status(400)
                    .format(format(xml, res, errorbuilder(req, errors.UNKNOWN_TYPE)));
                next();
            }
        });

        api.post(resource, function(req, res, next) {
            res
                .status(400)
                .format(format(xml, res, errorbuilder(req, errors.POST_RESOURCE)));
            next();
        });

        api.put(resource, function(req, res, next) {
            model.update(req.body, {where: {id: req.params.id}}).then(function() {
                res.format(format(xml, res, resourceurl(req, req.params.id)));
                next();
            });
        });

        api.delete(resource, function(req, res, next) {
            model.destroy({where: {id: req.params.id}}).then(function() {
                res.format(format(xml, res, req.baseUrl + collection));
                next();
            });
        });
    });

    return api;
};<|endoftext|>


<commit_before>/**
 * Poetry library
 * Facade to the lib exports
 * @name Poetry
 * @exports route
 * @exports endpoint
 * @exports session
 * @exports model
 * @exports db
 * @exports log
 * @exports emit
 * @exports on
 */

'use strict';
require('./checks'); // Check for Node version

const events = require('./methods/events');

module.exports = new Proxy( {

    //// Enpoint registration ////
    route: require( './methods/route' ),
    devRoute: require( './methods/devRoute' ),

    // Session
    session: require('./methods/session'),

    //// ORM ////
    model: require( './methods/model' ),
    db: require( './findDB' ),

    //// Logging ////
    log: require( './methods/log' ),

    //// Event messaging ////
    emit: events.emit,
    on: events.on,

    inspect: require('./methods/inspect')

}, {

    get( target, property ) {

        // Return target if exists
        if ( target[ property ] )
            return target[ property ];

        // Compatibility with Babel __esModule, etc
        if ( property.slice( 0, 2 ) == '__' )
            return undefined;

        //TODO: Handle onXXX generic methods
        throw new Error( `Poetry does not export "${property}".` );
    },

    // Avoid lib replacement
    set() {}

} );

module.exports.log.info( 'Poetry loaded' );
<commit_msg>add access to hapi<commit_after>/**
 * Poetry library
 * Facade to the lib exports
 * @name Poetry
 * @exports route
 * @exports endpoint
 * @exports session
 * @exports model
 * @exports db
 * @exports log
 * @exports emit
 * @exports on
 */

'use strict';
require('./checks'); // Check for Node version

const events = require('./methods/events');

module.exports = new Proxy( {

    //// Enpoint registration ////
    route: require( './methods/route' ),
    devRoute: require( './methods/devRoute' ),
    hapiServer: require('./server'),

    // Session
    session: require('./methods/session'),

    //// ORM ////
    model: require( './methods/model' ),
    db: require( './findDB' ),

    //// Logging ////
    log: require( './methods/log' ),

    //// Event messaging ////
    emit: events.emit,
    on: events.on,

    inspect: require('./methods/inspect')

}, {

    get( target, property ) {

        // Return target if exists
        if ( target[ property ] )
            return target[ property ];

        // Compatibility with Babel __esModule, etc
        if ( property.slice( 0, 2 ) == '__' )
            return undefined;

        //TODO: Handle onXXX generic methods
        throw new Error( `Poetry does not export "${property}".` );
    },

    // Avoid lib replacement
    set() {}

} );

module.exports.log.info( 'Poetry loaded' );
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const Boom = require('boom');
const Fs = require('fs');
const Hoek = require('hoek');
const Items = require('items');
const Path = require('path');

const _applyPoints = ['onRequest',
    'onPreAuth',
    'onPostAuth',
    'onPreHandler',
    'onPostHandler',
    'onPreResponse'];

const hasValidApplyPoint = (policy) => {

    return !policy.applyPoint || _applyPoints.indexOf(policy.applyPoint) !== -1;
};

// Memoizes by converting ['policy1', ..., 'policyN'] to 'policy1,...,policyN' as key
const determineAggregateApplyPoint = _.memoize((policyNames) => {

    Hoek.assert(Array.isArray(policyNames), 'Requires array of policy names.');
    Hoek.assert(policyNames.length > 0, 'Requires non-empty array of policy names.');
    Hoek.assert(_.intersection(data.names, policyNames).length === policyNames.length, 'Requires loaded policy names.');

    const firstPolicy = policyNames[0];

    let applyPoint;
    for (let i = 0; i < _applyPoints.length; ++i) {

        // Check if the first policy appears to have this apply point.
        if (!applyPoint &&
            Object.keys(data[_applyPoints[i]]).indexOf(firstPolicy) !== -1) {

            applyPoint = _applyPoints[i];
        }
    }

    Hoek.assert(applyPoint, 'Policies must be in a valid applyPoint.');
    Hoek.assert(_.intersection(Object.keys(data[applyPoint]), policyNames).length === policyNames.length,
                'Aggregate policies must be from same applyPoint.');

    return applyPoint;
});

let data = {
    names: [],
    rawPolicies: {},
    setHandlers: {}
};

/* adding arrays, to hold the policies */
_applyPoints.forEach((applyPoint) => {

    data[applyPoint] = {};
});

const runPolicies = function (policiesToRun, request, reply) {

    const checkPolicy = function (policy, next) {

        policy(request, reply, (err, canContinue, message) => {

            if (err) {
                // You can provide a custom hapi error object here
                return next(err);
            }
            if (canContinue) {
                return next(null, true);
            }
            return next(Boom.forbidden(message));
        });
    };

    // Run the policies in order
    Items.serial(policiesToRun, checkPolicy, (err) => {

        if (!reply._replied) {
            if (err) {
                return reply(err);
            }

            reply.continue();
        }
    });
};

/* generate handlers, one handler for each application point */
const handlers = {};
_applyPoints.forEach((applyPoint) => {

    handlers[applyPoint] = (request, reply) => {

        const applyPointPolicies = data[applyPoint];
        const routePolicies = Hoek.reach(request, 'route.settings.plugins.policies');
        if (!routePolicies) {
            return reply.continue();
        }

        let repliedWithError = false;
        const policiesToRun = routePolicies.reduce((tmpList, routePolicy) => {

            // Already replied
            if (repliedWithError) {
                return;
            }

            // Transform array to parallel, determine apply point in advance
            let aggregateApplyPoint;
            if (Array.isArray(routePolicy)) {

                aggregateApplyPoint = determineAggregateApplyPoint(routePolicy);

                if (aggregateApplyPoint === applyPoint) {
                    routePolicy = exports.parallel.apply(this, routePolicy);
                }
                else {
                    routePolicy = null;
                }
            }

            if (typeof routePolicy === 'string') {

                // Look for missing policies.  Probably due to misspelling.
                if (data.names.indexOf(routePolicy) === -1) {
                    repliedWithError = true;
                    return reply(Boom.notImplemented('Missing policy: ' + routePolicy));
                }

                if (applyPointPolicies[routePolicy]) {
                    tmpList.push(applyPointPolicies[routePolicy]);
                }

            }
            else if (typeof routePolicy === 'function') {

                // If an aggregate apply point wasn't already determined
                // but an aggregate apply point seems like it will be used, determine it from `policy.runs`.
                // `policy.runs` is an array of loaded policies reported by an aggregate policy
                // such as MrHorse.parallel, specifically for determining
                // its apply point ad hoc, notably here in the extension handler.
                if (!aggregateApplyPoint && routePolicy.runs && !routePolicy.applyPoint) {

                    aggregateApplyPoint = determineAggregateApplyPoint(routePolicy.runs);
                }

                if (!hasValidApplyPoint(routePolicy)) {
                    repliedWithError = true;
                    return reply(Boom.badImplementation('Trying to use incorrect applyPoint for the dynamic policy: ' + routePolicy.applyPoint));
                }

                const effectiveApplyPoint = routePolicy.applyPoint || aggregateApplyPoint || request.server.plugins.mrhorse.defaultApplyPoint;

                if (effectiveApplyPoint === applyPoint) {
                    tmpList.push(routePolicy);
                }

            }
            else if (routePolicy !== null) {

                repliedWithError = true;
                return reply(Boom.badImplementation('Policy not specified by name or by function.'));
            }

            return tmpList;
        }, []);

        // Already replied
        if (repliedWithError) {
            return;
        }

        runPolicies(policiesToRun, request, reply);
    };
});

const addPolicy = (policyName, policy, server, options) => {
    // Does this policy already exist
    if (hasPolicy(policyName)) {
        if (options.ignoreDuplicates) {
            return;
        }

        throw new Error('Trying to add a duplicate policy: ' + policyName);
    }

    // Check if the apply point is correct
    if (!hasValidApplyPoint(policy)) {
        throw new Error('Trying to set incorrect applyPoint for the policy: ' + policy.applyPoint);
    }

    // going further, filling the policies vs application points list
    if (policy.applyPoint === undefined || policy.applyPoint) {
        const applyPoint = policy.applyPoint || options.defaultApplyPoint;

        server.log(['info'], 'Adding a new policy called ' + policyName);
        data[applyPoint][policyName] = policy;
        data.rawPolicies[policyName] = policy;
        data.names.push(policyName);

        // connect the handler if this is the first pre policy
        if (!data.setHandlers[applyPoint]) {
            server.ext(applyPoint, handlers[applyPoint]);
            data.setHandlers[applyPoint] = true;
        }
    }
};

const loadPolicies = (server, options, next) => {

    let match = null;
    const re = /(.+)(\.js|\.ts)$/;

    options.defaultApplyPoint = options.defaultApplyPoint || 'onPreHandler'; // default application point

    const policyFiles = Fs.readdirSync(options.policyDirectory);
    if (policyFiles.length === 0) {
        return next();
    }

    const loadPolicyFile = (filename, addPolicyNext) => {

        // Only looking for .js files in the policies folder
        match = filename.match(re);
        if (match) {

            const policyData = require(Path.join(options.policyDirectory, filename));

            try {
                if (_.isPlainObject(policyData)) {
                    _.each(policyData, (policy, policyName) => addPolicy(policyName, policy, server, options));
                }
                else {
                    addPolicy(match[1], policyData, server, options);
                }
            }
            catch (err) {
                server.log(['error'], err.message);
                return addPolicyNext(err);
            }
        }

        addPolicyNext();
    };

    Items.serial(policyFiles, loadPolicyFile, (err) => {

        next(err);
    });
};

const hasPolicy = (policyName) => {

    return (data.names.indexOf(policyName) !== -1);
};

const reset = function reset() {

    data = {
        names: [],
        rawPolicies: {},
        setHandlers: {}
    };

    /* clear memoize cache */
    determineAggregateApplyPoint.cache.clear();

    /* adding arrays to hold the policies */
    _applyPoints.forEach((applyPoint) => {

        data[applyPoint] = {};
    });
};

exports.register = function register(server, options, next) {

    options.defaultApplyPoint = options.defaultApplyPoint || 'onPreHandler'; // default application point

    Hoek.assert(_applyPoints.indexOf(options.defaultApplyPoint) !== -1, 'Specified invalid defaultApplyPoint: ' + options.defaultApplyPoint);

    server.expose('loadPolicies', loadPolicies);
    server.expose('data', data);
    server.expose('reset', reset);
    server.expose('orPolicy', exports.orPolicy);
    server.expose('addPolicy', (policyName, policy) => addPolicy(policyName, policy, server, options));
    server.expose('hasPolicy', hasPolicy);
    server.expose('defaultApplyPoint', options.defaultApplyPoint);

    if (options.policyDirectory !== undefined) {
        loadPolicies(server, options, (err) => {

            next(err);
        });
    }
    else {
        next();
    }
};

exports.register.attributes = {
    pkg: require('../package.json')
};

/* Policy aggregation tools */
exports.parallel = function (/*policy1, policy2, [cb]*/) {

    Hoek.assert(arguments.length, 'Requires at least one argument.');

    const args = Array.prototype.slice.call(arguments);

    // This error aggregator is used by default, giving priority to error responses
    // by the policies' listed order.
    const defaultErrorHandler = (ranPolicies, results, next) => {

        for (let i = 0; i < ranPolicies.length; ++i) {

            const result = results[ranPolicies[i]];

            if (result.err || !result.canContinue) {

                next(result.err, result.canContinue, result.message);
                break;
            }

        }

        next(null, true);
    };

    // Determine the error handler and policies we're using
    let errorHandler;
    let policyNames;
    if (typeof args[args.length - 1] === 'function') {

        errorHandler = args[args.length - 1];
        policyNames = args.slice(0, -1);
    }
    else {

        errorHandler = defaultErrorHandler;
        policyNames = args;
    }

    Hoek.assert(_.uniq(policyNames).length === policyNames.length, 'Listed policies must be unique.');

    // Wraps policy for use in Items.parallel.execute, never errors.
    const wrapPolicy = (policy, request, reply) => {

        return function (next) {

            policy(request, reply, (err, canContinue, message) => {

                next(null, {
                    err,
                    canContinue,
                    message
                });
            });
        };
    };

    // Aggregate policy
    const aggregatePolicy = (request, reply, next) => {

        const policies = _(data.rawPolicies)
                        .pick(policyNames)
                        .mapValues((policy) => {

                            return wrapPolicy(policy, request, reply);
                        }).value();

        Items.parallel.execute(policies, (err, results) => {

            Hoek.assert(!err, 'There should never be an error here because of wrapPolicy.');

            errorHandler(policyNames, results, next);
        });
    };

    // Report to MrHorse handler which policies are going to be run
    aggregatePolicy.runs = policyNames;

    // Here ya go!
    return aggregatePolicy;
};

exports.orPolicy = function () {

    const args = Array.prototype.slice.call(arguments);

    args.push(
        (ranPolicies, results, next) => {

            // successful if at least one policy was OK
            const success = !_.every(ranPolicies, (policyName) => (results[ policyName ].canContinue === false));

            if (success) {
                return next(null, true, null);
            }

            // find leftmost failed policy
            const failed = _.find(results, { canContinue : false });

            return next(failed.err, false, failed.message);
        }
    );

    return exports.parallel.apply(this, args);
};
<commit_msg>Revert "allow typescript files for policies"<commit_after>'use strict';

const _ = require('lodash');
const Boom = require('boom');
const Fs = require('fs');
const Hoek = require('hoek');
const Items = require('items');
const Path = require('path');

const _applyPoints = ['onRequest',
    'onPreAuth',
    'onPostAuth',
    'onPreHandler',
    'onPostHandler',
    'onPreResponse'];

const hasValidApplyPoint = (policy) => {

    return !policy.applyPoint || _applyPoints.indexOf(policy.applyPoint) !== -1;
};

// Memoizes by converting ['policy1', ..., 'policyN'] to 'policy1,...,policyN' as key
const determineAggregateApplyPoint = _.memoize((policyNames) => {

    Hoek.assert(Array.isArray(policyNames), 'Requires array of policy names.');
    Hoek.assert(policyNames.length > 0, 'Requires non-empty array of policy names.');
    Hoek.assert(_.intersection(data.names, policyNames).length === policyNames.length, 'Requires loaded policy names.');

    const firstPolicy = policyNames[0];

    let applyPoint;
    for (let i = 0; i < _applyPoints.length; ++i) {

        // Check if the first policy appears to have this apply point.
        if (!applyPoint &&
            Object.keys(data[_applyPoints[i]]).indexOf(firstPolicy) !== -1) {

            applyPoint = _applyPoints[i];
        }
    }

    Hoek.assert(applyPoint, 'Policies must be in a valid applyPoint.');
    Hoek.assert(_.intersection(Object.keys(data[applyPoint]), policyNames).length === policyNames.length,
                'Aggregate policies must be from same applyPoint.');

    return applyPoint;
});

let data = {
    names: [],
    rawPolicies: {},
    setHandlers: {}
};

/* adding arrays, to hold the policies */
_applyPoints.forEach((applyPoint) => {

    data[applyPoint] = {};
});

const runPolicies = function (policiesToRun, request, reply) {

    const checkPolicy = function (policy, next) {

        policy(request, reply, (err, canContinue, message) => {

            if (err) {
                // You can provide a custom hapi error object here
                return next(err);
            }
            if (canContinue) {
                return next(null, true);
            }
            return next(Boom.forbidden(message));
        });
    };

    // Run the policies in order
    Items.serial(policiesToRun, checkPolicy, (err) => {

        if (!reply._replied) {
            if (err) {
                return reply(err);
            }

            reply.continue();
        }
    });
};

/* generate handlers, one handler for each application point */
const handlers = {};
_applyPoints.forEach((applyPoint) => {

    handlers[applyPoint] = (request, reply) => {

        const applyPointPolicies = data[applyPoint];
        const routePolicies = Hoek.reach(request, 'route.settings.plugins.policies');
        if (!routePolicies) {
            return reply.continue();
        }

        let repliedWithError = false;
        const policiesToRun = routePolicies.reduce((tmpList, routePolicy) => {

            // Already replied
            if (repliedWithError) {
                return;
            }

            // Transform array to parallel, determine apply point in advance
            let aggregateApplyPoint;
            if (Array.isArray(routePolicy)) {

                aggregateApplyPoint = determineAggregateApplyPoint(routePolicy);

                if (aggregateApplyPoint === applyPoint) {
                    routePolicy = exports.parallel.apply(this, routePolicy);
                }
                else {
                    routePolicy = null;
                }
            }

            if (typeof routePolicy === 'string') {

                // Look for missing policies.  Probably due to misspelling.
                if (data.names.indexOf(routePolicy) === -1) {
                    repliedWithError = true;
                    return reply(Boom.notImplemented('Missing policy: ' + routePolicy));
                }

                if (applyPointPolicies[routePolicy]) {
                    tmpList.push(applyPointPolicies[routePolicy]);
                }

            }
            else if (typeof routePolicy === 'function') {

                // If an aggregate apply point wasn't already determined
                // but an aggregate apply point seems like it will be used, determine it from `policy.runs`.
                // `policy.runs` is an array of loaded policies reported by an aggregate policy
                // such as MrHorse.parallel, specifically for determining
                // its apply point ad hoc, notably here in the extension handler.
                if (!aggregateApplyPoint && routePolicy.runs && !routePolicy.applyPoint) {

                    aggregateApplyPoint = determineAggregateApplyPoint(routePolicy.runs);
                }

                if (!hasValidApplyPoint(routePolicy)) {
                    repliedWithError = true;
                    return reply(Boom.badImplementation('Trying to use incorrect applyPoint for the dynamic policy: ' + routePolicy.applyPoint));
                }

                const effectiveApplyPoint = routePolicy.applyPoint || aggregateApplyPoint || request.server.plugins.mrhorse.defaultApplyPoint;

                if (effectiveApplyPoint === applyPoint) {
                    tmpList.push(routePolicy);
                }

            }
            else if (routePolicy !== null) {

                repliedWithError = true;
                return reply(Boom.badImplementation('Policy not specified by name or by function.'));
            }

            return tmpList;
        }, []);

        // Already replied
        if (repliedWithError) {
            return;
        }

        runPolicies(policiesToRun, request, reply);
    };
});

const addPolicy = (policyName, policy, server, options) => {
    // Does this policy already exist
    if (hasPolicy(policyName)) {
        if (options.ignoreDuplicates) {
            return;
        }

        throw new Error('Trying to add a duplicate policy: ' + policyName);
    }

    // Check if the apply point is correct
    if (!hasValidApplyPoint(policy)) {
        throw new Error('Trying to set incorrect applyPoint for the policy: ' + policy.applyPoint);
    }

    // going further, filling the policies vs application points list
    if (policy.applyPoint === undefined || policy.applyPoint) {
        const applyPoint = policy.applyPoint || options.defaultApplyPoint;

        server.log(['info'], 'Adding a new policy called ' + policyName);
        data[applyPoint][policyName] = policy;
        data.rawPolicies[policyName] = policy;
        data.names.push(policyName);

        // connect the handler if this is the first pre policy
        if (!data.setHandlers[applyPoint]) {
            server.ext(applyPoint, handlers[applyPoint]);
            data.setHandlers[applyPoint] = true;
        }
    }
};

const loadPolicies = (server, options, next) => {

    let match = null;
    const re = /(.+)\.js$/;

    options.defaultApplyPoint = options.defaultApplyPoint || 'onPreHandler'; // default application point

    const policyFiles = Fs.readdirSync(options.policyDirectory);
    if (policyFiles.length === 0) {
        return next();
    }

    const loadPolicyFile = (filename, addPolicyNext) => {

        // Only looking for .js files in the policies folder
        match = filename.match(re);
        if (match) {

            const policyData = require(Path.join(options.policyDirectory, filename));

            try {
                if (_.isPlainObject(policyData)) {
                    _.each(policyData, (policy, policyName) => addPolicy(policyName, policy, server, options));
                }
                else {
                    addPolicy(match[1], policyData, server, options);
                }
            }
            catch (err) {
                server.log(['error'], err.message);
                return addPolicyNext(err);
            }
        }

        addPolicyNext();
    };

    Items.serial(policyFiles, loadPolicyFile, (err) => {

        next(err);
    });
};

const hasPolicy = (policyName) => {

    return (data.names.indexOf(policyName) !== -1);
};

const reset = function reset() {

    data = {
        names: [],
        rawPolicies: {},
        setHandlers: {}
    };

    /* clear memoize cache */
    determineAggregateApplyPoint.cache.clear();

    /* adding arrays to hold the policies */
    _applyPoints.forEach((applyPoint) => {

        data[applyPoint] = {};
    });
};

exports.register = function register(server, options, next) {

    options.defaultApplyPoint = options.defaultApplyPoint || 'onPreHandler'; // default application point

    Hoek.assert(_applyPoints.indexOf(options.defaultApplyPoint) !== -1, 'Specified invalid defaultApplyPoint: ' + options.defaultApplyPoint);

    server.expose('loadPolicies', loadPolicies);
    server.expose('data', data);
    server.expose('reset', reset);
    server.expose('orPolicy', exports.orPolicy);
    server.expose('addPolicy', (policyName, policy) => addPolicy(policyName, policy, server, options));
    server.expose('hasPolicy', hasPolicy);
    server.expose('defaultApplyPoint', options.defaultApplyPoint);

    if (options.policyDirectory !== undefined) {
        loadPolicies(server, options, (err) => {

            next(err);
        });
    }
    else {
        next();
    }
};

exports.register.attributes = {
    pkg: require('../package.json')
};

/* Policy aggregation tools */
exports.parallel = function (/*policy1, policy2, [cb]*/) {

    Hoek.assert(arguments.length, 'Requires at least one argument.');

    const args = Array.prototype.slice.call(arguments);

    // This error aggregator is used by default, giving priority to error responses
    // by the policies' listed order.
    const defaultErrorHandler = (ranPolicies, results, next) => {

        for (let i = 0; i < ranPolicies.length; ++i) {

            const result = results[ranPolicies[i]];

            if (result.err || !result.canContinue) {

                next(result.err, result.canContinue, result.message);
                break;
            }

        }

        next(null, true);
    };

    // Determine the error handler and policies we're using
    let errorHandler;
    let policyNames;
    if (typeof args[args.length - 1] === 'function') {

        errorHandler = args[args.length - 1];
        policyNames = args.slice(0, -1);
    }
    else {

        errorHandler = defaultErrorHandler;
        policyNames = args;
    }

    Hoek.assert(_.uniq(policyNames).length === policyNames.length, 'Listed policies must be unique.');

    // Wraps policy for use in Items.parallel.execute, never errors.
    const wrapPolicy = (policy, request, reply) => {

        return function (next) {

            policy(request, reply, (err, canContinue, message) => {

                next(null, {
                    err,
                    canContinue,
                    message
                });
            });
        };
    };

    // Aggregate policy
    const aggregatePolicy = (request, reply, next) => {

        const policies = _(data.rawPolicies)
                        .pick(policyNames)
                        .mapValues((policy) => {

                            return wrapPolicy(policy, request, reply);
                        }).value();

        Items.parallel.execute(policies, (err, results) => {

            Hoek.assert(!err, 'There should never be an error here because of wrapPolicy.');

            errorHandler(policyNames, results, next);
        });
    };

    // Report to MrHorse handler which policies are going to be run
    aggregatePolicy.runs = policyNames;

    // Here ya go!
    return aggregatePolicy;
};

exports.orPolicy = function () {

    const args = Array.prototype.slice.call(arguments);

    args.push(
        (ranPolicies, results, next) => {

            // successful if at least one policy was OK
            const success = !_.every(ranPolicies, (policyName) => (results[ policyName ].canContinue === false));

            if (success) {
                return next(null, true, null);
            }

            // find leftmost failed policy
            const failed = _.find(results, { canContinue : false });

            return next(failed.err, false, failed.message);
        }
    );

    return exports.parallel.apply(this, args);
};
<|endoftext|>