<commit_before>const { callEndpoint } = require('./callEndpoint');
const { forceArray, transformKey, transformObjectKeys } = require('./util/transformers');
const errors = require('./errors');

/**
 * remove a string pattern from a string
 *
 * @param {string} str string to remove pattern from
 * @param {string|regex} pattern pattern to remove
 * @return {string} string with the pattern removed
 */
const removeFromString = str => pattern => str.replace(pattern, '');

/**
 * Special key transformer for transformObjectKeys to strip "ns2:" from the beginning of keys,
 * such as 'ns2:ItemAttributes'
 *
 * @param {any} k
 */
const transformAttributeSetKey = k => transformKey(removeFromString(k)(/^ns2:/));

/**
 * Returns a list of products and their attributes, based on a list of ASIN, GCID, SellerSKU, UPC,
 * EAN, ISBN, or JAN values
 *
 * @param {Object} options see https://docs.developer.amazonservices.com/en_UK/products/Products_GetMatchingProductForId.html
 * @param {string} options.MarketplaceId Identifier for marketplace (see getMarketplaces)
 * @param {string} options.IdType Type of lookup to perform: ASIN, GCID, SellerSKU, UPC, EAN, ISBN, JAN
 * @param {string[]} options.IdList List of codes to perform lookup on
 * @public
 * @returns {Product[]}
 */
const getMatchingProductForId = async (options) => {
    const result = await callEndpoint('GetMatchingProductForId', options);
    if (result.Error) {
        throw new errors.ServiceError(result.Error.Message);
    }
    // for a single return, flattenResult will drop this to an object, which is not desireable
    // in this particular case.
    const products = forceArray(result);
    const ret = products.map((p) => {
        const type = String(p.$.IdType).toLowerCase();
        if (p.Error) {
            return { Error: p.Error, [`${type}`]: p.$.Id };
        }
        const { SalesRankings: rankings } = p.Products.Product;
        if (rankings && rankings.SalesRank) {
            // eslint-disable-next-line no-param-reassign
            p.Products.Product.SalesRankings.SalesRank = forceArray(rankings.SalesRank);
        }
        return {
            results: forceArray(transformObjectKeys(p.Products.Product, transformAttributeSetKey)),
            // results: p.Products.Product.map(x => {
            //     return {
            //         ...x,
            //         attributeSets: transformObjectKeys(x.AttributeSets, transformAttributeSetKey),
            //     };
            //     // console.warn("**************** x", x);
            //     // return x;
            // }),
            [`${type}`]: p.$.Id,
            idType: type,
            id: p.$.Id,
        };
    });
    return ret;
};

module.exports = {
    getMatchingProductForId,
};
<commit_msg>getMatchingProductForId: fix always return array for salesRanks<commit_after>const { callEndpoint } = require('./callEndpoint');
const { forceArray, transformKey, transformObjectKeys } = require('./util/transformers');
const errors = require('./errors');

/**
 * remove a string pattern from a string
 *
 * @param {string} str string to remove pattern from
 * @param {string|regex} pattern pattern to remove
 * @return {string} string with the pattern removed
 */
const removeFromString = str => pattern => str.replace(pattern, '');

/**
 * Special key transformer for transformObjectKeys to strip "ns2:" from the beginning of keys,
 * such as 'ns2:ItemAttributes'
 *
 * @param {any} k
 */
const transformAttributeSetKey = k => transformKey(removeFromString(k)(/^ns2:/));

/**
 * Returns a list of products and their attributes, based on a list of ASIN, GCID, SellerSKU, UPC,
 * EAN, ISBN, or JAN values
 *
 * @param {Object} options see https://docs.developer.amazonservices.com/en_UK/products/Products_GetMatchingProductForId.html
 * @param {string} options.MarketplaceId Identifier for marketplace (see getMarketplaces)
 * @param {string} options.IdType Type of lookup to perform: ASIN, GCID, SellerSKU, UPC, EAN, ISBN, JAN
 * @param {string[]} options.IdList List of codes to perform lookup on
 * @public
 * @returns {Product[]}
 */
const getMatchingProductForId = async (options) => {
    const result = await callEndpoint('GetMatchingProductForId', options);
    if (result.Error) {
        throw new errors.ServiceError(result.Error.Message);
    }
    // for a single return, flattenResult will drop this to an object, which is not desireable
    // in this particular case.
    const products = forceArray(result);
    const ret = products.map((p) => {
        const type = String(p.$.IdType).toLowerCase();
        if (p.Error) {
            return { Error: p.Error, [`${type}`]: p.$.Id };
        }
        const transformedResults = forceArray(transformObjectKeys(p.Products.Product, transformAttributeSetKey));
        const results = transformedResults.map((x) => {
            // eslint-disable-next-line no-param-reassign
            if (x.salesRankings.salesRank) x.salesRankings.salesRank = forceArray(x.salesRankings.salesRank);
            return x;
        });
        return {
            results,
            // results: p.Products.Product.map(x => {
            //     return {
            //         ...x,
            //         attributeSets: transformObjectKeys(x.AttributeSets, transformAttributeSetKey),
            //     };
            //     // console.warn("**************** x", x);
            //     // return x;
            // }),
            [`${type}`]: p.$.Id,
            idType: type,
            id: p.$.Id,
        };
    });
    return ret;
};

module.exports = {
    getMatchingProductForId,
};
<|endoftext|>


<commit_before>var value = true
  , unique = function(iset){
      var set = {}
        , i = 0
        , l = iset.length

      for(; i < l; i++) {
        set[iset[i]] = value
      }

      return set
  }

var Set = function(input){
  var set

  this.contains = function(prop){
    return !!set[prop]
  }

  this.empty = function(){
    return Object.keys(set).length == 0
  }

  this.size = function(){
    return Object.keys(set).length
  }

  this.get = function(){
    return Object.keys(set)
  }

  this.add = function(prop){
    set[prop] = value
  }

  this.remove = function(prop){
    delete set[prop]
  }

  this.union = function(iset){
    return new Set(this.get().concat(iset.get()))
  }

  this.intersect = function(iset){
    var items = iset.get()
      , i = 0
      , l = items.length
      , oset = new Set()
      , prop

    for(; i < l; i++){
      prop = items[i]
      if(this.contains(prop)){
        oset.add(prop)
      }
    }

    items = this.get()

    for(i = 0, l = items.length; i < l; i++){
      prop = items[i]
      if(iset.contains(prop)){
        oset.add(prop)
      }
    }

    return oset
  }

  this.difference = function(iset){
    var items = iset.get()
      , i = 0
      , l = items.length
      , oset = this.union(iset)
      , prop

    for(; i < l; i++){
      prop = items[i]
      if(this.contains(prop)){
        oset.remove(prop)
      }
    }

    return oset
  }

  this.subset = function(iset){
    var items = iset.get()
      , subset = false
      , i = 0
      , l = items.length

    for(; i < l; i++){
      prop = items[i]
      if(this.contains(prop)){
        subset = true
      }
      else{
        subset = false
        break
      }
    }

    return subset
  }

  this.find = function(pred){
    return this.get().filter(pred)
  }

  this.clear = function(){
    set = {}
  }

  set = unique(input || [])
}

Set.unique = function(iset){
  return Object.keys(unique(iset))
}

module.exports = Set;
<commit_msg>adapt for non-CommonJS browser environment<commit_after>var Set = function () {

var value = true
  , unique = function(iset){
      var set = {}
        , i = 0
        , l = iset.length

      for(; i < l; i++) {
        set[iset[i]] = value
      }

      return set
  }

var Set = function(input){
  var set

  this.contains = function(prop){
    return !!set[prop]
  }

  this.empty = function(){
    return Object.keys(set).length == 0
  }

  this.size = function(){
    return Object.keys(set).length
  }

  this.get = function(){
    return Object.keys(set)
  }

  this.add = function(prop){
    set[prop] = value
  }

  this.remove = function(prop){
    delete set[prop]
  }

  this.union = function(iset){
    return new Set(this.get().concat(iset.get()))
  }

  this.intersect = function(iset){
    var items = iset.get()
      , i = 0
      , l = items.length
      , oset = new Set()
      , prop

    for(; i < l; i++){
      prop = items[i]
      if(this.contains(prop)){
        oset.add(prop)
      }
    }

    items = this.get()

    for(i = 0, l = items.length; i < l; i++){
      prop = items[i]
      if(iset.contains(prop)){
        oset.add(prop)
      }
    }

    return oset
  }

  this.difference = function(iset){
    var items = iset.get()
      , i = 0
      , l = items.length
      , oset = this.union(iset)
      , prop

    for(; i < l; i++){
      prop = items[i]
      if(this.contains(prop)){
        oset.remove(prop)
      }
    }

    return oset
  }

  this.subset = function(iset){
    var items = iset.get()
      , subset = false
      , i = 0
      , l = items.length

    for(; i < l; i++){
      prop = items[i]
      if(this.contains(prop)){
        subset = true
      }
      else{
        subset = false
        break
      }
    }

    return subset
  }

  this.find = function(pred){
    return this.get().filter(pred)
  }

  this.clear = function(){
    set = {}
  }

  set = unique(input || [])
}

Set.unique = function(iset){
  return Object.keys(unique(iset))
}

return Set

}()

if(typeof module === 'object' && module.hasOwnProperty('exports')){
  module.exports = Set;
}
<|endoftext|>


<commit_before>const EventEmitter = require('events').EventEmitter;
const MultiStream = require('multistream');
const through = require('through2').obj;
const csw = require('csw-client');
const _ = require('lodash');
const stringify = require('json-stable-stringify');
const debug = require('debug')('geogw:csw-harvester');
const sha1 = require('../helpers/hash').sha1;

class Harvester extends EventEmitter {

