<commit_before>"use strict";

var Runner = require('integra').Runner
  , Cover = require('integra').Cover
  , RCover = require('integra').RCover
  , f = require('util').format
  , m = require('mongodb-version-manager')
  , path = require('path')
  , NodeVersionFilter = require('./filters/node_version_filter')
  , MongoDBVersionFilter = require('./filters/mongodb_version_filter')
  , MongoDBTopologyFilter = require('./filters/mongodb_topology_filter')
  , ES6PromisesSupportedFilter = require('./filters/es6_promises_supported_filter')
  , ES6GeneratorsSupportedFilter = require('./filters/es6_generators_supported_filter')
  , TravisFilter = require('./filters/travis_filter')
  , FileFilter = require('integra').FileFilter
  , TestNameFilter = require('integra').TestNameFilter
  , ServerManager = require('mongodb-tools').ServerManager
  , ReplSetManager = require('mongodb-tools').ReplSetManager
  , ShardingManager = require('mongodb-tools').ShardingManager;

var detector = require('gleak')();
var smokePlugin = require('../lib/tools/smoke_plugin.js');
var argv = require('optimist')
    .usage('Usage: $0 -t [target] -e [environment] -n [name] -f [filename] -r [smoke report file]')
    .demand(['t'])
    .argv;

// Skipping parameters
var startupOptions = {
    skipStartup: true
  , skipRestart: true
  , skipShutdown: true
  , skip: false
}

// Skipping parameters
var startupOptions = {
    skipStartup: false
  , skipRestart: false
  , skipShutdown: false
  , skip: false
}

// Skipping parameters
if(argv.s) {
  var startupOptions = {
      skipStartup: true
    , skipRestart: true
    , skipShutdown: true
    , skip: false
  }
}

/**
 * Standalone MongoDB Configuration
 */
var f = require('util').format;
var Logger = require('../lib/connection/logger');

var Configuration = function(options) {
  options = options || {};
  var host = options.host || 'localhost';
  var port = options.port || 27017;
  var db = options.db || 'integration_tests';
  var mongo = null;
  var manager = options.manager;
  var skipStart = typeof options.skipStart == 'boolean' ? options.skipStart : false;
  var skipTermination = typeof options.skipTermination == 'boolean' ? options.skipTermination : false;
  var setName = options.setName || 'rs';

  // Default function
  var defaultFunction = function(self, _mongo) {
    return new _mongo.Server({
        host: self.host
      , port: self.port
    });
  };

  // Create a topology function
  var topology = options.topology || defaultFunction;

  return function(context) {
    mongo = require('..');

    return {
      start: function(callback) {
        var self = this;
        if(skipStart) return callback();
        // Start the db
        manager.start({purge:true, signal: -9}, function(err) {
          var server = topology(self, mongo);
          // Set up connect
          server.once('connect', function() {
            // Drop the database
            server.command(f("%s.$cmd", self.db), {dropDatabase: 1}, function(err, r) {
              server.destroy();
              callback();
            });
          });

          // Connect
          server.connect();
        });
      },

      stop: function(callback) {
        if(skipTermination) return callback();
        // manager.stop({signal: -9}, function() {

        //   // Print any global leaks
        //   detector.detect().forEach(function (name) {
        //     console.warn('found global leak: %s', name);
        //   });

        //   // Finish up the tests
        //   callback();
        // });
        var exec = require('child_process').exec;
        exec(f("killall %d mongod", -9), function(err, stdout, stderr) {
          setTimeout(function() {
            callback();
          }, 5000);
        });
      },

      restart: function(options, callback) {
        if(typeof options == 'function') callback = options, options = {purge:true, kill:true};
        if(skipTermination) return callback();

        manager.restart(options, function() {
          setTimeout(function() {
            callback();
          }, 1000);
        });
      },

      setup: function(callback) {
        callback();
      },

      teardown: function(callback) {
        callback();
      },

      newTopology: function(options, callback) {
        if(typeof options == 'function') {
          callback = options;
          options = {};
        }

        callback(null, topology(this, mongo));
      },

      newConnection: function(options, callback) {
        if(typeof options == 'function') {
          callback = options;
          options = {};
        }

        var server = topology(this, mongo);
        // Set up connect
        server.once('connect', function() {
          callback(null, server);
        });

        // Connect
        server.connect();
      },

      // Additional parameters needed
      require: mongo,
      port: port,
      host: host,
      setName: setName,
      db: db,
      manager: manager,
      writeConcern: function() { return {w: 1} }
    }
  }
}

// Set up the runner
var runner = new Runner({
    logLevel:'info'
  , runners: 1
  , failFast: true
});

var testFiles = [
    '/test/tests/functional/server_tests.js'
  , '/test/tests/functional/operations_tests.js'
  , '/test/tests/functional/basic_auth_tests.js'
  , '/test/tests/functional/extend_pick_strategy_tests.js'
  , '/test/tests/functional/mongos_tests.js'
  , '/test/tests/functional/extend_cursor_tests.js'
  , '/test/tests/functional/pool_tests.js'
  , '/test/tests/functional/connection_tests.js'
  , '/test/tests/functional/rs_topology_tests.js'
  , '/test/tests/functional/rs_topology_state_tests.js'
  , '/test/tests/functional/single_topology_tests.js'
  , '/test/tests/functional/cursor_tests.js'
  , '/test/tests/functional/error_tests.js'
  , '/test/tests/functional/tailable_cursor_tests.js'
  , '/test/tests/functional/operation_example_tests.js'
  , '/test/tests/functional/replset_failover_tests.js'
  , '/test/tests/functional/undefined_tests.js'
]

// Check if we support es6 generators
try {
  eval("(function *(){})");
  // Single server Mock Tests
  testFiles.push('/test/tests/functional/single_mocks/timeout_tests.js');

  // Replicaset Mock Tests
  testFiles.push('/test/tests/functional/rs_mocks/add_remove_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/connection_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/failover_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/monitoring_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/read_preferences_tests.js');

  // Mongos Mock Tests
  testFiles.push('/test/tests/functional/mongos_mocks/single_proxy_connection_tests.js');
  testFiles.push('/test/tests/functional/mongos_mocks/multiple_proxies_tests.js');
  testFiles.push('/test/tests/functional/mongos_mocks/proxy_failover_tests.js');
  testFiles.push('/test/tests/functional/mongos_mocks/proxy_read_preference_tests.js');
} catch(err) {}

// Add all the tests to run
testFiles.forEach(function(t) {
  if(t != "") runner.add(t);
});

// // Add the Coverage plugin
// runner.plugin(new Cover({
//  logLevel: "info"
//  , filters: [
//      /_tests.js/
//    , "js-bson"
//    , "/tests/"
//    , "/tools/"
//  ]
// }));

// // Add the RCoverage plugin
// runner.plugin(new RCover({
//    logLevel: "info"
//  , filters: [
//      /_tests.js/
//    , "js-bson"
//    , "/tests/"
//    , "/tools/"
//  ]
// }));

// Add a Node version plugin
runner.plugin(new NodeVersionFilter(startupOptions));
// Add a MongoDB version plugin
runner.plugin(new MongoDBVersionFilter(startupOptions));
// Add a Topology filter plugin
runner.plugin(new MongoDBTopologyFilter(startupOptions));
// Add a Filter allowing us to specify that a function requires Promises
runner.plugin(new ES6PromisesSupportedFilter())
// Add a Filter allowing us to validate if generators are available
runner.plugin(new ES6GeneratorsSupportedFilter())

// Exit when done
runner.on('exit', function(errors, results) {
  process.exit(0)
});

// Set Logger level for driver
// Logger.setLevel('info');
Logger.setLevel('error');
// Logger.setLevel('debug');
// Logger.filter('class', ['ReplSet', 'Server', 'Connection']);
// Logger.filter('class', ['ReplSet', 'Server', 'Pool', 'Connection']);
// Logger.filter('class', ['ReplSet', 'Server', 'Cursor']);
//Logger.filter('class', ['Mongos', 'Server']);
//Logger.filter('class', ['Mongos', 'Server']);
// Logger.filter('class', ['Mongos']);
// Logger.filter('class', ['ReplSet']);

// We want to export a smoke.py style json file
if(argv.r) {
  console.log("Writing smoke output to " + argv.r);
  smokePlugin.attachToRunner(runner, argv.r);
}

