<commit_before>'use strict';

const logger = require( 'brinkbit-logger' )({ __filename, transport: 'production' });

const port = process.env.PORT || 3000;
const mongodb = {
    ip: process.env.MONGO_IP || 'localhost',
    port: process.env.MONGO_PORT || '27017',
    user: process.env.MONGO_USER,
    pass: process.env.MONGO_PASS,
};
mongodb.uri = mongodb.user && mongodb.pass ?
    `mongodb://${mongodb.user}:${mongodb.pass}@${mongodb.ip}:${mongodb.port}/test` :
    `mongodb://${mongodb.ip}:${mongodb.port}/test`;

function connect( mongooseConnection ) {
    return new Promise(( resolve, reject ) => {
        if ( mongooseConnection.readyState === 1 ) {
            logger.warning( 'Already connected. Resolving.' );
            return resolve();
        }

        const mongodbURI = mongodb.uri;

        logger.info( `Attempting to connect to: ${mongodbURI}` );
        mongooseConnection
        .removeAllListeners( 'connected' ).on( 'connected', () => {
            logger.info( 'Connected!' );
            resolve();
        })
        .removeAllListeners( 'error' ).on( 'error', ( err ) => reject( err ))
        .open( mongodbURI );
    });
}

function disconnect( mongooseConnection ) {
    return new Promise(( resolve, reject ) => {
        if ( mongooseConnection.readyState === 0 ) {
            logger.warning( 'No connection to disconnect. Resolving.' );
            return resolve();
        }

        logger.info( 'Closing mongoose connection' );
        mongooseConnection
        .removeAllListeners( 'close' ).on( 'close', () => {
            logger.info( 'Mongoose connection closed' );
            resolve();
        })
        .removeAllListeners( 'error' ).on( 'error', ( err ) => reject( err ))
        .close();
    });
}

module.exports = ( mongooseConnection ) => {
    return {
        port,
        mongodb,
        connect: () => connect( mongooseConnection ),
        disconnect: () => disconnect( mongooseConnection ),
    };
};
<commit_msg>Add configuration for mongo db<commit_after>'use strict';

const logger = require( 'brinkbit-logger' )({ __filename, transport: 'production' });

const port = process.env.PORT || 3000;
const mongodb = {
    ip: process.env.MONGO_IP || 'localhost',
    port: process.env.MONGO_PORT || '27017',
    user: process.env.MONGO_USER,
    pass: process.env.MONGO_PASS,
    database: process.env.MONGO_DB || 'test',
};
mongodb.uri = mongodb.user && mongodb.pass ?
    `mongodb://${mongodb.user}:${mongodb.pass}@${mongodb.ip}:${mongodb.port}/${mongodb.database}` :
    `mongodb://${mongodb.ip}:${mongodb.port}/${mongodb.database}`;

function connect( mongooseConnection ) {
    return new Promise(( resolve, reject ) => {
        if ( mongooseConnection.readyState === 1 ) {
            logger.warning( 'Already connected. Resolving.' );
            return resolve();
        }

        const mongodbURI = mongodb.uri;

        logger.info( `Attempting to connect to: ${mongodbURI}` );
        mongooseConnection
        .removeAllListeners( 'connected' ).on( 'connected', () => {
            logger.info( 'Connected!' );
            resolve();
        })
        .removeAllListeners( 'error' ).on( 'error', ( err ) => reject( err ))
        .open( mongodbURI );
    });
}

function disconnect( mongooseConnection ) {
    return new Promise(( resolve, reject ) => {
        if ( mongooseConnection.readyState === 0 ) {
            logger.warning( 'No connection to disconnect. Resolving.' );
            return resolve();
        }

        logger.info( 'Closing mongoose connection' );
        mongooseConnection
        .removeAllListeners( 'close' ).on( 'close', () => {
            logger.info( 'Mongoose connection closed' );
            resolve();
        })
        .removeAllListeners( 'error' ).on( 'error', ( err ) => reject( err ))
        .close();
    });
}

module.exports = ( mongooseConnection ) => {
    return {
        port,
        mongodb,
        connect: () => connect( mongooseConnection ),
        disconnect: () => disconnect( mongooseConnection ),
    };
};
<|endoftext|>


<commit_before>/* eslint-env node */
'use strict';

var path = require('path');
var SilentError = require('silent-error');
var Funnel = require('broccoli-funnel');
var Rollup = require('broccoli-rollup');
var stew = require('broccoli-stew');
var Babel = require('broccoli-babel-transpiler');
var merge   = require('broccoli-merge-trees');
var version = require('./lib/version');

// allow toggling of heimdall instrumentation
var INSTRUMENT_HEIMDALL = false;
var args = process.argv;

for (var i = 0; i < args.length; i++) {
  if (args[i] === '--instrument') {
    INSTRUMENT_HEIMDALL = true;
    break;
  }
}
var NOOP_TREE = function(dir ) {
  return { inputTree: dir, rebuild: function() { return []; } };
};

process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL;

function isProductionEnv() {
  var isProd = /production/.test(process.env.EMBER_ENV);
  var isTest = process.env.EMBER_CLI_TEST_COMMAND;

  return isProd && !isTest;
}

module.exports = {
  name: 'ember-data',

  _warn: function(message) {
    var chalk = require('chalk');
    var warning = chalk.yellow('WARNING: ' + message);

    if (this.ui && this.ui.writeWarnLine) {
      this.ui.writeWarnLine(message);
    } else if (this.ui) {
      this.ui.writeLine(warning);
    } else {
      console.log(warning);
    }
  },

  init: function() {
    this._super.init && this._super.init.apply(this, arguments);

    var bowerDeps = this.project.bowerDependencies();

    var VersionChecker = require('ember-cli-version-checker');
    var options = this.options = this.options || {};

    var checker = new VersionChecker(this);
    // prevent errors when ember-cli-shims is no longer required
    var shims = bowerDeps['ember-cli-shims'] && checker.for('ember-cli-shims', 'bower');

    var semver = require('semver');
    var version = require('./package').version;

    if (process.env.EMBER_DATA_SKIP_VERSION_CHECKING_DO_NOT_USE_THIS_ENV_VARIABLE) {
      // Skip for node tests as we can't currently override the version of ember-cli-shims
      // before the test helpers run.
      return;
    }

    var hasShims = !!shims;
    var shimsHasEmberDataShims = hasShims && shims.satisfies('< 0.1.0');
    var emberDataNPMWithShimsIncluded = semver.satisfies(version, '^2.3.0-beta.3');

    if (bowerDeps['ember-data']) {
      this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed. If you need an ' +
                'earlier version of ember-data (< 2.3.0), you can leave this unchanged for now, but we strongly suggest you upgrade your version of Ember Data ' +
                'as soon as possible.');
      this._forceBowerUsage = true;

      var emberDataBower = checker.for('ember-data', 'bower');
      var emberDataBowerWithShimsIncluded = emberDataBower.satisifies('>= 2.3.0-beta.3');

      if (hasShims && !shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) {
        throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6');
      }

      if (hasShims && shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) {
        throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.');
      }

    } else {
      // NPM only, but ember-cli-shims does not match
      if (hasShims && shimsHasEmberDataShims && emberDataNPMWithShimsIncluded) {
        throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.');
      }
    }
  },

  blueprintsPath: function() {
    return path.join(__dirname, 'blueprints');
  },

  treeForApp: function(dir) {
    if (this._forceBowerUsage) { return NOOP_TREE(dir); }

    // this._super.treeForApp is undefined in ember-cli (1.13) for some reason.
    // TODO: investigate why treeForApp isn't on _super
    return dir;
  },

  treeForAddon: function(tree) {
    if (this._forceBowerUsage) { return NOOP_TREE(tree); }

    let babel = this.addons.find(addon => addon.name === 'ember-cli-babel');

    let treeWithVersion = merge([
      tree,
      version() // compile the VERSION into the build
    ]);

    let withPrivate    = new Funnel(tree, { include: ['-private/**'] });
    let withoutPrivate = new Funnel(treeWithVersion, {
      exclude: [
        '-private',
        isProductionEnv() ? '-debug' : false
      ].filter(Boolean),

      destDir: 'ember-data'
    });

    var privateTree = babel.transpileTree(withPrivate, {
      babel: this.buildBabelOptions(),
      'ember-cli-babel': {
        compileModules: false
      }
    });

    // use the default options
    var publicTree = babel.transpileTree(withoutPrivate);

    privateTree = new Rollup(privateTree, {
      rollup: {
        entry: '-private/index.js',
        targets: [
          { dest: '-private.js', format: 'amd', moduleId: 'ember-data/-private' }
        ],
        external: [
          'ember',
          'ember-inflector',
          'ember-data/version',
          'ember-data/-debug',
          'ember-data/adapters/errors'
        ]
        // cache: true|false Defaults to true
      }
    });

    // the output of treeForAddon is required to be modules/<your files>
    publicTree  = new Funnel(publicTree,  { destDir: 'modules' });
    privateTree = new Funnel(privateTree, { destDir: 'modules' });

    return merge([
      publicTree,
      privateTree
    ]);
  },

  buildBabelOptions() {
    let customPlugins = require('./lib/stripped-build-plugins')(process.env.EMBER_ENV);

    return {
      loose: true,
      plugins: customPlugins.plugins,
      postTransformPlugins: customPlugins.postTransformPlugins,
      exclude: [
        'transform-es2015-block-scoping',
      ]
    };
  },

  _setupBabelOptions: function() {
    if (this._hasSetupBabelOptions) {
      return;
    }

    this.options.babel = this.buildBabelOptions();

    this._hasSetupBabelOptions = true;
  },

  included: function(app) {
    this._super.included.apply(this, arguments);

    this._setupBabelOptions();

    if (this._forceBowerUsage) {
      this.app.import({
        development: app.bowerDirectory + '/ember-data/ember-data.js',
        production: app.bowerDirectory + '/ember-data/ember-data.prod.js'
      });
    }
  }
};
<commit_msg>[BUGFIX] remove forgotten broccoli-stew import<commit_after>/* eslint-env node */
'use strict';