    constructor(location, options) {
        if (!location) throw new Error('location param is required');
        options = options || {};

        super();

        this.matched = 0;
        this.failed = 0;
        this.started = 0;
        this.ignored = 0;
        this.unique = 0;

        const client = csw(location, {
            userAgent: 'InspireBot',
            concurrency: 5,
            encodeQs: options.encodeQs
        });

        debug('new harvester for location: %s', location);

        client.on('request', req => debug('request %s', req.url.href));

        const harvestOptions = {};

        if (options.forceConstraintLanguage) {
            harvestOptions.constraintLanguage = 'CQL_TEXT';
        }

        if (options.defineNamespace) {
            harvestOptions.namespace = 'xmlns(gmd=http://www.isotc211.org/2005/gmd)';
        }

        const internalHarvesters = [];

        const started = _.once(() => {
            this.emit('started');
        });

        const addHarvester = (harvester, name) => {
            harvester
                .once('started', () => {
                    this.started++;
                    this.matched += harvester.matched;
                    this.emit('internal-harvester:started', { name, matched: harvester.matched });
                    debug('started harvester %s', name);
                    started();
                    if (this.started === internalHarvesters.length) {
                        this.allStarted = true;
                        this.emit('all-started');
                    }
                })
                .once('failed', () => {
                    this.failed++;
                    this.emit('internal-harvester:failed', { name });
                    debug('harvester %s has failed', name);
                    if (this.failed === internalHarvesters.length) {
                        this.allFailed = true;
                        this.emit('all-failed');
                    }
                })
                .on('pageError', err => {
                    this.emit('internal-harvester:pageError', { name, err });
                });
            internalHarvesters.push(harvester);
        };

        addHarvester(client.harvest(Object.assign({ schema: 'inspire' }, harvestOptions)), 'inspire');

        if (options.dublinCoreFallback) {
            addHarvester(client.harvest(harvestOptions), 'dublin-core');
        }

        const recordIds = new Set();
        const ms = MultiStream(internalHarvesters, { objectMode: true });

        this.innerStream = ms.pipe(through((record, enc, cb) => {
            const ignore = (reason) => {
                record.ignoreReason = reason;
                this.ignored++;
                this.emit('ignore', record);
                cb();
            };

            const supportedTypes = {
                MD_Metadata: { modifiedKey: 'dateStamp', idKey: 'fileIdentifier' },
                Record: { modifiedKey: 'modified', idKey: 'identifier' }
            };

            if (!(record.type in supportedTypes)) return ignore('Not supported type');

            const typeOptions = supportedTypes[record.type];

            record.id = record.body[typeOptions.idKey];

            // Technical checks
            if (!record.id) return ignore('No identifier');
            if (record.id.length < 10) return ignore('Identifier too short');
            if (record.id.length > 255) return ignore('Identifier too long');
            if (recordIds.has(record.id)) return ignore('Record already seen');

            // Augment record meta
            record.hashedId = sha1(record.id);
            record.hash = sha1(stringify(_.omit(record.body, typeOptions.modifiedKey)));
            if (_.isDate(record.body[typeOptions.modifiedKey])) {
                record.modified = record.body[typeOptions.modifiedKey];
            }

            recordIds.add(record.id);
            this.unique++;
            cb(null, record);
        }));

        ms.on('error', err => this.emit('error', err));

        this.innerStream.on('end', () => recordIds.clear());
    }

    pipe(target) {
        return this.innerStream.pipe(target);
    }

    unpipe(target) {
        return this.innerStream.unpipe(target);
    }

}

exports.Harvester = Harvester;
<commit_msg>Enforce date checking<commit_after>const EventEmitter = require('events').EventEmitter;
const MultiStream = require('multistream');
const through = require('through2').obj;
const csw = require('csw-client');
const _ = require('lodash');
const stringify = require('json-stable-stringify');
const debug = require('debug')('geogw:csw-harvester');
const sha1 = require('../helpers/hash').sha1;
const moment = require('moment');

class Harvester extends EventEmitter {

    constructor(location, options) {
        if (!location) throw new Error('location param is required');
        options = options || {};

        super();

        this.matched = 0;
        this.failed = 0;
        this.started = 0;
        this.ignored = 0;
        this.unique = 0;

        const client = csw(location, {
            userAgent: 'InspireBot',
            concurrency: 5,
            encodeQs: options.encodeQs
        });

        debug('new harvester for location: %s', location);

        client.on('request', req => debug('request %s', req.url.href));

        const harvestOptions = {};

        if (options.forceConstraintLanguage) {
            harvestOptions.constraintLanguage = 'CQL_TEXT';
        }

        if (options.defineNamespace) {
            harvestOptions.namespace = 'xmlns(gmd=http://www.isotc211.org/2005/gmd)';
        }

        const internalHarvesters = [];

        const started = _.once(() => {
            this.emit('started');
        });

        const addHarvester = (harvester, name) => {
            harvester
                .once('started', () => {
                    this.started++;
                    this.matched += harvester.matched;
                    this.emit('internal-harvester:started', { name, matched: harvester.matched });
                    debug('started harvester %s', name);
                    started();
                    if (this.started === internalHarvesters.length) {
                        this.allStarted = true;
                        this.emit('all-started');
                    }
                })
                .once('failed', () => {
                    this.failed++;
                    this.emit('internal-harvester:failed', { name });
                    debug('harvester %s has failed', name);
                    if (this.failed === internalHarvesters.length) {
                        this.allFailed = true;
                        this.emit('all-failed');
                    }
                })
                .on('pageError', err => {
                    this.emit('internal-harvester:pageError', { name, err });
                });
            internalHarvesters.push(harvester);
        };

        addHarvester(client.harvest(Object.assign({ schema: 'inspire' }, harvestOptions)), 'inspire');

        if (options.dublinCoreFallback) {
            addHarvester(client.harvest(harvestOptions), 'dublin-core');
        }

        const recordIds = new Set();
        const ms = MultiStream(internalHarvesters, { objectMode: true });

        this.innerStream = ms.pipe(through((record, enc, cb) => {
            const ignore = (reason) => {
                record.ignoreReason = reason;
                this.ignored++;
                this.emit('ignore', record);
                cb();
            };

            const supportedTypes = {
                MD_Metadata: { modifiedKey: 'dateStamp', idKey: 'fileIdentifier' },
                Record: { modifiedKey: 'modified', idKey: 'identifier' }
            };

            if (!(record.type in supportedTypes)) return ignore('Not supported type');

            const typeOptions = supportedTypes[record.type];

            record.id = record.body[typeOptions.idKey];

            // Technical checks
            if (!record.id) return ignore('No identifier');
            if (record.id.length < 10) return ignore('Identifier too short');
            if (record.id.length > 255) return ignore('Identifier too long');
            if (recordIds.has(record.id)) return ignore('Record already seen');

            // Augment record meta
            record.hashedId = sha1(record.id);
            record.hash = sha1(stringify(_.omit(record.body, typeOptions.modifiedKey)));

            function getValidDate(date) {
              if (!date) return;
              const parsedValue = moment(date, moment.ISO_8601);
              if (parsedValue.isValid()) return parsedValue.toDate();
            }

            const modified = getValidDate(record.body[typeOptions.modifiedKey]);
            if (modified) record.modified = modified;

            recordIds.add(record.id);
            this.unique++;
            cb(null, record);
        }));

        ms.on('error', err => this.emit('error', err));

        this.innerStream.on('end', () => recordIds.clear());
    }

    pipe(target) {
        return this.innerStream.pipe(target);
    }

    unpipe(target) {
        return this.innerStream.unpipe(target);
    }

}

exports.Harvester = Harvester;
<|endoftext|>


<commit_before>// This is essentially a webpack-based compiler for
// index-static.jsx. Much of the code is largely
// based on James Long's "Backend Apps With Webpack"
// series of blog posts:
//
// http://jlongster.com/Backend-Apps-with-Webpack--Part-I
//
// Doing this allows us to use the same build toolchain
// for node and the browser, and also increases
// responsiveness during development via hot-loading.

var fs = require('fs');
var path = require('path');
var webpack = require('webpack');

function IndexStaticWatcher(options) {
  var self = {};
  var nodeModules = {};
  var outputDir = options.outputDir;
  var outputFilename = 'index-static.bundle.js';
  var indexStatic = null;

  // We want to make sure that npm modules aren't bundled;
  // we're only interested in bundling our own first-party
  // code.
  fs.readdirSync(options.nodeModulesDir)
    .filter(function(x) {
      return ['.bin'].indexOf(x) === -1;
    })
    .concat(options.externalModules || [])
    .forEach(function(mod) {
      nodeModules[mod] = 'commonjs ' + mod;
    });

  var compiler = webpack({
    entry: path.join(__dirname, 'index-static.jsx'),
    target: 'node',
    devtool: 'sourcemap',
    externals: nodeModules,
    module: {
      loaders: [
        { test: /\.jsx$/, loader: 'jsx-loader' }
      ]
    },
    plugins: [
      new webpack.BannerPlugin('require("source-map-support").install();',
                               { raw: true, entryOnly: false })
    ],
    output: {
      library: 'yup', // Actual value isn't used, just needs to be a string.
      libraryTarget: 'commonjs2',
      path: outputDir,
      filename: outputFilename
    }
  });

  var onBuild = function(successCb, failureCb, err, stats) {
    failureCb = failureCb || function() {};
    if (err) {
      console.log('Fatal error while compiling ' + outputFilename, err);
      return failureCb();
    }
    var jsonStats = stats.toJson();
    var hasErrors = jsonStats.errors.length > 0;
    if (hasErrors) {
      console.log(stats.toString({ colors: true }));
    }
    if (jsonStats.warnings.length > 0) {
      console.log(stats.toString({ colors: true }));
    }
    if (hasErrors) {
      failureCb();
    } else {
      var filename = path.join(outputDir, outputFilename);

      // webpack's hot-loading infrastructure is actually
      // a bit overkill for our needs; since anything
      // that's changed during development is in our
      // single bundle file, and since our static site
      // building process is stateless, we can just
      // delete our bundle from the require cache and
      // re-require it.

      delete require.cache[filename];

      indexStatic = require(filename);
      successCb(indexStatic);
    }
  };

  self.build = function(cb) {
    var success = function() {
      cb(null, indexStatic);
    };
    if (indexStatic) {
      return process.nextTick(success);
    }
    compiler.run(onBuild.bind(null, success, function failure() {
      cb(new Error('building ' + outputFilename + ' failed'));
    }));
  };

  self.watch = function(delay, successCb) {
    compiler.watch(delay, onBuild.bind(null, successCb, null));
  };

  return self;
}

IndexStaticWatcher.create = function() {
  var ROOT_DIR = path.normalize(path.join(__dirname, '..'));

  return IndexStaticWatcher({
    nodeModulesDir: path.join(ROOT_DIR, 'node_modules'),
    outputDir: path.join(ROOT_DIR, 'dist', 'index-static'),
    externalModules: [
      // Unfortunately, scanning through node_modules won't
      // catch require()'s of npm submodules, so we need
      // to include those manually.
      'react/addons'
    ]
  });
};

module.exports = IndexStaticWatcher;
<commit_msg>don't compile the same webpack bundle simultaneously.<commit_after>// This is essentially a webpack-based compiler for
// index-static.jsx. Much of the code is largely
// based on James Long's "Backend Apps With Webpack"
// series of blog posts:
//
// http://jlongster.com/Backend-Apps-with-Webpack--Part-I
//
// Doing this allows us to use the same build toolchain
// for node and the browser, and also increases
// responsiveness during development via hot-loading.

var fs = require('fs');
var path = require('path');
var webpack = require('webpack');

