<commit_before>// Load modules

var Http = require('http');
var Hoek = require('hoek');

// Declare internals

var internals = {};

exports.wrap = function (error, statusCode, message) {

    Hoek.assert(error instanceof Error, 'Cannot wrap non-Error object');
    return (error.isBoom ? error : internals.initialize(error, statusCode || 500, message));
};

exports.create = function (statusCode, message) {

    var error = new Error(message ? message : undefined);       // Avoids settings null message
    internals.initialize(error, statusCode);
    return error;
};

internals.initialize = function (error, statusCode, message) {

    Hoek.assert(!isNaN(parseFloat(statusCode)) && isFinite(statusCode) && statusCode >= 400, 'First argument must be a number (400+):', statusCode);

    error.isBoom = true;
    error.data = null;
    error.output = {
        statusCode: statusCode,
        payload: {},
        headers: {}
    };

    error.reformat = internals.reformat;
    error.reformat();

    if (message) {
        error.message = (message + (error.message ? ': ' + error.message : ''));
    }

    return error;
};

internals.reformat = function () {

    this.output.payload.statusCode = this.output.statusCode;
    this.output.payload.error = Http.STATUS_CODES[this.output.statusCode] || 'Unknown';
    if (this.message) {
        this.output.payload.message = this.message;
    }
};

// 4xx Client Errors

exports.badRequest = function (message) {

    return exports.create(400, message);
};

exports.unauthorized = function (message, scheme, attributes) {          // Or function (message, wwwAuthenticate[])

    var err = exports.create(401, message);

    if (!scheme) {
        return err;
    }

    var wwwAuthenticate = '';
    var i = 0;
    var il = 0;

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

        // function (message, scheme, attributes)

        wwwAuthenticate = scheme;
        if (attributes) {
            var names = Object.keys(attributes);
            for (i = 0, il = names.length; i < il; ++i) {
                if (i) {
                    wwwAuthenticate += ',';
                }

                var value = attributes[names[i]];
                if (value === null ||
                    value === undefined) {              // Value can be zero

                    value = '';
                }
                wwwAuthenticate += ' ' + names[i] + '="' + Hoek.escapeHeaderAttribute(value.toString()) + '"';
            }
        }

        if (message) {
            if (attributes) {
                wwwAuthenticate += ',';
            }
            wwwAuthenticate += ' error="' + Hoek.escapeHeaderAttribute(message) + '"';
        }
        else {
            err.isMissing = true;
        }
    }
    else {

        // function (message, wwwAuthenticate[])

        var wwwArray = scheme;
        for (i = 0, il = wwwArray.length; i < il; ++i) {
            if (i) {
                wwwAuthenticate += ', ';
            }

            wwwAuthenticate += wwwArray[i];
        }
    }

    err.output.headers['WWW-Authenticate'] = wwwAuthenticate;

    return err;
};

exports.forbidden = function (message) {

    return exports.create(403, message);
};

exports.notFound = function (message) {

    return exports.create(404, message);
};

exports.methodNotAllowed = function (message) {

    return exports.create(405, message);
};

exports.notAcceptable = function (message) {

    return exports.create(406, message);
};

exports.proxyAuthRequired = function (message) {

    return exports.create(407, message);
};

exports.clientTimeout = function (message) {

    return exports.create(408, message);
};

exports.conflict = function (message) {

    return exports.create(409, message);
};

exports.resourceGone = function (message) {

    return exports.create(410, message);
};

exports.lengthRequired = function (message) {

    return exports.create(411, message);
};

exports.preconditionFailed = function (message) {

    return exports.create(412, message);
};

exports.entityTooLarge = function (message) {

    return exports.create(413, message);
};

exports.uriTooLong = function (message) {

    return exports.create(414, message);
};

exports.unsupportedMediaType = function (message) {

    return exports.create(415, message);
};

exports.rangeNotSatisfiable = function (message) {

    return exports.create(416, message);
};

exports.expectationFailed = function (message) {

    return exports.create(417, message);
};

// 5xx Server Errors

exports.internal = function (message, data, statusCode) {

    var error = (data instanceof Error ? exports.wrap(data, statusCode, message) : exports.create(statusCode || 500, message));

    if (data instanceof Error === false) {
        error.data = data;
    }

    error.output.payload.message = 'An internal server error occurred';           // Hide actual error from user
    return error;
};

exports.notImplemented = function (message, data) {

    return exports.internal(message, data, 501);
};

exports.badGateway = function (message, data) {

    return exports.internal(message, data, 502);
};

exports.serverTimeout = function (message, data) {

    return exports.internal(message, data, 503);
};

exports.gatewayTimeout = function (message, data) {

    return exports.internal(message, data, 504);
};

exports.badImplementation = function (message, data) {

    var err = exports.internal(message, data, 500);
    err.isDeveloperError = true;
    return err;
};

<commit_msg>Don't override data if user error already have a data attribute<commit_after>// Load modules

var Http = require('http');
var Hoek = require('hoek');

// Declare internals

var internals = {};

exports.wrap = function (error, statusCode, message) {

    Hoek.assert(error instanceof Error, 'Cannot wrap non-Error object');
    return (error.isBoom ? error : internals.initialize(error, statusCode || 500, message));
};

exports.create = function (statusCode, message) {

    var error = new Error(message ? message : undefined);       // Avoids settings null message
    internals.initialize(error, statusCode);
    return error;
};

internals.initialize = function (error, statusCode, message) {

    Hoek.assert(!isNaN(parseFloat(statusCode)) && isFinite(statusCode) && statusCode >= 400, 'First argument must be a number (400+):', statusCode);

    error.isBoom = true;
    if (!error.data) {
        error.data = null;
    }
    error.output = {
        statusCode: statusCode,
        payload: {},
        headers: {}
    };

    error.reformat = internals.reformat;
    error.reformat();

    if (message) {
        error.message = (message + (error.message ? ': ' + error.message : ''));
    }

    return error;
};

internals.reformat = function () {

    this.output.payload.statusCode = this.output.statusCode;
    this.output.payload.error = Http.STATUS_CODES[this.output.statusCode] || 'Unknown';
    if (this.message) {
        this.output.payload.message = this.message;
    }
};

// 4xx Client Errors

exports.badRequest = function (message) {

    return exports.create(400, message);
};

exports.unauthorized = function (message, scheme, attributes) {          // Or function (message, wwwAuthenticate[])

    var err = exports.create(401, message);

    if (!scheme) {
        return err;
    }

    var wwwAuthenticate = '';
    var i = 0;
    var il = 0;

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

        // function (message, scheme, attributes)

        wwwAuthenticate = scheme;
        if (attributes) {
            var names = Object.keys(attributes);
            for (i = 0, il = names.length; i < il; ++i) {
                if (i) {
                    wwwAuthenticate += ',';
                }

                var value = attributes[names[i]];
                if (value === null ||
                    value === undefined) {              // Value can be zero

                    value = '';
                }
                wwwAuthenticate += ' ' + names[i] + '="' + Hoek.escapeHeaderAttribute(value.toString()) + '"';
            }
        }

        if (message) {
            if (attributes) {
                wwwAuthenticate += ',';
            }
            wwwAuthenticate += ' error="' + Hoek.escapeHeaderAttribute(message) + '"';
        }
        else {
            err.isMissing = true;
        }
    }
    else {

        // function (message, wwwAuthenticate[])

        var wwwArray = scheme;
        for (i = 0, il = wwwArray.length; i < il; ++i) {
            if (i) {
                wwwAuthenticate += ', ';
            }

            wwwAuthenticate += wwwArray[i];
        }
    }

    err.output.headers['WWW-Authenticate'] = wwwAuthenticate;

    return err;
};

exports.forbidden = function (message) {

    return exports.create(403, message);
};

exports.notFound = function (message) {

    return exports.create(404, message);
};

exports.methodNotAllowed = function (message) {

    return exports.create(405, message);
};

exports.notAcceptable = function (message) {

    return exports.create(406, message);
};

exports.proxyAuthRequired = function (message) {

    return exports.create(407, message);
};

exports.clientTimeout = function (message) {

    return exports.create(408, message);
};

exports.conflict = function (message) {

    return exports.create(409, message);
};

exports.resourceGone = function (message) {

    return exports.create(410, message);
};

exports.lengthRequired = function (message) {

    return exports.create(411, message);
};

exports.preconditionFailed = function (message) {

    return exports.create(412, message);
};

exports.entityTooLarge = function (message) {

    return exports.create(413, message);
};

exports.uriTooLong = function (message) {

    return exports.create(414, message);
};