// Are we running a functional test
if(argv.t == 'functional') {
  //
  // Single server
  var config = {
      host: 'localhost'
    , port: 27017
    // , skipStart: false
    // , skipTermination: false
    , skipStart: startupOptions.skipStartup
    , skipTermination: startupOptions.skipShutdown
    , manager: new ServerManager({
        dbpath: path.join(path.resolve('db'), f("data-%d", 27017))
      , logpath: path.join(path.resolve('db'), f("data-%d.log", 27017))
    })
  }

  if(argv.e == 'replicaset') {
    //
    // Replicaset
    config = {
        host: 'localhost'
      , port: 31000
      , setName: 'rs'
      , fork:null
      , skipStart: startupOptions.skipStartup
      , skipTermination: startupOptions.skipShutdown
      , topology: function(self, _mongo) {
        return new _mongo.ReplSet([{
            host: 'localhost'
          , port: 31000
        }], { setName: 'rs' });
      }
      , manager: new ReplSetManager({
          dbpath: path.join(path.resolve('db'))
        , logpath: path.join(path.resolve('db'))
        , tags: [{loc: "ny"}, {loc: "sf"}, {loc: "sf"}]
        , arbiters: 1
        , passives: 1
      })
    }
  } else if(argv.e == 'sharded') {
    //
    // Sharded
    config = {
        host: 'localhost'
      , port: 50000
      , skipStart: startupOptions.skipStartup
      , skipTermination: startupOptions.skipShutdown
      , topology: function(self, _mongo) {
        return new _mongo.Mongos([{
            host: 'localhost'
          , port: 50000
        }]);
      }, manager: new ShardingManager({
          dbpath: path.join(path.resolve('db'))
        , logpath: path.join(path.resolve('db'))
        , tags: [{loc: "ny"}, {loc: "sf"}, {loc: "sf"}]
        , mongosStartPort: 50000
        , replsetStartPort: 31000
      })
    }
  }

  // If we have a test we are filtering by
  if(argv.f) {
    runner.plugin(new FileFilter(argv.f));
  }

  if(argv.n) {
    runner.plugin(new TestNameFilter(argv.n));
  }

  // Add travis filter
  runner.plugin(new TravisFilter());

  // Skip startup
  if(startupOptions.skipStartup) {
    return runner.run(Configuration(config));
  }

  // Kill any running MongoDB processes and
  // `install $MONGODB_VERSION` || `use existing installation` || `install stable`
  m(function(err){
    if(err) return console.error(err) && process.exit(1);

    m.current(function(err, version){
      if(err) return console.error(err) && process.exit(1);
      console.log('Running tests against MongoDB version `%s`', version);
      // Run the configuration
      runner.run(Configuration(config));
    });
  });
}
<commit_msg>fix for runner to skip version download<commit_after>"use strict";

var Runner = require('integra').Runner
  , Cover = require('integra').Cover
  , RCover = require('integra').RCover
  , f = require('util').format
  , m = require('mongodb-version-manager')
  , path = require('path')
  , NodeVersionFilter = require('./filters/node_version_filter')
  , MongoDBVersionFilter = require('./filters/mongodb_version_filter')
  , MongoDBTopologyFilter = require('./filters/mongodb_topology_filter')
  , ES6PromisesSupportedFilter = require('./filters/es6_promises_supported_filter')
  , ES6GeneratorsSupportedFilter = require('./filters/es6_generators_supported_filter')
  , TravisFilter = require('./filters/travis_filter')
  , FileFilter = require('integra').FileFilter
  , TestNameFilter = require('integra').TestNameFilter
  , ServerManager = require('mongodb-tools').ServerManager
  , ReplSetManager = require('mongodb-tools').ReplSetManager
  , ShardingManager = require('mongodb-tools').ShardingManager;

var detector = require('gleak')();
var smokePlugin = require('../lib/tools/smoke_plugin.js');
var argv = require('optimist')
    .usage('Usage: $0 -t [target] -e [environment] -n [name] -f [filename] -r [smoke report file]')
    .demand(['t'])
    .argv;

// Skipping parameters
var startupOptions = {
    skipStartup: true
  , skipRestart: true
  , skipShutdown: true
  , skip: false
}

// Skipping parameters
var startupOptions = {
    skipStartup: false
  , skipRestart: false
  , skipShutdown: false
  , skip: false
}

// Skipping parameters
if(argv.s) {
  var startupOptions = {
      skipStartup: true
    , skipRestart: true
    , skipShutdown: true
    , skip: false
  }
}

/**
 * Standalone MongoDB Configuration
 */
var f = require('util').format;
var Logger = require('../lib/connection/logger');

var Configuration = function(options) {
  options = options || {};
  var host = options.host || 'localhost';
  var port = options.port || 27017;
  var db = options.db || 'integration_tests';
  var mongo = null;
  var manager = options.manager;
  var skipStart = typeof options.skipStart == 'boolean' ? options.skipStart : false;
  var skipTermination = typeof options.skipTermination == 'boolean' ? options.skipTermination : false;
  var setName = options.setName || 'rs';

  // Default function
  var defaultFunction = function(self, _mongo) {
    return new _mongo.Server({
        host: self.host
      , port: self.port
    });
  };

  // Create a topology function
  var topology = options.topology || defaultFunction;

  return function(context) {
    mongo = require('..');

    return {
      start: function(callback) {
        var self = this;
        if(skipStart) return callback();
        // Start the db
        manager.start({purge:true, signal: -9}, function(err) {
          var server = topology(self, mongo);
          // Set up connect
          server.once('connect', function() {
            // Drop the database
            server.command(f("%s.$cmd", self.db), {dropDatabase: 1}, function(err, r) {
              server.destroy();
              callback();
            });
          });

          // Connect
          server.connect();
        });
      },

      stop: function(callback) {
        if(skipTermination) return callback();
        // manager.stop({signal: -9}, function() {

        //   // Print any global leaks
        //   detector.detect().forEach(function (name) {
        //     console.warn('found global leak: %s', name);
        //   });

        //   // Finish up the tests
        //   callback();
        // });
        var exec = require('child_process').exec;
        exec(f("killall %d mongod", -9), function(err, stdout, stderr) {
          setTimeout(function() {
            callback();
          }, 5000);
        });
      },

      restart: function(options, callback) {
        if(typeof options == 'function') callback = options, options = {purge:true, kill:true};
        if(skipTermination) return callback();

        manager.restart(options, function() {
          setTimeout(function() {
            callback();
          }, 1000);
        });
      },

      setup: function(callback) {
        callback();
      },

      teardown: function(callback) {
        callback();
      },

      newTopology: function(options, callback) {
        if(typeof options == 'function') {
          callback = options;
          options = {};
        }

        callback(null, topology(this, mongo));
      },

      newConnection: function(options, callback) {
        if(typeof options == 'function') {
          callback = options;
          options = {};
        }

        var server = topology(this, mongo);
        // Set up connect
        server.once('connect', function() {
          callback(null, server);
        });

        // Connect
        server.connect();
      },

      // Additional parameters needed
      require: mongo,
      port: port,
      host: host,
      setName: setName,
      db: db,
      manager: manager,
      writeConcern: function() { return {w: 1} }
    }
  }
}

// Set up the runner
var runner = new Runner({
    logLevel:'info'
  , runners: 1
  , failFast: true
});

var testFiles = [
    '/test/tests/functional/server_tests.js'
  , '/test/tests/functional/operations_tests.js'
  , '/test/tests/functional/basic_auth_tests.js'
  , '/test/tests/functional/extend_pick_strategy_tests.js'
  , '/test/tests/functional/mongos_tests.js'
  , '/test/tests/functional/extend_cursor_tests.js'
  , '/test/tests/functional/pool_tests.js'
  , '/test/tests/functional/connection_tests.js'
  , '/test/tests/functional/rs_topology_tests.js'
  , '/test/tests/functional/rs_topology_state_tests.js'
  , '/test/tests/functional/single_topology_tests.js'
  , '/test/tests/functional/cursor_tests.js'
  , '/test/tests/functional/error_tests.js'
  , '/test/tests/functional/tailable_cursor_tests.js'
  , '/test/tests/functional/operation_example_tests.js'
  , '/test/tests/functional/replset_failover_tests.js'
  , '/test/tests/functional/undefined_tests.js'
]

// Check if we support es6 generators
try {
  eval("(function *(){})");
  // Single server Mock Tests
  testFiles.push('/test/tests/functional/single_mocks/timeout_tests.js');

  // Replicaset Mock Tests
  testFiles.push('/test/tests/functional/rs_mocks/add_remove_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/connection_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/failover_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/monitoring_tests.js');
  testFiles.push('/test/tests/functional/rs_mocks/read_preferences_tests.js');

  // Mongos Mock Tests
  testFiles.push('/test/tests/functional/mongos_mocks/single_proxy_connection_tests.js');
  testFiles.push('/test/tests/functional/mongos_mocks/multiple_proxies_tests.js');
  testFiles.push('/test/tests/functional/mongos_mocks/proxy_failover_tests.js');
  testFiles.push('/test/tests/functional/mongos_mocks/proxy_read_preference_tests.js');
} catch(err) {}

// Add all the tests to run
testFiles.forEach(function(t) {
  if(t != "") runner.add(t);
});

// // Add the Coverage plugin
// runner.plugin(new Cover({
//  logLevel: "info"
//  , filters: [
//      /_tests.js/
//    , "js-bson"
//    , "/tests/"
//    , "/tools/"
//  ]
// }));

// // Add the RCoverage plugin
// runner.plugin(new RCover({
//    logLevel: "info"
//  , filters: [
//      /_tests.js/
//    , "js-bson"
//    , "/tests/"
//    , "/tools/"
//  ]
// }));

// Add a Node version plugin
runner.plugin(new NodeVersionFilter(startupOptions));
// Add a MongoDB version plugin
runner.plugin(new MongoDBVersionFilter(startupOptions));
// Add a Topology filter plugin
runner.plugin(new MongoDBTopologyFilter(startupOptions));
// Add a Filter allowing us to specify that a function requires Promises
runner.plugin(new ES6PromisesSupportedFilter())
// Add a Filter allowing us to validate if generators are available
runner.plugin(new ES6GeneratorsSupportedFilter())

// Exit when done
runner.on('exit', function(errors, results) {
  process.exit(0)
});

// Set Logger level for driver
// Logger.setLevel('info');
Logger.setLevel('error');
// Logger.setLevel('debug');
// Logger.filter('class', ['ReplSet', 'Server', 'Connection']);
// Logger.filter('class', ['ReplSet', 'Server', 'Pool', 'Connection']);
// Logger.filter('class', ['ReplSet', 'Server', 'Cursor']);
//Logger.filter('class', ['Mongos', 'Server']);
//Logger.filter('class', ['Mongos', 'Server']);
// Logger.filter('class', ['Mongos']);
// Logger.filter('class', ['ReplSet']);