function IndexStaticWatcher(options) {
  var self = {};
  var nodeModules = {};
  var outputDir = options.outputDir;
  var outputFilename = 'index-static.bundle.js';
  var indexStatic = null;
  var buildInProgress = false;

  // We want to make sure that npm modules aren't bundled;
  // we're only interested in bundling our own first-party
  // code.
  fs.readdirSync(options.nodeModulesDir)
    .filter(function(x) {
      return ['.bin'].indexOf(x) === -1;
    })
    .concat(options.externalModules || [])
    .forEach(function(mod) {
      nodeModules[mod] = 'commonjs ' + mod;
    });

  var compiler = webpack({
    entry: path.join(__dirname, 'index-static.jsx'),
    target: 'node',
    devtool: 'sourcemap',
    externals: nodeModules,
    module: {
      loaders: [
        { test: /\.jsx$/, loader: 'jsx-loader' }
      ]
    },
    plugins: [
      new webpack.BannerPlugin('require("source-map-support").install();',
                               { raw: true, entryOnly: false })
    ],
    output: {
      library: 'yup', // Actual value isn't used, just needs to be a string.
      libraryTarget: 'commonjs2',
      path: outputDir,
      filename: outputFilename
    }
  });

  var onBuild = function(successCb, failureCb, err, stats) {
    failureCb = failureCb || function() {};
    if (err) {
      console.log('Fatal error while compiling ' + outputFilename, err);
      return failureCb();
    }
    var jsonStats = stats.toJson();
    var hasErrors = jsonStats.errors.length > 0;
    if (hasErrors) {
      console.log(stats.toString({ colors: true }));
    }
    if (jsonStats.warnings.length > 0) {
      console.log(stats.toString({ colors: true }));
    }
    if (hasErrors) {
      failureCb();
    } else {
      var filename = path.join(outputDir, outputFilename);

      // webpack's hot-loading infrastructure is actually
      // a bit overkill for our needs; since anything
      // that's changed during development is in our
      // single bundle file, and since our static site
      // building process is stateless, we can just
      // delete our bundle from the require cache and
      // re-require it.

      delete require.cache[filename];

      indexStatic = require(filename);
      successCb(indexStatic);
    }
  };

  self.build = function(cb) {
    var success = function() {
      buildInProgress = false;
      cb(null, indexStatic);
    };
    if (indexStatic) {
      return process.nextTick(success);
    } else if (buildInProgress) {
      return setTimeout(self.build.bind(null, cb), 100);
    }
    buildInProgress = true;
    compiler.run(onBuild.bind(null, success, function failure() {
      buildInProgress = false;
      cb(new Error('building ' + outputFilename + ' failed'));
    }));
  };

  self.watch = function(delay, successCb) {
    compiler.watch(delay, onBuild.bind(null, successCb, null));
  };

  return self;
}

IndexStaticWatcher.create = function() {
  var ROOT_DIR = path.normalize(path.join(__dirname, '..'));

  return IndexStaticWatcher({
    nodeModulesDir: path.join(ROOT_DIR, 'node_modules'),
    outputDir: path.join(ROOT_DIR, 'dist', 'index-static'),
    externalModules: [
      // Unfortunately, scanning through node_modules won't
      // catch require()'s of npm submodules, so we need
      // to include those manually.
      'react/addons'
    ]
  });
};

module.exports = IndexStaticWatcher;
<|endoftext|>


<commit_before>/**global angular,markdownit */
(function(factory) {
  /* istanbul ignore if */
  if (typeof module === 'object' && typeof module.exports === 'object') {
    module.exports = factory(require('angular'), require('markdown-it'));
  } else {
    factory(angular, markdownit);
  }
})(function(angular, markdownit) {
  'use strict';

  function markdownItProvider() {

    var options = {};
    var presetName = 'default';

    return {
      config: function(preset, opts) {
        // fizzbuzz anyone?
        if (angular.isString(preset) && angular.isObject(opts)) {
          presetName = preset;
          options = opts;
        } else if (angular.isString(preset)) {
          presetName = preset;
        } else if (angular.isObject(preset)) {
          options = preset;
        }
      },
      $get: function() {
        return markdownit(presetName, options);
      }
    };
  }

  function markdownItDirective($sanitize, markdownIt) {

    var attribute = 'markdownIt';

    var render = function(value) {
      return value ? $sanitize(markdownIt.render(value)) : '';
    };

    var link = function(scope, element, attrs) {
      if (attrs[attribute]) {
        scope.$watch(attribute, function(value) {
          element.html(render(value));
        });
      } else {
        element.html(render(element.text()));
      }
    };

    return {
      restrict: 'AE',
      scope: {
        markdownIt: '='
      },
      replace: true,
      link: link
    };
  }

  angular.module('mdMarkdownIt', ['ngSanitize'])
    .provider('markdownItConverter', markdownItProvider)
    .directive('markdownIt', ['$sanitize', 'markdownItConverter', markdownItDirective]);

});
<commit_msg>test: really ignore common-js detection in test coverage<commit_after>/**global angular,markdownit */
(function(factory) {
  /* istanbul ignore next */
  if (typeof module === 'object' && typeof module.exports === 'object') {
    module.exports = factory(require('angular'), require('markdown-it'));
  } else {
    factory(angular, markdownit);
  }
})(function(angular, markdownit) {
  'use strict';

  function markdownItProvider() {

    var options = {};
    var presetName = 'default';

    return {
      config: function(preset, opts) {
        // fizzbuzz anyone?
        if (angular.isString(preset) && angular.isObject(opts)) {
          presetName = preset;
          options = opts;
        } else if (angular.isString(preset)) {
          presetName = preset;
        } else if (angular.isObject(preset)) {
          options = preset;
        }
      },
      $get: function() {
        return markdownit(presetName, options);
      }
    };
  }

  function markdownItDirective($sanitize, markdownIt) {

    var attribute = 'markdownIt';

    var render = function(value) {
      return value ? $sanitize(markdownIt.render(value)) : '';
    };

    var link = function(scope, element, attrs) {
      if (attrs[attribute]) {
        scope.$watch(attribute, function(value) {
          element.html(render(value));
        });
      } else {
        element.html(render(element.text()));
      }
    };

    return {
      restrict: 'AE',
      scope: {
        markdownIt: '='
      },
      replace: true,
      link: link
    };
  }

  angular.module('mdMarkdownIt', ['ngSanitize'])
    .provider('markdownItConverter', markdownItProvider)
    .directive('markdownIt', ['$sanitize', 'markdownItConverter', markdownItDirective]);

});
<|endoftext|>


<commit_before>import { AmbientLight, DirectionalLight, Vector3 } from 'three';

const three = window.THREE
  ? window.THREE // Prefer consumption from global THREE, if exists
  : { AmbientLight, DirectionalLight, Vector3 };

import { DragControls as ThreeDragControls } from 'three/examples/jsm/controls/DragControls.js';

import ThreeForceGraph from 'three-forcegraph';
import ThreeRenderObjects from 'three-render-objects';

import accessorFn from 'accessor-fn';
import Kapsule from 'kapsule';

import linkKapsule from './kapsule-link.js';

//

const CAMERA_DISTANCE2NODES_FACTOR = 170;

//

// Expose config from forceGraph
const bindFG = linkKapsule('forceGraph', ThreeForceGraph);
const linkedFGProps = Object.assign(...[
  'jsonUrl',
  'graphData',
  'numDimensions',
  'dagMode',
  'dagLevelDistance',
  'dagNodeFilter',
  'onDagError',
  'nodeRelSize',
  'nodeId',
  'nodeVal',
  'nodeResolution',
  'nodeColor',
  'nodeAutoColorBy',
  'nodeOpacity',
  'nodeVisibility',
  'nodeThreeObject',
  'nodeThreeObjectExtend',
  'linkSource',
  'linkTarget',
  'linkVisibility',
  'linkColor',
  'linkAutoColorBy',
  'linkOpacity',
  'linkWidth',
  'linkResolution',
  'linkCurvature',
  'linkCurveRotation',
  'linkMaterial',
  'linkThreeObject',
  'linkThreeObjectExtend',
  'linkPositionUpdate',
  'linkDirectionalArrowLength',
  'linkDirectionalArrowColor',
  'linkDirectionalArrowRelPos',
  'linkDirectionalArrowResolution',
  'linkDirectionalParticles',
  'linkDirectionalParticleSpeed',
  'linkDirectionalParticleWidth',
  'linkDirectionalParticleColor',
  'linkDirectionalParticleResolution',
  'forceEngine',
  'd3AlphaDecay',
  'd3VelocityDecay',
  'd3AlphaMin',
  'ngraphPhysics',
  'warmupTicks',
  'cooldownTicks',
  'cooldownTime',
  'onEngineTick',
  'onEngineStop'
].map(p => ({ [p]: bindFG.linkProp(p)})));
const linkedFGMethods = Object.assign(...[
  'refresh',
  'getGraphBbox',
  'd3Force',
  'd3ReheatSimulation',
  'emitParticle'
].map(p => ({ [p]: bindFG.linkMethod(p)})));

// Expose config from renderObjs
const bindRenderObjs = linkKapsule('renderObjs', ThreeRenderObjects);
const linkedRenderObjsProps = Object.assign(...[
  'width',
  'height',
  'backgroundColor',
  'showNavInfo',
  'enablePointerInteraction'
].map(p => ({ [p]: bindRenderObjs.linkProp(p)})));
const linkedRenderObjsMethods = Object.assign(
  ...[
    'cameraPosition',
    'postProcessingComposer'
  ].map(p => ({ [p]: bindRenderObjs.linkMethod(p)})),
  {
    graph2ScreenCoords: bindRenderObjs.linkMethod('getScreenCoords'),
    screen2GraphCoords: bindRenderObjs.linkMethod('getSceneCoords')
  }
);

//