exports.unsupportedMediaType = function (message) {

    return exports.create(415, message);
};

exports.rangeNotSatisfiable = function (message) {

    return exports.create(416, message);
};

exports.expectationFailed = function (message) {

    return exports.create(417, message);
};

// 5xx Server Errors

exports.internal = function (message, data, statusCode) {

    var error = (data instanceof Error ? exports.wrap(data, statusCode, message) : exports.create(statusCode || 500, message));

    if (data instanceof Error === false) {
        error.data = data;
    }

    error.output.payload.message = 'An internal server error occurred';           // Hide actual error from user
    return error;
};

exports.notImplemented = function (message, data) {

    return exports.internal(message, data, 501);
};

exports.badGateway = function (message, data) {

    return exports.internal(message, data, 502);
};

exports.serverTimeout = function (message, data) {

    return exports.internal(message, data, 503);
};

exports.gatewayTimeout = function (message, data) {

    return exports.internal(message, data, 504);
};

exports.badImplementation = function (message, data) {

    var err = exports.internal(message, data, 500);
    err.isDeveloperError = true;
    return err;
};

<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var env = require('gulp-env');
var fs = require('fs');

var projectPath = 'app/';
var outputPath = 'public/build/';
var configPath = 'config/';

var envFile = configPath + 'env.prod.json';
if( fs.existsSync(configPath + 'env.local.json') ) {
  envFile = configPath + 'env.local.json';
}
console.log('Using env file: ' + envFile);

/**
 *  Check the SASS style.
 */
gulp.task('styles:ci', function () {
  gulp.src(projectPath + '**/*.s+(a|c)ss')
  .pipe(sassLint())
  .pipe(sassLint.format())
  .pipe(sassLint.failOnError())
});

<commit_msg>Remove not usedn gulp task any more<commit_after>'use strict';

var gulp = require('gulp');
var env = require('gulp-env');
var fs = require('fs');

var projectPath = 'app/';
var outputPath = 'public/build/';
var configPath = 'config/';

var envFile = configPath + 'env.prod.json';
if( fs.existsSync(configPath + 'env.local.json') ) {
  envFile = configPath + 'env.local.json';
}
console.log('Using env file: ' + envFile);

<|endoftext|>


<commit_before>export default function(patterns, callback) {
    return function watch(resolve, reject) {
        const chokidar = require('chokidar');

        chokidar
            .watch(patterns, { persistent: true })
            .on('change', function(file) {
                callback(file).catch(reject);
            })
            .on('error', reject);

        callback(patterns).catch(reject);
    };
}
<commit_msg>:heavy_plus_sign: fire callback on "new file added" event<commit_after>export default function(patterns, callback) {
    return function watch(resolve, reject) {
        const chokidar = require('chokidar');

        chokidar
            .watch(patterns, { persistent: true })
            .on('change', function(file) {
                callback(file).catch(reject);
            })
            .on('add', function(file) {
                callback(file).catch(reject);
            })
            .on('error', reject);

        callback(patterns).catch(reject);
    };
}
<|endoftext|>


<commit_before>/**
 * Dependencies
 */

var Path = require('path'),
    _ = require('lodash'),
    utils = require('./utils'),
    crossAdapterRunner = require('../features/crossAdapter/core/crossAdapter'),
    mocha = require('mocha');

/**
 * Test Runner
 *
 * @param {Object} options
 * @api public
 */

module.exports = function(options) {

  if(!options.adapter) throw new Error('Must supply an adapter');
  if(!options.interfaces) throw new Error('Must supply a list of supported interfaces');
  if(!Array.isArray(options.interfaces)) throw new Error('Must supply a list of supported interfaces');

  this.adapter = options.adapter;
  this.config = options.config || {};
  this.interfaces = options.interfaces;
  this.features = _.clone(options.features || []);

  // cross-adapter is a special case since it requires a clean test cache for
  // running existing associations tests
  var crossAdapterIndex = this.features.indexOf('crossAdapter');
  if (crossAdapterIndex === -1) {
    crossAdapterIndex = this.features.indexOf('cross-adapter');
  }
  var runCrossAdapterTests;
  if(crossAdapterIndex >= 0){
    this.features.splice(crossAdapterIndex, 1);
    runCrossAdapterTests = true;
  }

  // Attach config to adapter
  // this.adapter.config = this.config;
  global.Connections = {
    'test': this.config
  };

  global.Connections.test.adapter = 'wl_tests';

  // Globalize Adapter
  global.Adapter = this.adapter;

  // Build an array of files to test
  var filter = '\\.(' + ['js'].join('|') + ')$';

  var files = [];

  this.interfaces.forEach(function(interface) {
    var interfacePath = Path.resolve(__dirname,'../interfaces/' + interface);
    files = files.concat(utils.fileLookup(interfacePath, filter, true));
  });

  this.features.forEach(function(feature) {
    var parts = feature.split('.');
    if (parts.length > 2) {
      throw new Error("Only one level of sub-features is supported, please use only one '.': " + feature);
    }

    var featurePath = Path.resolve(__dirname,'../features/' + parts[0] + '/core');
    files = files.concat(utils.fileLookup(featurePath, filter, true));

    if (parts.length == 2) {
      featurePath = Path.resolve(__dirname,'../features/' + parts[0] + '/' + parts[1]);
      files = files.concat(utils.fileLookup(featurePath, filter, true));
    }
  });
  // There might be duplicate files if multiple sub-features of a single feature is being tested.
  files = _.unique(files);

  // Build a Mocha Runner
  var test = new mocha(_.merge({
    timeout: 6000
  }, options.mocha||{}));

  if (options.mochaChainableMethods){
    _.forEach(options.mochaChainableMethods, function(arg, method){
      test[method](arg);
    });
  }

  // Set Global Placeholders for Ontologies
  global.Associations = {};
  global.Semantic = {};
  global.Queryable = {};
  global.Migratable = {};
  global.Sql = {};

  // Allow Adapter to be a global without warning about a leak
  test.globals([Adapter, Connections, Associations, Semantic, Queryable, Sql]);
  test.files = files;

  var exit = function(err, failOnError){
    if (err && failOnError) {
      var exitCode = isNaN(err) ? 1 : err;
      process.exit(exitCode);
    } else {
      process.exit(0);
    }
  };

  console.time('time elapsed');
  var runner = test.run(function(err) {
    console.timeEnd('time elapsed');

    if(runCrossAdapterTests){
      crossAdapterRunner.cleanTestCache(test.files);
      crossAdapterRunner(options, function(crossAdapterErr){
        exit(err || crossAdapterErr, options.failOnError);
      });
    } else {
      exit(err, options.failOnError);
    }
  });

  runner.on('fail', function (e) {
    console.error(e.err);
  });
};
<commit_msg>Globalize features array, and don't attempt to load files for a feature if there's no core file<commit_after>/**
 * Dependencies
 */

var Path = require('path'),
    _ = require('lodash'),
    utils = require('./utils'),
    crossAdapterRunner = require('../features/crossAdapter/core/crossAdapter'),
    mocha = require('mocha');

/**
 * Test Runner
 *
 * @param {Object} options
 * @api public
 */