var path = require('path');
var SilentError = require('silent-error');
var Funnel = require('broccoli-funnel');
var Rollup = require('broccoli-rollup');
var Babel = require('broccoli-babel-transpiler');
var merge   = require('broccoli-merge-trees');
var version = require('./lib/version');

// allow toggling of heimdall instrumentation
var INSTRUMENT_HEIMDALL = false;
var args = process.argv;

for (var i = 0; i < args.length; i++) {
  if (args[i] === '--instrument') {
    INSTRUMENT_HEIMDALL = true;
    break;
  }
}
var NOOP_TREE = function(dir ) {
  return { inputTree: dir, rebuild: function() { return []; } };
};

process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL;

function isProductionEnv() {
  var isProd = /production/.test(process.env.EMBER_ENV);
  var isTest = process.env.EMBER_CLI_TEST_COMMAND;

  return isProd && !isTest;
}

module.exports = {
  name: 'ember-data',

  _warn: function(message) {
    var chalk = require('chalk');
    var warning = chalk.yellow('WARNING: ' + message);

    if (this.ui && this.ui.writeWarnLine) {
      this.ui.writeWarnLine(message);
    } else if (this.ui) {
      this.ui.writeLine(warning);
    } else {
      console.log(warning);
    }
  },

  init: function() {
    this._super.init && this._super.init.apply(this, arguments);

    var bowerDeps = this.project.bowerDependencies();

    var VersionChecker = require('ember-cli-version-checker');
    var options = this.options = this.options || {};

    var checker = new VersionChecker(this);
    // prevent errors when ember-cli-shims is no longer required
    var shims = bowerDeps['ember-cli-shims'] && checker.for('ember-cli-shims', 'bower');

    var semver = require('semver');
    var version = require('./package').version;

    if (process.env.EMBER_DATA_SKIP_VERSION_CHECKING_DO_NOT_USE_THIS_ENV_VARIABLE) {
      // Skip for node tests as we can't currently override the version of ember-cli-shims
      // before the test helpers run.
      return;
    }

    var hasShims = !!shims;
    var shimsHasEmberDataShims = hasShims && shims.satisfies('< 0.1.0');
    var emberDataNPMWithShimsIncluded = semver.satisfies(version, '^2.3.0-beta.3');

    if (bowerDeps['ember-data']) {
      this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed. If you need an ' +
                'earlier version of ember-data (< 2.3.0), you can leave this unchanged for now, but we strongly suggest you upgrade your version of Ember Data ' +
                'as soon as possible.');
      this._forceBowerUsage = true;

      var emberDataBower = checker.for('ember-data', 'bower');
      var emberDataBowerWithShimsIncluded = emberDataBower.satisifies('>= 2.3.0-beta.3');

      if (hasShims && !shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) {
        throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6');
      }

      if (hasShims && shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) {
        throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.');
      }

    } else {
      // NPM only, but ember-cli-shims does not match
      if (hasShims && shimsHasEmberDataShims && emberDataNPMWithShimsIncluded) {
        throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.');
      }
    }
  },

  blueprintsPath: function() {
    return path.join(__dirname, 'blueprints');
  },

  treeForApp: function(dir) {
    if (this._forceBowerUsage) { return NOOP_TREE(dir); }

    // this._super.treeForApp is undefined in ember-cli (1.13) for some reason.
    // TODO: investigate why treeForApp isn't on _super
    return dir;
  },

  treeForAddon: function(tree) {
    if (this._forceBowerUsage) { return NOOP_TREE(tree); }

    let babel = this.addons.find(addon => addon.name === 'ember-cli-babel');

    let treeWithVersion = merge([
      tree,
      version() // compile the VERSION into the build
    ]);

    let withPrivate    = new Funnel(tree, { include: ['-private/**'] });
    let withoutPrivate = new Funnel(treeWithVersion, {
      exclude: [
        '-private',
        isProductionEnv() ? '-debug' : false
      ].filter(Boolean),

      destDir: 'ember-data'
    });

    var privateTree = babel.transpileTree(withPrivate, {
      babel: this.buildBabelOptions(),
      'ember-cli-babel': {
        compileModules: false
      }
    });

    // use the default options
    var publicTree = babel.transpileTree(withoutPrivate);

    privateTree = new Rollup(privateTree, {
      rollup: {
        entry: '-private/index.js',
        targets: [
          { dest: '-private.js', format: 'amd', moduleId: 'ember-data/-private' }
        ],
        external: [
          'ember',
          'ember-inflector',
          'ember-data/version',
          'ember-data/-debug',
          'ember-data/adapters/errors'
        ]
        // cache: true|false Defaults to true
      }
    });

    // the output of treeForAddon is required to be modules/<your files>
    publicTree  = new Funnel(publicTree,  { destDir: 'modules' });
    privateTree = new Funnel(privateTree, { destDir: 'modules' });

    return merge([
      publicTree,
      privateTree
    ]);
  },

  buildBabelOptions() {
    let customPlugins = require('./lib/stripped-build-plugins')(process.env.EMBER_ENV);

    return {
      loose: true,
      plugins: customPlugins.plugins,
      postTransformPlugins: customPlugins.postTransformPlugins,
      exclude: [
        'transform-es2015-block-scoping',
      ]
    };
  },

  _setupBabelOptions: function() {
    if (this._hasSetupBabelOptions) {
      return;
    }

    this.options.babel = this.buildBabelOptions();

    this._hasSetupBabelOptions = true;
  },

  included: function(app) {
    this._super.included.apply(this, arguments);

    this._setupBabelOptions();

    if (this._forceBowerUsage) {
      this.app.import({
        development: app.bowerDirectory + '/ember-data/ember-data.js',
        production: app.bowerDirectory + '/ember-data/ember-data.prod.js'
      });
    }
  }
};
<|endoftext|>


<commit_before>const fs = require('fs');
const uuid = require('uuid');
process.env.CHROME_BIN = require('puppeteer').executablePath();

module.exports = function init(config) {
  let customLaunchers;
  let browsers;
  if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
    /* eslint-disable */
    if (!fs.existsSync('sauce.json')) {
      console.log('Create a sauce.json with your credentials based on the sauce-sample.json file if you want to test in diffirent browsers in the cloud.');
    } else {
      process.env.SAUCE_ENABLED = require('./sauce.json').enabled;
      process.env.SAUCE_USERNAME = require('./sauce.json').username;
      process.env.SAUCE_ACCESS_KEY = require('./sauce.json').accessKey;
    }
    /* eslint-enable */
  } else {
    process.env.SAUCE_ENABLED = true;
  }

  if (process.env.SAUCE_ENABLED === 'true') {
    customLaunchers = {
      slChromeWin7: {
        base: 'SauceLabs',
        browserName: 'chrome',
        platform: 'Windows 7',
      },
      slFirefoxWin7: {
        base: 'SauceLabs',
        browserName: 'firefox',
        platform: 'Windows 7',
        version: '56',
      },
      slIe10Win7: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '10',
      },
      slIe9Win7: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '9',
      },
      slIe11Win10: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 10',
        version: '11',
      },
      slME25Win10: {
        base: 'SauceLabs',
        browserName: 'microsoftedge',
        platform: 'Windows 10',
        version: '13',
      },
      slSafariOsx: {
        base: 'SauceLabs',
        browserName: 'safari',
        platform: 'OS X 10.10',
      },
      // slIphone: {
      //   base: 'SauceLabs',
      //   browserName: 'Safari',
      //   platform: 'iOS',
      //   version: '11',
      //   deviceName: 'iPhone 5 Simulator',
      // },
      // slIpad: {
      //   base: 'SauceLabs',
      //   browserName: 'Safari',
      //   platform: 'iOS',
      //   version: '11',
      //   deviceName: 'iPad Air Simulator',
      // },
      slAndroid: {
        base: 'SauceLabs',
        browserName: 'Browser',
        platform: 'Linux',
        version: '5.1',
        deviceName: 'Android Emulator',
      },
      slSamsungAndroid: {
        base: 'SauceLabs',
        browserName: 'Browser',
        platform: 'Android',
        version: '7.0',
        deviceName: 'Samsung Galaxy S8 HD GoogleAPI Emulator',
      },
    };
    browsers = Object.keys(customLaunchers);
  } else {
    customLaunchers = null;
    browsers = ['Chrome'];
  }

  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',
    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha'],
    plugins: ['karma-mocha',
      'karma-chrome-launcher',
      'karma-safari-launcher',
      'mocha',
      'karma-mocha-reporter',
      'karma-sauce-launcher'],
    client: {
      mocha: {
        timeout: 7000,
      },
    },
    sauceLabs: {
      testName: 'Digital Data Manager Unit Tests',
      tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER || uuid.v4(),
      recordScreenshots: false,
      startConnect: true,
      // connectOptions: {
      //   port: 5757,
      //   logfile: 'sauce_connect.log'
      // },
      // public: 'public'
    },
    // list of files / patterns to load in the browser
    files: [
      'build/segmentstream-test.js',
    ],
    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    // preprocessors: {
    //  'src/**/*.js': ['browserify'],
    //  'test/**/*.js': ['browserify']
    // },
    //
    // browserify: {
    //  debug: true,
    //  transform: ['babelify', ['polyify', { 'browsers': 'IE >= 7' }]],
    //  configure: function(bundle) {
    //    bundle.on('bundled', function(err, content) {
    //      console.log(content);
    //    });
    //  }
    // },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: process.env.MOCHA ? ['mocha', 'saucelabs'] : ['dots', 'saucelabs'],

    mochaReporter: {
      showDiff: true,
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR ||
    // config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_ERROR,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // Increase timeout in case connection in CI is slow
    captureTimeout: 120000,
    customLaunchers,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultanous
    concurrency: 1,
    browserDisconnectTimeout: 10000,
    browserDisconnectTolerance: 10,
    browserNoActivityTimeout: 20000,
  });
};
<commit_msg>fixed ios tests<commit_after>const fs = require('fs');
const uuid = require('uuid');
process.env.CHROME_BIN = require('puppeteer').executablePath();