export default Kapsule({

  props: {
    nodeLabel: { default: 'name', triggerUpdate: false },
    linkLabel: { default: 'name', triggerUpdate: false },
    linkHoverPrecision: { default: 1, onChange: (p, state) => state.renderObjs.lineHoverPrecision(p), triggerUpdate: false },
    enableNavigationControls: {
      default: true,
      onChange(enable, state) {
        const controls = state.renderObjs.controls();
        if (controls) {
          controls.enabled = enable;
        }
      },
      triggerUpdate: false
    },
    enableNodeDrag: { default: true, triggerUpdate: false },
    onNodeDrag: { default: () => {}, triggerUpdate: false },
    onNodeDragEnd: { default: () => {}, triggerUpdate: false },
    onNodeClick: { triggerUpdate: false },
    onNodeRightClick: { triggerUpdate: false },
    onNodeHover: { triggerUpdate: false },
    onLinkClick: { triggerUpdate: false },
    onLinkRightClick: { triggerUpdate: false },
    onLinkHover: { triggerUpdate: false },
    onBackgroundClick: { triggerUpdate: false },
    onBackgroundRightClick: { triggerUpdate: false },
    ...linkedFGProps,
    ...linkedRenderObjsProps
  },

  methods: {
    zoomToFit: function(state, transitionDuration, padding, ...bboxArgs) {
      state.renderObjs.fitToBbox(
        state.forceGraph.getGraphBbox(...bboxArgs),
        transitionDuration,
        padding
      );
      return this;
    },
    pauseAnimation: function(state) {
      if (state.animationFrameRequestId !== null) {
        cancelAnimationFrame(state.animationFrameRequestId);
        state.animationFrameRequestId = null;
      }
      return this;
    },

    resumeAnimation: function(state) {
      if (state.animationFrameRequestId === null) {
        this._animationCycle();
      }
      return this;
    },
    _animationCycle(state) {
      if (state.enablePointerInteraction) {
        // reset canvas cursor (override dragControls cursor)
        this.renderer().domElement.style.cursor = null;
      }

      // Frame cycle
      state.forceGraph.tickFrame();
      state.renderObjs.tick();
      state.animationFrameRequestId = requestAnimationFrame(this._animationCycle);
    },
    scene: state => state.renderObjs.scene(), // Expose scene
    camera: state => state.renderObjs.camera(), // Expose camera
    renderer: state => state.renderObjs.renderer(), // Expose renderer
    controls: state => state.renderObjs.controls(), // Expose controls
    tbControls: state => state.renderObjs.tbControls(), // To be deprecated
    _destructor: function() {
      this.pauseAnimation();
      this.graphData({ nodes: [], links: []});
    },
    ...linkedFGMethods,
    ...linkedRenderObjsMethods
  },

  stateInit: ({ controlType, rendererConfig, extraRenderers }) => ({
    forceGraph: new ThreeForceGraph(),
    renderObjs: ThreeRenderObjects({ controlType, rendererConfig, extraRenderers })
  }),

  init: function(domNode, state) {
    // Wipe DOM
    domNode.innerHTML = '';

    // Add relative container
    domNode.appendChild(state.container = document.createElement('div'));
    state.container.style.position = 'relative';

    // Add renderObjs
    const roDomNode = document.createElement('div');
    state.container.appendChild(roDomNode);
    state.renderObjs(roDomNode);
    const camera = state.renderObjs.camera();
    const renderer = state.renderObjs.renderer();
    const controls = state.renderObjs.controls();
    controls.enabled = !!state.enableNavigationControls;
    state.lastSetCameraZ = camera.position.z;

    // Add info space
    let infoElem;
    state.container.appendChild(infoElem = document.createElement('div'));
    infoElem.className = 'graph-info-msg';
    infoElem.textContent = '';

    // config forcegraph
    state.forceGraph
      .onLoading(() => { infoElem.textContent = 'Loading...' })
      .onFinishLoading(() => { infoElem.textContent = '' })
      .onUpdate(() => {
        // sync graph data structures
        state.graphData = state.forceGraph.graphData();

        // re-aim camera, if still in default position (not user modified)
        if (camera.position.x === 0 && camera.position.y === 0 && camera.position.z === state.lastSetCameraZ && state.graphData.nodes.length) {
          camera.lookAt(state.forceGraph.position);
          state.lastSetCameraZ = camera.position.z = Math.cbrt(state.graphData.nodes.length) * CAMERA_DISTANCE2NODES_FACTOR;
        }
      })
      .onFinishUpdate(() => {
        // Setup node drag interaction
        if (state._dragControls) {
          const curNodeDrag = state.graphData.nodes.find(node => node.__initialFixedPos && !node.__disposeControlsAfterDrag); // detect if there's a node being dragged using the existing drag controls
          if (curNodeDrag) {
            curNodeDrag.__disposeControlsAfterDrag = true; // postpone previous controls disposal until drag ends
          } else {
            state._dragControls.dispose(); // cancel previous drag controls
          }

          state._dragControls = undefined;
        }

        if (state.enableNodeDrag && state.enablePointerInteraction && state.forceEngine === 'd3') { // Can't access node positions programatically in ngraph
          const dragControls = state._dragControls = new ThreeDragControls(
            state.graphData.nodes.map(node => node.__threeObj).filter(obj => obj),
            camera,
            renderer.domElement
          );

          dragControls.addEventListener('dragstart', function (event) {
            controls.enabled = false; // Disable controls while dragging

            // track drag object movement
            event.object.__initialPos = event.object.position.clone();
            event.object.__prevPos = event.object.position.clone();

            const node = getGraphObj(event.object).__data;
            !node.__initialFixedPos && (node.__initialFixedPos = {fx: node.fx, fy: node.fy, fz: node.fz});
            !node.__initialPos && (node.__initialPos = {x: node.x, y: node.y, z: node.z});

            // lock node
            ['x', 'y', 'z'].forEach(c => node[`f${c}`] = node[c]);

            // drag cursor
            renderer.domElement.classList.add('grabbable');
          });

          dragControls.addEventListener('drag', function (event) {
            const nodeObj = getGraphObj(event.object);

            if (!event.object.hasOwnProperty('__graphObjType')) {
              // If dragging a child of the node, update the node object instead
              const initPos = event.object.__initialPos;
              const prevPos = event.object.__prevPos;
              const newPos = event.object.position;

              nodeObj.position.add(newPos.clone().sub(prevPos)); // translate node object by the motion delta
              prevPos.copy(newPos);
              newPos.copy(initPos); // reset child back to its initial position
            }

            const node = nodeObj.__data;
            const newPos = nodeObj.position;
            const translate = {x: newPos.x - node.x, y: newPos.y - node.y, z: newPos.z - node.z};
            // Move fx/fy/fz (and x/y/z) of nodes based on object new position
            ['x', 'y', 'z'].forEach(c => node[`f${c}`] = node[c] = newPos[c]);

            state.forceGraph
              .d3AlphaTarget(0.3) // keep engine running at low intensity throughout drag
              .resetCountdown();  // prevent freeze while dragging

            node.__dragged = true;
            state.onNodeDrag(node, translate);
          });

          dragControls.addEventListener('dragend', function (event) {
            delete(event.object.__initialPos); // remove tracking attributes
            delete(event.object.__prevPos);

            const node = getGraphObj(event.object).__data;

            // dispose previous controls if needed
            if (node.__disposeControlsAfterDrag) {
              dragControls.dispose();
              delete(node.__disposeControlsAfterDrag);
            }

            const initFixedPos = node.__initialFixedPos;
            const initPos = node.__initialPos;
            const translate = {x: initPos.x - node.x, y: initPos.y - node.y, z: initPos.z - node.z};
            if (initFixedPos) {
              ['x', 'y', 'z'].forEach(c => {
                const fc = `f${c}`;
                if (initFixedPos[fc] === undefined) {
                  delete(node[fc])
                }
              });
              delete(node.__initialFixedPos);
              delete(node.__initialPos);
              if (node.__dragged) {
                delete(node.__dragged);
                state.onNodeDragEnd(node, translate);
              }
            }

            state.forceGraph
              .d3AlphaTarget(0)   // release engine low intensity
              .resetCountdown();  // let the engine readjust after releasing fixed nodes

            if (state.enableNavigationControls) {
              controls.enabled = true; // Re-enable controls
              controls.domElement && controls.domElement.ownerDocument && controls.domElement.ownerDocument.dispatchEvent(
                // simulate mouseup to ensure the controls don't take over after dragend
                new PointerEvent('pointerup', { pointerType: 'mouse' })
              );
            }

            // clear cursor
            renderer.domElement.classList.remove('grabbable');
          });
        }
      });

    // config renderObjs
    state.renderObjs
      .objects([ // Populate scene
        new three.AmbientLight(0xbbbbbb),
        new three.DirectionalLight(0xffffff, 0.6),
        state.forceGraph
      ])
      .hoverOrderComparator((a, b) => {
        // Prioritize graph objects
        const aObj = getGraphObj(a);
        if (!aObj) return 1;
        const bObj = getGraphObj(b);
        if (!bObj) return -1;

        // Prioritize nodes over links
        const isNode = o => o.__graphObjType === 'node';
        return isNode(bObj) - isNode(aObj);
      })
      .tooltipContent(obj => {
        const graphObj = getGraphObj(obj);
        return graphObj ? accessorFn(state[`${graphObj.__graphObjType}Label`])(graphObj.__data) || '' : '';
      })
      .hoverDuringDrag(false)
      .onHover(obj => {
        // Update tooltip and trigger onHover events
        const hoverObj = getGraphObj(obj);

        if (hoverObj !== state.hoverObj) {
          const prevObjType = state.hoverObj ? state.hoverObj.__graphObjType : null;
          const prevObjData = state.hoverObj ? state.hoverObj.__data : null;
          const objType = hoverObj ? hoverObj.__graphObjType : null;
          const objData = hoverObj ? hoverObj.__data : null;
          if (prevObjType && prevObjType !== objType) {
            // Hover out
            const fn = state[`on${prevObjType === 'node' ? 'Node' : 'Link'}Hover`];
            fn && fn(null, prevObjData);
          }
          if (objType) {
            // Hover in
            const fn = state[`on${objType === 'node' ? 'Node' : 'Link'}Hover`];
            fn && fn(objData, prevObjType === objType ? prevObjData : null);
          }

          // set pointer if hovered object is clickable
          renderer.domElement.classList[
            ((obj && state[`on${objType === 'node' ? 'Node' : 'Link'}Click`]) || (!obj && state.onBackgroundClick)) ? 'add' : 'remove'
          ]('clickable');

          state.hoverObj = hoverObj;
        }
      })
      .clickAfterDrag(false)
      .onClick((obj, ev) => {
        const graphObj = getGraphObj(obj);
        if (graphObj) {
          const fn = state[`on${graphObj.__graphObjType === 'node' ? 'Node' : 'Link'}Click`];
          fn && fn(graphObj.__data, ev);
        } else {
          state.onBackgroundClick && state.onBackgroundClick(ev);
        }
      })
      .onRightClick((obj, ev) => {
        // Handle right-click events
        const graphObj = getGraphObj(obj);
        if (graphObj) {
          const fn = state[`on${graphObj.__graphObjType === 'node' ? 'Node' : 'Link'}RightClick`];
          fn && fn(graphObj.__data, ev);
        } else {
          state.onBackgroundRightClick && state.onBackgroundRightClick(ev);
        }
      });

    //

    // Kick-off renderer
    this._animationCycle();
  }
});

//