module.exports = function(options) {

  if(!options.adapter) throw new Error('Must supply an adapter');
  if(!options.interfaces) throw new Error('Must supply a list of supported interfaces');
  if(!Array.isArray(options.interfaces)) throw new Error('Must supply a list of supported interfaces');

  this.adapter = options.adapter;
  this.config = options.config || {};
  this.interfaces = options.interfaces;
  this.features = _.clone(options.features || []);

  // cross-adapter is a special case since it requires a clean test cache for
  // running existing associations tests
  var crossAdapterIndex = this.features.indexOf('crossAdapter');
  if (crossAdapterIndex === -1) {
    crossAdapterIndex = this.features.indexOf('cross-adapter');
  }
  var runCrossAdapterTests;
  if(crossAdapterIndex >= 0){
    this.features.splice(crossAdapterIndex, 1);
    runCrossAdapterTests = true;
  }

  // Attach config to adapter
  // this.adapter.config = this.config;
  global.Connections = {
    'test': this.config
  };

  global.Connections.test.adapter = 'wl_tests';

  // Globalize Adapter
  global.Adapter = this.adapter;

  // Build an array of files to test
  var filter = '\\.(' + ['js'].join('|') + ')$';

  var files = [];

  this.interfaces.forEach(function(interface) {
    var interfacePath = Path.resolve(__dirname,'../interfaces/' + interface);
    files = files.concat(utils.fileLookup(interfacePath, filter, true));
  });

  this.features.forEach(function(feature) {
    var parts = feature.split('.');
    if (parts.length > 2) {
      throw new Error("Only one level of sub-features is supported, please use only one '.': " + feature);
    }

    var featurePath = Path.resolve(__dirname,'../features/' + parts[0] + '/core');
    if (require('fs').existsSync(featurePath)) {
      files = files.concat(utils.fileLookup(featurePath, filter, true));

      if (parts.length == 2) {
        featurePath = Path.resolve(__dirname,'../features/' + parts[0] + '/' + parts[1]);
        files = files.concat(utils.fileLookup(featurePath, filter, true));
      }
    }
  });
  // There might be duplicate files if multiple sub-features of a single feature is being tested.
  files = _.unique(files);

  // Build a Mocha Runner
  var test = new mocha(_.merge({
    timeout: 6000
  }, options.mocha||{}));

  if (options.mochaChainableMethods){
    _.forEach(options.mochaChainableMethods, function(arg, method){
      test[method](arg);
    });
  }

  // Set Global Placeholders for Ontologies
  global.Associations = {};
  global.Semantic = {};
  global.Queryable = {};
  global.Migratable = {};
  global.Sql = {};
  global.adapterFeatures = this.features;

  // Allow Adapter to be a global without warning about a leak
  test.globals([Adapter, Connections, Associations, Semantic, Queryable, Sql, adapterFeatures]);
  test.files = files;

  var exit = function(err, failOnError){
    if (err && failOnError) {
      var exitCode = isNaN(err) ? 1 : err;
      process.exit(exitCode);
    } else {
      process.exit(0);
    }
  };

  console.time('time elapsed');
  var runner = test.run(function(err) {
    console.timeEnd('time elapsed');

    if(runCrossAdapterTests){
      crossAdapterRunner.cleanTestCache(test.files);
      crossAdapterRunner(options, function(crossAdapterErr){
        exit(err || crossAdapterErr, options.failOnError);
      });
    } else {
      exit(err, options.failOnError);
    }
  });

  runner.on('fail', function (e) {
    console.error(e.err);
  });
};
<|endoftext|>


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

exports.scrub_creds = function scrub_creds(url) {
  return url.replace(/^(https?:\/\/)[^:]+:[^@]+@(.*)$/, '$1$2'); // Scrub username and password
}

exports.JP = JSON.parse;
exports.JS = JSON.stringify;
exports.JDUP = function(obj) { return JSON.parse(JSON.stringify(obj)) };

var timeouts = { 'setTimeout': setTimeout
               , 'clearTimeout': clearTimeout
               }

exports.setTimeout   = function() { return timeouts.setTimeout.apply(this, arguments) }
exports.clearTimeout = function() { return timeouts.clearTimeout.apply(this, arguments) }
exports.timeouts = function(set, clear) {
  timeouts.setTimeout = set
  timeouts.clearTimeout = clear
}

// Wrap log4js so it will not be a dependency.
var VERBOSE;
if(require.isBrowser)
  VERBOSE = true;
else
  verbose = (process.env.verbose === 'true');

var noop = process.env.TAP_DIAG
            ? console.error
            : function() {}

var noops = { "trace": noop
            , "debug": VERBOSE ? console.log   : noop
            , "info" : VERBOSE ? console.info  : noop
            , "warn" : VERBOSE ? console.warn  : noop
            , "error": VERBOSE ? console.error : noop
            , "fatal": VERBOSE ? console.error : noop

            , "setLevel": noop
            }

try {
  if(! process.env.log_plain)
    exports.log4js = require('log4js');
} catch(e) {
  exports.log4js = null;
}

exports.log4js = exports.log4js || { 'getLogger': function() { return noops } }
<commit_msg>Clean up handling a non-log4js situation<commit_after>// Copyright 2011 Iris Couch
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

exports.scrub_creds = function scrub_creds(url) {
  return url.replace(/^(https?:\/\/)[^:]+:[^@]+@(.*)$/, '$1$2'); // Scrub username and password
}

exports.JP = JSON.parse;
exports.JS = JSON.stringify;
exports.JDUP = function(obj) { return JSON.parse(JSON.stringify(obj)) };

var timeouts = { 'setTimeout': setTimeout
               , 'clearTimeout': clearTimeout
               }

exports.setTimeout   = function() { return timeouts.setTimeout.apply(this, arguments) }
exports.clearTimeout = function() { return timeouts.clearTimeout.apply(this, arguments) }
exports.timeouts = function(set, clear) {
  timeouts.setTimeout = set
  timeouts.clearTimeout = clear
}

// Wrap log4js so it will not be a dependency.
var VERBOSE;
if(require.isBrowser)
  VERBOSE = true;
else
  VERBOSE = (process.env.verbose === 'true');

var noop = function() {}
if(process.env.TAP_DIAG)
  noop = console.error

function noops() {
  return { "trace": noop
         , "debug": VERBOSE ? console.log   : noop
         , "info" : VERBOSE ? console.info  : noop
         , "warn" : VERBOSE ? console.warn  : noop
         , "error": VERBOSE ? console.error : noop
         , "fatal": VERBOSE ? console.error : noop

         , "setLevel": noop
         }
}

try {
  if(! process.env.log_plain)
    exports.log4js = require('log4js');
} catch(e) {
  exports.log4js = null;
}

exports.log4js = exports.log4js || { 'getLogger': function() { return noops() } }
<|endoftext|>


<commit_before>'use strict'
const gulp = require('gulp')
const del = require('del');
const templateCache = require('gulp-angular-templatecache')
const minifyHtml = require('gulp-minify-html')
const concat = require('gulp-concat')
const uglify = require('gulp-uglify')
const rename = require('gulp-rename')
const ngannotate = require('gulp-ng-annotate')
const closure = require('gulp-jsclosure')
const p = require('path')
const runSequence = require('run-sequence');
var cssnano = require('gulp-cssnano');
var deleteLines = require('gulp-delete-lines');
var useref = require('gulp-useref');
var gulpif = require('gulp-if');
var inject = require('gulp-inject');

const jsFilePaths = [
	'app/*.js',
	'app/directives/**/*.js',
	'app/services/*.js',
	'app/controllers/*.js'
];

const jsLibFilePaths = [
	"node_modules/jquery/dist/jquery.min.js",
	"node_modules/jQuery.print/jQuery.print.js",
	"node_modules/moment/min/moment.min.js",
	"node_modules/bootstrap/dist/js/bootstrap.min.js",
	"node_modules/eonasdan-bootstrap-datetimepicker-npm/build/js/bootstrap-datetimepicker.min.js",
	"node_modules/angular/angular.min.js",
	"node_modules/angular-route/angular-route.min.js",
	"node_modules/angular-animate/angular-animate.min.js",
	"node_modules/angular-aria/angular-aria.min.js",
	"node_modules/angular-messages/angular-messages.min.js",
	"node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js",
	"node_modules/angular-file-upload/dist/angular-file-upload.min.js",
	"node_modules/mdPickers/dist/mdPickers.min.js",
	"node_modules/clipboard/dist/clipboard.min.js",
	"node_modules/ngclipboard/dist/ngclipboard.min.js",
	"node_modules/angular-local-storage/dist/angular-local-storage.min.js",
	"node_modules/ms-signalr-client/jquery.signalR.min.js",
	"node_modules/angular-signalr-hub/signalr-hub.min.js"
]

const cssFilePaths = [
	"node_modules/bootstrap/dist/css/bootstrap-theme.css",
	"node_modules/bootstrap/dist/css/bootstrap.css",
	"node_modules/font-awesome/css/font-awesome.css",
	"app/content/styles/style.css",
	"app/content/styles/sidebar.css",
	"app/content/component/loadinSnake/loading-snake.css",
	"app/content/component/sk-cube/sk-cube.css",
	"app/content/component/spinner/spinner.css",
	"node_modules/eonasdan-bootstrap-datetimepicker-npm/build/css/bootstrap-datetimepicker.min.css"
]

gulp.task('clean', function (cb) {
	del(['dist']).then(function (paths) {
		console.log('Deleted files and folders:\n', paths.join('\n'));
        cb();
	});
});

gulp.task('bundle', function () {
	//first load the services, then the directives and then the controller
	return gulp.src(jsFilePaths)
			.pipe(ngannotate())
			.pipe(concat('main.js'))
			.pipe(uglify())
			.pipe(rename({suffix: '.min'}))
			.pipe(gulp.dest('dist/app'));
})