module.exports = function init(config) {
  let customLaunchers;
  let browsers;
  if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
    /* eslint-disable */
    if (!fs.existsSync('sauce.json')) {
      console.log('Create a sauce.json with your credentials based on the sauce-sample.json file if you want to test in diffirent browsers in the cloud.');
    } else {
      process.env.SAUCE_ENABLED = require('./sauce.json').enabled;
      process.env.SAUCE_USERNAME = require('./sauce.json').username;
      process.env.SAUCE_ACCESS_KEY = require('./sauce.json').accessKey;
    }
    /* eslint-enable */
  } else {
    process.env.SAUCE_ENABLED = true;
  }

  if (process.env.SAUCE_ENABLED === 'true') {
    customLaunchers = {
      slChromeWin7: {
        base: 'SauceLabs',
        browserName: 'chrome',
        platform: 'Windows 7',
      },
      slFirefoxWin7: {
        base: 'SauceLabs',
        browserName: 'firefox',
        platform: 'Windows 7',
        version: '56',
      },
      slIe10Win7: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '10',
      },
      slIe9Win7: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '9',
      },
      slIe11Win10: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 10',
        version: '11',
      },
      slME25Win10: {
        base: 'SauceLabs',
        browserName: 'microsoftedge',
        platform: 'Windows 10',
        version: '13',
      },
      slSafariOsx: {
        base: 'SauceLabs',
        browserName: 'safari',
        platform: 'OS X 10.10',
      },
      slIphone: {
        base: 'SauceLabs',
        browserName: 'Safari',
        platform: 'iOS',
        version: '10.3',
        deviceName: 'iPhone 6s Plus Simulator',
      },
      // commented out because of 10 minute test timeout limit
      // slIpad: {
      //   base: 'SauceLabs',
      //   browserName: 'Safari',
      //   platform: 'iOS',
      //   version: '10.3',
      //   deviceName: 'iPad Air Simulator',
      // },
      slAndroid: {
        base: 'SauceLabs',
        browserName: 'Browser',
        platform: 'Linux',
        version: '5.1',
        deviceName: 'Android Emulator',
      },
      slSamsungAndroid: {
        base: 'SauceLabs',
        browserName: 'Browser',
        platform: 'Android',
        version: '7.0',
        deviceName: 'Samsung Galaxy S8 HD GoogleAPI Emulator',
      },
    };
    browsers = Object.keys(customLaunchers);
  } else {
    customLaunchers = null;
    browsers = ['Chrome'];
  }

  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',
    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha'],
    plugins: ['karma-mocha',
      'karma-chrome-launcher',
      'karma-safari-launcher',
      'mocha',
      'karma-mocha-reporter',
      'karma-sauce-launcher'],
    client: {
      mocha: {
        timeout: 7000,
      },
    },
    sauceLabs: {
      testName: 'Digital Data Manager Unit Tests',
      tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER || uuid.v4(),
      recordScreenshots: false,
      startConnect: true,
      // connectOptions: {
      //   port: 5757,
      //   logfile: 'sauce_connect.log'
      // },
      // public: 'public'
    },
    // list of files / patterns to load in the browser
    files: [
      'build/segmentstream-test.js',
    ],
    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    // preprocessors: {
    //  'src/**/*.js': ['browserify'],
    //  'test/**/*.js': ['browserify']
    // },
    //
    // browserify: {
    //  debug: true,
    //  transform: ['babelify', ['polyify', { 'browsers': 'IE >= 7' }]],
    //  configure: function(bundle) {
    //    bundle.on('bundled', function(err, content) {
    //      console.log(content);
    //    });
    //  }
    // },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: process.env.MOCHA ? ['mocha', 'saucelabs'] : ['dots', 'saucelabs'],

    mochaReporter: {
      showDiff: true,
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR ||
    // config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_ERROR,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // Increase timeout in case connection in CI is slow
    captureTimeout: 120000,
    customLaunchers,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultanous
    concurrency: 1,
    browserDisconnectTimeout: 10000,
    browserDisconnectTolerance: 10,
    browserNoActivityTimeout: 20000,
  });
};
<|endoftext|>


<commit_before>/*eslint no-process-env:0 no-param-reassign:0*/

'use strict';

var util = require('util');
var winston = require('winston');
var winex = require('./winex');
var raven = require('raven');
var { omit, merge } = require('lodash');

var sysLogLevels;

// Exposes `winston.transports.Loggly`.
require('winston-loggly');

sysLogLevels = {
  levels: {
    emerg: 0,
    alert: 1,
    crit: 2,
    error: 3,
    warning: 4,
    notice: 5,
    info: 6,
    debug: 7,
  },
};

/**
 * Create a log object for public consumption.
 *
 * Usage:
 *
 * l = new Log(options);
 * l.info('blah', {});
 * l.error('oops', {}, err);
 * app.use(l.middleware());
 *
 * @param {Object}   options            Options
 * @param {Object[]} options.transports Should look like:
 *                                      [
 *                                        {
 *                                          Console: {
 *                                            level: 'info',
 *                                            json: true,
 *                                            prettyPrint: true
 *                                          }
 *                                        },
 *                                        {
 *                                          ...
 *                                        }
 *                                      ]
 * @param {Object} options.sentry Config passed to sentry raven instance.
 *                                Should look like:
 *                                {
 *                                  // the account token
 *                                  dsn: string;
 *                                  // pass directly to raven constructor
 *                                  // refer to https://goo.gl/9Ud7Mz
 *                                  options: Object;
 *                                }
 *
 * @return {void}
 */
function Log(options) {
  var logTransports;
  var winstonOpts;
  var winstonLog;

  if (!options || !options.transports) {
    throw new Error('No transports found');
  }

  logTransports = options.transports.map(function(t) {
    var cls = Object.keys(t)[0];
    var opts = t[cls];
    var Transport = winston.transports[cls];
    return new Transport(opts);
  });

  winstonOpts = {
    levels: sysLogLevels.levels,
    transports: logTransports,
  };

  winstonLog = new winston.Logger(winstonOpts);
  this._winexConstructor = winex.factory(winstonLog, {});
  this.middleware = this._winexConstructor.middleware;

  if (options.sentry) {
    this.ravenClient = new raven.Client(
      options.sentry.dsn,
      options.sentry.options
    );
  } else {
    this.ravenClient = new raven.Client(false);
  }
}

/**
 * Helper function for attaching methods to the logger prototype.
 *
 * @param {string} level  Logging level, e.g. 'debug'.
 *
 * @return {Function} Logging method to attach to the Log prototype.
 */
function _logger(level) {
  return function(message, meta, error) {
    var log = new this._winexConstructor();

    if (util.isError(meta)) {
      error = meta;
      meta = null;
    }

    if (meta) {
      log.addMeta(meta);
    }

    if (error) {
      this.ravenClient.captureException(error, _getSentryMeta(meta));
      log.addError(error);
    }

    log[level](message);
  };
}

/**
 * Format log meta to sentry optional attribute. See:
 * https://docs.getsentry.com/hosted/clients/node/usage/#optional-attributes
 *
 * @param {Object} [meta] Meta data passed to logger
 *
 * @return {Object} Optional attributes for sentry. Default will look like:
 *                  {
 *                    tags: {
 *                      env: 'development'
 *                    }
 *                  }
 */
function _getSentryMeta(meta) {
  var _meta = meta || {};

  return merge(
    {
      tags: {
        env: process.env.NODE_ENV || 'development',
      },
    },
    {
      extra: omit(_meta, ['tags', 'fingerprint', 'level']),
      tags: _meta.tags,
      fingerprint: _meta.fingerprint,
      level: _meta.level,
    }
  );
}

Object.keys(sysLogLevels.levels).forEach(function(level) {
  Log.prototype[level] = _logger(level);
});

module.exports = {
  Log: Log,
  _getSentryMeta: _getSentryMeta,
};
<commit_msg>Comments.<commit_after>/*eslint no-process-env:0 no-param-reassign:0*/

'use strict';

var util = require('util');
var winston = require('winston');
var winex = require('./winex');
var raven = require('raven');
var { omit, merge } = require('lodash');

var sysLogLevels;

// Exposes `winston.transports.Loggly`.
require('winston-loggly');

sysLogLevels = {
  levels: {
    emerg: 0,
    alert: 1,
    crit: 2,
    error: 3,
    warning: 4,
    notice: 5,
    info: 6,
    debug: 7,
  },
};

/**
 * Create a log object for public consumption.
 *
 * Usage:
 *
 * l = new Log(options);
 * l.info('blah', {});
 * l.error('oops', {}, err);
 * app.use(l.middleware());
 *
 * @param {Object}   options            Options
 * @param {Object[]} options.transports Should look like:
 *                                      [
 *                                        {
 *                                          Console: {
 *                                            level: 'info',
 *                                            json: true,
 *                                            prettyPrint: true
 *                                          }
 *                                        },
 *                                        {
 *                                          ...
 *                                        }
 *                                      ]
 * @param {Object} options.sentry Config passed to sentry raven instance.
 *                                Should look like:
 *                                {
 *                                  // the account token
 *                                  dsn: string;
 *                                  // pass directly to raven constructor
 *                                  // refer to https://goo.gl/9Ud7Mz
 *                                  options: Object;
 *                                }
 *
 * @return {void}
 */