function getGraphObj(object) {
  let obj = object;
  // recurse up object chain until finding the graph object
  while (obj && !obj.hasOwnProperty('__graphObjType')) {
    obj = obj.parent;
  }
  return obj;
}
<commit_msg>Fix pointer cursor condition<commit_after>import { AmbientLight, DirectionalLight, Vector3 } from 'three';

const three = window.THREE
  ? window.THREE // Prefer consumption from global THREE, if exists
  : { AmbientLight, DirectionalLight, Vector3 };

import { DragControls as ThreeDragControls } from 'three/examples/jsm/controls/DragControls.js';

import ThreeForceGraph from 'three-forcegraph';
import ThreeRenderObjects from 'three-render-objects';

import accessorFn from 'accessor-fn';
import Kapsule from 'kapsule';

import linkKapsule from './kapsule-link.js';

//

const CAMERA_DISTANCE2NODES_FACTOR = 170;

//

// Expose config from forceGraph
const bindFG = linkKapsule('forceGraph', ThreeForceGraph);
const linkedFGProps = Object.assign(...[
  'jsonUrl',
  'graphData',
  'numDimensions',
  'dagMode',
  'dagLevelDistance',
  'dagNodeFilter',
  'onDagError',
  'nodeRelSize',
  'nodeId',
  'nodeVal',
  'nodeResolution',
  'nodeColor',
  'nodeAutoColorBy',
  'nodeOpacity',
  'nodeVisibility',
  'nodeThreeObject',
  'nodeThreeObjectExtend',
  'linkSource',
  'linkTarget',
  'linkVisibility',
  'linkColor',
  'linkAutoColorBy',
  'linkOpacity',
  'linkWidth',
  'linkResolution',
  'linkCurvature',
  'linkCurveRotation',
  'linkMaterial',
  'linkThreeObject',
  'linkThreeObjectExtend',
  'linkPositionUpdate',
  'linkDirectionalArrowLength',
  'linkDirectionalArrowColor',
  'linkDirectionalArrowRelPos',
  'linkDirectionalArrowResolution',
  'linkDirectionalParticles',
  'linkDirectionalParticleSpeed',
  'linkDirectionalParticleWidth',
  'linkDirectionalParticleColor',
  'linkDirectionalParticleResolution',
  'forceEngine',
  'd3AlphaDecay',
  'd3VelocityDecay',
  'd3AlphaMin',
  'ngraphPhysics',
  'warmupTicks',
  'cooldownTicks',
  'cooldownTime',
  'onEngineTick',
  'onEngineStop'
].map(p => ({ [p]: bindFG.linkProp(p)})));
const linkedFGMethods = Object.assign(...[
  'refresh',
  'getGraphBbox',
  'd3Force',
  'd3ReheatSimulation',
  'emitParticle'
].map(p => ({ [p]: bindFG.linkMethod(p)})));

// Expose config from renderObjs
const bindRenderObjs = linkKapsule('renderObjs', ThreeRenderObjects);
const linkedRenderObjsProps = Object.assign(...[
  'width',
  'height',
  'backgroundColor',
  'showNavInfo',
  'enablePointerInteraction'
].map(p => ({ [p]: bindRenderObjs.linkProp(p)})));
const linkedRenderObjsMethods = Object.assign(
  ...[
    'cameraPosition',
    'postProcessingComposer'
  ].map(p => ({ [p]: bindRenderObjs.linkMethod(p)})),
  {
    graph2ScreenCoords: bindRenderObjs.linkMethod('getScreenCoords'),
    screen2GraphCoords: bindRenderObjs.linkMethod('getSceneCoords')
  }
);

//

export default Kapsule({

  props: {
    nodeLabel: { default: 'name', triggerUpdate: false },
    linkLabel: { default: 'name', triggerUpdate: false },
    linkHoverPrecision: { default: 1, onChange: (p, state) => state.renderObjs.lineHoverPrecision(p), triggerUpdate: false },
    enableNavigationControls: {
      default: true,
      onChange(enable, state) {
        const controls = state.renderObjs.controls();
        if (controls) {
          controls.enabled = enable;
        }
      },
      triggerUpdate: false
    },
    enableNodeDrag: { default: true, triggerUpdate: false },
    onNodeDrag: { default: () => {}, triggerUpdate: false },
    onNodeDragEnd: { default: () => {}, triggerUpdate: false },
    onNodeClick: { triggerUpdate: false },
    onNodeRightClick: { triggerUpdate: false },
    onNodeHover: { triggerUpdate: false },
    onLinkClick: { triggerUpdate: false },
    onLinkRightClick: { triggerUpdate: false },
    onLinkHover: { triggerUpdate: false },
    onBackgroundClick: { triggerUpdate: false },
    onBackgroundRightClick: { triggerUpdate: false },
    ...linkedFGProps,
    ...linkedRenderObjsProps
  },

  methods: {
    zoomToFit: function(state, transitionDuration, padding, ...bboxArgs) {
      state.renderObjs.fitToBbox(
        state.forceGraph.getGraphBbox(...bboxArgs),
        transitionDuration,
        padding
      );
      return this;
    },
    pauseAnimation: function(state) {
      if (state.animationFrameRequestId !== null) {
        cancelAnimationFrame(state.animationFrameRequestId);
        state.animationFrameRequestId = null;
      }
      return this;
    },

    resumeAnimation: function(state) {
      if (state.animationFrameRequestId === null) {
        this._animationCycle();
      }
      return this;
    },
    _animationCycle(state) {
      if (state.enablePointerInteraction) {
        // reset canvas cursor (override dragControls cursor)
        this.renderer().domElement.style.cursor = null;
      }

      // Frame cycle
      state.forceGraph.tickFrame();
      state.renderObjs.tick();
      state.animationFrameRequestId = requestAnimationFrame(this._animationCycle);
    },
    scene: state => state.renderObjs.scene(), // Expose scene
    camera: state => state.renderObjs.camera(), // Expose camera
    renderer: state => state.renderObjs.renderer(), // Expose renderer
    controls: state => state.renderObjs.controls(), // Expose controls
    tbControls: state => state.renderObjs.tbControls(), // To be deprecated
    _destructor: function() {
      this.pauseAnimation();
      this.graphData({ nodes: [], links: []});
    },
    ...linkedFGMethods,
    ...linkedRenderObjsMethods
  },

  stateInit: ({ controlType, rendererConfig, extraRenderers }) => ({
    forceGraph: new ThreeForceGraph(),
    renderObjs: ThreeRenderObjects({ controlType, rendererConfig, extraRenderers })
  }),

  init: function(domNode, state) {
    // Wipe DOM
    domNode.innerHTML = '';

    // Add relative container
    domNode.appendChild(state.container = document.createElement('div'));
    state.container.style.position = 'relative';

    // Add renderObjs
    const roDomNode = document.createElement('div');
    state.container.appendChild(roDomNode);
    state.renderObjs(roDomNode);
    const camera = state.renderObjs.camera();
    const renderer = state.renderObjs.renderer();
    const controls = state.renderObjs.controls();
    controls.enabled = !!state.enableNavigationControls;
    state.lastSetCameraZ = camera.position.z;

    // Add info space
    let infoElem;
    state.container.appendChild(infoElem = document.createElement('div'));
    infoElem.className = 'graph-info-msg';
    infoElem.textContent = '';

    // config forcegraph
    state.forceGraph
      .onLoading(() => { infoElem.textContent = 'Loading...' })
      .onFinishLoading(() => { infoElem.textContent = '' })
      .onUpdate(() => {
        // sync graph data structures
        state.graphData = state.forceGraph.graphData();

        // re-aim camera, if still in default position (not user modified)
        if (camera.position.x === 0 && camera.position.y === 0 && camera.position.z === state.lastSetCameraZ && state.graphData.nodes.length) {
          camera.lookAt(state.forceGraph.position);
          state.lastSetCameraZ = camera.position.z = Math.cbrt(state.graphData.nodes.length) * CAMERA_DISTANCE2NODES_FACTOR;
        }
      })
      .onFinishUpdate(() => {
        // Setup node drag interaction
        if (state._dragControls) {
          const curNodeDrag = state.graphData.nodes.find(node => node.__initialFixedPos && !node.__disposeControlsAfterDrag); // detect if there's a node being dragged using the existing drag controls
          if (curNodeDrag) {
            curNodeDrag.__disposeControlsAfterDrag = true; // postpone previous controls disposal until drag ends
          } else {
            state._dragControls.dispose(); // cancel previous drag controls
          }

          state._dragControls = undefined;
        }

        if (state.enableNodeDrag && state.enablePointerInteraction && state.forceEngine === 'd3') { // Can't access node positions programatically in ngraph
          const dragControls = state._dragControls = new ThreeDragControls(
            state.graphData.nodes.map(node => node.__threeObj).filter(obj => obj),
            camera,
            renderer.domElement
          );

          dragControls.addEventListener('dragstart', function (event) {
            controls.enabled = false; // Disable controls while dragging

            // track drag object movement
            event.object.__initialPos = event.object.position.clone();
            event.object.__prevPos = event.object.position.clone();

            const node = getGraphObj(event.object).__data;
            !node.__initialFixedPos && (node.__initialFixedPos = {fx: node.fx, fy: node.fy, fz: node.fz});
            !node.__initialPos && (node.__initialPos = {x: node.x, y: node.y, z: node.z});

            // lock node
            ['x', 'y', 'z'].forEach(c => node[`f${c}`] = node[c]);

            // drag cursor
            renderer.domElement.classList.add('grabbable');
          });

          dragControls.addEventListener('drag', function (event) {
            const nodeObj = getGraphObj(event.object);

            if (!event.object.hasOwnProperty('__graphObjType')) {
              // If dragging a child of the node, update the node object instead
              const initPos = event.object.__initialPos;
              const prevPos = event.object.__prevPos;
              const newPos = event.object.position;

              nodeObj.position.add(newPos.clone().sub(prevPos)); // translate node object by the motion delta
              prevPos.copy(newPos);
              newPos.copy(initPos); // reset child back to its initial position
            }

            const node = nodeObj.__data;
            const newPos = nodeObj.position;
            const translate = {x: newPos.x - node.x, y: newPos.y - node.y, z: newPos.z - node.z};
            // Move fx/fy/fz (and x/y/z) of nodes based on object new position
            ['x', 'y', 'z'].forEach(c => node[`f${c}`] = node[c] = newPos[c]);

            state.forceGraph
              .d3AlphaTarget(0.3) // keep engine running at low intensity throughout drag
              .resetCountdown();  // prevent freeze while dragging

            node.__dragged = true;
            state.onNodeDrag(node, translate);
          });

          dragControls.addEventListener('dragend', function (event) {
            delete(event.object.__initialPos); // remove tracking attributes
            delete(event.object.__prevPos);

            const node = getGraphObj(event.object).__data;

            // dispose previous controls if needed
            if (node.__disposeControlsAfterDrag) {
              dragControls.dispose();
              delete(node.__disposeControlsAfterDrag);
            }

            const initFixedPos = node.__initialFixedPos;
            const initPos = node.__initialPos;
            const translate = {x: initPos.x - node.x, y: initPos.y - node.y, z: initPos.z - node.z};
            if (initFixedPos) {
              ['x', 'y', 'z'].forEach(c => {
                const fc = `f${c}`;
                if (initFixedPos[fc] === undefined) {
                  delete(node[fc])
                }
              });
              delete(node.__initialFixedPos);
              delete(node.__initialPos);
              if (node.__dragged) {
                delete(node.__dragged);
                state.onNodeDragEnd(node, translate);
              }
            }

            state.forceGraph
              .d3AlphaTarget(0)   // release engine low intensity
              .resetCountdown();  // let the engine readjust after releasing fixed nodes

            if (state.enableNavigationControls) {
              controls.enabled = true; // Re-enable controls
              controls.domElement && controls.domElement.ownerDocument && controls.domElement.ownerDocument.dispatchEvent(
                // simulate mouseup to ensure the controls don't take over after dragend
                new PointerEvent('pointerup', { pointerType: 'mouse' })
              );
            }

            // clear cursor
            renderer.domElement.classList.remove('grabbable');
          });
        }
      });

    // config renderObjs
    state.renderObjs
      .objects([ // Populate scene
        new three.AmbientLight(0xbbbbbb),
        new three.DirectionalLight(0xffffff, 0.6),
        state.forceGraph
      ])
      .hoverOrderComparator((a, b) => {
        // Prioritize graph objects
        const aObj = getGraphObj(a);
        if (!aObj) return 1;
        const bObj = getGraphObj(b);
        if (!bObj) return -1;

        // Prioritize nodes over links
        const isNode = o => o.__graphObjType === 'node';
        return isNode(bObj) - isNode(aObj);
      })
      .tooltipContent(obj => {
        const graphObj = getGraphObj(obj);
        return graphObj ? accessorFn(state[`${graphObj.__graphObjType}Label`])(graphObj.__data) || '' : '';
      })
      .hoverDuringDrag(false)
      .onHover(obj => {
        // Update tooltip and trigger onHover events
        const hoverObj = getGraphObj(obj);

        if (hoverObj !== state.hoverObj) {
          const prevObjType = state.hoverObj ? state.hoverObj.__graphObjType : null;
          const prevObjData = state.hoverObj ? state.hoverObj.__data : null;
          const objType = hoverObj ? hoverObj.__graphObjType : null;
          const objData = hoverObj ? hoverObj.__data : null;
          if (prevObjType && prevObjType !== objType) {
            // Hover out
            const fn = state[`on${prevObjType === 'node' ? 'Node' : 'Link'}Hover`];
            fn && fn(null, prevObjData);
          }
          if (objType) {
            // Hover in
            const fn = state[`on${objType === 'node' ? 'Node' : 'Link'}Hover`];
            fn && fn(objData, prevObjType === objType ? prevObjData : null);
          }

          // set pointer if hovered object is clickable
          renderer.domElement.classList[
            ((hoverObj && state[`on${objType === 'node' ? 'Node' : 'Link'}Click`]) || (!hoverObj && state.onBackgroundClick)) ? 'add' : 'remove'
          ]('clickable');

          state.hoverObj = hoverObj;
        }
      })
      .clickAfterDrag(false)
      .onClick((obj, ev) => {
        const graphObj = getGraphObj(obj);
        if (graphObj) {
          const fn = state[`on${graphObj.__graphObjType === 'node' ? 'Node' : 'Link'}Click`];
          fn && fn(graphObj.__data, ev);
        } else {
          state.onBackgroundClick && state.onBackgroundClick(ev);
        }
      })
      .onRightClick((obj, ev) => {
        // Handle right-click events
        const graphObj = getGraphObj(obj);
        if (graphObj) {
          const fn = state[`on${graphObj.__graphObjType === 'node' ? 'Node' : 'Link'}RightClick`];
          fn && fn(graphObj.__data, ev);
        } else {
          state.onBackgroundRightClick && state.onBackgroundRightClick(ev);
        }
      });

    //

    // Kick-off renderer
    this._animationCycle();
  }
});