gulp.task('bundle-css', function(){
	return gulp.src(cssFilePaths)
		.pipe(cssnano())
		.pipe(concat('style.min.css'))
		.pipe(gulp.dest('dist/app'));
})

gulp.task('bundle-libs', function(){
	return gulp.src(jsLibFilePaths)
		.pipe(concat('lib.js'))
		.pipe(uglify())
		.pipe(rename({suffix: '.min'}))
		.pipe(gulp.dest('dist/app'));
});

gulp.task('copy-assets', function(){
	return gulp.src(['app/content/**/**/*'])
			.pipe(gulp.dest('dist/app/content/'))
});

gulp.task('copy-templates', function(){
	return gulp.src('app/views/**/*')
		.pipe(gulp.dest('dist/app/views/'))
});

gulp.task('remove-js-css', function(){
	return gulp.src('index.html')
			.pipe(deleteLines({
				'filters': [
					/<script\s+type=["']text\/javascript["']\s+src=/i
				]
			}))
			.pipe(deleteLines({
				'filters': [
					/<link\s+rel=["']/i
				]
			}))
			.pipe(gulp.dest('dist/'))
})

gulp.task('inject-index', function(){
	var bundlesSources = gulp.src(['./dist/app/**.css', './dist/app/**.js'], {read: false});

	return gulp.src('/dist/index.html')
				.pipe(inject(bundlesSources, { ignorePath: 'dist' }))
				.pipe(gulp.dest('dist/'));
});

gulp.task('build', function(callback){
	runSequence('clean',
				'bundle','bundle-libs',
				'bundle-css',
				'copy-assets',
				'copy-templates',
				'remove-js-css',
				'inject-index',
				callback);
});

<commit_msg>google maps and fonts are not working<commit_after>'use strict'
const gulp = require('gulp')
const del = require('del');
const templateCache = require('gulp-angular-templatecache')
const minifyHtml = require('gulp-minify-html')
const concat = require('gulp-concat')
const uglify = require('gulp-uglify')
const rename = require('gulp-rename')
const ngannotate = require('gulp-ng-annotate')
const closure = require('gulp-jsclosure')
const p = require('path')
const runSequence = require('run-sequence');
var cssnano = require('gulp-cssnano');
var deleteLines = require('gulp-delete-lines');
var useref = require('gulp-useref');
var gulpif = require('gulp-if');
var inject = require('gulp-inject');

const jsFilePaths = [
	'app/*.js',
	'app/directives/**/*.js',
	'app/services/*.js',
	'app/controllers/*.js'
];

const jsLibFilePaths = [
	"node_modules/jquery/dist/jquery.min.js",
	"node_modules/jQuery.print/jQuery.print.js",
	"node_modules/moment/min/moment.min.js",
	"node_modules/bootstrap/dist/js/bootstrap.min.js",
	"node_modules/eonasdan-bootstrap-datetimepicker-npm/build/js/bootstrap-datetimepicker.min.js",
	"node_modules/angular/angular.min.js",
	"node_modules/angular-route/angular-route.min.js",
	"node_modules/angular-animate/angular-animate.min.js",
	"node_modules/angular-aria/angular-aria.min.js",
	"node_modules/angular-messages/angular-messages.min.js",
	"node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js",
	"node_modules/angular-file-upload/dist/angular-file-upload.min.js",
	"node_modules/mdPickers/dist/mdPickers.min.js",
	"node_modules/clipboard/dist/clipboard.min.js",
	"node_modules/ngclipboard/dist/ngclipboard.min.js",
	"node_modules/angular-local-storage/dist/angular-local-storage.min.js",
	"node_modules/ms-signalr-client/jquery.signalR.min.js",
	"node_modules/angular-signalr-hub/signalr-hub.min.js"
]

const cssFilePaths = [
	"node_modules/bootstrap/dist/css/bootstrap-theme.css",
	"node_modules/bootstrap/dist/css/bootstrap.css",
	"node_modules/font-awesome/css/font-awesome.css",
	"app/content/styles/style.css",
	"app/content/styles/sidebar.css",
	"app/content/component/loadinSnake/loading-snake.css",
	"app/content/component/sk-cube/sk-cube.css",
	"app/content/component/spinner/spinner.css",
	"node_modules/eonasdan-bootstrap-datetimepicker-npm/build/css/bootstrap-datetimepicker.min.css"
]

gulp.task('clean', function (cb) {
	del(['dist']).then(function (paths) {
		console.log('Deleted files and folders:\n', paths.join('\n'));
        cb();
	});
});

gulp.task('bundle', function () {
	//first load the services, then the directives and then the controller
	return gulp.src(jsFilePaths)
			.pipe(ngannotate())
			.pipe(concat('main.js'))
			.pipe(uglify())
			.pipe(rename({suffix: '.min'}))
			.pipe(gulp.dest('dist/'));
})

gulp.task('bundle-css', function(){
	return gulp.src(cssFilePaths)
		.pipe(cssnano())
		.pipe(concat('style.min.css'))
		.pipe(gulp.dest('dist/app'));
})

gulp.task('bundle-libs', function(){
	return gulp.src(jsLibFilePaths)
		.pipe(concat('lib.js'))
		// .pipe(uglify())
		// .pipe(rename({suffix: '.min'}))
		.pipe(gulp.dest('dist/app'));
});

gulp.task('copy-assets', function(){
	return gulp.src(['app/content/**/**/*'])
			.pipe(gulp.dest('dist/app/content/'))
});

gulp.task('copy-templates', function(){
	return gulp.src('app/views/**/*')
		.pipe(gulp.dest('dist/app/views/'))
});

gulp.task('copy-directives', function(){
	return gulp.src('app/directives/**/*.html')
		.pipe(gulp.dest('dist/app/directives/'))
})

gulp.task('remove-js-css', function(){
	return gulp.src('index.html')
			.pipe(deleteLines({
				'filters': [
					/<script\s+type=["']text\/javascript["']\s+src=/i
				]
			}))
			.pipe(deleteLines({
				'filters': [
					/<link\s+rel=["']/i
				]
			}))
			.pipe(gulp.dest('dist/'))
})

gulp.task('inject-index', function(){
	var bundlesSources = gulp.src(['./dist/app/**.css', './dist/app/**.js'], {read: false});

	return gulp.src('/dist/index.html')
				.pipe(inject(bundlesSources, { ignorePath: 'dist' }))
				.pipe(gulp.dest('dist/'));
});

gulp.task('build', function(callback){
	runSequence('clean',
				'bundle','bundle-libs',
				'bundle-css',
				'copy-assets',
				'copy-templates',
				'copy-directives',
				'remove-js-css',
				'inject-index',
				callback);
});

<|endoftext|>


<commit_before>// Dependencies
var Ul = require("ul")
  , Abs = require("abs")
  , ReadJson = require("r-json")
  , WriteJson = require("w-json")
  , Moment = require("moment")
  , Gry = require("gry")
  , IsThere = require("is-there")
  , CliPie = require("cli-pie")
  , CliGhCal = require("cli-gh-cal")
  ;

// Constants
const STORE_PATH = Abs("~/.git-stats")
    , DATE_FORMAT = "MMM D, YYYY"
    ;

// Constructor
var GitStats = module.exports = {};

/**
 * record
 * Records a new commit.
 *
 * @name record
 * @function
 * @param {Object} data The commit data containing:
 *
 *  - `date` (String|Date): The date object or a string in a format that can be parsed.
 *  - `url` (String): The repository remote url.
 *  - `hash` (String): The commit hash.
 *
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.record = function (data, callback) {

    // Validate data
    callback = callback || function (err) { if (err) throw err; };
    data = Object(data);
    if (typeof data.date === "string") {
        data.date = new Moment(new Date(data.date));
    }

    if (!data.date || !/^Moment|Date$/.test(data.date.constructor.name)) {
        callback(new Error("The date field should be a string or a date object."));
        return GitStats;
    }

    if (typeof data.hash !== "string" || !data.hash) {
        callback(new Error("Invalid hash."));
        return GitStats;
    }

    if (typeof data.url !== "string" || !data.url) {
        callback(new Error("Invalid url field. This commit is not recorded into the git-stats history since you haven't added the remote url. You can import the previous commits using the git-stats-importer tool."));
        return GitStats;
    }

    // Get stats
    GitStats.get(function (err, stats) {
        stats = stats || {};
        var day = data.date.format(DATE_FORMAT)
          , today = stats[day] = Object(stats[day])
          , repo = today[data.url] = Object(today[data.url])
          ;

        repo[data.hash] = { date: data.date };

        GitStats.save(stats, callback);
    });

    return GitStats;
};

/**
 * get
 * Gets the git stats.
 *
 * @name get
 * @function
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.get = function (callback) {
    ReadJson(STORE_PATH, "utf-8", function (err, data) {

        if (err && err.code === "ENOENT") {
           return GitStats.save({}, function (err) {
               callback(err, {});
           });
        }

        if (err) { return callback(err); }
        callback(null, data);
    });
    return GitStats;
};

/**
 * save
 * Saves the provided stats.
 *
 * @name save
 * @function
 * @param {Object} stats The stats to be saved.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.save = function (stats, callback) {
    WriteJson(STORE_PATH, stats, callback);
    return GitStats;
};

/**
 * iterateDays
 * Iterate through the days, calling the callback function on each day.
 *
 * @name iterateDays
 * @function
 * @param {Object} data An object containing the following fields:
 *
 *  - `start` (Moment): A `Moment` date object representing the start date (default: *an year ago*).
 *  - `end` (Moment): A `Moment` date object representing the end date (default: *now*).
 *  - `format` (String): The format of the date (default: `"MMM D, YYYY"`).
 *
 * @param {Function} callback The callback function called with the current day formatted (type: string) and the `Moment` date object.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.iterateDays = function (data, callback) {

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    // Merge the defaults
    data.end = data.end || Moment();
    data.start = data.start || Moment().subtract(1, "years");
    data.format = data.format || DATE_FORMAT;

    var start = new Moment(data.start.format(DATE_FORMAT), DATE_FORMAT)
      , end = new Moment(data.end.format(DATE_FORMAT), DATE_FORMAT)
      , tomrrow = Moment(end.format(DATE_FORMAT), DATE_FORMAT).add(1, "days")
      , endStr = tomrrow.format(DATE_FORMAT)
      , cDay = null
      ;

    while (start.format(DATE_FORMAT) !== endStr) {
        cDay = start.format(data.format);
        callback(cDay, start);
        start.add(1, "days");
    }

    return GitStats;
};

/**
 * graph
 * Creates an object with the stats on the provided period (default: *last year*).
 *
 * @name graph
 * @function
 * @param {Object} data The object passed to the `iterateDays` method.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.graph = function (data, callback) {

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    // Get commits
    GitStats.get(function (err, stats) {
        if (err) { return callback(err); }

        var cDayObj = null
          , year = {}
          ;

        // Iterate days
        GitStats.iterateDays(data, function (cDay) {
            cDayObj = year[cDay] = {
                _: stats[cDay] || {}
              , c: 0
            };

            Object.keys(cDayObj._).forEach(function (c) {
                cDayObj.c += Object.keys(cDayObj._[c]).length;
            });
        });

        callback(null, year);
    });

    return GitStats;
};

/**
 * calendar
 * Creates the calendar data for the provided period (default: *last year*).
 *
 * @name calendar
 * @function
 * @param {Object} data The object passed to the `graph` method.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.calendar = function (data, callback) {
    GitStats.graph(data, function (err, graph) {
        if (err) { return callback(err); }

        var cal = { total: 0, days: {}, cStreak: 0, lStreak: 0, max: 0 }
          , cDay = null
          , days = Object.keys(graph)
          , levels = null
          , cLevel = 0
          ;

        days.forEach(function (c) {
            cDay = graph[c];
            cal.total += cDay.c;
            if (cDay.c > cal.max) {
                cal.max = cDay.c;
            }

            if (cDay.c > 0) {
                if (++cal.cStreak > cal.lStreak) {
                    cal.lStreak = cal.cStreak;
                }
            } else {
                cal.cStreak = 0;
            }
        });

        levels = cal.max / (LEVELS.length * 2);
        days.forEach(function (c) {
            cDay = graph[c];
            cal.days[c] = {
                c: cDay.c
              , level: !levels
              ? 0 : (cLevel = Math.round(cDay.c / levels)) >= 4
              ? 4 : !cLevel && cDay.c > 0 ? 1 : cLevel
            };
        });

        callback(null, cal);
    });
    return GitStats;
};

/**
 * ansiCalendar
 * Creates the ANSI contributions calendar.
 *
 * @name ansiCalendar
 * @function
 * @param {Object} data The object passed to the `calendar` method.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.ansiCalendar = function (data, callback) {

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    GitStats.graph(data, function (err, graph) {
        var cal = [];

        GitStats.iterateDays(data, function (cDay) {
            cDayObj = graph[cDay];
            if (!cDayObj) { return; }
            cal.push([cDay, cDayObj.c]);
        });

        callback(null, CliGhCal(cal, {
            theme: data.theme
          , start: data.start
          , end: data.end
        }));
    });

    return GitStats;
};

GitStats.authors = function (options, callback) {
    var repo = new Gry(options.repo);
    repo.exec("shortlog -s -n --all", function (err, stdout) {
        if (err) { return callback(err); }
        lines = stdout.split("\n");
        pieData = stdout.split("\n").map(function (c) {
            var splits = c.split("\t").map(function (cc) {
                return cc.trim();
            });
            return {
                value: parseInt(splits[0])
              , label: splits[1]
            };
        });
        callback(null, pieData);
    });
};

GitStats.authorsPie = function (options, callback) {
    if (typeof options === "string") {
        options = {
            repo: options
        };
    }

    options = Ul.merge(options, {
        radius: process.stdout.rows / 2 || 20
    });

    if (!IsThere.sync(options.repo)) {
        return callback(new Error("Repository is missing."));
    }

    var repo = new Gry(options.repo)
      , pie = null
      , pieData = []
      ;

    GitStats.authors(options, function (err, authors) {
        if (err) { return callback(err); }
        if (authors.length > 50) {
            var others = {
                value: authors.slice(50).reduce(function (a, b) {
                    debugger
                    return a + b.value;
                }, 0)
              , label: "Others"
            };
            debugger
            authors = authors.slice(0, 50);
            authors.push(others);
        }

        pie = new CliPie(options.radius, authors, {
            legend: true
          , flat: true
          , no_ansi: options.no_ansi
        });

        callback(null, pie.toString());
    });
};
<commit_msg>Fixed is-there api<commit_after>// Dependencies
var Ul = require("ul")
  , Abs = require("abs")
  , ReadJson = require("r-json")
  , WriteJson = require("w-json")
  , Moment = require("moment")
  , Gry = require("gry")
  , IsThere = require("is-there")
  , CliPie = require("cli-pie")
  , CliGhCal = require("cli-gh-cal")
  ;

// Constants
const STORE_PATH = Abs("~/.git-stats")
    , DATE_FORMAT = "MMM D, YYYY"
    ;

// Constructor
var GitStats = module.exports = {};

/**
 * record
 * Records a new commit.
 *
 * @name record
 * @function
 * @param {Object} data The commit data containing:
 *
 *  - `date` (String|Date): The date object or a string in a format that can be parsed.
 *  - `url` (String): The repository remote url.
 *  - `hash` (String): The commit hash.
 *
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.record = function (data, callback) {

    // Validate data
    callback = callback || function (err) { if (err) throw err; };
    data = Object(data);
    if (typeof data.date === "string") {
        data.date = new Moment(new Date(data.date));
    }

    if (!data.date || !/^Moment|Date$/.test(data.date.constructor.name)) {
        callback(new Error("The date field should be a string or a date object."));
        return GitStats;
    }

    if (typeof data.hash !== "string" || !data.hash) {
        callback(new Error("Invalid hash."));
        return GitStats;
    }

    if (typeof data.url !== "string" || !data.url) {
        callback(new Error("Invalid url field. This commit is not recorded into the git-stats history since you haven't added the remote url. You can import the previous commits using the git-stats-importer tool."));
        return GitStats;
    }

    // Get stats
    GitStats.get(function (err, stats) {
        stats = stats || {};
        var day = data.date.format(DATE_FORMAT)
          , today = stats[day] = Object(stats[day])
          , repo = today[data.url] = Object(today[data.url])
          ;

        repo[data.hash] = { date: data.date };

        GitStats.save(stats, callback);
    });

    return GitStats;
};

/**
 * get
 * Gets the git stats.
 *
 * @name get
 * @function
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.get = function (callback) {
    ReadJson(STORE_PATH, "utf-8", function (err, data) {

        if (err && err.code === "ENOENT") {
           return GitStats.save({}, function (err) {
               callback(err, {});
           });
        }

        if (err) { return callback(err); }
        callback(null, data);
    });
    return GitStats;
};

/**
 * save
 * Saves the provided stats.
 *
 * @name save
 * @function
 * @param {Object} stats The stats to be saved.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.save = function (stats, callback) {
    WriteJson(STORE_PATH, stats, callback);
    return GitStats;
};

/**
 * iterateDays
 * Iterate through the days, calling the callback function on each day.
 *
 * @name iterateDays
 * @function
 * @param {Object} data An object containing the following fields:
 *
 *  - `start` (Moment): A `Moment` date object representing the start date (default: *an year ago*).
 *  - `end` (Moment): A `Moment` date object representing the end date (default: *now*).
 *  - `format` (String): The format of the date (default: `"MMM D, YYYY"`).
 *
 * @param {Function} callback The callback function called with the current day formatted (type: string) and the `Moment` date object.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.iterateDays = function (data, callback) {

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    // Merge the defaults
    data.end = data.end || Moment();
    data.start = data.start || Moment().subtract(1, "years");
    data.format = data.format || DATE_FORMAT;

    var start = new Moment(data.start.format(DATE_FORMAT), DATE_FORMAT)
      , end = new Moment(data.end.format(DATE_FORMAT), DATE_FORMAT)
      , tomrrow = Moment(end.format(DATE_FORMAT), DATE_FORMAT).add(1, "days")
      , endStr = tomrrow.format(DATE_FORMAT)
      , cDay = null
      ;

    while (start.format(DATE_FORMAT) !== endStr) {
        cDay = start.format(data.format);
        callback(cDay, start);
        start.add(1, "days");
    }

    return GitStats;
};

/**
 * graph
 * Creates an object with the stats on the provided period (default: *last year*).
 *
 * @name graph
 * @function
 * @param {Object} data The object passed to the `iterateDays` method.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.graph = function (data, callback) {

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    // Get commits
    GitStats.get(function (err, stats) {
        if (err) { return callback(err); }

        var cDayObj = null
          , year = {}
          ;

        // Iterate days
        GitStats.iterateDays(data, function (cDay) {
            cDayObj = year[cDay] = {
                _: stats[cDay] || {}
              , c: 0
            };

            Object.keys(cDayObj._).forEach(function (c) {
                cDayObj.c += Object.keys(cDayObj._[c]).length;
            });
        });

        callback(null, year);
    });

    return GitStats;
};

/**
 * calendar
 * Creates the calendar data for the provided period (default: *last year*).
 *
 * @name calendar
 * @function
 * @param {Object} data The object passed to the `graph` method.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.calendar = function (data, callback) {
    GitStats.graph(data, function (err, graph) {
        if (err) { return callback(err); }

        var cal = { total: 0, days: {}, cStreak: 0, lStreak: 0, max: 0 }
          , cDay = null
          , days = Object.keys(graph)
          , levels = null
          , cLevel = 0
          ;

        days.forEach(function (c) {
            cDay = graph[c];
            cal.total += cDay.c;
            if (cDay.c > cal.max) {
                cal.max = cDay.c;
            }

            if (cDay.c > 0) {
                if (++cal.cStreak > cal.lStreak) {
                    cal.lStreak = cal.cStreak;
                }
            } else {
                cal.cStreak = 0;
            }
        });

        levels = cal.max / (LEVELS.length * 2);
        days.forEach(function (c) {
            cDay = graph[c];
            cal.days[c] = {
                c: cDay.c
              , level: !levels
              ? 0 : (cLevel = Math.round(cDay.c / levels)) >= 4
              ? 4 : !cLevel && cDay.c > 0 ? 1 : cLevel
            };
        });

        callback(null, cal);
    });
    return GitStats;
};

/**
 * ansiCalendar
 * Creates the ANSI contributions calendar.
 *
 * @name ansiCalendar
 * @function
 * @param {Object} data The object passed to the `calendar` method.
 * @param {Function} callback The callback function.
 * @return {GitStats} The `GitStats` object.
 */
GitStats.ansiCalendar = function (data, callback) {

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    GitStats.graph(data, function (err, graph) {
        var cal = [];

        GitStats.iterateDays(data, function (cDay) {
            cDayObj = graph[cDay];
            if (!cDayObj) { return; }
            cal.push([cDay, cDayObj.c]);
        });

        callback(null, CliGhCal(cal, {
            theme: data.theme
          , start: data.start
          , end: data.end
        }));
    });

    return GitStats;
};

GitStats.authors = function (options, callback) {
    var repo = new Gry(options.repo);
    repo.exec("shortlog -s -n --all", function (err, stdout) {
        if (err) { return callback(err); }
        lines = stdout.split("\n");
        pieData = stdout.split("\n").map(function (c) {
            var splits = c.split("\t").map(function (cc) {
                return cc.trim();
            });
            return {
                value: parseInt(splits[0])
              , label: splits[1]
            };
        });
        callback(null, pieData);
    });
};

GitStats.authorsPie = function (options, callback) {
    if (typeof options === "string") {
        options = {
            repo: options
        };
    }

    options = Ul.merge(options, {
        radius: process.stdout.rows / 2 || 20
    });

    if (!IsThere(options.repo)) {
        return callback(new Error("Repository is missing."));
    }

    var repo = new Gry(options.repo)
      , pie = null
      , pieData = []
      ;

    GitStats.authors(options, function (err, authors) {
        if (err) { return callback(err); }
        if (authors.length > 50) {
            var others = {
                value: authors.slice(50).reduce(function (a, b) {
                    debugger
                    return a + b.value;
                }, 0)
              , label: "Others"
            };
            debugger
            authors = authors.slice(0, 50);
            authors.push(others);
        }

        pie = new CliPie(options.radius, authors, {
            legend: true
          , flat: true
          , no_ansi: options.no_ansi
        });

        callback(null, pie.toString());
    });
};
<|endoftext|>


<commit_before>'use strict';

/**
 * ip2region client for nodejs (Base on https://github.com/lionsoul2014/ip2region)
 *
 * project: https://github.com/yourtion/node-ip2region
 *
 * @author Yourtion Guo <yourtion@gmail.com>
 * */
const fs = require('fs');
const path = require('path');

function createDebug() {
  if (process.env.NODE_ENV === 'dev') return require('debug')('ip2region:');
  return () => { };
}
const debug = createDebug();

/**
 * Get long value from buffer with specified offset
 *
 * @param {Buffer} buffer
 * @param {Number} offset
 * @returns {Number} long value
 */
const getLong = function (buffer, offset){
  let val = ((buffer[offset] & 0x000000FF) |
      ((buffer[offset + 1] << 8) & 0x0000FF00) |
      ((buffer[offset + 2] << 16) & 0x00FF0000) |
      ((buffer[offset + 3] << 24) & 0xFF000000)
  );
  // convert to unsigned int
  if (val < 0) {
    val = val >>> 0;
  }
  return val;
};

// for ip2long
const ipbase = [ 16777216, 65536, 256, 1 ];
/**
 * Convert ip to long (xxx.xxx.xxx.xxx to a integer)
 *
 * @param {String} ip IP Address
 * @returns {Number} long value
 */
const ip2long = function (ip) {
  let val = 0;
  ip.split('.').forEach((ele, i) => {
    val += ipbase[i] * ele;
  });
  return val;
};

class IP2Region {

  constructor(options = { inMemory: true }) {
    this.options = Object.assign({ dbPath: '../data/ip2region.db' }, options);
    if(path.isAbsolute(this.options.dbPath)) {
      this.dbFilePath = path;
    } else {
      this.dbFilePath = path.resolve(__dirname, this.options.dbPath);
    }

    if (!fs.existsSync(this.dbFilePath)) {
      throw(new Error('[ip2region] db file not exists : ' + this.dbFilePath));
    }

    // init basic search environment
    this.superBlock = new Buffer(8);
    this.indexBlockLength = 12;
    this.totalHeaderLength = 4096;

    if(this.options.inMemory) {
      this.data = fs.readFileSync(this.dbFilePath);
      this.data.copy(this.superBlock, 0, 0, 8);
    } else {
      try {
        this.db = fs.openSync(this.dbFilePath, 'r');
      } catch(e) {
        throw(new Error('[ip2region] Can not open ip2region.db file , path : ' + this.dbFilePath));
      }
      fs.readSync(this.db, this.superBlock, 0, 8, 0);
    }

    this.firstIndexPtr = getLong(this.superBlock, 0);
    this.lastIndexPtr = getLong(this.superBlock, 4);
    this.totalBlocks = (this.lastIndexPtr - this.firstIndexPtr) / this.indexBlockLength + 1;

    this.headerIndexBuffer = new Buffer(this.totalHeaderLength);
    this.headerSip = [];
    this.headerPtr = [];
    this.headerLen = 0;

    let dataPtr = 0;
    // header index handler
    if(this.options.inMemory) {
      this.data.copy(this.headerIndexBuffer, 0, 8, this.totalHeaderLength + 8);
    } else {
      fs.readSync(this.db, this.headerIndexBuffer, 0, this.totalHeaderLength, 8);
    }
    this.headerSip = [];
    this.headerPtr = [];

    let startIp = 0;
    for (let i = 0; i < this.totalHeaderLength; i += 8) {
      startIp = getLong(this.headerIndexBuffer, i);
      dataPtr = getLong(this.headerIndexBuffer, i + 4);
      if (dataPtr === 0) break;

      this.headerSip.push(startIp);
      this.headerPtr.push(dataPtr);
      // header index size count
      this.headerLen += 1;
    }

  }

  parseResult(res) {
    // 城市Id|国家|区域|省份|城市|ISP
    const data = res.region.split('|');
    return {
      id: res.city,
      country: data[0],
      region: data[1],
      province: data[2],
      city: data[3],
      isp: data[4],
    };
  }

  search(ip, parse = true) {
    return this.inMemoryBtreeSearch(ip, parse);
  }

  inMemoryBinarySearch(ip, parse = false) {
    if(typeof ip === 'string') ip = ip2long(ip);
    let low = 0;
    let mid = 0;
    let high = this.totalBlocks;
    let dataPos = 0;
    let pos = 0;
    let sip = 0;
    let eip = 0;

    // binary search
    while(low <= high) {
      mid = ((low + high) >> 1);
      pos = this.firstIndexPtr + mid * this.indexBlockLength;
      sip = getLong(this.data, pos);
      debug(' sip : ' + sip + ' eip : ' + eip);
      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(this.data, pos + 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPos = getLong(this.data, pos + 8);
          break;
        }
      }
    }

    // read data
    if (dataPos === 0) return null;

    const dataLen = ((dataPos >> 24) & 0xFF);
    dataPos = (dataPos & 0x00FFFFFF);

    const city_id = getLong(this.data, dataPos);
    const data = this.data.toString('utf8', dataPos + 4, dataPos + dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }

  binarySearchSync(ip, parse = false) {
    let low = 0;
    let mid = 0;
    let high = this.totalBlocks;
    let dataPos = 0;
    let pos = 0;
    let sip = 0;
    let eip = 0;
    const indexBuffer = new Buffer(12);

    if(typeof ip === 'string') ip = ip2long(ip);

    // binary search
    while(low <= high) {
      mid = ((low + high) >> 1);
      pos = this.firstIndexPtr + mid * this.indexBlockLength;
      if (this.data) {
        sip = getLong(this.data, pos);
      } else {
        fs.readSync(this.db, indexBuffer, 0, this.indexBlockLength, pos);
        sip = getLong(indexBuffer, 0);
      }

      debug(' sip : ' + sip + ' eip : ' + eip);
      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(indexBuffer, 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPos = getLong(indexBuffer, 8);
          break;
        }
      }
    }

    // read data
    if (dataPos === 0) return null;

    const dataLen = ((dataPos >> 24) & 0xFF);
    dataPos = (dataPos & 0x00FFFFFF);
    const dataBuffer = new Buffer(dataLen);

    fs.readSync(this.db, dataBuffer, 0, dataLen, dataPos);

    const city_id = getLong(dataBuffer, 0);
    const data = dataBuffer.toString('utf8', 4, dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }

  inMemoryBtreeSearch(ip, parse = false){

    if(typeof ip === 'string') ip = ip2long(ip);
    // first search  (in header index)
    let low = 0;
    let mid = 0;
    let high = this.headerLen;
    let sptr = 0;
    let eptr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);

      if (ip === this.headerSip[mid]) {
        if (mid > 0) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
        } else {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
        }
        break;
      }

      if (ip < this.headerSip[mid]) {
        if (mid === 0) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        } else if (ip > this.headerSip[mid - 1]) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        }
        high = mid - 1;
      } else {
        if (mid === this.headerLen - 1) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        } else if (ip <= this.headerSip[mid + 1]) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        }
        low = mid + 1;
      }
    }

    // match nothing
    if (sptr === 0) return null;

    // second search (in index)
    const blockLen = eptr - sptr;
    low = 0;
    high = blockLen / this.indexBlockLength;

    let p = 0;
    let sip = 0;
    let eip = 0;
    let dataPtr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);
      p = mid * this.indexBlockLength;
      sip = getLong(this.data, sptr + p);

      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(this.data, sptr + p + 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPtr = getLong(this.data, sptr + p + 8);
          break;
        }
      }
    }

    // read data
    if (dataPtr === 0) return null;
    const dataLen = ((dataPtr >> 24) & 0xFF);
    dataPtr = (dataPtr & 0x00FFFFFF);
    const city_id = getLong(this.data, dataPtr);
    const data = this.data.toString('utf8', dataPtr + 4, dataPtr + dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }

  btreeSearchSync(ip, parse = false){

    if(typeof ip === 'string') ip = ip2long(ip);
    // first search  (in header index)
    let low = 0;
    let mid = 0;
    let high = this.headerLen;
    let sptr = 0;
    let eptr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);

      if (ip === this.headerSip[mid]) {
        if (mid > 0) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
        } else {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
        }
        break;
      }

      if (ip < this.headerSip[mid]) {
        if (mid === 0) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        } else if (ip > this.headerSip[mid - 1]) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        }
        high = mid - 1;
      } else {
        if (mid === this.headerLen - 1) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        } else if (ip <= this.headerSip[mid + 1]) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        }
        low = mid + 1;
      }
    }

    // match nothing
    if (sptr === 0) return null;

    // second search (in index)
    const blockLen = eptr - sptr;
    const blockBuffer = new Buffer(blockLen + this.indexBlockLength);
    fs.readSync(this.db, blockBuffer, 0, blockLen + this.indexBlockLength, sptr);

    low = 0;
    high = blockLen / this.indexBlockLength;

    let p = 0;
    let sip = 0;
    let eip = 0;
    let dataPtr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);
      p = mid * this.indexBlockLength;
      sip = getLong(blockBuffer, p);

      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(blockBuffer, p + 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPtr = getLong(blockBuffer, p + 8);
          break;
        }
      }
    }

    // read data
    if (dataPtr === 0) return null;
    const dataLen = ((dataPtr >> 24) & 0xFF);
    dataPtr = (dataPtr & 0x00FFFFFF);
    const dataBuffer = new Buffer(dataLen);

    fs.readSync(this.db, dataBuffer, 0, dataLen, dataPtr);

    const city_id = getLong(dataBuffer, 0);
    const data = dataBuffer.toString('utf8', 4, dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }
}