// We want to export a smoke.py style json file
if(argv.r) {
  console.log("Writing smoke output to " + argv.r);
  smokePlugin.attachToRunner(runner, argv.r);
}

// Are we running a functional test
if(argv.t == 'functional') {
  //
  // Single server
  var config = {
      host: 'localhost'
    , port: 27017
    // , skipStart: false
    // , skipTermination: false
    , skipStart: startupOptions.skipStartup
    , skipTermination: startupOptions.skipShutdown
    , manager: new ServerManager({
        dbpath: path.join(path.resolve('db'), f("data-%d", 27017))
      , logpath: path.join(path.resolve('db'), f("data-%d.log", 27017))
    })
  }

  if(argv.e == 'replicaset') {
    //
    // Replicaset
    config = {
        host: 'localhost'
      , port: 31000
      , setName: 'rs'
      , fork:null
      , skipStart: startupOptions.skipStartup
      , skipTermination: startupOptions.skipShutdown
      , topology: function(self, _mongo) {
        return new _mongo.ReplSet([{
            host: 'localhost'
          , port: 31000
        }], { setName: 'rs' });
      }
      , manager: new ReplSetManager({
          dbpath: path.join(path.resolve('db'))
        , logpath: path.join(path.resolve('db'))
        , tags: [{loc: "ny"}, {loc: "sf"}, {loc: "sf"}]
        , arbiters: 1
        , passives: 1
      })
    }
  } else if(argv.e == 'sharded') {
    //
    // Sharded
    config = {
        host: 'localhost'
      , port: 50000
      , skipStart: startupOptions.skipStartup
      , skipTermination: startupOptions.skipShutdown
      , topology: function(self, _mongo) {
        return new _mongo.Mongos([{
            host: 'localhost'
          , port: 50000
        }]);
      }, manager: new ShardingManager({
          dbpath: path.join(path.resolve('db'))
        , logpath: path.join(path.resolve('db'))
        , tags: [{loc: "ny"}, {loc: "sf"}, {loc: "sf"}]
        , mongosStartPort: 50000
        , replsetStartPort: 31000
      })
    }
  }

  // If we have a test we are filtering by
  if(argv.f) {
    runner.plugin(new FileFilter(argv.f));
  }

  if(argv.n) {
    runner.plugin(new TestNameFilter(argv.n));
  }

  // Add travis filter
  runner.plugin(new TravisFilter());

  // Skip startup
  if(startupOptions.skipStartup) {
    return runner.run(Configuration(config));
  }

  // Skip the version download and use local mongod in PATH
  if(argv.l) {
    return runner.run(config);
  }

  // Kill any running MongoDB processes and
  // `install $MONGODB_VERSION` || `use existing installation` || `install stable`
  m(function(err){
    if(err) return console.error(err) && process.exit(1);

    m.current(function(err, version){
      if(err) return console.error(err) && process.exit(1);
      console.log('Running tests against MongoDB version `%s`', version);
      // Run the configuration
      runner.run(Configuration(config));
    });
  });
}
<|endoftext|>


<commit_before>module.exports = Parser;

var FileStructure = require('./file');
var MonicError = require('./error');

var fs = require('fs');
var async = require('async');

/**
 * Объект парсера файла
 * @constructor
 */
function Parser() {
	this._cache = {};
	this._realpathCache = {};
}

/**
 * Проверить существование указанного файла
 * и вернуть абсолютный путь к нему
 *
 * @param {string} file - адрес файла
 * @param {function(Error, string=)} callback - функция обратного вызова
 */
Parser.prototype.normalizePath = function (file, callback) {
	if (this._realpathCache[file]) {
		callback(null, this._realpathCache[file]);

	} else {
		async.waterfall([
			(callback) => {
				fs.exists(file, (exists) => {
					callback(null, exists);
				});
			},

			(exists, callback) => {
				if (!exists) {
					return callback(new Error(`File ${file} not found`));
				}

				fs.realpath(file, callback);
			},

			(src, callback) => {
				fs.stat(file, (err, stat) => {
					callback(err, stat, src.replace(/\\/g, '/'));
				});
			},

			(stat, src, callback) => {
				if (!stat.isFile()) {
					return callback(new Error(`File ${file} not found`));
				}

				this._realpathCache[file] = src;
				callback(null, src);
			}

		], callback);
	}
};

/**
 * Провести парсинг указанного файла
 * и вернуть его структуру
 *
 * @param {string} file - адрес файла
 * @param {function(Error, FileStructure=, string=)} callback - функция обратного вызова
 */
Parser.prototype.parseFile = function (file, callback) {
	this.normalizePath(file, (err, path) => {
		if (err) {
			return callback(err);
		}

		if (this._cache[path]) {
			return callback(null, this._cache[path], path);
		}

		fs.readFile(path, 'utf8', (err, content) => {
			if (err) {
				return callback(err);
			}

			this.parse(path, content, callback);
		});
	});
};

/**
 * Провести парсинг заданного текста
 * и вернуть его структуру
 *
 * @param {string} file - адрес файла
 * @param {string} content - содержимое файла
 * @param {function(Error, FileStructure=, string=)} callback - функция обратного вызова
 */