//

function getGraphObj(object) {
  let obj = object;
  // recurse up object chain until finding the graph object
  while (obj && !obj.hasOwnProperty('__graphObjType')) {
    obj = obj.parent;
  }
  return obj;
}
<|endoftext|>


<commit_before>var glob = require('glob');
var fs = require('fs');
var _ = require('lodash');
var protagonist = require('protagonist');
var async = require('async');
var urlParser = require('../url-parser');
var route = require('../route');

var autoOptionsAction = require('../json/auto-options-action.json');
var ROUTE_MAP = null;

var parseAction = function(uriTemplate, action) {
    var parsedUrl = urlParser.parse(uriTemplate);
    var key = parsedUrl.url;

    ROUTE_MAP[key] = ROUTE_MAP[key] || { urlExpression: parsedUrl.url, methods: {} };
    ROUTE_MAP[key].methods[action.method] = ROUTE_MAP[key].methods[action.method] || [];

    var routeHandlers = route.getRouteHandlers(key, parsedUrl, action);
    Array.prototype.push.apply(ROUTE_MAP[key].methods[action.method], routeHandlers);

    console.log('[LOG]'.white, 'Setup Route:', action.method.green, key.yellow, action.name.blue);
};

var parseBlueprint = function(filePath, autoOptions) {
    return function(cb) {
        var data = fs.readFileSync(filePath, {encoding: 'utf8'});
        protagonist.parse(data, function(err, result) {
            if (err) {
                console.log(err);
                return;
            }

            var allRoutesList = [];
            result.ast.resourceGroups.forEach(function(resourceGroup){
                resourceGroup.resources.forEach(function(resource){
                    resource.actions.forEach(function(action){
                        parseAction(resource.uriTemplate, action);
                        saveRouteToTheList(resource, action);
                    });
                });
            });

            // add OPTIONS route where its missing - this must be done after all routes are parsed
            if (autoOptions) {
                addOptionsRoutesWhereMissing(allRoutesList);
            }

            cb();

            /**
             * Adds route and its action to the allRoutesList. It appends the action when route already exists in the list.
             * @param resource Route URI
             * @param action HTTP action
             */
            function saveRouteToTheList(resource, action) {
                // used to add options routes later
                if (typeof allRoutesList[resource.uriTemplate] === 'undefined') {
                    allRoutesList[resource.uriTemplate] = [];
                }
                allRoutesList[resource.uriTemplate].push(action);
            }

            function addOptionsRoutesWhereMissing(allRoutes) {
                var routesWithoutOptions = [];
                // extracts only routes without OPTIONS
                _.forIn(allRoutes, function (actions, route) {
                    var containsOptions = _.reduce(actions, function (previousResult, iteratedAction) {
                        return previousResult || (iteratedAction.method === 'OPTIONS');
                    }, false);
                    if (!containsOptions) {
                        routesWithoutOptions.push(route);
                    }
                });

                _.forEach(routesWithoutOptions, function (uriTemplate) {
                    // adds prepared OPTIONS action for route
                    parseAction(uriTemplate, autoOptionsAction);
                });
            }
        });
    };
};

var setup = function(options, cb) {
    var sourceFiles = options.sourceFiles;
    var autoOptions = options.autoOptions;
    glob(sourceFiles, {} , function (err, files) {
        if (err) {
            console.error('Failed to parse contracts path.', err);
            process.exit(1);
        }

        var asyncFunctions = [];

        files.forEach(function(filePath) {
            asyncFunctions.push(parseBlueprint(filePath, autoOptions));
        });

        async.series(asyncFunctions, function(err) {
            cb(err);
        });
    });
};

module.exports = function(options, cb) {
    if (ROUTE_MAP) {
        cb(null, ROUTE_MAP);
    }
    else {
        ROUTE_MAP = {};
        setup(options, function(err) {
            cb(err, ROUTE_MAP);
        });
    }
};
<commit_msg>Always reset ROUTE_MAP<commit_after>var glob = require('glob');
var fs = require('fs');
var _ = require('lodash');
var protagonist = require('protagonist');
var async = require('async');
var urlParser = require('../url-parser');
var route = require('../route');

var autoOptionsAction = require('../json/auto-options-action.json');
var ROUTE_MAP = null;

var parseAction = function(uriTemplate, action) {
    var parsedUrl = urlParser.parse(uriTemplate);
    var key = parsedUrl.url;

    ROUTE_MAP[key] = ROUTE_MAP[key] || { urlExpression: parsedUrl.url, methods: {} };
    ROUTE_MAP[key].methods[action.method] = ROUTE_MAP[key].methods[action.method] || [];

    var routeHandlers = route.getRouteHandlers(key, parsedUrl, action);
    Array.prototype.push.apply(ROUTE_MAP[key].methods[action.method], routeHandlers);

    console.log('[LOG]'.white, 'Setup Route:', action.method.green, key.yellow, action.name.blue);
};

var parseBlueprint = function(filePath, autoOptions) {
    return function(cb) {
        var data = fs.readFileSync(filePath, {encoding: 'utf8'});
        protagonist.parse(data, function(err, result) {
            if (err) {
                console.log(err);
                return;
            }

            var allRoutesList = [];
            result.ast.resourceGroups.forEach(function(resourceGroup){
                resourceGroup.resources.forEach(function(resource){
                    resource.actions.forEach(function(action){
                        parseAction(resource.uriTemplate, action);
                        saveRouteToTheList(resource, action);
                    });
                });
            });

            // add OPTIONS route where its missing - this must be done after all routes are parsed
            if (autoOptions) {
                addOptionsRoutesWhereMissing(allRoutesList);
            }

            cb();

            /**
             * Adds route and its action to the allRoutesList. It appends the action when route already exists in the list.
             * @param resource Route URI
             * @param action HTTP action
             */
            function saveRouteToTheList(resource, action) {
                // used to add options routes later
                if (typeof allRoutesList[resource.uriTemplate] === 'undefined') {
                    allRoutesList[resource.uriTemplate] = [];
                }
                allRoutesList[resource.uriTemplate].push(action);
            }

            function addOptionsRoutesWhereMissing(allRoutes) {
                var routesWithoutOptions = [];
                // extracts only routes without OPTIONS
                _.forIn(allRoutes, function (actions, route) {
                    var containsOptions = _.reduce(actions, function (previousResult, iteratedAction) {
                        return previousResult || (iteratedAction.method === 'OPTIONS');
                    }, false);
                    if (!containsOptions) {
                        routesWithoutOptions.push(route);
                    }
                });

                _.forEach(routesWithoutOptions, function (uriTemplate) {
                    // adds prepared OPTIONS action for route
                    parseAction(uriTemplate, autoOptionsAction);
                });
            }
        });
    };
};