function Log(options) {
  var logTransports;
  var winstonOpts;
  var winstonLog;

  if (!options || !options.transports) {
    throw new Error('No transports found');
  }

  logTransports = options.transports.map(function(t) {
    var cls = Object.keys(t)[0];
    var opts = t[cls];
    var Transport = winston.transports[cls];
    return new Transport(opts);
  });

  winstonOpts = {
    levels: sysLogLevels.levels,
    transports: logTransports,
  };

  winstonLog = new winston.Logger(winstonOpts);
  this._winexConstructor = winex.factory(winstonLog, {});

  /*
    Opts for request-logging middleware (applies to all logs generated by the
    instance of the middleware):

    @type       {String} type description (e.g., "server" or "client")
    @meta       {Object} descriptive fields to attach to log
    @errNoStack {boolean} When true, don't include stack when logging errors.
    @info404    {boolean} When true, log 404s as info instead of warning.
  */
  this.middleware = this._winexConstructor.middleware;

  if (options.sentry) {
    this.ravenClient = new raven.Client(
      options.sentry.dsn,
      options.sentry.options
    );
  } else {
    this.ravenClient = new raven.Client(false);
  }
}

/**
 * Helper function for attaching methods to the logger prototype.
 *
 * @param {string} level  Logging level, e.g. 'debug'.
 *
 * @return {Function} Logging method to attach to the Log prototype.
 */
function _logger(level) {
  return function(message, meta, error) {
    var log = new this._winexConstructor();

    if (util.isError(meta)) {
      error = meta;
      meta = null;
    }

    if (meta) {
      log.addMeta(meta);
    }

    if (error) {
      this.ravenClient.captureException(error, _getSentryMeta(meta));
      log.addError(error);
    }

    log[level](message);
  };
}

/**
 * Format log meta to sentry optional attribute. See:
 * https://docs.getsentry.com/hosted/clients/node/usage/#optional-attributes
 *
 * @param {Object} [meta] Meta data passed to logger
 *
 * @return {Object} Optional attributes for sentry. Default will look like:
 *                  {
 *                    tags: {
 *                      env: 'development'
 *                    }
 *                  }
 */
function _getSentryMeta(meta) {
  var _meta = meta || {};

  return merge(
    {
      tags: {
        env: process.env.NODE_ENV || 'development',
      },
    },
    {
      extra: omit(_meta, ['tags', 'fingerprint', 'level']),
      tags: _meta.tags,
      fingerprint: _meta.fingerprint,
      level: _meta.level,
    }
  );
}

Object.keys(sysLogLevels.levels).forEach(function(level) {
  Log.prototype[level] = _logger(level);
});

module.exports = {
  Log: Log,
  _getSentryMeta: _getSentryMeta,
};
<|endoftext|>


<commit_before>'use strict';

var BrowserWindow  = require('browser-window')
var globalShortcut = require('global-shortcut')

var url            = require('url')
var querystring    = require('querystring')

var config         = require('./lib/config')

var menubar        = require('menubar')
var mb             = menubar({
  dir           : __dirname + '/app',
  preloadWindow : true, // TODO: enable if already logged in
  width         : 400,
  height        : 500,
  resizable     : false
})

var debug = process.env.NODE_ENV === 'development'

/**
 * Window references
 */
var debugWindow = null

mb.on('ready', function() {

  if (debug)
    debugWindow = new BrowserWindow({
      width  : 995,
      height : 600,
      type   : 'desktop',
      frame  : true
    })

  function doLogin() {

    mb.window.loadUrl('https://soundcloud.com/connect?client_id=f17c1d67b83c86194fad2b1948061c9e&response_type=token&scope=non-expiring&display=next&redirect_uri=cumulus://oauth/callback')
  }

  function initialize() {

    if (debug) {
      debugWindow.openDevTools()
      debugWindow.loadUrl('file://' + __dirname + '/app/index.html')
    }

    mb.window.setSize(320, 500)
    mb.window.setMaximumSize(320, 600)
    mb.window.setMinimumSize(320, 400)
    mb.window.setResizable(true)
    mb.window.loadUrl('file://' + __dirname + '/app/index.html')
  }

  /**
   * register Cumulus protocol
   */
  var protocol = require('protocol')
  protocol.registerProtocol('cumulus', function(req) {

    // parse access token
    var hash  = url.parse(req.url).hash.substr(1)
    var token = querystring.parse(hash).access_token

    config.set('access_token', token, function(err) {
      if (err)
        throw err
      else
        initialize()
    })

  })

  // check if we already have an access_token
  config.get('access_token', function(err, value) {
    if (err)
      throw err

    if (typeof value !== 'undefined')
      initialize()
    else
      doLogin()
  })

  function _sendGlobalShortcut(accelerator) {
    if (!mb.window) return
    mb.window.webContents.send('GlobalShortcuts', accelerator)
  }

  globalShortcut.register('MediaPlayPause', function() {
    _sendGlobalShortcut('MediaPlayPause')
  })

  globalShortcut.register('MediaNextTrack', function() {
    _sendGlobalShortcut('MediaNextTrack')
  })

  globalShortcut.register('MediaPreviousTrack', function() {
    _sendGlobalShortcut('MediaPreviousTrack')
  })

})
<commit_msg>Cleanup<commit_after>'use strict';

var BrowserWindow  = require('browser-window')
var globalShortcut = require('global-shortcut')

var url            = require('url')
var querystring    = require('querystring')

var config         = require('./lib/config')

var menubar        = require('menubar')
var mb             = menubar({
  dir           : __dirname + '/app',
  preloadWindow : true, // TODO: enable if already logged in
  width         : 400,
  height        : 500,
  resizable     : false
})

var debug = process.env.NODE_ENV === 'development'

/**
 * Window references
 */
var debugWindow = null

mb.on('ready', function() {

  if (debug)
    debugWindow = new BrowserWindow({
      width  : 995,
      height : 600,
      type   : 'desktop',
      frame  : true
    })

  function doLogin() {
    mb.window.loadUrl('https://soundcloud.com/connect?client_id=f17c1d67b83c86194fad2b1948061c9e&response_type=token&scope=non-expiring&display=next&redirect_uri=cumulus://oauth/callback')
  }

  function initialize() {

    if (debug) {
      debugWindow.openDevTools()
      debugWindow.loadUrl('file://' + __dirname + '/app/index.html')
    }

    mb.window.setSize(320, 500)
    mb.window.setMaximumSize(320, 600)
    mb.window.setMinimumSize(320, 400)
    mb.window.setResizable(true)
    mb.window.loadUrl('file://' + __dirname + '/app/index.html')
  }

  /**
   * register Cumulus protocol
   */
  var protocol = require('protocol')
  protocol.registerProtocol('cumulus', function(req) {

    // parse access token
    var hash  = url.parse(req.url).hash.substr(1)
    var token = querystring.parse(hash).access_token

    config.set('access_token', token, function(err) {
      if (err)
        throw err
      else
        initialize()
    })

  })

  // check if we already have an access_token
  config.get('access_token', function(err, value) {
    if (err)
      throw err

    if (typeof value !== 'undefined')
      initialize()
    else
      doLogin()
  })

  function _sendGlobalShortcut(accelerator) {
    if (!mb.window) return
    mb.window.webContents.send('GlobalShortcuts', accelerator)
  }

  globalShortcut.register('MediaPlayPause', function() {
    _sendGlobalShortcut('MediaPlayPause')
  })

  globalShortcut.register('MediaNextTrack', function() {
    _sendGlobalShortcut('MediaNextTrack')
  })

  globalShortcut.register('MediaPreviousTrack', function() {
    _sendGlobalShortcut('MediaPreviousTrack')
  })

})
<|endoftext|>


<commit_before>// Karma configuration
// Generated on Fri Jul 05 2013 01:57:57 GMT-0400 (EDT)