Parser.prototype.parse = function (file, content, callback) {
	if (this._cache[file]) {
		return callback(null, this._cache[file], file);
	}

	// Поддержка import в CSS
	content = content.replace(/@import url\(("|')(.*?)\1\);/gim, '//#include $2');

	// Поддержка require
	content = content.replace(/require\('(.*?)'\);/gim, '//#include $1');

	var fileStructure = new FileStructure(file);
	this._cache[file] = fileStructure;

	var lines = content.split(/\r?\n/);

	var parseLines = (start) => {
		var i;
		var errors = [];

		var appendError = (err) => {
			var msg = err.message;
			var line = i + 1;

			errors.push(new MonicError(msg, file, line));
			fileStructure.error(msg);
		};

		var asyncParseCallback = (err) => {
			if (err) {
				appendError(err);
			}

			parseLines(i + 1);
		};

		for (i = start; i < lines.length; i++) {
			let line = lines[i];

			if (line.match(/^\s*\/\/#([\s\S]*)$/)) {
				if (RegExp.$1) {
					let command = RegExp.$1.split(' '),
						dir = String(command.shift());

					let key = '_' + dir,
						params = command.join(' ');

					if (/^(include|without)$/.test(dir)) {
						return this[key](fileStructure, params, asyncParseCallback);

					} else if (/^(label|endlabel|if|endif|set|unset)$/.test(dir)) {
						try {
							this[key](fileStructure, params);

						} catch (err) {
							appendError(err);
						}

					} else {
						appendError(new Error(`Unknown directive ${dir}`));
					}
				}

			} else {
				fileStructure.addCode(line + (i < lines.length - 1 ? '\n' : ''));
			}
		}

		callback(null, fileStructure, file);
	};

	parseLines(0);
};

/**
 * Директива #include
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} params - параметры директивы
 * @param {function(Error=)} callback - функция обратного вызова
 */
Parser.prototype._include = function (file, params, callback) {
	var paramsParts = params.split('::'),
		includeFileName = paramsParts.shift();

	if (includeFileName) {
		let path = file.getRelativePathOf(includeFileName);
		this.parseFile(path, (err, includeFile) => {
			if (err) {
				return callback(err);
			}

			file.addInclude(includeFile, paramsParts);
			callback();
		});

	} else {
		try {
			file.addInclude(file, paramsParts);
			callback();

		} catch (err) {
			callback(err);
		}
	}
};

/**
 * Директива #without
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 * @param {function(Error=)} callback - функция обратного вызова
 */
Parser.prototype._without = function (file, value, callback) {
	var paramsParts = value.split('::'),
		includeFname = file.getRelativePathOf(paramsParts.shift());

	this.parseFile(includeFname, (err, includeFile) => {
		if (err) {
			return callback(err);
		}

		file.addWithout(includeFile, paramsParts);
		callback();
	});
};

/**
 * Директива #label
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._label = function (file, value) {
	file.beginLabel(value);
};

/**
 * Директива #endlabel
 * @param {!FileStructure} file - структура файла
 */
Parser.prototype._endlabel = function (file) {
	file.endLabel();
};

/**
 * Директива #if
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._if = function (file, value) {
	if (!value.trim()) {
		throw new Error('Bad "if" directive');
	}

	var args = value.split(/\s+/),
		res = true;

	if (args.length > 1 && args[0] === 'not') {
		res = false;
		args.shift();
	}

	file.beginIf(args[0], res);
};

/**
 * Директива #endif
 * @param {!FileStructure} file - структура файла
 */
Parser.prototype._endif = function (file) {
	file.endIf();
};

/**
 * Директива #set
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._set = function (file, value) {
	if (!value.trim()) {
		throw new Error('Bad set directive');
	}

	file.addSet(value.split(/\s+/)[0]);
};

/**
 * Директива #unset
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._unset = function (file, value) {
	if (!value.trim()) {
		throw new Error('Bad unset directive');
	}

	file.addUnset(value.split(/\s+/)[0]);
};
<commit_msg>Рефакторинг<commit_after>module.exports = Parser;

var FileStructure = require('./file');
var MonicError = require('./error');

var fs = require('fs');
var async = require('async');

/**
 * Объект парсера файла
 * @constructor
 */
function Parser() {
	this._cache = {};
	this._realpathCache = {};
}

/**
 * Проверить существование указанного файла
 * и вернуть абсолютный путь к нему
 *
 * @param {string} file - адрес файла
 * @param {function(Error, string=)} callback - функция обратного вызова
 */
Parser.prototype.normalizePath = function (file, callback) {
	if (this._realpathCache[file]) {
		callback(null, this._realpathCache[file]);

	} else {
		async.waterfall([
			(callback) => {
				fs.exists(file, (exists) => {
					callback(null, exists);
				});
			},

			(exists, callback) => {
				if (!exists) {
					return callback(new Error(`File ${file} not found`));
				}

				fs.realpath(file, callback);
			},

			(src, callback) => {
				fs.stat(file, (err, stat) => {
					callback(err, stat, src.replace(/\\/g, '/'));
				});
			},

			(stat, src, callback) => {
				if (!stat.isFile()) {
					return callback(new Error(`File ${file} not found`));
				}

				this._realpathCache[file] = src;
				callback(null, src);
			}

		], callback);
	}
};

/**
 * Провести парсинг указанного файла
 * и вернуть его структуру
 *
 * @param {string} file - адрес файла
 * @param {function(Error, FileStructure=, string=)} callback - функция обратного вызова
 */
Parser.prototype.parseFile = function (file, callback) {
	this.normalizePath(file, (err, src) => {
		if (err) {
			return callback(err);
		}

		if (this._cache[src]) {
			return callback(null, this._cache[src], src);
		}

		fs.readFile(src, 'utf8', (err, content) => {
			if (err) {
				return callback(err);
			}

			this.parse(src, content, callback);
		});
	});
};

/**
 * Провести парсинг заданного текста
 * и вернуть его структуру
 *
 * @param {string} file - адрес файла
 * @param {string} content - содержимое файла
 * @param {function(Error, FileStructure=, string=)} callback - функция обратного вызова
 */
Parser.prototype.parse = function (file, content, callback) {
	if (this._cache[file]) {
		return callback(null, this._cache[file], file);
	}

	// Поддержка import в CSS
	content = content.replace(/@import url\(("|')(.*?)\1\);/gim, '//#include $2');

	// Поддержка require
	content = content.replace(/require\('(.*?)'\);/gim, '//#include $1');

	var fileStructure = new FileStructure(file);
	this._cache[file] = fileStructure;

	var lines = content.split(/\r?\n/);

	var parseLines = (start) => {
		var i;
		var errors = [];

		var appendError = (err) => {
			var msg = err.message;
			var line = i + 1;

			errors.push(new MonicError(msg, file, line));
			fileStructure.error(msg);
		};

		var asyncParseCallback = (err) => {
			if (err) {
				appendError(err);
			}

			parseLines(i + 1);
		};

		for (i = start; i < lines.length; i++) {
			let line = lines[i];

			if (line.match(/^\s*\/\/#([\s\S]*)$/)) {
				if (RegExp.$1) {
					let command = RegExp.$1.split(' '),
						dir = String(command.shift());

					let key = '_' + dir,
						params = command.join(' ');

					if (/^(include|without)$/.test(dir)) {
						return this[key](fileStructure, params, asyncParseCallback);

					} else if (/^(label|endlabel|if|endif|set|unset)$/.test(dir)) {
						try {
							this[key](fileStructure, params);

						} catch (err) {
							appendError(err);
						}

					} else {
						appendError(new Error(`Unknown directive ${dir}`));
					}
				}

			} else {
				fileStructure.addCode(line + (i < lines.length - 1 ? '\n' : ''));
			}
		}

		callback(null, fileStructure, file);
	};

	parseLines(0);
};

/**
 * Директива #include
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} params - параметры директивы
 * @param {function(Error=)} callback - функция обратного вызова
 */
Parser.prototype._include = function (file, params, callback) {
	var paramsParts = params.split('::'),
		includeFileName = paramsParts.shift();

	if (includeFileName) {
		let src = file.getRelativePathOf(includeFileName);
		this.parseFile(src, (err, includeFile) => {
			if (err) {
				return callback(err);
			}

			file.addInclude(includeFile, paramsParts);
			callback();
		});

	} else {
		try {
			file.addInclude(file, paramsParts);
			callback();

		} catch (err) {
			callback(err);
		}
	}
};

/**
 * Директива #without
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 * @param {function(Error=)} callback - функция обратного вызова
 */
Parser.prototype._without = function (file, value, callback) {
	var paramsParts = value.split('::'),
		includeFname = file.getRelativePathOf(paramsParts.shift());

	this.parseFile(includeFname, (err, includeFile) => {
		if (err) {
			return callback(err);
		}

		file.addWithout(includeFile, paramsParts);
		callback();
	});
};

/**
 * Директива #label
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._label = function (file, value) {
	file.beginLabel(value);
};

/**
 * Директива #endlabel
 * @param {!FileStructure} file - структура файла
 */
Parser.prototype._endlabel = function (file) {
	file.endLabel();
};

/**
 * Директива #if
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._if = function (file, value) {
	if (!value.trim()) {
		throw new Error('Bad "if" directive');
	}

	var args = value.split(/\s+/),
		res = true;

	if (args.length > 1 && args[0] === 'not') {
		res = false;
		args.shift();
	}

	file.beginIf(args[0], res);
};

/**
 * Директива #endif
 * @param {!FileStructure} file - структура файла
 */
Parser.prototype._endif = function (file) {
	file.endIf();
};

/**
 * Директива #set
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._set = function (file, value) {
	if (!value.trim()) {
		throw new Error('Bad set directive');
	}

	file.addSet(value.split(/\s+/)[0]);
};

/**
 * Директива #unset
 *
 * @param {!FileStructure} file - структура файла
 * @param {string} value - значение директивы
 */
Parser.prototype._unset = function (file, value) {
	if (!value.trim()) {
		throw new Error('Bad unset directive');
	}

	file.addUnset(value.split(/\s+/)[0]);
};
<|endoftext|>


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

'use strict';

// Import this first so we can use it to wrap other modules we import.
var promisify = require("promisify-node");

var ghPages = require('gh-pages');
var gitconfiglocal = require('gitconfiglocal');
var gutil = require('gulp-util');

module.exports = promisify(function(config, callback) {
  config = config || {};

  var rootDir = config.rootDir ? config.rootDir : '.';

  if ('GH_TOKEN' in process.env) {
    // We're using a token to authenticate with GitHub, so we have to embed
    // the token into the repo URL (if it isn't already there).
    gitconfiglocal('./', function(error, config) {
      if (error) {
        callback(error);
        return;
      }

      if ('remote' in config && 'origin' in config.remote && 'url' in config.remote.origin) {
        var url = config.remote.origin.url;
        var match;
        if (match = url.match(/^git@github.com:([^/]+)\/([^.]+)\.git$/) ||
                    url.match(/^https:\/\/github.com\/([^/]+)\/([^.]+)\.git$/)) {
          url = 'https://' + process.env.GH_TOKEN + '@github.com/' + match[1] + '/' + match[2] + '.git';
        }

        ghPages.publish(rootDir, {
          // We can't log here because it would leak the GitHub token on Travis.
          // logger: gutil.log,
          repo: url,
        }, callback);
      } else {
        callback('repo has no origin url');
      }
    });
  } else {
    // We aren't using a token to authenticate with GitHub, so we don't have to
    // alter the repo URL.
    ghPages.publish(rootDir, {
      logger: gutil.log,
    }, callback);
  }
});
<commit_msg>Warn when the rootDir contains the node_modules directory. Fixes #15<commit_after>/**
 * Copyright 2015 Mozilla
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

// Import this first so we can use it to wrap other modules we import.
var promisify = require("promisify-node");

var ghPages = require('gh-pages');
var gitconfiglocal = require('gitconfiglocal');
var gutil = require('gulp-util');

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

module.exports = promisify(function(config, callback) {
  config = config || {};

  var rootDir = config.rootDir ? config.rootDir : '.';

  if (fs.existsSync(path.join(rootDir, 'node_modules'))) {
    gutil.log(gutil.colors.red('With the current value of the \'rootDir\' option, the entire node_modules directory is going to be deployed. Please make sure this is what you really want.'));
  }

  if ('GH_TOKEN' in process.env) {
    // We're using a token to authenticate with GitHub, so we have to embed
    // the token into the repo URL (if it isn't already there).
    gitconfiglocal('./', function(error, config) {
      if (error) {
        callback(error);
        return;
      }

      if ('remote' in config && 'origin' in config.remote && 'url' in config.remote.origin) {
        var url = config.remote.origin.url;
        var match;
        if (match = url.match(/^git@github.com:([^/]+)\/([^.]+)\.git$/) ||
                    url.match(/^https:\/\/github.com\/([^/]+)\/([^.]+)\.git$/)) {
          url = 'https://' + process.env.GH_TOKEN + '@github.com/' + match[1] + '/' + match[2] + '.git';
        }

        ghPages.publish(rootDir, {
          // We can't log here because it would leak the GitHub token on Travis.
          // logger: gutil.log,
          repo: url,
        }, callback);
      } else {
        callback('repo has no origin url');
      }
    });
  } else {
    // We aren't using a token to authenticate with GitHub, so we don't have to
    // alter the repo URL.
    ghPages.publish(rootDir, {
      logger: gutil.log,
    }, callback);
  }
});
<|endoftext|>


<commit_before>
angular.module('os.query.globaldata', ['os.query.models', 'os.biospecimen.models'])
  .factory('QueryGlobalData', function($translate, $q, CollectionProtocol, Form, SavedQuery, QueryUtil, Util) {
    var QueryGlobalData = function() {
      this.cpsQ = undefined;
      this.cpList = undefined;
      this.defSelectList = [];
    };

    QueryGlobalData.prototype.getCps = function() {
      var d = $q.defer();

      if (!this.cpsQ) {
        var that = this;
        this.cpsQ = CollectionProtocol.query().then(
          function(result) {
            return $translate('common.none').then(
              function(none) {
                result.unshift({id: -1, shortTitle: none, title: none});
                that.cpList = result;
                return that.cpList;
              }
            );
          }
        );
      }

      this.cpsQ.then(function(result) { d.resolve(result); });
      return d.promise;
    };

    QueryGlobalData.prototype.loadCpForms = function(cp) {
      var d = $q.defer();
      if (!this.formsQ) {
        this.formsQ = Form.listQueryForms();
      }

      if (!cp.forms) {
        cp.forms = [];
        this.formsQ.then(
          function(forms) {
            Util.unshiftAll(cp.forms, forms);
            angular.forEach(cp.forms, function(form) {
              form.cp = cp;
            });
            d.resolve(cp.forms);
          }
        );
      } else {
        d.resolve(cp.forms);
      }

      return d.promise;
    }

    QueryGlobalData.prototype.newQueryCtx = function(savedQuery) {
      savedQuery = savedQuery || {};

      var selectList = savedQuery.selectList;
      if (!selectList) {
        selectList = [];
        initDefSelectList(this, selectList);
      }

      this.queryCtx = {
        currentFilter: {},
        disableCpSelection: false,
        id: savedQuery.id,
        title: savedQuery.title,
        filters: [],
        filtersMap: {},
        exprNodes: [],
        filterId: 0,
        selectedFields: selectList,
        reporting: savedQuery.reporting || {type: 'none', params: {}},
        selectedCp: {id: savedQuery.cpId},
        isValid: true,
        drivingForm: 'Participant',
        wideRowMode: savedQuery.wideRowMode || 'DEEP'
      };

      var that = this;
      if (!savedQuery.cpId || savedQuery.cpId == -1) {
        this.getCps().then(
          function(cps) {
            that.queryCtx.selectedCp = cps[0];
          }
        );
      }

      return this.queryCtx;
    }

    QueryGlobalData.prototype.clearQueryCtx = function() {
      this.queryCtx = undefined;
    }

    QueryGlobalData.prototype.setQueryCtx = function(queryCtx) {
      this.queryCtx = queryCtx;
    }

    QueryGlobalData.prototype.getQueryCtx = function(queryId, cpId) {
      if (this.queryCtx && !cpId) {
        return this.queryCtx;
      }

      if (!queryId || queryId <= 0) {
        return this.newQueryCtx();
      }

      var that = this;
      return SavedQuery.getById(queryId).then(
        function(savedQuery) {
          return createQueryCtx(that, savedQuery, cpId);
        }
      );
    };

    function createQueryCtx(queryGlobal, savedQuery, cpId) {
      var queryCtx = queryGlobal.newQueryCtx(savedQuery);
      return queryGlobal.getCps().then(
        function(cps) {
          if (!!cpId) {
            savedQuery.cpId = cpId;
          }

          var selectedCp = queryCtx.selectedCp = getCp(cps, savedQuery.cpId || -1);
          if (!selectedCp) {
            return undefined;
          }

          var promise = queryGlobal.loadCpForms(selectedCp).then(
            function(forms) {
              recreateUiFilters(queryCtx, savedQuery.filters);
              recreateUiExprNodes(queryCtx, savedQuery.queryExpression);
              return $q.all(loadFormFieldsNeededForFilters(queryCtx.filters));
            }
          );

          return promise.then(
            function() {
              fleshOutFilterFields(queryCtx);
              return queryCtx;
            }
          )
        }
      );
    }

    function getCp(cps, cpId) {
      for (var i = 0; i < cps.length; ++i) {
        if (cps[i].id == cpId) {
          return cps[i];
        }
      }

      return null;
    }

    function recreateUiFilters(queryCtx, filters) {
      var uiFilters = queryCtx.filters = [];
      var filtersMap = queryCtx.filtersMap = {};
      var filterId = 0;

      angular.forEach(filters, function(filter) {
        var uiFilter = QueryUtil.getUiFilter(queryCtx.selectedCp, filter);
        uiFilters.push(uiFilter);
        filtersMap[uiFilter.id] = uiFilter;

        if (filterId < uiFilter.id) {
          filterId = uiFilter.id;
        }
      });

      queryCtx.filterId = filterId;
    }

    function recreateUiExprNodes(queryCtx, queryExpressions) {
      var exprNodes = queryCtx.exprNodes = [];
      angular.forEach(queryExpressions, function(expr) {
        if (expr.nodeType == 'FILTER') {
          exprNodes.push({type: 'filter', value: expr.value});
        } else if (expr.nodeType == 'OPERATOR') {
          exprNodes.push({type: 'op', value: QueryUtil.getOpByModel(expr.value).name});
        } else if (expr.nodeType == 'PARENTHESIS') {
          exprNodes.push({type: 'paren', value: expr.value == 'LEFT' ? '(' : ')'});
        }
      });

      return exprNodes;
    }

    function loadFormFieldsNeededForFilters(filters) {
      var promises = [];
      var loadedForms = {};
      angular.forEach(filters, function(filter) {
        if (filter.expr) {
          return;
        }

        var form = filter.form;
        if (!loadedForms[form.name]) {
          promises.push(form.getFields());
          loadedForms[form.name] = true;
        }
      });

      return promises;
    }

    function fleshOutFilterFields(queryCtx) {
      for (var i = 0; i < queryCtx.filters.length; ++i) {
        var filter = queryCtx.filters[i];
        if (filter.expr) {
          continue;
        }

        filter.field = filter.form.getField(filter.fieldName);
        if (!filter.field) {
          return undefined;
        }
      }

      QueryUtil.disableCpSelection(queryCtx);
    }

    function initDefSelectList(queryGlobal, selectList) {
      if (queryGlobal.defSelectList.length > 0) {
        Util.unshiftAll(selectList, queryGlobal.defSelectList);
        return;
      }

      getDefParticipantForm(queryGlobal).then(
        function(form) {
          form.getFields().then(
            function(fields) {
              angular.forEach(fields, function(field) {
                if (field.type == 'SUBFORM') {
                  return;
                }

                queryGlobal.defSelectList.push('Participant.' + field.name);
              });

              Util.unshiftAll(selectList, queryGlobal.defSelectList);
            }
          );
        }
      );
    }

    function getDefParticipantForm(queryGlobal) {
      return queryGlobal.getCps().then(
        function(cps) {
          return getParticipantForm(queryGlobal, cps[0]);
        }
      );
    }

    function getParticipantForm(queryGlobal, cp) {
      return queryGlobal.loadCpForms(cp).then(
        function(forms) {
          for (var i = 0; i < forms.length; ++i) {
            if (forms[i].name == 'Participant') {
              return forms[i];
            }
          }

          return null;
        }
      );
    }

    return QueryGlobalData;
  })

  .factory('QueryCtxHolder', function() {
    var queryCtx;

    return {
      getCtx: function() {
        return queryCtx;
      },

      setCtx: function(ctx) {
        queryCtx = ctx;
      },

      clearCtx: function() {
        queryCtx = undefined;
      }
    };
  });
<commit_msg>OPSMN-2919: Clear out fields when copying generic query forms to CP specific forms list. This allows to load CP specific fields and therefore the extension/attached forms.<commit_after>
angular.module('os.query.globaldata', ['os.query.models', 'os.biospecimen.models'])
  .factory('QueryGlobalData', function($translate, $q, CollectionProtocol, Form, SavedQuery, QueryUtil, Util) {
    var QueryGlobalData = function() {
      this.cpsQ = undefined;
      this.cpList = undefined;
      this.defSelectList = [];
    };

    QueryGlobalData.prototype.getCps = function() {
      var d = $q.defer();

      if (!this.cpsQ) {
        var that = this;
        this.cpsQ = CollectionProtocol.query().then(
          function(result) {
            return $translate('common.none').then(
              function(none) {
                result.unshift({id: -1, shortTitle: none, title: none});
                that.cpList = result;
                return that.cpList;
              }
            );
          }
        );
      }

      this.cpsQ.then(function(result) { d.resolve(result); });
      return d.promise;
    };

    QueryGlobalData.prototype.loadCpForms = function(cp) {
      var d = $q.defer();
      if (!this.formsQ) {
        this.formsQ = Form.listQueryForms();
      }

      if (!cp.forms) {
        cp.forms = [];
        this.formsQ.then(
          function(forms) {
            Util.unshiftAll(cp.forms, angular.copy(forms));

            var refCp = new CollectionProtocol(cp);
            delete refCp.forms;

            angular.forEach(cp.forms, function(form) {
              form.cp = refCp;
              form.fields = undefined;
            });
            d.resolve(cp.forms);
          }
        );
      } else {
        d.resolve(cp.forms);
      }

      return d.promise;
    }

    QueryGlobalData.prototype.newQueryCtx = function(savedQuery) {
      savedQuery = savedQuery || {};

      var selectList = savedQuery.selectList;
      if (!selectList) {
        selectList = [];
        initDefSelectList(this, selectList);
      }

      this.queryCtx = {
        currentFilter: {},
        disableCpSelection: false,
        id: savedQuery.id,
        title: savedQuery.title,
        filters: [],
        filtersMap: {},
        exprNodes: [],
        filterId: 0,
        selectedFields: selectList,
        reporting: savedQuery.reporting || {type: 'none', params: {}},
        selectedCp: {id: savedQuery.cpId},
        isValid: true,
        drivingForm: 'Participant',
        wideRowMode: savedQuery.wideRowMode || 'DEEP'
      };

      var that = this;
      if (!savedQuery.cpId || savedQuery.cpId == -1) {
        this.getCps().then(
          function(cps) {
            that.queryCtx.selectedCp = cps[0];
          }
        );
      }

      return this.queryCtx;
    }

    QueryGlobalData.prototype.clearQueryCtx = function() {
      this.queryCtx = undefined;
    }

    QueryGlobalData.prototype.setQueryCtx = function(queryCtx) {
      this.queryCtx = queryCtx;
    }

    QueryGlobalData.prototype.getQueryCtx = function(queryId, cpId) {
      if (this.queryCtx && !cpId) {
        return this.queryCtx;
      }

      if (!queryId || queryId <= 0) {
        return this.newQueryCtx();
      }

      var that = this;
      return SavedQuery.getById(queryId).then(
        function(savedQuery) {
          return createQueryCtx(that, savedQuery, cpId);
        }
      );
    };

    function createQueryCtx(queryGlobal, savedQuery, cpId) {
      var queryCtx = queryGlobal.newQueryCtx(savedQuery);
      return queryGlobal.getCps().then(
        function(cps) {
          if (!!cpId) {
            savedQuery.cpId = cpId;
          }

          var selectedCp = queryCtx.selectedCp = getCp(cps, savedQuery.cpId || -1);
          if (!selectedCp) {
            return undefined;
          }

          var promise = queryGlobal.loadCpForms(selectedCp).then(
            function(forms) {
              recreateUiFilters(queryCtx, savedQuery.filters);
              recreateUiExprNodes(queryCtx, savedQuery.queryExpression);
              return $q.all(loadFormFieldsNeededForFilters(queryCtx.filters));
            }
          );

          return promise.then(
            function() {
              fleshOutFilterFields(queryCtx);
              return queryCtx;
            }
          )
        }
      );
    }

    function getCp(cps, cpId) {
      for (var i = 0; i < cps.length; ++i) {
        if (cps[i].id == cpId) {
          return cps[i];
        }
      }

      return null;
    }

    function recreateUiFilters(queryCtx, filters) {
      var uiFilters = queryCtx.filters = [];
      var filtersMap = queryCtx.filtersMap = {};
      var filterId = 0;

      angular.forEach(filters, function(filter) {
        var uiFilter = QueryUtil.getUiFilter(queryCtx.selectedCp, filter);
        uiFilters.push(uiFilter);
        filtersMap[uiFilter.id] = uiFilter;

        if (filterId < uiFilter.id) {
          filterId = uiFilter.id;
        }
      });

      queryCtx.filterId = filterId;
    }

    function recreateUiExprNodes(queryCtx, queryExpressions) {
      var exprNodes = queryCtx.exprNodes = [];
      angular.forEach(queryExpressions, function(expr) {
        if (expr.nodeType == 'FILTER') {
          exprNodes.push({type: 'filter', value: expr.value});
        } else if (expr.nodeType == 'OPERATOR') {
          exprNodes.push({type: 'op', value: QueryUtil.getOpByModel(expr.value).name});
        } else if (expr.nodeType == 'PARENTHESIS') {
          exprNodes.push({type: 'paren', value: expr.value == 'LEFT' ? '(' : ')'});
        }
      });

      return exprNodes;
    }

    function loadFormFieldsNeededForFilters(filters) {
      var promises = [];
      var loadedForms = {};
      angular.forEach(filters, function(filter) {
        if (filter.expr) {
          return;
        }

        var form = filter.form;
        if (!loadedForms[form.name]) {
          promises.push(form.getFields());
          loadedForms[form.name] = true;
        }
      });

      return promises;
    }

    function fleshOutFilterFields(queryCtx) {
      for (var i = 0; i < queryCtx.filters.length; ++i) {
        var filter = queryCtx.filters[i];
        if (filter.expr) {
          continue;
        }

        filter.field = filter.form.getField(filter.fieldName);
        if (!filter.field) {
          return undefined;
        }
      }

      QueryUtil.disableCpSelection(queryCtx);
    }

    function initDefSelectList(queryGlobal, selectList) {
      if (queryGlobal.defSelectList.length > 0) {
        Util.unshiftAll(selectList, queryGlobal.defSelectList);
        return;
      }

      getDefParticipantForm(queryGlobal).then(
        function(form) {
          form.getFields().then(
            function(fields) {
              angular.forEach(fields, function(field) {
                if (field.type == 'SUBFORM') {
                  return;
                }

                queryGlobal.defSelectList.push('Participant.' + field.name);
              });

              Util.unshiftAll(selectList, queryGlobal.defSelectList);
            }
          );
        }
      );
    }

    function getDefParticipantForm(queryGlobal) {
      return queryGlobal.getCps().then(
        function(cps) {
          return getParticipantForm(queryGlobal, cps[0]);
        }
      );
    }

    function getParticipantForm(queryGlobal, cp) {
      return queryGlobal.loadCpForms(cp).then(
        function(forms) {
          for (var i = 0; i < forms.length; ++i) {
            if (forms[i].name == 'Participant') {
              return forms[i];
            }
          }

          return null;
        }
      );
    }

    return QueryGlobalData;
  })

  .factory('QueryCtxHolder', function() {
    var queryCtx;

    return {
      getCtx: function() {
        return queryCtx;
      },

      setCtx: function(ctx) {
        queryCtx = ctx;
      },

      clearCtx: function() {
        queryCtx = undefined;
      }
    };
  });
<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Arrow for popups
//>>label: popuparrow
//>>group: Widgets
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css
//>>css.structure: ../css/structure/jquery.mobile.popup.arrow.css

define( [ "jquery", "./popup" ],

function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");

( function( $, undefined ) {

var uiTemplate = $(
		'

' +
		'
' +
			'
' +
				'

' +
			'
' +
		'
'
	),
	// Needed for transforming coordinates from screen to arrow background
	txFactor = Math.sqrt( 2 ) / 2,
	ieHack = false;

$( document ).on( "mobileinit", function() {
	ieHack = ( $.mobile.browser.oldIE && $.mobile.browser.oldIE <= 8 );
	if ( ieHack ) {
		// Add class "ie" to the container
		uiTemplate.eq( 1 ).addClass( "ie" );
	}
});

function getArrow() {
	var clone = uiTemplate.clone(),
		gd = clone.eq( 0 ),
		ct = clone.eq( 1 ),
		ar = ct.children(),
		bg = ar.children();

	return { arEls: ct.add( gd ), gd: gd, ct: ct, ar: ar, bg: bg };
}

$.widget( "mobile.popup", $.mobile.popup, {
	options: {
		arrow: false,
		arrowSides: "t,b,l,r"
	},

	_unenhance: function() {
		var ar = this._ui.arrow;

		if ( ar ) {
			ar.arEls.remove();
		}

		return this._super();
	},

	_updateArrow: function( direction ) {
		var ar = this._ui.arrow,
			oldTheme = ar.ct.jqmData( "oldTheme" ),
			theme = "ui-body-" + ( this.options.theme || $.mobile.getInheritedTheme( this.element, "c" ) );

		// Remove old direction and theme
		ar.ct.removeClass( "l t r b" );
		if ( oldTheme ) {
			ar.ar.removeClass( oldTheme );
			ar.bg.removeClass( oldTheme );
		}

		ar.ar.toggleClass( "ui-overlay-shadow", this.options.shadow );

		// Set new direction and theme
		ar.ct.jqmData( "oldTheme", theme );
		ar.ct.addClass( direction );
		ar.ar.addClass( theme );
		ar.bg.addClass( theme );
	},

	// Pretend to show an arrow described by @p and @dir and calculate the
	// distance from the desired point. If a best-distance is passed in, return
	// the minimum of the one passed in and the one calculated.
	_tryAnArrow: function( p, dir, desired, s, best ) {
		var result, r, diff, desiredForArrow = {}, tip = {};

		// If the arrow has no wiggle room along the edge of the popup, it cannot
		// be displayed along the requested edge without it sticking out.
		if ( s.arFull[ p.dimKey ] > s.guideDims[ p.dimKey ] ) {
			return best;
		}

		desiredForArrow[ p.fst ] = desired[ p.fst ] + ( s.arHalf[ p.oDimKey ] + s.menuHalf[ p.oDimKey ] ) * p.offsetFactor;
		desiredForArrow[ p.snd ] = desired[ p.snd ];

		result = s.result || this._calculateFinalLocation( desiredForArrow, s.clampInfo );
		r = { x: result.left, y: result.top };

		tip[ p.fst ] = r[ p.fst ] + p.tipOffset;
		tip[ p.snd ] = Math.max( result[ p.prop ] + s.guideOffset[ p.prop ] + s.arHalf[ p.dimKey ],
			Math.min( result[ p.prop ] + s.guideOffset[ p.prop ] + s.guideDims[ p.dimKey ] - s.arHalf[ p.dimKey ],
				desired[ p.snd ] ) );

		diff = Math.abs( desired.x - tip.x ) + Math.abs( desired.y - tip.y );
		if ( !best || diff < best.diff ) {
			best = { dir: dir, diff: diff, result: result, posProp: p.prop, posVal: tip[ p.snd ] - s.arHalf[ p.dimKey ] - result[ p.prop ] };
		}

		return best;
	},

	_getPlacementState: function( clamp ) {
		var offset,
			ar = this._ui.arrow,
			state = {
				clampInfo: this._clampPopupWidth( !clamp ),
				arFull: { cx: ar.ct.width(), cy: ar.ct.height() },
				guideDims: { cx: ar.gd.width(), cy: ar.gd.height() },
				guideOffset: ar.gd.offset()
			};

		offset = this.element.offset();
		// The arrow box moves between guideOffset and guideOffset + guideDims - arFull
		state.guideOffset = { left: state.guideOffset.left - offset.left, top: state.guideOffset.top - offset.top };
		state.arHalf = { cx: state.arFull.cx / 2, cy: state.arFull.cy / 2 };
		state.menuHalf = { cx: state.clampInfo.menuSize.cx / 2, cy: state.clampInfo.menuSize.cy / 2 };

		return state;
	},

	_placementCoords: function( desired ) {
		var state, menuFull, best, params, bgOffset, diff,
			bgRef = {},
			ar = this._ui.arrow ;

		if ( !this.options.arrow ) {
			return this._super( desired );
		}

		ar.arEls.show();

		state = this._getPlacementState( true );
		menuFull = state.clampInfo.menuSize;

		params = {
			"l": { fst: "x", snd: "y", prop: "top", dimKey: "cy", oDimKey: "cx", offsetFactor: 1, tipOffset: -( state.arHalf.cx ) },
			"r": { fst: "x", snd: "y", prop: "top", dimKey: "cy", oDimKey: "cx", offsetFactor: -1, tipOffset: menuFull.cx + state.arHalf.cx },
			"b": { fst: "y", snd: "x", prop: "left", dimKey: "cx", oDimKey: "cy", offsetFactor: -1, tipOffset: menuFull.cy + state.arHalf.cy },
			"t": { fst: "y", snd: "x", prop: "left", dimKey: "cx", oDimKey: "cy", offsetFactor: 1, tipOffset: -( state.arHalf.cx ) }
		};

		// Try each side specified in the options to see on which one the arrow
		// should be placed such that the distance between the tip of the arrow and
		// the desired coordinates is the shortest.
		$.each( this.options.arrowSides.split( "," ),
			$.proxy( function( key, value ) {
				best = this._tryAnArrow( params[ value ], value, desired, state, best );
			}, this ) );

		// Could not place the arrow along any of the edges - behave as if showing
		// the arrow was turned off.
		if ( !best ) {
			ar.arEls.hide();
			return this._super( desired );
		}

		// Move the arrow into place
		ar.ct.removeAttr( "style" ).show().css( best.posProp, best.posVal );
		this._updateArrow( best.dir );

		// Do not move/size the background div on IE, because we use the arrow div for background as well.
		if ( !ieHack ) {
			bgRef[ params[ best.dir ].fst ] = ar.ct.offset();
			bgRef[ params[ best.dir ].snd ] = this.element.offset();
			bgOffset = ar.bg
				.removeAttr( "style" )
				.css( ( "cx" === params[ best.dir ].dimKey ? "width" : "height" ), menuFull[ params[ best.dir ].dimKey ] )
				.offset();
			diff = { dx: bgRef.x.left - bgOffset.left, dy: bgRef.y.top - bgOffset.top };
			ar.bg.css( { left: txFactor * diff.dy + txFactor * diff.dx, top: txFactor * diff.dy - txFactor * diff.dx } );
		}

		return best.result;
	},

	_setArrow: function( value ) {
		var ar = this._ui.arrow;

		if ( value ) {
			if ( !ar ) {
				ar = this._ui.arrow = getArrow();
			}
			ar.arEls.appendTo( this.element ).hide();
		} else if ( ar ) {
			ar.arEls.remove();
		}
	}
});

})( jQuery );

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>Popup arrow: Simplifying decision as to whether the IE workaround is needed.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Arrow for popups
//>>label: popuparrow
//>>group: Widgets
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css
//>>css.structure: ../css/structure/jquery.mobile.popup.arrow.css

define( [ "jquery", "./popup" ],

function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");

( function( $, undefined ) {

var ieHack = ( $.mobile.browser.oldIE && $.mobile.browser.oldIE <= 8 ),
	uiTemplate = $(
		'

' +
		'
' +
			'
' +
				'

' +
			'
' +
		'
'
	),
	// Needed for transforming coordinates from screen to arrow background
	txFactor = Math.sqrt( 2 ) / 2;

function getArrow() {
	var clone = uiTemplate.clone(),
		gd = clone.eq( 0 ),
		ct = clone.eq( 1 ),
		ar = ct.children(),
		bg = ar.children();

	return { arEls: ct.add( gd ), gd: gd, ct: ct, ar: ar, bg: bg };
}

$.widget( "mobile.popup", $.mobile.popup, {
	options: {
		arrow: false,
		arrowSides: "t,b,l,r"
	},

	_unenhance: function() {
		var ar = this._ui.arrow;

		if ( ar ) {
			ar.arEls.remove();
		}

		return this._super();
	},

	_updateArrow: function( direction ) {
		var ar = this._ui.arrow,
			oldTheme = ar.ct.jqmData( "oldTheme" ),
			theme = "ui-body-" + ( this.options.theme || $.mobile.getInheritedTheme( this.element, "c" ) );

		// Remove old direction and theme
		ar.ct.removeClass( "l t r b" );
		if ( oldTheme ) {
			ar.ar.removeClass( oldTheme );
			ar.bg.removeClass( oldTheme );
		}

		ar.ar.toggleClass( "ui-overlay-shadow", this.options.shadow );

		// Set new direction and theme
		ar.ct.jqmData( "oldTheme", theme );
		ar.ct.addClass( direction );
		ar.ar.addClass( theme );
		ar.bg.addClass( theme );
	},

	// Pretend to show an arrow described by @p and @dir and calculate the
	// distance from the desired point. If a best-distance is passed in, return
	// the minimum of the one passed in and the one calculated.
	_tryAnArrow: function( p, dir, desired, s, best ) {
		var result, r, diff, desiredForArrow = {}, tip = {};

		// If the arrow has no wiggle room along the edge of the popup, it cannot
		// be displayed along the requested edge without it sticking out.
		if ( s.arFull[ p.dimKey ] > s.guideDims[ p.dimKey ] ) {
			return best;
		}

		desiredForArrow[ p.fst ] = desired[ p.fst ] + ( s.arHalf[ p.oDimKey ] + s.menuHalf[ p.oDimKey ] ) * p.offsetFactor;
		desiredForArrow[ p.snd ] = desired[ p.snd ];

		result = s.result || this._calculateFinalLocation( desiredForArrow, s.clampInfo );
		r = { x: result.left, y: result.top };

		tip[ p.fst ] = r[ p.fst ] + p.tipOffset;
		tip[ p.snd ] = Math.max( result[ p.prop ] + s.guideOffset[ p.prop ] + s.arHalf[ p.dimKey ],
			Math.min( result[ p.prop ] + s.guideOffset[ p.prop ] + s.guideDims[ p.dimKey ] - s.arHalf[ p.dimKey ],
				desired[ p.snd ] ) );

		diff = Math.abs( desired.x - tip.x ) + Math.abs( desired.y - tip.y );
		if ( !best || diff < best.diff ) {
			best = { dir: dir, diff: diff, result: result, posProp: p.prop, posVal: tip[ p.snd ] - s.arHalf[ p.dimKey ] - result[ p.prop ] };
		}

		return best;
	},

	_getPlacementState: function( clamp ) {
		var offset,
			ar = this._ui.arrow,
			state = {
				clampInfo: this._clampPopupWidth( !clamp ),
				arFull: { cx: ar.ct.width(), cy: ar.ct.height() },
				guideDims: { cx: ar.gd.width(), cy: ar.gd.height() },
				guideOffset: ar.gd.offset()
			};

		offset = this.element.offset();
		// The arrow box moves between guideOffset and guideOffset + guideDims - arFull
		state.guideOffset = { left: state.guideOffset.left - offset.left, top: state.guideOffset.top - offset.top };
		state.arHalf = { cx: state.arFull.cx / 2, cy: state.arFull.cy / 2 };
		state.menuHalf = { cx: state.clampInfo.menuSize.cx / 2, cy: state.clampInfo.menuSize.cy / 2 };

		return state;
	},

	_placementCoords: function( desired ) {
		var state, menuFull, best, params, bgOffset, diff,
			bgRef = {},
			ar = this._ui.arrow ;

		if ( !this.options.arrow ) {
			return this._super( desired );
		}

		ar.arEls.show();

		state = this._getPlacementState( true );
		menuFull = state.clampInfo.menuSize;

		params = {
			"l": { fst: "x", snd: "y", prop: "top", dimKey: "cy", oDimKey: "cx", offsetFactor: 1, tipOffset: -( state.arHalf.cx ) },
			"r": { fst: "x", snd: "y", prop: "top", dimKey: "cy", oDimKey: "cx", offsetFactor: -1, tipOffset: menuFull.cx + state.arHalf.cx },
			"b": { fst: "y", snd: "x", prop: "left", dimKey: "cx", oDimKey: "cy", offsetFactor: -1, tipOffset: menuFull.cy + state.arHalf.cy },
			"t": { fst: "y", snd: "x", prop: "left", dimKey: "cx", oDimKey: "cy", offsetFactor: 1, tipOffset: -( state.arHalf.cx ) }
		};

		// Try each side specified in the options to see on which one the arrow
		// should be placed such that the distance between the tip of the arrow and
		// the desired coordinates is the shortest.
		$.each( this.options.arrowSides.split( "," ),
			$.proxy( function( key, value ) {
				best = this._tryAnArrow( params[ value ], value, desired, state, best );
			}, this ) );

		// Could not place the arrow along any of the edges - behave as if showing
		// the arrow was turned off.
		if ( !best ) {
			ar.arEls.hide();
			return this._super( desired );
		}

		// Move the arrow into place
		ar.ct.removeAttr( "style" ).show().css( best.posProp, best.posVal );
		this._updateArrow( best.dir );

		// Do not move/size the background div on IE, because we use the arrow div for background as well.
		if ( !ieHack ) {
			bgRef[ params[ best.dir ].fst ] = ar.ct.offset();
			bgRef[ params[ best.dir ].snd ] = this.element.offset();
			bgOffset = ar.bg
				.removeAttr( "style" )
				.css( ( "cx" === params[ best.dir ].dimKey ? "width" : "height" ), menuFull[ params[ best.dir ].dimKey ] )
				.offset();
			diff = { dx: bgRef.x.left - bgOffset.left, dy: bgRef.y.top - bgOffset.top };
			ar.bg.css( { left: txFactor * diff.dy + txFactor * diff.dx, top: txFactor * diff.dy - txFactor * diff.dx } );
		}

		return best.result;
	},

	_setArrow: function( value ) {
		var ar = this._ui.arrow;

		if ( value ) {
			if ( !ar ) {
				ar = this._ui.arrow = getArrow();
			}
			ar.arEls.appendTo( this.element ).hide();
		} else if ( ar ) {
			ar.arEls.remove();
		}
	}
});

})( jQuery );

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>


<commit_before>/**
 * ZIP Format Plugin
 *
 * @module plugins/zip
 * @license [MIT]{@link https://github.com/archiverjs/node-archiver/blob/master/LICENSE}
 * @copyright (c) 2012-2014 Chris Talkington, contributors.
 */
var engine = require('zip-stream');
var util = require('archiver-utils');

/**
 * @constructor
 * @param {ZipOptions} [options]
 * @param {String} [options.comment] Sets the zip archive comment.
 * @param {Boolean} [options.forceLocalTime=false] Forces the archive to contain local file times instead of UTC.
 * @param {Boolean} [options.forceZip64=false] Forces the archive to contain ZIP64 headers.
 * @param {Boolean} [options.store=false] Sets the compression method to STORE.
 * @param {Object} [options.zlib] Passed to [zlib]{@link https://nodejs.org/api/zlib.html#zlib_class_options}
 */
var Zip = function(options) {
  if (!(this instanceof Zip)) {
    return new Zip(options);
  }

  options = this.options = util.defaults(options, {
    comment: '',
    forceUTC: false,
    store: false
  });

  this.supports = {
    directory: true,
    symlink: true
  };

  this.engine = new engine(options);
};

/**
 * @param  {(Buffer|Stream)} source
 * @param  {ZipEntryData} data
 * @param  {String} data.name Sets the entry name including internal path.
 * @param  {(String|Date)} [data.date=NOW()] Sets the entry date.
 * @param  {Number} [data.mode=D:0755/F:0644] Sets the entry permissions.
 * @param  {String} [data.prefix] Sets a path prefix for the entry name. Useful
 * when working with methods like `directory` or `glob`.
 * @param  {fs.Stats} [data.stats] Sets the fs stat data for this entry allowing
 * for reduction of fs stat calls when stat data is already known.
 * @param  {Boolean} [data.store=ZipOptions.store] Sets the compression method to STORE.
 * @param  {Function} callback
 * @return void
 */
Zip.prototype.append = function(source, data, callback) {
  this.engine.entry(source, data, callback);
};

/**
 * @return void
 */
Zip.prototype.finalize = function() {
  this.engine.finalize();
};

/**
 * @return this.engine
 */
Zip.prototype.on = function() {
  return this.engine.on.apply(this.engine, arguments);
};

/**
 * @return this.engine
 */
Zip.prototype.pipe = function() {
  return this.engine.pipe.apply(this.engine, arguments);
};

/**
 * @return this.engine
 */
Zip.prototype.unpipe = function() {
  return this.engine.unpipe.apply(this.engine, arguments);
};

module.exports = Zip;

/**
 * @typedef {Object} ZipOptions
 * @global
 * @property {String} [comment] Sets the zip archive comment.
 * @property {Boolean} [forceLocalTime=false] Forces the archive to contain local file times instead of UTC.
 * @property {Boolean} [forceZip64=false] Forces the archive to contain ZIP64 headers.
 * @property {Boolean} [store=false] Sets the compression method to STORE.
 * @property {Object} [zlib] Passed to [zlib]{@link https://nodejs.org/api/zlib.html#zlib_class_options}
 * to control compression.
 * @property {*} [*] See [zip-stream]{@link https://archiverjs.com/zip-stream/ZipStream.html} documentation for current list of properties.
 */

/**
 * @typedef {Object} ZipEntryData
 * @global
 * @property {String} name Sets the entry name including internal path.
 * @property {(String|Date)} [date=NOW()] Sets the entry date.
 * @property {Number} [mode=D:0755/F:0644] Sets the entry permissions.
 * @property {String} [prefix] Sets a path prefix for the entry name. Useful
 * when working with methods like `directory` or `glob`.
 * @property {fs.Stats} [stats] Sets the fs stat data for this entry allowing
 * for reduction of fs stat calls when stat data is already known.
 * @property {Boolean} [store=ZipOptions.store] Sets the compression method to STORE.
 */

/**
 * ZipStream Module
 * @external ZipStream
 * @see {@link https://www.archiverjs.com/zip-stream/ZipStream.html}
 */
<commit_msg>Update zip.js<commit_after>/**
 * ZIP Format Plugin
 *
 * @module plugins/zip
 * @license [MIT]{@link https://github.com/archiverjs/node-archiver/blob/master/LICENSE}
 * @copyright (c) 2012-2014 Chris Talkington, contributors.
 */
var engine = require('zip-stream');
var util = require('archiver-utils');

/**
 * @constructor
 * @param {ZipOptions} [options]
 * @param {String} [options.comment] Sets the zip archive comment.
 * @param {Boolean} [options.forceLocalTime=false] Forces the archive to contain local file times instead of UTC.
 * @param {Boolean} [options.forceZip64=false] Forces the archive to contain ZIP64 headers.
 * @param {Boolean} [options.namePrependSlash=false] Prepends a forward slash to archive file paths.
 * @param {Boolean} [options.store=false] Sets the compression method to STORE.
 * @param {Object} [options.zlib] Passed to [zlib]{@link https://nodejs.org/api/zlib.html#zlib_class_options}
 */
var Zip = function(options) {
  if (!(this instanceof Zip)) {
    return new Zip(options);
  }

  options = this.options = util.defaults(options, {
    comment: '',
    forceUTC: false,
    namePrependSlash: false,
    store: false
  });

  this.supports = {
    directory: true,
    symlink: true
  };

  this.engine = new engine(options);
};

/**
 * @param  {(Buffer|Stream)} source
 * @param  {ZipEntryData} data
 * @param  {String} data.name Sets the entry name including internal path.
 * @param  {(String|Date)} [data.date=NOW()] Sets the entry date.
 * @param  {Number} [data.mode=D:0755/F:0644] Sets the entry permissions.
 * @param  {String} [data.prefix] Sets a path prefix for the entry name. Useful
 * when working with methods like `directory` or `glob`.
 * @param  {fs.Stats} [data.stats] Sets the fs stat data for this entry allowing
 * for reduction of fs stat calls when stat data is already known.
 * @param  {Boolean} [data.store=ZipOptions.store] Sets the compression method to STORE.
 * @param  {Function} callback
 * @return void
 */
Zip.prototype.append = function(source, data, callback) {
  this.engine.entry(source, data, callback);
};

/**
 * @return void
 */
Zip.prototype.finalize = function() {
  this.engine.finalize();
};

/**
 * @return this.engine
 */
Zip.prototype.on = function() {
  return this.engine.on.apply(this.engine, arguments);
};

/**
 * @return this.engine
 */
Zip.prototype.pipe = function() {
  return this.engine.pipe.apply(this.engine, arguments);
};

/**
 * @return this.engine
 */
Zip.prototype.unpipe = function() {
  return this.engine.unpipe.apply(this.engine, arguments);
};

module.exports = Zip;

/**
 * @typedef {Object} ZipOptions
 * @global
 * @property {String} [comment] Sets the zip archive comment.
 * @property {Boolean} [forceLocalTime=false] Forces the archive to contain local file times instead of UTC.
 * @property {Boolean} [forceZip64=false] Forces the archive to contain ZIP64 headers.
 * @prpperty {Boolean} [namePrependSlash=false] Prepends a forward slash to archive file paths.
 * @property {Boolean} [store=false] Sets the compression method to STORE.
 * @property {Object} [zlib] Passed to [zlib]{@link https://nodejs.org/api/zlib.html#zlib_class_options}
 * to control compression.
 * @property {*} [*] See [zip-stream]{@link https://archiverjs.com/zip-stream/ZipStream.html} documentation for current list of properties.
 */

/**
 * @typedef {Object} ZipEntryData
 * @global
 * @property {String} name Sets the entry name including internal path.
 * @property {(String|Date)} [date=NOW()] Sets the entry date.
 * @property {Number} [mode=D:0755/F:0644] Sets the entry permissions.
 * @property {Boolean} [namePrependSlash=ZipOptions.namePrependSlash] Prepends a forward slash to archive file paths.
 * @property {String} [prefix] Sets a path prefix for the entry name. Useful
 * when working with methods like `directory` or `glob`.
 * @property {fs.Stats} [stats] Sets the fs stat data for this entry allowing
 * for reduction of fs stat calls when stat data is already known.
 * @property {Boolean} [store=ZipOptions.store] Sets the compression method to STORE.
 */

/**
 * ZipStream Module
 * @external ZipStream
 * @see {@link https://www.archiverjs.com/zip-stream/ZipStream.html}
 */
<|endoftext|>