var setup = function(options, cb) {
    var sourceFiles = options.sourceFiles;
    var autoOptions = options.autoOptions;
    glob(sourceFiles, {} , function (err, files) {
        if (err) {
            console.error('Failed to parse contracts path.', err);
            process.exit(1);
        }

        var asyncFunctions = [];

        files.forEach(function(filePath) {
            asyncFunctions.push(parseBlueprint(filePath, autoOptions));
        });

        async.series(asyncFunctions, function(err) {
            cb(err);
        });
    });
};

module.exports = function(options, cb) {
    ROUTE_MAP = {};
    setup(options, function(err) {
        cb(err, ROUTE_MAP);
    });
};
<|endoftext|>


<commit_before>'use strict'

var getSchoolStudentAccessGroup = require('./sharedFunctions/school-student-access-group')

function generateMetadataDocument (options) {
  if (!options) {
    throw new Error('Missing required input: options')
  }
  if (!options.title) {
    throw new Error('Missing required input: options.title')
  }
  if (!options.personalIdNumber) {
    throw new Error('Missing required input: options.personalIdNumber')
  }
  if (!options.schoolName) {
    throw new Error('Missing required input: options.schoolName')
  }
  if (!options.schoolOrgNumber) {
    throw new Error('Missing required input: options.schoolOrgNumber')
  }
  if (!options.file) {
    throw new Error('Missing required input: options.file')
  }
  if (!options.fileTitle) {
    throw new Error('Missing required input: options.fileTitle')
  }
  if (!options.caseNumber) {
    throw new Error('Missing required input: options.caseNumber')
  }

  var schoolGroup = getSchoolStudentAccessGroup(options)
  var meta = {
    'clientService': 'CaseService',
    'clientMethod': 'CreateCase',
    'args': {
      'parameter': {
        'AccessCode': '13', // Codetable: Accesscode
        'AccessGroup': schoolGroup, // Codetable: Tilgangsgruppe navn
        'Category': '111', // Codetable: Document category
        'Contacts': [
          {
            'DocumentContactParameter': [
              {
                'Role': 'Sender',
                'ReferenceNumber': options.schoolOrgNumber
              },
              {
                'ExternalId': options.personalIdNumber, // Personnummer / orgnr
                'Role': 'Recipient' // 5: Avsender 6: Mottaker Codetable: Activity - Contact Role
              }
            ]
          }
        ],
        'Files': [
          {
            'CreateFileParameter': {
              'Base64Data': options.file, // Must be base64 encoded
              'Category': '1', // Codetable: File category
              'Format': 'PDF', // Codetable: File format
              'Title': options.fileTitle,
              'VersionFormat': 'A' // Codetable: File status
            }
          }
        ],
        'Paragraph': 'Offl §13 jfr Fvl §13', // Codetable: Paragraph
        'ResponsibleEnterpriseNumber': '974568020', // Recnr ansvarlig virksomhet
        'Status': '6', // Codetable: Document status
        'Title': 'Varsel',
        'UnofficialTitle': options.title,
        'Archive': '2', // Codetable: Document archive
        'CaseNumber': options.caseNumber,
        'SendersReference': ''
      }
    }
  }
  return meta
}

module.exports = generateMetadataDocument
<commit_msg>Add-document<commit_after>'use strict'

var getSchoolStudentAccessGroup = require('./sharedFunctions/school-student-access-group')

function generateMetadataDocument (options) {
  if (!options) {
    throw new Error('Missing required input: options')
  }
  if (!options.title) {
    throw new Error('Missing required input: options.title')
  }
  if (!options.personalIdNumber) {
    throw new Error('Missing required input: options.personalIdNumber')
  }
  if (!options.schoolName) {
    throw new Error('Missing required input: options.schoolName')
  }
  if (!options.schoolOrgNumber) {
    throw new Error('Missing required input: options.schoolOrgNumber')
  }
  if (!options.file) {
    throw new Error('Missing required input: options.file')
  }
  if (!options.fileTitle) {
    throw new Error('Missing required input: options.fileTitle')
  }
  if (!options.caseNumber) {
    throw new Error('Missing required input: options.caseNumber')
  }

  var schoolGroup = getSchoolStudentAccessGroup(options)
  var meta = {
    'clientService': 'DocumentService',
    'clientMethod': 'CreateDocument',
    'args': {
      'parameter': {
        'AccessCode': '13', // Codetable: Accesscode
        'AccessGroup': schoolGroup, // Codetable: Tilgangsgruppe navn
        'Category': '111', // Codetable: Document category
        'Contacts': [
          {
            'DocumentContactParameter': [
              {
                'Role': 'Sender',
                'ReferenceNumber': options.schoolOrgNumber
              },
              {
                'ExternalId': options.personalIdNumber, // Personnummer / orgnr
                'Role': 'Recipient' // 5: Avsender 6: Mottaker Codetable: Activity - Contact Role
              }
            ]
          }
        ],
        'Files': [
          {
            'CreateFileParameter': {
              'Base64Data': options.file, // Must be base64 encoded
              'Category': '1', // Codetable: File category
              'Format': 'PDF', // Codetable: File format
              'Title': options.fileTitle,
              'VersionFormat': 'A' // Codetable: File status
            }
          }
        ],
        'Paragraph': 'Offl §13 jfr Fvl §13', // Codetable: Paragraph
        'ResponsibleEnterpriseNumber': '974568020', // Recnr ansvarlig virksomhet
        'Status': '6', // Codetable: Document status
        'Title': 'Varsel',
        'UnofficialTitle': options.title,
        'Archive': '2', // Codetable: Document archive
        'CaseNumber': options.caseNumber,
        'SendersReference': ''
      }
    }
  }
  return meta
}

module.exports = generateMetadataDocument
<|endoftext|>


<commit_before>// Copyright © 2014 Intel Corporation. All rights reserved.
// Use  of this  source  code is  governed by  an Apache v2
// license that can be found in the LICENSE-APACHE-V2 file.

var Path = require('path');
var AndroidSDK = require("./AndroidSDK");
var Console = require("./Console");
var Project = require("./Project");
var TemplateFile = require("./TemplateFile");

/**
 * Android project class.
 * @throws {@link AndroidSDK~SDKNotFoundError} If the Android SDK was not found in the environment.
 * @constructor
 */
function AndroidProject() {

    this._sdk = new AndroidSDK();
}
AndroidProject.prototype = Project;

AndroidProject.prototype.generateTemplates =
function(packageId, apiTarget, path) {

    var parts = packageId.split('.');
    var packageName = parts[parts.length - 1];
    var data = {
        "packageId" : packageId,
        "packageName" : packageName,
        "apiTarget" : apiTarget
    };

    // AndroidManifest.xml
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "AndroidManifest.xml.tpl");
    tpl.render(data, path + Path.sep + "AndroidManifest.xml");

    // build.xml
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "build.xml.tpl");
    tpl.render(data, path + Path.sep + "build.xml");

    // project.properties
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "project.properties.tpl");
    tpl.render(data, path + Path.sep + "project.properties");

    // MainActivity.java
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "MainActivity.java.tpl");
    var activityPath = path + Path.sep +
                       "src" + Path.sep +
                       parts.join(Path.sep);
    tpl.render(data, activityPath + Path.sep + "MainActivity.java");

    return true;
};

/**
 * Implements {@link Project.generate}
 */
AndroidProject.prototype.generate =
function(packageId, callback) {

    var minApiLevel = 14;
    var apiTarget;
    this._sdk.queryTarget(minApiLevel,
                          function(apiTarget, errormsg) {

        if (errormsg) {
            callback(errormsg);
            return;
        }

        this._sdk.generateProjectTemplate(packageId, apiTarget,
                                          function(path, logmsg, errormsg) {

            if (!path || errormsg) {
                callback(errormsg);
                return;
            }

            Console.log("Project template created at '" + path + "'");

            this.generateTemplates(packageId, apiTarget, path);

            callback(null);

        }.bind(this));
    }.bind(this));
};

AndroidProject.prototype.update =
function() {

    // TODO implement
};

AndroidProject.prototype.refresh =
function() {

    // TODO implement
};

AndroidProject.prototype.build =
function() {

    // TODO implement
};

module.exports = AndroidProject;
<commit_msg>AndroidProject: Implement copying xwalk, jars and resources from app template<commit_after>// Copyright © 2014 Intel Corporation. All rights reserved.
// Use  of this  source  code is  governed by  an Apache v2
// license that can be found in the LICENSE-APACHE-V2 file.

var Path = require('path');
var ShellJS = require("shelljs");
var AndroidSDK = require("./AndroidSDK");
var Console = require("./Console");
var Project = require("./Project");
var TemplateFile = require("./TemplateFile");

/**
 * Android project class.
 * @throws {@link AndroidSDK~SDKNotFoundError} If the Android SDK was not found in the environment.
 * @constructor
 */
function AndroidProject() {

    this._sdk = new AndroidSDK();
}
AndroidProject.prototype = Project;

AndroidProject.prototype.generateTemplates =
function(packageId, apiTarget, path) {

    var parts = packageId.split('.');
    var packageName = parts[parts.length - 1];
    var data = {
        "packageId" : packageId,
        "packageName" : packageName,
        "apiTarget" : apiTarget
    };

    // AndroidManifest.xml
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "AndroidManifest.xml.tpl");
    tpl.render(data, path + Path.sep + "AndroidManifest.xml");

    // build.xml
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "build.xml.tpl");
    tpl.render(data, path + Path.sep + "build.xml");

    // project.properties
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "project.properties.tpl");
    tpl.render(data, path + Path.sep + "project.properties");

    // MainActivity.java
    var tpl = new TemplateFile(__dirname + Path.sep +
                               ".."+ Path.sep +
                               "data" + Path.sep +
                               "MainActivity.java.tpl");
    var activityPath = path + Path.sep +
                       "src" + Path.sep +
                       parts.join(Path.sep);
    tpl.render(data, activityPath + Path.sep + "MainActivity.java");

    // Copy
    var dirs = ShellJS.ls('crosswalk-*.*.*.*');
    if (dirs.length === 0) {
        Console.error("Unpacked Crosswalk not found in current directory");
        return false;
    }
    var appTplPath = dirs[0];

    // Copy xwalk_core_library
    ShellJS.cp("-r",
               appTplPath + Path.sep + "xwalk_core_library",
               path);

    // Copy jars
    ShellJS.cp(appTplPath + Path.sep + "template" + Path.sep + "libs" + Path.sep + "*.jar",
               path + Path.sep + "libs");

    // Copy res
    ShellJS.cp("-r",
               appTplPath + Path.sep + "template" + Path.sep + "res",
               path);

    return true;
};