module.exports = function(config) {
  config.set({

    // base path, that will be used to resolve files and exclude
    basePath: 'tmp/public',

    // list of files / patterns to load in the browser
    files: [
      'vendor/loader.js',
      'vendor/jquery/jquery.js',
      'vendor/handlebars/handlebars.js',
      'vendor/ember/index.js',
      'vendor/ember/ember-data.js',
      'assets/templates.js',
      'assets/app.js',
      'tests/test_helper.js',
      'tests/tests.js',
      'tests/test_loader.js'
    ],

    frameworks: ['qunit'],

    plugins: [
      'karma-qunit',
      'karma-coverage',
      'karma-phantomjs-launcher',
      'karma-chrome-launcher',
      'karma-firefox-launcher',
      'karma-safari-launcher'
    ],

    preprocessors: {
      'assets/*.js': 'coverage'
    },

    // list of files to exclude
    exclude: [],

    // test results reporter to use
    // possible values: 'dots', 'progress', 'junit'
    reporters: 'coverage',

    coverageReporter: {
      type : ['text'],
      dir : 'coverage/'
    },

    // web server port
    port: 9876,

    // cli runner port
    runnerPort: 9100,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: ['Firefox'],

    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};
<commit_msg>Fix ember data in karma conf<commit_after>// Karma configuration
// Generated on Fri Jul 05 2013 01:57:57 GMT-0400 (EDT)

module.exports = function(config) {
  config.set({

    // base path, that will be used to resolve files and exclude
    basePath: 'tmp/public',

    // list of files / patterns to load in the browser
    files: [
      'vendor/loader.js',
      'vendor/jquery/jquery.js',
      'vendor/handlebars/handlebars.js',
      'vendor/ember/index.js',
      'vendor/ember-data/index.js',
      'assets/templates.js',
      'assets/app.js',
      'tests/test_helper.js',
      'tests/tests.js',
      'tests/test_loader.js'
    ],

    frameworks: ['qunit'],

    plugins: [
      'karma-qunit',
      'karma-coverage',
      'karma-phantomjs-launcher',
      'karma-chrome-launcher',
      'karma-firefox-launcher',
      'karma-safari-launcher'
    ],

    preprocessors: {
      'assets/*.js': 'coverage'
    },

    // list of files to exclude
    exclude: [],

    // test results reporter to use
    // possible values: 'dots', 'progress', 'junit'
    reporters: 'coverage',

    coverageReporter: {
      type : ['text'],
      dir : 'coverage/'
    },

    // web server port
    port: 9876,

    // cli runner port
    runnerPort: 9100,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: ['Firefox'],

    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};
<|endoftext|>


<commit_before>/**!
 * TinyModel
 * @author romantaraban <rom.taraban@gmail.com>
 * @license MIT
 *
 * Model's event system is based on this Publish/Subscribe implementataion https://github.com/romantaraban/tiny-model
 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['./node_modules/pubsub/index'], factory);
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(require('pubsub'));
  } else {
    // Browser globals (root is window)
    root.TinyModel = factory(root.PubSub);
  }
}(this, function(PubSub) {
  "use strict";

  /**
   * Returns nested properties of an object. Throws an error when trying to access property of undefined object
   * @param {bool} obj, {string} ptop
   */
  var getDescentProp = function(obj, prop) {
    var path = prop.split('.');
    while (path.length) {
      obj = obj[path.shift()];
    }
    return obj;
  }

  var TinyModel = function(data) {
    this.state = data || {};
  };

  TinyModel.prototype = Object.create(PubSub.prototype);

  TinyModel.prototype.set = function() {
    if (typeof(arguments[0]) === 'string' && arguments.length > 1) {
      if (/\./.test(arguments[0])) {
        // split path into property names
        var path = arguments[0].split('.');
        // new property name
        var newPropName = path[path.length - 1];
        // new value to assing
        var newValue = arguments[1];
        // get parrent object of descent preperty or exit if it doesn't exist
        try {
          var parentProp = getDescentProp(this.state, arguments[0].replace(/\.(?:.(?!\.))+$/gim, ''));
        } catch (error) {
          throw error;
        }
        // check most descant parent property for type
        if (typeof(parentProp) === 'object') {
          // assing value to property
          if (parentProp[newPropName] === newValue) {
            return;
          }
          parentProp[newPropName] = newValue;
          // bubble event from descent property to top level
          for (var l = path.length, curPropPath; l > 0; l--) {
            curPropPath = path.slice(0, l).join('.');
            this.trigger('change:' + curPropPath, curPropPath, getDescentProp(this.state, curPropPath));
          }
        } else {
          // if not an object - then we can't set child properties to it, throw an error
          throw new Error(curPropPath + 'is not an object');
        }
      } else if (this.state[arguments[0]] !== arguments[1]) {
        this.state[arguments[0]] = arguments[1];
        this.trigger('change:' + arguments[0], arguments[0], arguments[1]);
      }
    } else if (typeof(arguments[0]) === 'object') {
      var data = arguments[0];
      for (var prop in data) {
        if (data.hasOwnProperty(prop)) {
          if (this.state[prop] !== data[prop]) {
            this.state[prop] = data[prop];
            this.trigger('change:' + prop, prop, data[prop]);
          }
        }
      }
    }
  };

  TinyModel.prototype.get = function(prop) {
    if (arguments.length > 1) {
      return Array.prototype.reduce.call(arguments, function(cache, el) {
        if (/\./.test(el)) {
          // get descent property
          try {
            cache[el.replace(/^.*(?:\.)/, '')] = getDescentProp(this.state, el);
          } catch (error) {
            throw new Error("Can\'t access property of undefined object," + error);
          }
        } else {
          cache[el] = this.state[el];
        }
        return cache;
      }.bind(this), {});
    } else {
      if (/\./.test(prop)) {
        // get descent property
        try {
          return getDescentProp(this.state, prop);
        } catch (error) {
          throw new Error("Can\'t access property of undefined object," + error);
        }
      } else {
        return this.state[prop];
      }
    }
  };

  TinyModel.prototype.remove = function(prop) {
    if (this.state[prop]) {
      var value = this.state[prop];
      delete this.state[prop];
      this.trigger('remove:' + prop, prop, value);
    }
  };

  TinyModel.prototype.reset = function() {
    for (var prop in this.state) {
      this.remove(prop);
    }
  };

  return TinyModel;

}));
<commit_msg>Update index.js<commit_after>/**!
 * TinyModel
 * @author romantaraban <rom.taraban@gmail.com>
 * @license MIT
 *
 * Model's event system is based on this Publish/Subscribe implementataion https://github.com/romantaraban/tiny-model
 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['./node_modules/pubsub/index'], factory);
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(require('pubsub'));
  } else {
    // Browser globals (root is window)
    root.TinyModel = factory(root.PubSub);
  }
}(this, function(PubSub) {
  "use strict";

  /**
   * Returns nested properties of an object. Throws an error when trying to access property of undefined object
   * @param {bool} obj, {string} ptop
   */
  var getDescentProp = function(obj, prop) {
    var path = prop.split('.');
    while (path.length) {
      obj = obj[path.shift()];
    }
    return obj;
  }

  var TinyModel = function(data) {
    this.state = data || {};
  };

  TinyModel.prototype = Object.create(PubSub.prototype);

  TinyModel.prototype.set = function() {
    if (typeof(arguments[0]) === 'string' && arguments.length > 1) {
      if (/\./.test(arguments[0])) {
        // split path into property names
        var path = arguments[0].split('.');
        // new property name
        var newPropName = path[path.length - 1];
        // new value to assing
        var newValue = arguments[1];
        // get parrent object of descent preperty or exit if it doesn't exist
        try {
          var parentProp = getDescentProp(this.state, arguments[0].replace(/\.(?:.(?!\.))+$/gim, ''));
        } catch (error) {
          throw error;
        }
        // check most descent parent property for type
        if (typeof(parentProp) === 'object') {
          // assing value to property
          if (parentProp[newPropName] === newValue) {
            return;
          }
          parentProp[newPropName] = newValue;
          // bubble event from descent property to top level
          for (var l = path.length, curPropPath; l > 0; l--) {
            curPropPath = path.slice(0, l).join('.');
            this.trigger('change:' + curPropPath, curPropPath, getDescentProp(this.state, curPropPath));
          }
        } else {
          // if not an object - then we can't set child properties to it, throw an error
          throw new Error(curPropPath + 'is not an object');
        }
      } else if (this.state[arguments[0]] !== arguments[1]) {
        this.state[arguments[0]] = arguments[1];
        this.trigger('change:' + arguments[0], arguments[0], arguments[1]);
      }
    } else if (typeof(arguments[0]) === 'object') {
      var data = arguments[0];
      for (var prop in data) {
        if (data.hasOwnProperty(prop)) {
          if (this.state[prop] !== data[prop]) {
            this.state[prop] = data[prop];
            this.trigger('change:' + prop, prop, data[prop]);
          }
        }
      }
    }
  };

  TinyModel.prototype.get = function(prop) {
    if (arguments.length > 1) {
      return Array.prototype.reduce.call(arguments, function(cache, el) {
        if (/\./.test(el)) {
          // get descent property
          try {
            cache[el.replace(/^.*(?:\.)/, '')] = getDescentProp(this.state, el);
          } catch (error) {
            throw new Error("Can\'t access property of undefined object," + error);
          }
        } else {
          cache[el] = this.state[el];
        }
        return cache;
      }.bind(this), {});
    } else {
      if (/\./.test(prop)) {
        // get descent property
        try {
          return getDescentProp(this.state, prop);
        } catch (error) {
          throw new Error("Can\'t access property of undefined object," + error);
        }
      } else {
        return this.state[prop];
      }
    }
  };

  TinyModel.prototype.remove = function(prop) {
    if (this.state[prop]) {
      var value = this.state[prop];
      delete this.state[prop];
      this.trigger('remove:' + prop, prop, value);
    }
  };

  TinyModel.prototype.reset = function() {
    for (var prop in this.state) {
      this.remove(prop);
    }
  };

  return TinyModel;

}));
<|endoftext|>


<commit_before>// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html