module.exports = IP2Region;
<commit_msg>bug fix<commit_after>'use strict';

/**
 * ip2region client for nodejs (Base on https://github.com/lionsoul2014/ip2region)
 *
 * project: https://github.com/yourtion/node-ip2region
 *
 * @author Yourtion Guo <yourtion@gmail.com>
 * */
const fs = require('fs');
const path = require('path');

function createDebug() {
  if (process.env.NODE_ENV === 'dev') return require('debug')('ip2region:');
  return () => { };
}
const debug = createDebug();

/**
 * Get long value from buffer with specified offset
 *
 * @param {Buffer} buffer
 * @param {Number} offset
 * @returns {Number} long value
 */
const getLong = function (buffer, offset){
  let val = ((buffer[offset] & 0x000000FF) |
      ((buffer[offset + 1] << 8) & 0x0000FF00) |
      ((buffer[offset + 2] << 16) & 0x00FF0000) |
      ((buffer[offset + 3] << 24) & 0xFF000000)
  );
  // convert to unsigned int
  if (val < 0) {
    val = val >>> 0;
  }
  return val;
};

// for ip2long
const ipbase = [ 16777216, 65536, 256, 1 ];
/**
 * Convert ip to long (xxx.xxx.xxx.xxx to a integer)
 *
 * @param {String} ip IP Address
 * @returns {Number} long value
 */