/**
 * Implements {@link Project.generate}
 */
AndroidProject.prototype.generate =
function(packageId, callback) {

    var minApiLevel = 19;
    var apiTarget;
    this._sdk.queryTarget(minApiLevel,
                          function(apiTarget, errormsg) {

        if (errormsg) {
            callback(errormsg);
            return;
        }

        this._sdk.generateProjectTemplate(packageId, apiTarget,
                                          function(path, logmsg, errormsg) {

            if (!path || errormsg) {
                callback(errormsg);
                return;
            }

            var ret = this.generateTemplates(packageId, apiTarget, path);
            if (!ret) {
                callback("Creating project template failed.");
                return;
            }

            Console.log("Project template created at '" + path + "'");
            callback(null);

        }.bind(this));
    }.bind(this));
};

AndroidProject.prototype.update =
function() {

    // TODO implement
};

AndroidProject.prototype.refresh =
function() {

    // TODO implement
};

AndroidProject.prototype.build =
function() {

    // TODO implement
};

module.exports = AndroidProject;
<|endoftext|>


<commit_before>import path from 'path';
import fs from 'fs-extra';

import CompositeGitStrategy from '../composite-git-strategy';
import {toNativePathSep} from '../helpers';

/**
 * Locate the nearest git working directory above a given starting point, caching results.
 */
export default class WorkdirCache {
  constructor(maxSize = 1000) {
    this.maxSize = maxSize;
    this.known = new Map();
  }

  async find(startPath) {
    const cached = this.known.get(startPath);
    if (cached !== undefined) {
      return cached;
    }

    const workDir = await this.revParse(startPath);

    if (this.known.size >= this.maxSize) {
      this.known.clear();
    }
    this.known.set(startPath, workDir);

    return workDir;
  }

  invalidate() {
    this.known.clear();
  }

  async revParse(startPath) {
    try {
      const startDir = (await fs.stat(startPath)).isDirectory() ? startPath : path.dirname(startPath);

      // Within a git worktree, return a non-empty string containing the path to the worktree root.
      // Within a gitdir or outside of a worktree, return an empty string.
      // Throw if startDir does not exist.
      const topLevel = await CompositeGitStrategy.create(startDir).exec(['rev-parse', '--show-toplevel']);
      if (/\S/.test(topLevel)) {
        return toNativePathSep(topLevel.trim());
      }

      // Within a gitdir, return the absolute path to the gitdir.
      // Outside of a gitdir or worktree, throw.
      const gitDir = await CompositeGitStrategy.create(startDir).exec(['rev-parse', '--absolute-git-dir']);
      return this.revParse(path.resolve(gitDir, '..'));
    } catch (e) {
      if (atom.config.get('github.reportCannotLocateWorkspaceError')) {
        // eslint-disable-next-line no-console
        console.error(
          `Unable to locate git workspace root for ${startPath}. Expected if ${startPath} is not in a git repository.`,
          e,
        );
      }
      return null;
    }
  }
}
<commit_msg>Shhh istanbul. That one's too much of a pain to mock<commit_after>import path from 'path';
import fs from 'fs-extra';

import CompositeGitStrategy from '../composite-git-strategy';
import {toNativePathSep} from '../helpers';

/**
 * Locate the nearest git working directory above a given starting point, caching results.
 */
export default class WorkdirCache {
  constructor(maxSize = 1000) {
    this.maxSize = maxSize;
    this.known = new Map();
  }

  async find(startPath) {
    const cached = this.known.get(startPath);
    if (cached !== undefined) {
      return cached;
    }

    const workDir = await this.revParse(startPath);

    if (this.known.size >= this.maxSize) {
      this.known.clear();
    }
    this.known.set(startPath, workDir);

    return workDir;
  }

  invalidate() {
    this.known.clear();
  }

  async revParse(startPath) {
    try {
      const startDir = (await fs.stat(startPath)).isDirectory() ? startPath : path.dirname(startPath);

      // Within a git worktree, return a non-empty string containing the path to the worktree root.
      // Within a gitdir or outside of a worktree, return an empty string.
      // Throw if startDir does not exist.
      const topLevel = await CompositeGitStrategy.create(startDir).exec(['rev-parse', '--show-toplevel']);
      if (/\S/.test(topLevel)) {
        return toNativePathSep(topLevel.trim());
      }

      // Within a gitdir, return the absolute path to the gitdir.
      // Outside of a gitdir or worktree, throw.
      const gitDir = await CompositeGitStrategy.create(startDir).exec(['rev-parse', '--absolute-git-dir']);
      return this.revParse(path.resolve(gitDir, '..'));
    } catch (e) {
      /* istanbul ignore if */
      if (atom.config.get('github.reportCannotLocateWorkspaceError')) {
        // eslint-disable-next-line no-console
        console.error(
          `Unable to locate git workspace root for ${startPath}. Expected if ${startPath} is not in a git repository.`,
          e,
        );
      }
      return null;
    }
  }
}
<|endoftext|>


<commit_before>const axios = require('axios');
const chalk = require('chalk');

const helpers = require('../helpers');

exports.nextLaunch = function (argv) {
  let launchCount = argv.limit > 1 ? argv.limit : 1;

  axios.get('https://launchlibrary.net/1.2/launch/next/' + launchCount).then((response) => {
    let nextCount = response.data.launches.length;
    let timezone = argv.timezone;
    let timezoneError = false;

    for (let i = 0; i < nextCount; i++) {
      let next = response.data.launches[i];
      let title = chalk.yellow('Next launch:') + ' ' + next.id + ' ' + next.name;
      let schedule = chalk.cyan('Scheduled launch attempt:') + ' ' + next.net;

      if (timezone && timezone.length > 0 && !timezoneError) {
        helpers.convertTimezone(next.net, timezone, function (error, data) {
          if (!error) {
            schedule = chalk.cyan('Scheduled launch attempt:') + ' ' + data;
            return;
          }
          timezoneError = true;
          return helpers.printMessage(chalk.red(error));
        });
      }

      if (next.tbddate === 1 || next.tbdtime === 1) {
        schedule += ' ' + chalk.bgYellow.black(' TBD ');
      }

      let vidCount = next.vidURLs.length;
      let broadcasts = vidCount < 1 ? chalk.cyan('Broadcasts: ') + 'TBD / Unavailable' : chalk.cyan('Broadcasts:');

      if (vidCount >= 1) {
        for (let i = 0; i < vidCount; i++) {
          broadcasts += ' ' + next.vidURLs[i];
        }
      }

      let dataBreak = '';
      if (nextCount > 1) {
        dataBreak = '\n';
      }

      if (argv.details) {
        let rocket = chalk.cyan('Rocket:') + ' ' + next.rocket.name;

        let missionCount = next.missions.length;
        let missions = missionCount < 1 ? chalk.cyan('Missions: ') + 'TBD / Unknown' : chalk.cyan('Missions:');

        if (missionCount >= 1) {
          for (let i = 0; i < missionCount; i++) {
            let missionNo = i + +1 + ')';
            let missionType = '[' + next.missions[i].typeName + ']';
            let missionDescription = next.missions[i].description;

            missions += '\n' + chalk.yellow(missionNo + ' ' + missionType) + ' ' + missionDescription;
          }
        }

        helpers.printMessage(title + '\n' + schedule + '\n' + broadcasts + '\n' + rocket + '\n' + missions + dataBreak);
      } else {
        helpers.printMessage(title + '\n' + schedule + '\n' + broadcasts + dataBreak);
      }
    }
  }).catch(function (error) {
    let errorData = error.response.data;
    let errorMessage = chalk.red(errorData.status + ': ' + errorData.msg);
    helpers.printError(errorMessage);
  });
};
<commit_msg>Update time conversion error printing<commit_after>const axios = require('axios');
const chalk = require('chalk');

const helpers = require('../helpers');

exports.nextLaunch = function (argv) {
  let launchCount = argv.limit > 1 ? argv.limit : 1;

  axios.get('https://launchlibrary.net/1.2/launch/next/' + launchCount).then((response) => {
    let nextCount = response.data.launches.length;
    let timezone = argv.timezone;
    let timezoneError = false;

    for (let i = 0; i < nextCount; i++) {
      let next = response.data.launches[i];
      let title = chalk.yellow('Next launch:') + ' ' + next.id + ' ' + next.name;
      let schedule = chalk.cyan('Scheduled launch attempt:') + ' ' + next.net;

      if (timezone && timezone.length > 0 && !timezoneError) {
        helpers.convertTimezone(next.net, timezone, function (error, data) {
          if (!error) {
            schedule = chalk.cyan('Scheduled launch attempt:') + ' ' + data;
            return;
          }
          timezoneError = true;
          let errorMessage = chalk.red('error: ' + error);
          return helpers.printError(errorMessage);
        });
      }

      if (next.tbddate === 1 || next.tbdtime === 1) {
        schedule += ' ' + chalk.bgYellow.black(' TBD ');
      }

      let vidCount = next.vidURLs.length;
      let broadcasts = vidCount < 1 ? chalk.cyan('Broadcasts: ') + 'TBD / Unavailable' : chalk.cyan('Broadcasts:');

      if (vidCount >= 1) {
        for (let i = 0; i < vidCount; i++) {
          broadcasts += ' ' + next.vidURLs[i];
        }
      }

      let dataBreak = '';
      if (nextCount > 1) {
        dataBreak = '\n';
      }

      if (argv.details) {
        let rocket = chalk.cyan('Rocket:') + ' ' + next.rocket.name;

        let missionCount = next.missions.length;
        let missions = missionCount < 1 ? chalk.cyan('Missions: ') + 'TBD / Unknown' : chalk.cyan('Missions:');

        if (missionCount >= 1) {
          for (let i = 0; i < missionCount; i++) {
            let missionNo = i + +1 + ')';
            let missionType = '[' + next.missions[i].typeName + ']';
            let missionDescription = next.missions[i].description;

            missions += '\n' + chalk.yellow(missionNo + ' ' + missionType) + ' ' + missionDescription;
          }
        }

        helpers.printMessage(title + '\n' + schedule + '\n' + broadcasts + '\n' + rocket + '\n' + missions + dataBreak);
      } else {
        helpers.printMessage(title + '\n' + schedule + '\n' + broadcasts + dataBreak);
      }
    }
  }).catch(function (error) {
    let errorData = error.response.data;
    let errorMessage = chalk.red(errorData.status + ': ' + errorData.msg);
    helpers.printError(errorMessage);
  });
};
<|endoftext|>