module.exports = function(config) {
  config.set({
    // base path, that will be used to resolve files and exclude
    basePath: '',

    // testing framework to use (jasmine/mocha/qunit/...)
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'app/bower_components/angular/angular.js',
      'app/bower_components/angular-cookies/angular-cookies.js',
      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-sanitize/angular-sanitize.js',
      'app/bower_components/angular-resource/angular-resource.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
      'app/scripts/*.js',
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [],

    // web server port
    port: 8080,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};
<commit_msg>Updates Karma to run with PhantomJS<commit_after>// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html

module.exports = function(config) {
  config.set({
    // base path, that will be used to resolve files and exclude
    basePath: '',

    // testing framework to use (jasmine/mocha/qunit/...)
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'app/bower_components/angular/angular.js',
      'app/bower_components/angular-cookies/angular-cookies.js',
      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-sanitize/angular-sanitize.js',
      'app/bower_components/angular-resource/angular-resource.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
      'app/scripts/*.js',
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [],

    // web server port
    port: 8080,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: ['PhantomJS'],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};
<|endoftext|>


<commit_before>var hash = require('./lib/hash')
var writer = require('./lib/writer')
var hypercore = require('hypercore')
var remove = require('unordered-array-remove')
var raf = require('random-access-file')
var mutexify = require('mutexify')
var thunky = require('thunky')
var codecs = require('codecs')
var events = require('events')
var inherits = require('inherits')
var toBuffer = require('to-buffer')
var protocol = null // lazy load on replicate

module.exports = DB

function DB (storage, key, opts) {
  if (!(this instanceof DB)) return new DB(storage, key, opts)
  events.EventEmitter.call(this)

  if (isOptions(key)) {
    opts = key
    key = null
  }

  if (!opts) opts = {}

  var self = this

  this.key = key ? toBuffer(key, 'hex') : null
  this.discoveryKey = null
  this.local = null
  this.source = null
  this.opened = false
  this.sparse = !!opts.sparse

  this._codec = opts.valueEncoding ? codecs(opts.valueEncoding) : null
  this._storage = typeof storage === 'string' ? fileStorage : storage
  this._map = opts.map || null
  this._reduce = opts.reduce || null
  this._writers = []
  this._lock = mutexify() // unneeded once we support batching
  this._localWriter = null
  this.setMaxListeners(0) // use ._streams array instead

  this.ready = thunky(open)
  this.ready(onready)

  function onready (err) {
    self.opened = !err
    if (err) self.emit('error', err)
    else self.emit('ready')
  }

  function open (cb) {
    self._open(cb)
  }

  function fileStorage (name) {
    return raf(name, {directory: storage})
  }
}

inherits(DB, events.EventEmitter)

DB.prototype.heads = function (cb) {
  var result = []
  var error = null
  var self = this
  var missing = 0
  var i = 0

  this.ready(onready)

  function onready (err) {
    if (err) return cb(err)

    for (; i < self._writers.length; i++) {
      missing++
      self._writers[i].head(onhead)
    }
  }

  function onhead (err, val, updated) {
    if (updated) onready(null)

    if (err) error = err
    else if (val) result[val.feed] = val
    if (--missing) return

    if (error) return cb(error)

    for (var i = 0; i < result.length; i++) {
      var head = result[i]
      if (!head) continue

      for (var j = 0; j < head.clock.length; j++) {
        if (result[j] && result[j].seq < head.clock[j]) result[j] = null
      }
    }

    cb(null, result.filter(Boolean))
  }
}

DB.prototype.authorize = function (key, cb) {
  this._createWriter(toBuffer(key, 'hex'))
  this.put('', '', cb)
}

DB.prototype.replicate = function (opts) {
  if (!protocol) protocol = require('hypercore-protocol')
  if (!opts) opts = {}

  var len = this._writers.length
  opts.expectedFeeds = len

  var self = this
  var stream = protocol(opts)

  opts.stream = stream

  this.ready(function (err) {
    if (err) return stream.destroy(err)
    if (stream.destroyed) return

    for (var i = 0; i < self._writers.length; i++) {
      self._writers[i].feed.replicate(opts)
    }

    self.on('_writer', onwriter)
    if (!self.sparse) {
      onappend()
      self.on('append', onappend)
    }

    stream.on('close', onclose)
    stream.on('end', onclose)

    function onclose () {
      self.removeListener('append', onappend)
      self.removeListener('_writer', onwriter)
    }

    function onappend () {
      // hack! make api in hypercore-protocol for this
      if (stream.destroyed) return
      stream.expectedFeeds += 1e9
      self._update(function () {
        stream.expectedFeeds -= 1e9
        stream.expectedFeeds += (self._writers.length - len)
        len = self._writers.length
        if (!stream.expectedFeeds) stream.finalize()
      })
    }

    function onwriter (w) {
      if (stream.destroyed) return
      w.feed.replicate(opts)
    }
  })

  return stream
}

DB.prototype.put = function (key, value, cb) {
  var self = this

  this._lock(function (release) {
    self._put(key, value, function (err) {
      release(cb, err)
    })
  })
}

DB.prototype._put = function (key, value, cb) {
  if (!cb) cb = noop

  var self = this
  var path = hash(key, true)

  this.heads(function (err, heads) {
    if (err) return cb(err)

    if (!self._localWriter) self._localWriter = self._createWriter(self.local.key, 'local')

    var feed = self._localWriter.id
    var clock = []
    var i = 0

    for (i = 0; i < self._writers.length; i++) {
      clock.push(i === feed ? 0 : self._writers[i].feed.length)
    }

    var node = {
      seq: self._localWriter.feed.length,
      feed: feed,
      key: key,
      path: path,
      value: value,
      clock: clock,
      trie: []
    }

    if (!heads.length) {
      self._localWriter.append(node, ondone)
      return
    }

    var missing = heads.length
    var error = null

    for (i = 0; i < heads.length; i++) {
      self._visitPut(key, path, 0, 0, 0, heads[i], heads, node.trie, onput)
    }

    function onput (err) {
      if (err) error = err
      if (--missing) return

      if (error) return cb(err)

      self._localWriter.append(node, ondone)
    }

    function ondone (err) {
      if (err) return cb(err)
      return cb(null, self._map ? self._map(node) : node)
    }
  })
}

DB.prototype.path = function (key, cb) {
  var path = []
  this._get(key, null, onvisit, done)

  function onvisit (node) {
    path.push(node)
    return true
  }

  function done (err) {
    if (err) return cb(err)
    cb(null, path)
  }
}

DB.prototype.get = function (key, cb) {
  this._get(key, [], ondefaultvisit, cb)
}

DB.prototype._get = function (key, result, visit, cb) {
  var path = hash(key, true)
  var self = this

  this.heads(function (err, heads) {
    if (err) return cb(err)
    if (!heads.length) return cb(null, null)

    var missing = heads.length
    var error = null

    for (var i = 0; i < heads.length; i++) {
      self._visitGet(key, path, 0, heads[i], heads, result, visit, onget)
    }

    function onget (err) {
      if (err) error = err
      if (--missing) return
      if (error) return cb(error)

      if (!result || !result.length) return cb(null, null)

      if (self._map) result = result.map(self._map)
      if (self._reduce) result = result.reduce(self._reduce)

      cb(null, result)
    }
  })
}

DB.prototype._visitPut = function (key, path, i, j, k, node, heads, trie, cb) {
  var writers = this._writers
  var self = this
  var missing = 0
  var error = null
  var vals = null
  var remoteVals = null

  for (; i < path.length; i++) {
    var val = path[i]
    var local = trie[i]
    var remote = node.trie[i] || []

    // copy old trie
    for (; j < remote.length; j++) {
      if (j === val && val !== hash.TERMINATE) continue

      if (!local) local = trie[i] = []
      vals = local[j] = local[j] || []
      remoteVals = remote[j] || []

      for (; k < remoteVals.length; k++) {
        var rval = remoteVals[k]

        if (val === hash.TERMINATE) {
          writers[rval.feed].get(rval.seq, onfilterdups)
          return
        }

        if (noDup(vals, rval)) vals.push(rval)
      }
      k = 0
    }
    j = 0

    if (node.path[i] !== val || (node.path[i] === hash.TERMINATE && node.key !== key)) {
      // trie is splitting
      if (!local) local = trie[i] = []
      vals = local[node.path[i]] = local[node.path[i]] || []
      remoteVals = remote[val]
      vals.push({feed: node.feed, seq: node.seq})

      if (!remoteVals || !remoteVals.length) return cb(null)

      missing = remoteVals.length
      error = null

      for (var l = 0; l < remoteVals.length; l++) {
        writers[remoteVals[l].feed].get(remoteVals[l].seq, onremoteval)
      }
      return
    }
  }

  cb(null)

  function onfilterdups (err, val) {
    if (err) return cb(err)
    var valPointer = {feed: val.feed, seq: val.seq}
    if (val.key !== key && noDup(vals, valPointer)) vals.push(valPointer)
    self._visitPut(key, path, i, j, k + 1, node, heads, trie, cb)
  }

  function onremoteval (err, val) {
    if (err) return onvisit(err)
    if (!updateHead(val, node, heads)) return onvisit(null)
    self._visitPut(key, path, i + 1, j, k, val, heads, trie, onvisit)
  }

  function onvisit (err) {
    if (err) error = err
    if (!--missing) cb(error)
  }
}

DB.prototype._open = function (cb) {
  var self = this
  var source = this._createFeed(this.key, 'source')

  source.on('ready', function () {
    self.source = source
    self.key = source.key
    self.discoveryKey = source.discoveryKey

    var w = self._createWriter(self.key, 'source')

    if (source.writable) {
      self.local = source
      self._localWriter = w
      return self._update(cb)
    }

    var local = self._createFeed(null, 'local')

    local.on('ready', function () {
      self.local = local
      self._update(cb)
    })
  })
}

DB.prototype._update = function (cb) {
  if (!cb) cb = noop

  var self = this
  var missing = this._writers.length
  var error = null
  var i = 0

  for (; i < this._writers.length; i++) {
    this._writers[i].head(done)
  }

  function done (err, head, updated) {
    if (err) error = err

    if (updated) {
      for (; i < self._writers.length; i++) {
        missing++
        self._writers[i].head(done)
      }
    }
    if (!--missing) cb(error)
  }
}

DB.prototype._createFeed = function (key, dir) {
  if (!dir) {
    dir = key.toString('hex')
    dir = 'peers/' + dir.slice(0, 2) + '/' + dir.slice(2)
  }

  if (key) {
    if (this.local && this.local.key && this.local.key.equals(key)) return this.local
    if (this.source && this.source.key && this.source.key.equals(key)) return this.source
  }

  var self = this
  var feed = hypercore(storage, key, {sparse: this.sparse})

  feed.on('error', onerror)
  feed.on('append', onappend)

  return feed

  function onerror (err) {
    self.emit('error', err)
  }

  function onappend () {
    self.emit('append', this)
  }

  function storage (name) {
    return self._storage(dir + '/' + name)
  }
}

DB.prototype._createWriter = function (key, dir) {
  for (var i = 0; i < this._writers.length; i++) {
    var w = this._writers[i]
    if (key && w.key.equals(key)) return w
  }

  var res = writer(this, this._createFeed(key, dir), this._writers.length)

  this._writers.push(res)
  this.emit('_writer', res)

  return res
}

DB.prototype._visitGet = function (key, path, i, node, heads, result, onvisit, cb) {
  var self = this
  var writers = this._writers
  var missing = 0
  var error = null
  var trie = null
  var vals = null

  if (!onvisit(node)) return cb(null)

  for (; i < path.length; i++) {
    if (node.path[i] === path[i]) continue

    // check trie
    trie = node.trie[i]
    if (!trie) return cb(null)

    vals = trie[path[i]]

    // not found
    if (!vals || !vals.length) return cb(null)

    missing = vals.length
    error = null

    for (var j = 0; j < vals.length; j++) {
      writers[vals[j].feed].get(vals[j].seq, onval)
    }

    return
  }

  // check for collisions
  trie = node.trie[path.length - 1]
  vals = trie && trie[hash.TERMINATE]

  // already visited node so passing null as visitor
  pushMaybe(key, node, result, null)

  if (!vals || !vals.length) return cb(null)

  missing = vals.length
  error = null

  for (var k = 0; k < vals.length; k++) {
    writers[vals[k].feed].get(vals[k].seq, onpush)
  }

  function onpush (err, val) {
    if (err) error = err
    else pushMaybe(key, val, result, onvisit)
    if (!--missing) cb(error)
  }

  function onval (err, val) {
    if (err) return done(err)

    if (!updateHead(val, node, heads)) {
      onvisit(val)
      done(null)
      return
    }

    self._visitGet(key, path, i + 1, val, heads, result, onvisit, done)
  }

  function done (err) {
    if (err) error = err
    if (!--missing) cb(error)
  }
}

function noop () {}

function ondefaultvisit (node) {
  return true
}

function updateHead (newNode, oldNode, heads) {
  var i = heads.indexOf(oldNode)
  if (i !== -1) remove(heads, i)
  if (!isHead(newNode, heads)) return false
  heads.push(newNode)
  return true
}

function isHead (node, heads) {
  for (var i = 0; i < heads.length; i++) {
    var head = heads[i]
    if (head.feed === node.feed) return false
    if (node.seq < head.clock[node.feed]) return false
  }
  return true
}

function pushMaybe (key, node, results, onvisit) {
  if (!results || (onvisit && !onvisit(node))) return
  if (node.key === key && noDup(results, node)) results.push(node)
}

function noDup (list, val) {
  for (var i = 0; i < list.length; i++) {
    if (list[i].feed === val.feed && list[i].seq === val.seq) {
      return false
    }
  }
  return true
}

function isOptions (opts) {
  return !!(opts && typeof opts !== 'string' && !Buffer.isBuffer(opts))
}
<commit_msg>add .watch<commit_after>var hash = require('./lib/hash')
var writer = require('./lib/writer')
var hypercore = require('hypercore')
var remove = require('unordered-array-remove')
var raf = require('random-access-file')
var mutexify = require('mutexify')
var thunky = require('thunky')
var codecs = require('codecs')
var events = require('events')
var inherits = require('inherits')
var toBuffer = require('to-buffer')
var protocol = null // lazy load on replicate

module.exports = DB

function DB (storage, key, opts) {
  if (!(this instanceof DB)) return new DB(storage, key, opts)
  events.EventEmitter.call(this)

  if (isOptions(key)) {
    opts = key
    key = null
  }

  if (!opts) opts = {}

  var self = this

  this.key = key ? toBuffer(key, 'hex') : null
  this.discoveryKey = null
  this.local = null
  this.source = null
  this.opened = false
  this.sparse = !!opts.sparse

  this._codec = opts.valueEncoding ? codecs(opts.valueEncoding) : null
  this._storage = typeof storage === 'string' ? fileStorage : storage
  this._map = opts.map || null
  this._reduce = opts.reduce || null
  this._writers = []
  this._lock = mutexify() // unneeded once we support batching
  this._localWriter = null
  this.setMaxListeners(0) // use ._streams array instead

  this.ready = thunky(open)
  this.ready(onready)

  function onready (err) {
    self.opened = !err
    if (err) self.emit('error', err)
    else self.emit('ready')
  }

  function open (cb) {
    self._open(cb)
  }

  function fileStorage (name) {
    return raf(name, {directory: storage})
  }
}

inherits(DB, events.EventEmitter)

DB.prototype.heads = function (cb) {
  var result = []
  var error = null
  var self = this
  var missing = 0
  var i = 0

  this.ready(onready)

  function onready (err) {
    if (err) return cb(err)

    for (; i < self._writers.length; i++) {
      missing++
      self._writers[i].head(onhead)
    }
  }

  function onhead (err, val, updated) {
    if (updated) onready(null)

    if (err) error = err
    else if (val) result[val.feed] = val
    if (--missing) return

    if (error) return cb(error)

    for (var i = 0; i < result.length; i++) {
      var head = result[i]
      if (!head) continue

      for (var j = 0; j < head.clock.length; j++) {
        if (result[j] && result[j].seq < head.clock[j]) result[j] = null
      }
    }

    cb(null, result.filter(Boolean))
  }
}

DB.prototype.authorize = function (key, cb) {
  this._createWriter(toBuffer(key, 'hex'))
  this.put('', '', cb)
}

DB.prototype.replicate = function (opts) {
  if (!protocol) protocol = require('hypercore-protocol')
  if (!opts) opts = {}

  var len = this._writers.length
  opts.expectedFeeds = len

  var self = this
  var stream = protocol(opts)

  opts.stream = stream

  this.ready(function (err) {
    if (err) return stream.destroy(err)
    if (stream.destroyed) return

    for (var i = 0; i < self._writers.length; i++) {
      self._writers[i].feed.replicate(opts)
    }

    self.on('_writer', onwriter)
    if (!self.sparse) {
      onappend()
      self.on('append', onappend)
    }

    stream.on('close', onclose)
    stream.on('end', onclose)

    function onclose () {
      self.removeListener('append', onappend)
      self.removeListener('_writer', onwriter)
    }

    function onappend () {
      // hack! make api in hypercore-protocol for this
      if (stream.destroyed) return
      stream.expectedFeeds += 1e9
      self._update(function () {
        stream.expectedFeeds -= 1e9
        stream.expectedFeeds += (self._writers.length - len)
        len = self._writers.length
        if (!stream.expectedFeeds) stream.finalize()
      })
    }

    function onwriter (w) {
      if (stream.destroyed) return
      w.feed.replicate(opts)
    }
  })

  return stream
}

DB.prototype.watch = function (key, onchange) {
  var self = this
  var prev = null

  update()
  this.on('append', update)

  return function unwatch () {
    onchange = noop
    self.removeListener('append', update)
  }

  function update () {
    self._closest(key, check)
  }

  function check (err, nodes) {
    if (err) return onchange(err)

    if (!prev) {
      prev = nodes
      return
    }

    var changed = nodes.length !== prev.length
    for (var i = 0; i < nodes.length && !changed; i++) {
      changed = nodes[i].feed !== prev[i].feed || nodes[i].seq !== prev[i].seq
    }

    prev = nodes
    if (changed) onchange(null)
  }
}

DB.prototype._closest = function (key, cb) {
  var nodes = []
  var len = hash(key).length

  this._get(key, null, onvisit, done)

  function onvisit (node, matchLength, head) {
    if (!head) return
    if (matchLength >= len && noDup(nodes, node)) {
      nodes.push(node)
    }
  }

  function done (err) {
    if (err) return cb(err)
    cb(null, nodes.sort(sortNodes))
  }
}

DB.prototype.put = function (key, value, cb) {
  var self = this

  this._lock(function (release) {
    self._put(key, value, function (err) {
      release(cb, err)
    })
  })
}

DB.prototype._put = function (key, value, cb) {
  if (!cb) cb = noop

  var self = this
  var path = hash(key, true)

  this.heads(function (err, heads) {
    if (err) return cb(err)

    if (!self._localWriter) self._localWriter = self._createWriter(self.local.key, 'local')

    var feed = self._localWriter.id
    var clock = []
    var i = 0

    for (i = 0; i < self._writers.length; i++) {
      clock.push(i === feed ? 0 : self._writers[i].feed.length)
    }

    var node = {
      seq: self._localWriter.feed.length,
      feed: feed,
      key: key,
      path: path,
      value: value,
      clock: clock,
      trie: []
    }

    if (!heads.length) {
      self._localWriter.append(node, ondone)
      return
    }

    var missing = heads.length
    var error = null

    for (i = 0; i < heads.length; i++) {
      self._visitPut(key, path, 0, 0, 0, heads[i], heads, node.trie, onput)
    }

    function onput (err) {
      if (err) error = err
      if (--missing) return

      if (error) return cb(err)

      self._localWriter.append(node, ondone)
    }

    function ondone (err) {
      if (err) return cb(err)
      return cb(null, self._map ? self._map(node) : node)
    }
  })
}

DB.prototype.path = function (key, cb) {
  var path = []
  this._get(key, null, onvisit, done)

  function onvisit (node) {
    path.push(node)
  }

  function done (err) {
    if (err) return cb(err)
    cb(null, path)
  }
}

DB.prototype.get = function (key, cb) {
  this._get(key, [], noop, cb)
}

DB.prototype._get = function (key, result, visit, cb) {
  var path = hash(key, true)
  var self = this

  this.heads(function (err, heads) {
    if (err) return cb(err)
    if (!heads.length) return cb(null, null)

    var missing = heads.length
    var error = null

    for (var i = 0; i < heads.length; i++) {
      self._visitGet(key, path, 0, heads[i], heads, result, visit, onget)
    }

    function onget (err) {
      if (err) error = err
      if (--missing) return
      if (error) return cb(error)

      if (!result || !result.length) return cb(null, null)

      if (self._map) result = result.map(self._map)
      if (self._reduce) result = result.reduce(self._reduce)

      cb(null, result)
    }
  })
}

DB.prototype._visitPut = function (key, path, i, j, k, node, heads, trie, cb) {
  var writers = this._writers
  var self = this
  var missing = 0
  var error = null
  var vals = null
  var remoteVals = null

  for (; i < path.length; i++) {
    var val = path[i]
    var local = trie[i]
    var remote = node.trie[i] || []

    // copy old trie
    for (; j < remote.length; j++) {
      if (j === val && val !== hash.TERMINATE) continue

      if (!local) local = trie[i] = []
      vals = local[j] = local[j] || []
      remoteVals = remote[j] || []

      for (; k < remoteVals.length; k++) {
        var rval = remoteVals[k]

        if (val === hash.TERMINATE) {
          writers[rval.feed].get(rval.seq, onfilterdups)
          return
        }

        if (noDup(vals, rval)) vals.push(rval)
      }
      k = 0
    }
    j = 0

    if (node.path[i] !== val || (node.path[i] === hash.TERMINATE && node.key !== key)) {
      // trie is splitting
      if (!local) local = trie[i] = []
      vals = local[node.path[i]] = local[node.path[i]] || []
      remoteVals = remote[val]
      vals.push({feed: node.feed, seq: node.seq})

      if (!remoteVals || !remoteVals.length) return cb(null)

      missing = remoteVals.length
      error = null

      for (var l = 0; l < remoteVals.length; l++) {
        writers[remoteVals[l].feed].get(remoteVals[l].seq, onremoteval)
      }
      return
    }
  }

  cb(null)

  function onfilterdups (err, val) {
    if (err) return cb(err)
    var valPointer = {feed: val.feed, seq: val.seq}
    if (val.key !== key && noDup(vals, valPointer)) vals.push(valPointer)
    self._visitPut(key, path, i, j, k + 1, node, heads, trie, cb)
  }

  function onremoteval (err, val) {
    if (err) return onvisit(err)
    if (!updateHead(val, node, heads)) return onvisit(null)
    self._visitPut(key, path, i + 1, j, k, val, heads, trie, onvisit)
  }

  function onvisit (err) {
    if (err) error = err
    if (!--missing) cb(error)
  }
}

DB.prototype._open = function (cb) {
  var self = this
  var source = this._createFeed(this.key, 'source')

  source.on('ready', function () {
    self.source = source
    self.key = source.key
    self.discoveryKey = source.discoveryKey

    var w = self._createWriter(self.key, 'source')

    if (source.writable) {
      self.local = source
      self._localWriter = w
      return self._update(cb)
    }

    var local = self._createFeed(null, 'local')

    local.on('ready', function () {
      self.local = local
      self._update(cb)
    })
  })
}

DB.prototype._update = function (cb) {
  if (!cb) cb = noop

  var self = this
  var missing = this._writers.length
  var error = null
  var i = 0

  for (; i < this._writers.length; i++) {
    this._writers[i].head(done)
  }

  function done (err, head, updated) {
    if (err) error = err

    if (updated) {
      for (; i < self._writers.length; i++) {
        missing++
        self._writers[i].head(done)
      }
    }
    if (!--missing) cb(error)
  }
}

DB.prototype._createFeed = function (key, dir) {
  if (!dir) {
    dir = key.toString('hex')
    dir = 'peers/' + dir.slice(0, 2) + '/' + dir.slice(2)
  }

  if (key) {
    if (this.local && this.local.key && this.local.key.equals(key)) return this.local
    if (this.source && this.source.key && this.source.key.equals(key)) return this.source
  }

  var self = this
  var feed = hypercore(storage, key, {sparse: this.sparse})

  feed.on('error', onerror)
  feed.on('append', onappend)

  return feed

  function onerror (err) {
    self.emit('error', err)
  }

  function onappend () {
    self.emit('append', this)
  }

  function storage (name) {
    return self._storage(dir + '/' + name)
  }
}

DB.prototype._createWriter = function (key, dir) {
  for (var i = 0; i < this._writers.length; i++) {
    var w = this._writers[i]
    if (key && w.key.equals(key)) return w
  }

  var res = writer(this, this._createFeed(key, dir), this._writers.length)

  this._writers.push(res)
  this.emit('_writer', res)

  return res
}

DB.prototype._visitGet = function (key, path, i, node, heads, result, onvisit, cb) {
  var self = this
  var writers = this._writers
  var missing = 0
  var error = null
  var trie = null
  var vals = null

  for (; i < path.length; i++) {
    if (node.path[i] === path[i]) continue
    onvisit(node, i, true)

    // check trie
    trie = node.trie[i]
    if (!trie) return cb(null)

    vals = trie[path[i]]

    // not found
    if (!vals || !vals.length) return cb(null)

    missing = vals.length
    error = null

    for (var j = 0; j < vals.length; j++) {
      writers[vals[j].feed].get(vals[j].seq, onval)
    }

    return
  }

  // check for collisions
  trie = node.trie[path.length - 1]
  vals = trie && trie[hash.TERMINATE]

  pushMaybe(key, node, result, onvisit)

  if (!vals || !vals.length) return cb(null)

  missing = vals.length
  error = null

  for (var k = 0; k < vals.length; k++) {
    writers[vals[k].feed].get(vals[k].seq, onpush)
  }

  function onpush (err, val) {
    if (err) error = err
    else pushMaybe(key, val, result, onvisit)
    if (!--missing) cb(error)
  }

  function onval (err, val) {
    if (err) return done(err)

    if (!updateHead(val, node, heads)) {
      onvisit(val, i, false)
      done(null)
      return
    }

    self._visitGet(key, path, i + 1, val, heads, result, onvisit, done)
  }

  function done (err) {
    if (err) error = err
    if (!--missing) cb(error)
  }
}

function noop () {}

function updateHead (newNode, oldNode, heads) {
  var i = heads.indexOf(oldNode)
  if (i !== -1) remove(heads, i)
  if (!isHead(newNode, heads)) return false
  heads.push(newNode)
  return true
}

function isHead (node, heads) {
  for (var i = 0; i < heads.length; i++) {
    var head = heads[i]
    if (head.feed === node.feed) return false
    if (node.seq < head.clock[node.feed]) return false
  }
  return true
}

function pushMaybe (key, node, results, onvisit) {
  onvisit(node, node.path.length, true)
  if (results && node.key === key && noDup(results, node)) results.push(node)
}

function noDup (list, val) {
  for (var i = 0; i < list.length; i++) {
    if (list[i].feed === val.feed && list[i].seq === val.seq) {
      return false
    }
  }
  return true
}

function isOptions (opts) {
  return !!(opts && typeof opts !== 'string' && !Buffer.isBuffer(opts))
}

function sortNodes (a, b) {
  if (a.feed === b.feed) return a.seq - b.seq
  return a.feed - b.feed
}
<|endoftext|>


<commit_before>/**
 * npm-clone <https://github.com/tunnckoCore/npm-clone>
 *
 * Copyright (c) 2015 Charlike Mike Reagent, contributors.
 * Released under the MIT license.
 */

'use strict';

var fs = require('fs');
var got = require('got');
var tar = require('tar-fs');
var path = require('path');
var zlib = require('zlib');
var format = require('util').format;
var JSONStream = require('JSONStream');
var parseSemver = require('parse-semver');
var registryUrl = require('registry-url');

module.exports = function npmClone(name) {
  var parts = name.split('/');
  var url = false;

  if (parts.length > 1) {
    name = parts[parts.length - 1];
    url = registryUrl(parts[0]);
  }

  url = url || registryUrl();
  parts = parseSemver(name);
  var _name = parts.name;
  var basename = format('%s-%s', _name, parts.version);
  url = format('%s%s', url, _name);

  if (parts.range !== '*') {

    // TODO: should this be moved to `parse-semver`?
    parts.version = parts.range.replace(/^[^0-9]+/, '').replace(/\s+.*$/, '');

    basename = format('%s-%s', _name, parts.version);
    url = format('%s%s/-/%s.tgz', url, _name, basename);

    var basename_tgz = path.join(__dirname, basename + '.tgz');
    var basename_tar = path.join(__dirname, basename + '.tar');

    got(url)
    .pipe(zlib.createGunzip())
    .pipe(tar.extract('./my-tagdfgdfgrball'));
    return;
  }

  // clone latest version
  // got(url + '/latest')

};
<commit_msg>cleanup<commit_after>/**
 * npm-clone <https://github.com/tunnckoCore/npm-clone>
 *
 * Copyright (c) 2015 Charlike Mike Reagent, contributors.
 * Released under the MIT license.
 */

'use strict';

var fs = require('fs');
var got = require('got');
var tar = require('tar-fs');
var path = require('path');
var zlib = require('zlib');
var format = require('util').format;
var JSONStream = require('JSONStream');
var parseSemver = require('parse-semver');
var registryUrl = require('registry-url');

module.exports = function npmClone(name) {
  var parts = name.split('/');
  var url = false;

  if (parts.length > 1) {
    name = parts[parts.length - 1];
    url = registryUrl(parts[0]);
  }

  url = url || registryUrl();
  parts = parseSemver(name);
  var _name = parts.name;
  var basename = format('%s-%s', _name, parts.version);
  url = format('%s%s', url, _name);

  if (parts.range !== '*') {

    // @todo should this be moved to `parse-semver`?
    parts.version = parts.range.replace(/^[^0-9]+/, '').replace(/\s+.*$/, '');

    basename = format('%s-%s', _name, parts.version);
    url = format('%s%s/-/%s.tgz', url, _name, basename);

    got(url)
    .pipe(zlib.createGunzip())
    .pipe(tar.extract(basename)); // @todo
    return;
  }

  // clone latest version
  // got(url + '/latest')

};
<|endoftext|>


<commit_before>// Karma configuration
// Generated on Mon Mar 20 2017 15:06:42 GMT+0100 (CET)

const webpackConfig = require('./webpack.test.config.js');

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
    ],

    plugins: [
      require('karma-webpack'),
      require('karma-coverage'),
      require('karma-chrome-launcher'),
      require('karma-jasmine')
    ],

    // list of files to exclude
    exclude: [
    ],

    webpack: webpackConfig,
    webpackServer: {
      noInfo: true
    },

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    mime: {
      'text/x-typescript': ['ts','tsx']
    },

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<commit_msg>chore: remove webpack, add rollup to test package<commit_after>// Karma configuration
// Generated on Mon Mar 20 2017 15:06:42 GMT+0100 (CET)

const nodeResolve = require('rollup-plugin-node-resolve');
const commonjs = require('rollup-plugin-commonjs');
const angular = require('rollup-plugin-angular');
const typescript = require('rollup-plugin-typescript');

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'test/*.ts',
      'src/*.spec.ts'
    ],

    plugins: [
      require('karma-coverage'),
      require('karma-chrome-launcher'),
      require('karma-rollup-plugin'),
      require('karma-jasmine')
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/*.ts': ['rollup'],
      'src/*.spec.ts': ['rollup']
    },

    rollupPreprocessor: {
      context: 'this',
      // will help to prevent conflicts between different tests entries
      moduleName: '@ngx-docs/material',
      format: 'iife',
      sourceMap: 'inline',
      // rollup settings. See Rollup documentation
      plugins: [
        angular(),
        typescript({
          typescript: require('./node_modules/typescript')
        }),
        commonjs(),
        nodeResolve({
          jsnext: true,
          browser: true,
          extensions: [ '.js', '.json', 'html']
        })
      ],
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    mime: {
      'text/x-typescript': ['ts','tsx']
    },

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<|endoftext|>