const ip2long = function (ip) {
  let val = 0;
  ip.split('.').forEach((ele, i) => {
    val += ipbase[i] * ele;
  });
  return val;
};

class IP2Region {

  constructor(options = { inMemory: true }) {
    this.options = Object.assign({ dbPath: '../data/ip2region.db' }, options);
    if(path.isAbsolute(this.options.dbPath)) {
      this.dbFilePath = this.options.dbPath;
    } else {
      this.dbFilePath = path.resolve(__dirname, this.options.dbPath);
    }

    if (!fs.existsSync(this.dbFilePath)) {
      throw(new Error('[ip2region] db file not exists : ' + this.dbFilePath));
    }

    // init basic search environment
    this.superBlock = new Buffer(8);
    this.indexBlockLength = 12;
    this.totalHeaderLength = 4096;

    if(this.options.inMemory) {
      this.data = fs.readFileSync(this.dbFilePath);
      this.data.copy(this.superBlock, 0, 0, 8);
    } else {
      try {
        this.db = fs.openSync(this.dbFilePath, 'r');
      } catch(e) {
        throw(new Error('[ip2region] Can not open ip2region.db file , path : ' + this.dbFilePath));
      }
      fs.readSync(this.db, this.superBlock, 0, 8, 0);
    }

    this.firstIndexPtr = getLong(this.superBlock, 0);
    this.lastIndexPtr = getLong(this.superBlock, 4);
    this.totalBlocks = (this.lastIndexPtr - this.firstIndexPtr) / this.indexBlockLength + 1;

    this.headerIndexBuffer = new Buffer(this.totalHeaderLength);
    this.headerSip = [];
    this.headerPtr = [];
    this.headerLen = 0;

    let dataPtr = 0;
    // header index handler
    if(this.options.inMemory) {
      this.data.copy(this.headerIndexBuffer, 0, 8, this.totalHeaderLength + 8);
    } else {
      fs.readSync(this.db, this.headerIndexBuffer, 0, this.totalHeaderLength, 8);
    }
    this.headerSip = [];
    this.headerPtr = [];

    let startIp = 0;
    for (let i = 0; i < this.totalHeaderLength; i += 8) {
      startIp = getLong(this.headerIndexBuffer, i);
      dataPtr = getLong(this.headerIndexBuffer, i + 4);
      if (dataPtr === 0) break;

      this.headerSip.push(startIp);
      this.headerPtr.push(dataPtr);
      // header index size count
      this.headerLen += 1;
    }

  }

  parseResult(res) {
    // 城市Id|国家|区域|省份|城市|ISP
    const data = res.region.split('|');
    return {
      id: res.city,
      country: data[0],
      region: data[1],
      province: data[2],
      city: data[3],
      isp: data[4],
    };
  }

  search(ip, parse = true) {
    return this.inMemoryBtreeSearch(ip, parse);
  }

  inMemoryBinarySearch(ip, parse = false) {
    if(typeof ip === 'string') ip = ip2long(ip);
    let low = 0;
    let mid = 0;
    let high = this.totalBlocks;
    let dataPos = 0;
    let pos = 0;
    let sip = 0;
    let eip = 0;

    // binary search
    while(low <= high) {
      mid = ((low + high) >> 1);
      pos = this.firstIndexPtr + mid * this.indexBlockLength;
      sip = getLong(this.data, pos);
      debug(' sip : ' + sip + ' eip : ' + eip);
      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(this.data, pos + 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPos = getLong(this.data, pos + 8);
          break;
        }
      }
    }

    // read data
    if (dataPos === 0) return null;

    const dataLen = ((dataPos >> 24) & 0xFF);
    dataPos = (dataPos & 0x00FFFFFF);

    const city_id = getLong(this.data, dataPos);
    const data = this.data.toString('utf8', dataPos + 4, dataPos + dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }

  binarySearchSync(ip, parse = false) {
    let low = 0;
    let mid = 0;
    let high = this.totalBlocks;
    let dataPos = 0;
    let pos = 0;
    let sip = 0;
    let eip = 0;
    const indexBuffer = new Buffer(12);

    if(typeof ip === 'string') ip = ip2long(ip);

    // binary search
    while(low <= high) {
      mid = ((low + high) >> 1);
      pos = this.firstIndexPtr + mid * this.indexBlockLength;
      if (this.data) {
        sip = getLong(this.data, pos);
      } else {
        fs.readSync(this.db, indexBuffer, 0, this.indexBlockLength, pos);
        sip = getLong(indexBuffer, 0);
      }

      debug(' sip : ' + sip + ' eip : ' + eip);
      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(indexBuffer, 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPos = getLong(indexBuffer, 8);
          break;
        }
      }
    }

    // read data
    if (dataPos === 0) return null;

    const dataLen = ((dataPos >> 24) & 0xFF);
    dataPos = (dataPos & 0x00FFFFFF);
    const dataBuffer = new Buffer(dataLen);

    fs.readSync(this.db, dataBuffer, 0, dataLen, dataPos);

    const city_id = getLong(dataBuffer, 0);
    const data = dataBuffer.toString('utf8', 4, dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }

  inMemoryBtreeSearch(ip, parse = false){

    if(typeof ip === 'string') ip = ip2long(ip);
    // first search  (in header index)
    let low = 0;
    let mid = 0;
    let high = this.headerLen;
    let sptr = 0;
    let eptr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);

      if (ip === this.headerSip[mid]) {
        if (mid > 0) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
        } else {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
        }
        break;
      }

      if (ip < this.headerSip[mid]) {
        if (mid === 0) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        } else if (ip > this.headerSip[mid - 1]) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        }
        high = mid - 1;
      } else {
        if (mid === this.headerLen - 1) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        } else if (ip <= this.headerSip[mid + 1]) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        }
        low = mid + 1;
      }
    }

    // match nothing
    if (sptr === 0) return null;

    // second search (in index)
    const blockLen = eptr - sptr;
    low = 0;
    high = blockLen / this.indexBlockLength;

    let p = 0;
    let sip = 0;
    let eip = 0;
    let dataPtr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);
      p = mid * this.indexBlockLength;
      sip = getLong(this.data, sptr + p);

      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(this.data, sptr + p + 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPtr = getLong(this.data, sptr + p + 8);
          break;
        }
      }
    }

    // read data
    if (dataPtr === 0) return null;
    const dataLen = ((dataPtr >> 24) & 0xFF);
    dataPtr = (dataPtr & 0x00FFFFFF);
    const city_id = getLong(this.data, dataPtr);
    const data = this.data.toString('utf8', dataPtr + 4, dataPtr + dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }

  btreeSearchSync(ip, parse = false){

    if(typeof ip === 'string') ip = ip2long(ip);
    // first search  (in header index)
    let low = 0;
    let mid = 0;
    let high = this.headerLen;
    let sptr = 0;
    let eptr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);

      if (ip === this.headerSip[mid]) {
        if (mid > 0) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
        } else {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
        }
        break;
      }

      if (ip < this.headerSip[mid]) {
        if (mid === 0) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        } else if (ip > this.headerSip[mid - 1]) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        }
        high = mid - 1;
      } else {
        if (mid === this.headerLen - 1) {
          sptr = this.headerPtr[mid - 1];
          eptr = this.headerPtr[mid];
          break;
        } else if (ip <= this.headerSip[mid + 1]) {
          sptr = this.headerPtr[mid];
          eptr = this.headerPtr[mid + 1];
          break;
        }
        low = mid + 1;
      }
    }

    // match nothing
    if (sptr === 0) return null;

    // second search (in index)
    const blockLen = eptr - sptr;
    const blockBuffer = new Buffer(blockLen + this.indexBlockLength);
    fs.readSync(this.db, blockBuffer, 0, blockLen + this.indexBlockLength, sptr);

    low = 0;
    high = blockLen / this.indexBlockLength;

    let p = 0;
    let sip = 0;
    let eip = 0;
    let dataPtr = 0;

    while(low <= high) {
      mid = ((low + high) >> 1);
      p = mid * this.indexBlockLength;
      sip = getLong(blockBuffer, p);

      if (ip < sip) {
        high = mid - 1;
      } else {
        eip = getLong(blockBuffer, p + 4);
        if (ip > eip) {
          low = mid + 1;
        } else {
          dataPtr = getLong(blockBuffer, p + 8);
          break;
        }
      }
    }

    // read data
    if (dataPtr === 0) return null;
    const dataLen = ((dataPtr >> 24) & 0xFF);
    dataPtr = (dataPtr & 0x00FFFFFF);
    const dataBuffer = new Buffer(dataLen);

    fs.readSync(this.db, dataBuffer, 0, dataLen, dataPtr);

    const city_id = getLong(dataBuffer, 0);
    const data = dataBuffer.toString('utf8', 4, dataLen);

    debug(city_id);
    debug(data);

    if(parse) {
      return this.parseResult({ city: city_id, region: data });
    }
    return { city: city_id, region: data };
  }
}

module.exports = IP2Region;
<|endoftext|>