<commit_before>/**
 * skipper-better-s3
 *
 * @author     Robert Rossmann <rr.rossmann@me.com>
 * @copyright  2015 Robert Rossmann
 * @license    http://choosealicense.com/licenses/bsd-3-clause  BSD-3-Clause License
 */

'use strict'

const WritableStream = require('stream').Writable
    , AWS = require('aws-sdk')
    , mime = require('mime')
    , merge = require('semantic-merge')
    , uuid = require('node-uuid')
    , local = require('./util/local')

module.exports = class Uploader extends WritableStream {

  constructor (opts) {

    // Initialise this writable stream in object mode
    super({ objectMode: true })

    const scope = local(this)

    // Save configuration options and the S3 client to local scope
    scope.opts = opts
    scope.client = new AWS.S3(opts.service)
  }

  _write (stream, encoding, done) {

    // Fix the content type header on the request in case it was incorrectly detected
    // Wrong detection can happen when uploading via curl, for example.
    // This will also help the S3 library to properly detect and set the Content-Type in storage.
    stream.headers['content-type'] = mime.lookup(stream.fd)

    const scope = local(this)
        , params = merge({ Key: stream.fd
                         , Body: stream
                         , ContentType: stream.headers['content-type']
                        })
                   .and(scope.opts.request)
                   .excluding('onProgress')
                   .into({})
        , request = scope.client.upload(params, (err, data) => {
          // Attach the response data to the stream - Skipper packages this in its response to the
          // caller for further reuse
          stream.extra = data

          return done(err, data)
        })

    // Attach progress handler
    this.trackProgress(request, scope.opts.request.onProgress)
  }

  trackProgress (request, handler) {

    // If there's no handler provided, do not attach any listeners
    if (typeof handler !== 'function')
      return

    // Generate a per-request unique ID
    const id = uuid.v4()

    request.on('httpUploadProgress', progress => {
      // Prepare Skipper-specific progress structure
      const written = progress.loaded
      // S3 docs say that progress.total may not always be present, so let's have some fallback
          , total = progress.total || request.body.byteCount || null
          , data =
            { id: id
            , fd: request.body.fd
            , name: request.body.name
            , written: written
            , total: total
            // If total is null, performing bitwise-or will change the result to 0
            // It also rounds down to an integer, which is kinda nice
            , percent: written / total * 100 | 0
            }

      handler(data)
    })
  }
}
<commit_msg>Strip double quotes from around the ETag<commit_after>/**
 * skipper-better-s3
 *
 * @author     Robert Rossmann <rr.rossmann@me.com>
 * @copyright  2015 Robert Rossmann
 * @license    http://choosealicense.com/licenses/bsd-3-clause  BSD-3-Clause License
 */

'use strict'

const WritableStream = require('stream').Writable
    , AWS = require('aws-sdk')
    , mime = require('mime')
    , merge = require('semantic-merge')
    , uuid = require('node-uuid')
    , local = require('./util/local')

module.exports = class Uploader extends WritableStream {

  constructor (opts) {

    // Initialise this writable stream in object mode
    super({ objectMode: true })

    const scope = local(this)

    // Save configuration options and the S3 client to local scope
    scope.opts = opts
    scope.client = new AWS.S3(opts.service)
  }

  _write (stream, encoding, done) {

    // Fix the content type header on the request in case it was incorrectly detected
    // Wrong detection can happen when uploading via curl, for example.
    // This will also help the S3 library to properly detect and set the Content-Type in storage.
    stream.headers['content-type'] = mime.lookup(stream.fd)

    const scope = local(this)
        , params = merge({ Key: stream.fd
                         , Body: stream
                         , ContentType: stream.headers['content-type']
                        })
                   .and(scope.opts.request)
                   .excluding('onProgress')
                   .into({})
        , request = scope.client.upload(params, (err, data) => {
          // Attach the response data to the stream - Skipper packages this in its response to the
          // caller for further reuse
          stream.extra = data
          // The ETag returned in the response is enclosed in double-quotes - I find this quite
          // irritating since I usually only care about the actual value - let's fix that once and
          // for all, for everyone!
          stream.extra.ETag = stream.extra.ETag.replace(/"/g, '')

          return done(err, data)
        })

    // Attach progress handler
    this.trackProgress(request, scope.opts.request.onProgress)
  }

  trackProgress (request, handler) {

    // If there's no handler provided, do not attach any listeners
    if (typeof handler !== 'function')
      return

    // Generate a per-request unique ID
    const id = uuid.v4()

    request.on('httpUploadProgress', progress => {
      // Prepare Skipper-specific progress structure
      const written = progress.loaded
      // S3 docs say that progress.total may not always be present, so let's have some fallback
          , total = progress.total || request.body.byteCount || null
          , data =
            { id: id
            , fd: request.body.fd
            , name: request.body.name
            , written: written
            , total: total
            // If total is null, performing bitwise-or will change the result to 0
            // It also rounds down to an integer, which is kinda nice
            , percent: written / total * 100 | 0
            }

      handler(data)
    })
  }
}
<|endoftext|>


<commit_before>var ValidationError = require('./error.js'),
	ranges = require('./ranges.js'),
	unique = require('./unique.js');

var copyObject = function(obj) {
	var copy = {};
	for (var key in obj) copy[key] = obj[key];
	return copy;
};

var validateObject = function(obj, schema, callback, keyPath) {

	if (obj) {

		if ('Object' != obj.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type Object.'));
		}

		// Copy schema
		var schemaCopy = {};
		for (var key in schema.schema) schemaCopy[key] = schema.schema[key];

		// Put validated object here
		var validObj = {};

		return (function validateNextKey() {

			for (var key in schemaCopy) break;
			if (!key) return callback(null, validObj);

			var keySchema = schemaCopy[key];
			delete schemaCopy[key];

			validateAny(obj[key], keySchema, function(err, validatedObj) {
				if (err) return callback(err);
				validObj[key] = validatedObj;
				validateNextKey();
			}, keyPath.concat([key]));

		})();

	}

	return callback(null, obj);

};

var validateArray = function(arr, schema, callback, keyPath) {

	if (arr) {

		var validArray = [];

		return (function validateNext(idx) {

			if (idx == arr.length) {

				if (schema.len && !ranges.testIndex(schema.len, validArray.length)) {
					return callback(new ValidationError(keyPath, schema, 'Array length is not within range of \'' + schema.len + '\''));
				}

				if (schema.unique && validArray.length > 1) {
					for (var idx1 = 0 ; idx1 < validArray.length - 1 ; idx1++) {
						for (var idx2 = idx1 + 1 ; idx2 < validArray.length ; idx2++ ) {
							if (unique.equals(validArray[idx1], validArray[idx2])) {
								keyPath = keyPath.concat([ idx1.toString() ]);
								return callback(new ValidationError(keyPath, schema, 'Is not unique.'));
							}
						}
					}
				}

				return callback(null, validArray);

			}

			validateAny(arr[idx], schema.schema, function(err, validObj) {
				if (err) return callback(err);
				validArray.push(validObj);
				validateNext(idx + 1);
			}, keyPath.concat([ idx.toString() ]));

		})(0);

	}

	return callback(null, arr);

};

var validateString = function(str, schema, callback, keyPath) {

	if (str) {

		var validStr = str;

		if ('String' != validStr.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type string.'));
		};

		if (schema.trim) {
			validStr = validStr.replace(/^\s+|\s+$/g,'');
		}

		if (schema.match) {
			if ('RegExp' != schema.match.constructor.name) {
				throw new Error('Schema {type: String}: match is not a RegExp.');
			}
			if (!schema.match.test(validStr)) {
				return callback(new ValidationError(keyPath, schema, 'Does not match expression ' + schema.match.source + '.'));
			}
		}

		return callback(null, validStr);

	}

	return callback(null, str);

};

var validateNumber = function(num, schema, callback, keyPath) {

	if (num) {

		var validNum = num;

		if ('String' == validNum.constructor.name && /^[0-9]+(?:\.[0.9])?$/.test(num)) {
			validNum = parseFloat(validNum);
		} else if ('Number' != validNum.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type number.'));
		}

		if (schema.range) {
			if (!ranges.testIndex(schema.range, validNum)) {
				return callback(new ValidationError(keyPath, schema, 'Not within range of ' + schema.range));
			}
		}

		return callback(null, validNum);

	}

	return callback(null, num);

};

var validateBoolean = function(val, schema, callback, keyPath) {

	if (val) {

		if ('String' == val.constructor.name && /^true|false$/i.test(val)) {
			val = /^true$/i.test(val);
		}

		if ('Boolean' != val.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type boolean.'));
		}

		return callback(null, val);

	}

	return callback(null, val);

};

var validateAny = function(obj, schema, callback, keyPath) {

	// Type Shortcuts
	if (!schema.type) {
		if ('Object' == schema.constructor.name) return validateAny(obj, { type: Object, schema: schema }, callback, keyPath);
		if ('Array' == schema.constructor.name) {
			if (schema.length == 0) return callback(new Error('Array shortcut must contain a schema object.'));
			return validateAny(obj, { type: Array, schema: schema[0] }, callback, keyPath);
		}
	}

	if (!obj) {
		if (schema.default) {
			if ('Function' == schema.default.constructor.name) {
				return schema.default(function(defaultValue) {
					callback(null, defaultValue);
				});
			} else {
				return callback(null, schema.default);
			}
		}
		if (schema.required) return callback(new ValidationError(keyPath, schema, 'Key is required.'));
	}

	if ('Object' == schema.type.name) return validateObject(obj, schema, callback, keyPath);
	if ('Array' == schema.type.name) return validateArray(obj, schema, callback, keyPath);
	if ('String' == schema.type.name) return validateString(obj, schema, callback, keyPath);
	if ('Number' == schema.type.name) return validateNumber(obj, schema, callback, keyPath);
	if ('Boolean' == schema.type.name) return validateBoolean(obj, schema, callback, keyPath);

	throw new Error('Cannot validate schema of type ' + schema.type.name + '.');

};

var validate = function(obj, schema, callback, keyPath) {

	if (!schema) throw new Error('Missing parameter schema');
	if (!callback) throw new Error('Missing parameter callback');

	keyPath = keyPath || [];

	return validateAny(obj, schema, callback, keyPath);

};

module.exports.validate = validate;
<commit_msg>In doubt of old implementation added function to global scope. Changed it.<commit_after>var ValidationError = require('./error.js'),
	ranges = require('./ranges.js'),
	unique = require('./unique.js');

var copyObject = function(obj) {
	var copy = {};
	for (var key in obj) copy[key] = obj[key];
	return copy;
};

var validateObject = function(obj, schema, callback, keyPath) {

	if (obj) {

		if ('Object' != obj.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type Object.'));
		}

		// Copy schema
		var schemaCopy = {};
		for (var key in schema.schema) schemaCopy[key] = schema.schema[key];

		// Put validated object here
		var validObj = {};

		var validateNextKey = function() {
			for (var key in schemaCopy) break;
			if (!key) return callback(null, validObj);

			var keySchema = schemaCopy[key];
			delete schemaCopy[key];

			validateAny(obj[key], keySchema, function(err, validatedObj) {
				if (err) return callback(err);
				validObj[key] = validatedObj;
				validateNextKey();
			}, keyPath.concat([key]));
		};

		return validateNextKey();

	}

	return callback(null, obj);

};

var validateArray = function(arr, schema, callback, keyPath) {

	if (arr) {

		var validArray = [];

		var validateNext = function(idx) {

			if (idx == arr.length) {

				if (schema.len && !ranges.testIndex(schema.len, validArray.length)) {
					return callback(new ValidationError(keyPath, schema, 'Array length is not within range of \'' + schema.len + '\''));
				}

				if (schema.unique && validArray.length > 1) {
					for (var idx1 = 0 ; idx1 < validArray.length - 1 ; idx1++) {
						for (var idx2 = idx1 + 1 ; idx2 < validArray.length ; idx2++ ) {
							if (unique.equals(validArray[idx1], validArray[idx2])) {
								keyPath = keyPath.concat([ idx1.toString() ]);
								return callback(new ValidationError(keyPath, schema, 'Is not unique.'));
							}
						}
					}
				}

				return callback(null, validArray);

			}

			validateAny(arr[idx], schema.schema, function(err, validObj) {
				if (err) return callback(err);
				validArray.push(validObj);
				validateNext(idx + 1);
			}, keyPath.concat([ idx.toString() ]));

		};

		return validateNext(0);

	}

	return callback(null, arr);

};

var validateString = function(str, schema, callback, keyPath) {

	if (str) {

		var validStr = str;

		if ('String' != validStr.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type string.'));
		};

		if (schema.trim) {
			validStr = validStr.replace(/^\s+|\s+$/g,'');
		}

		if (schema.match) {
			if ('RegExp' != schema.match.constructor.name) {
				throw new Error('Schema {type: String}: match is not a RegExp.');
			}
			if (!schema.match.test(validStr)) {
				return callback(new ValidationError(keyPath, schema, 'Does not match expression ' + schema.match.source + '.'));
			}
		}

		return callback(null, validStr);

	}

	return callback(null, str);

};

var validateNumber = function(num, schema, callback, keyPath) {

	if (num) {

		var validNum = num;

		if ('String' == validNum.constructor.name && /^[0-9]+(?:\.[0.9])?$/.test(num)) {
			validNum = parseFloat(validNum);
		} else if ('Number' != validNum.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type number.'));
		}

		if (schema.range) {
			if (!ranges.testIndex(schema.range, validNum)) {
				return callback(new ValidationError(keyPath, schema, 'Not within range of ' + schema.range));
			}
		}

		return callback(null, validNum);

	}

	return callback(null, num);

};

var validateBoolean = function(val, schema, callback, keyPath) {

	if (val) {

		if ('String' == val.constructor.name && /^true|false$/i.test(val)) {
			val = /^true$/i.test(val);
		}

		if ('Boolean' != val.constructor.name) {
			return callback(new ValidationError(keyPath, schema, 'Is not of type boolean.'));
		}

		return callback(null, val);

	}

	return callback(null, val);

};

var validateAny = function(obj, schema, callback, keyPath) {

	// Type Shortcuts
	if (!schema.type) {
		if ('Object' == schema.constructor.name) return validateAny(obj, { type: Object, schema: schema }, callback, keyPath);
		if ('Array' == schema.constructor.name) {
			if (schema.length == 0) return callback(new Error('Array shortcut must contain a schema object.'));
			return validateAny(obj, { type: Array, schema: schema[0] }, callback, keyPath);
		}
	}

	if (!obj) {
		if (schema.default) {
			if ('Function' == schema.default.constructor.name) {
				return schema.default(function(defaultValue) {
					callback(null, defaultValue);
				});
			} else {
				return callback(null, schema.default);
			}
		}
		if (schema.required) return callback(new ValidationError(keyPath, schema, 'Key is required.'));
	}

	if ('Object' == schema.type.name) return validateObject(obj, schema, callback, keyPath);
	if ('Array' == schema.type.name) return validateArray(obj, schema, callback, keyPath);
	if ('String' == schema.type.name) return validateString(obj, schema, callback, keyPath);
	if ('Number' == schema.type.name) return validateNumber(obj, schema, callback, keyPath);
	if ('Boolean' == schema.type.name) return validateBoolean(obj, schema, callback, keyPath);

	throw new Error('Cannot validate schema of type ' + schema.type.name + '.');

};

var validate = function(obj, schema, callback, keyPath) {

	if (!schema) throw new Error('Missing parameter schema');
	if (!callback) throw new Error('Missing parameter callback');

	keyPath = keyPath || [];

	return validateAny(obj, schema, callback, keyPath);

};

module.exports.validate = validate;
<|endoftext|>


<commit_before>'use strict';

const BbPromise = require('bluebird');
const path = require('path');
const fse = require('fs-extra');
const glob = require('glob');
const lib = require('./index');
const _ = require('lodash');
const Configuration = require('./Configuration');

/**
 * For automatic entry detection we sort the found files to solve ambiguities.
 * This should cover most of the cases. For complex setups the user should
 * build his own entries with help of the other exports.
 */
const preferredExtensions = [
  '.js',
  '.ts',
  '.jsx',
  '.tsx'
];

module.exports = {
  validate() {
    const getHandlerFile = handler => {
      // Check if handler is a well-formed path based handler.
      const handlerEntry = /(.*)\..*?$/.exec(handler);
      if (handlerEntry) {
        return handlerEntry[1];
      }
    };

    const getEntryExtension = fileName => {
      const files = glob.sync(`${fileName}.*`, {
        cwd: this.serverless.config.servicePath,
        nodir: true,
        ignore: this.configuration.excludeFiles ? this.configuration.excludeFiles : undefined
      });

      if (_.isEmpty(files)) {
        // If we cannot find any handler we should terminate with an error
        throw new this.serverless.classes.Error(`No matching handler found for '${fileName}' in '${this.serverless.config.servicePath}'. Check your service definition.`);
      }

      // Move preferred file extensions to the beginning
      const sortedFiles = _.uniq(
        _.concat(
          _.sortBy(
            _.filter(files, file => _.includes(preferredExtensions, path.extname(file))),
            a => _.size(a)
          ),
          files
        )
      );

      if (_.size(sortedFiles) > 1) {
        this.serverless.cli.log(`WARNING: More than one matching handlers found for '${fileName}'. Using '${_.first(sortedFiles)}'.`);
      }
      return path.extname(_.first(sortedFiles));
    };

    const getEntryForFunction = (name, serverlessFunction) => {
      const handler = serverlessFunction.handler;

      const handlerFile = getHandlerFile(handler);
      if (!handlerFile) {
        _.get(this.serverless, 'service.provider.name') !== 'google' &&
          this.serverless.cli.log(`\nWARNING: Entry for ${name}@${handler} could not be retrieved.\nPlease check your service config if you want to use lib.entries.`);
        return {};
      }
      const ext = getEntryExtension(handlerFile);

      // Create a valid entry key
      return {
        [handlerFile]: `./${handlerFile}${ext}`
      };
    };

    // Initialize plugin configuration
    this.configuration = new Configuration(this.serverless.service.custom);
    this.options.verbose && this.serverless.cli.log(`Using configuration:\n${JSON.stringify(this.configuration, null, 2)}`);
    if (this.configuration.hasLegacyConfig) {
      this.serverless.cli.log('Legacy configuration detected. Consider to use "custom.webpack" as object (see README).');
    }

    this.webpackConfig = this.configuration.config || this.configuration.webpackConfig;

    // Expose entries - must be done before requiring the webpack configuration
    const entries = {};

    const functions = this.serverless.service.getAllFunctions();
    if (this.options.function) {
      const serverlessFunction = this.serverless.service.getFunction(this.options.function);
      const entry = getEntryForFunction.call(this, this.options.function, serverlessFunction);
      _.merge(entries, entry);
    } else {
      _.forEach(functions, (func, index) => {
        const entry = getEntryForFunction.call(this, functions[index], this.serverless.service.getFunction(func));
        _.merge(entries, entry);
      });
    }

    // Expose service file and options
    lib.serverless = this.serverless;
    lib.options = this.options;
    lib.entries = entries;

    if (_.isString(this.webpackConfig)) {
      const webpackConfigFilePath = path.join(this.serverless.config.servicePath, this.webpackConfig);
      if (!this.serverless.utils.fileExistsSync(webpackConfigFilePath)) {
        return BbPromise.reject(new this.serverless.classes
          .Error('The webpack plugin could not find the configuration file at: ' + webpackConfigFilePath));
      }
      try {
        this.webpackConfig = require(webpackConfigFilePath);
      } catch (err) {
        this.serverless.cli.log(`Could not load webpack config '${webpackConfigFilePath}'`);
        return BbPromise.reject(err);
      }
    }

    // Intermediate function to handle async webpack config
    const processConfig = _config => {
      this.webpackConfig = _config;
      // Default context
      if (!this.webpackConfig.context) {
        this.webpackConfig.context = this.serverless.config.servicePath;
      }

      // Default target
      if (!this.webpackConfig.target) {
        this.webpackConfig.target = 'node';
      }

      // Default output
      if (!this.webpackConfig.output || _.isEmpty(this.webpackConfig.output)) {
        const outputPath = path.join(this.serverless.config.servicePath, '.webpack');
        this.webpackConfig.output = {
          libraryTarget: 'commonjs2',
          path: outputPath,
          filename: '[name].js',
        };
      }

      // Custom output path
      if (this.options.out) {
        this.webpackConfig.output.path = path.join(this.serverless.config.servicePath, this.options.out);
      }

      if (this.skipCompile) {
        this.serverless.cli.log('Skipping build and using existing compiled output');
        if (!fse.pathExistsSync(this.webpackConfig.output.path)) {
          return BbPromise.reject(new this.serverless.classes
            .Error('No compiled output found'));
        }
        this.keepOutputDirectory = true;
      }

      if (!this.keepOutputDirectory) {
        this.options.verbose && this.serverless.cli.log(`Removing ${this.webpackConfig.output.path}`);
        fse.removeSync(this.webpackConfig.output.path);
      }
      this.webpackOutputPath = this.webpackConfig.output.path;

      // In case of individual packaging we have to create a separate config for each function
      if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) {
        this.options.verbose && this.serverless.cli.log('Using multi-compile (individual packaging)');
        this.multiCompile = true;

        if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) {
          return BbPromise.reject(new this.serverless.classes
            .Error('Webpack entry must be automatically resolved when package.individually is set to true. ' +
              'In webpack.config.js, remove the entry declaration or set entry to slsw.lib.entries.'));
        }

        // Lookup associated Serverless functions
        const allEntryFunctions = _.map(
          this.serverless.service.getAllFunctions(),
          funcName => {
            const func = this.serverless.service.getFunction(funcName);
            const handler = func.handler;
            const handlerFile = path.relative('.', getHandlerFile(handler));
            return {
              handlerFile,
              funcName,
              func
            };
          }
        );

        this.entryFunctions = _.flatMap(entries, (value, key) => {
          const entry = path.relative('.', value);
          const entryFile = _.replace(entry, new RegExp(`${path.extname(entry)}$`), '');

          const entryFuncs = _.filter(allEntryFunctions, [ 'handlerFile', entryFile ]);
          if (_.isEmpty(entryFuncs)) {
            // We have to make sure that for each entry there is an entry function item.
            entryFuncs.push({});
          }
          _.forEach(entryFuncs, entryFunc => {
            entryFunc.entry = {
              key,
              value
            };
          });
          return entryFuncs;
        });

        this.webpackConfig = _.map(this.entryFunctions, entryFunc => {
          const config = _.cloneDeep(this.webpackConfig);
          config.entry = {
            [entryFunc.entry.key]: entryFunc.entry.value
          };
          const compileName = entryFunc.funcName || _.camelCase(entryFunc.entry.key);
          config.output.path = path.join(config.output.path, compileName);
          return config;
        });
      } else {
        this.webpackConfig.output.path = path.join(this.webpackConfig.output.path, 'service');
      }

      return BbPromise.resolve();
    };

    // Webpack config can be a Promise, If it's a Promise wait for resolved config object.
    if (this.webpackConfig && _.isFunction(this.webpackConfig.then)) {
      return BbPromise.resolve(this.webpackConfig.then(config => processConfig(config)));
    } else {
      return processConfig(this.webpackConfig);
    }
  },
};
<commit_msg>default webpackConfig.node should be false<commit_after>'use strict';

const BbPromise = require('bluebird');
const path = require('path');
const fse = require('fs-extra');
const glob = require('glob');
const lib = require('./index');
const _ = require('lodash');
const Configuration = require('./Configuration');

/**
 * For automatic entry detection we sort the found files to solve ambiguities.
 * This should cover most of the cases. For complex setups the user should
 * build his own entries with help of the other exports.
 */
const preferredExtensions = [
  '.js',
  '.ts',
  '.jsx',
  '.tsx'
];

module.exports = {
  validate() {
    const getHandlerFile = handler => {
      // Check if handler is a well-formed path based handler.
      const handlerEntry = /(.*)\..*?$/.exec(handler);
      if (handlerEntry) {
        return handlerEntry[1];
      }
    };

    const getEntryExtension = fileName => {
      const files = glob.sync(`${fileName}.*`, {
        cwd: this.serverless.config.servicePath,
        nodir: true,
        ignore: this.configuration.excludeFiles ? this.configuration.excludeFiles : undefined
      });

      if (_.isEmpty(files)) {
        // If we cannot find any handler we should terminate with an error
        throw new this.serverless.classes.Error(`No matching handler found for '${fileName}' in '${this.serverless.config.servicePath}'. Check your service definition.`);
      }

      // Move preferred file extensions to the beginning
      const sortedFiles = _.uniq(
        _.concat(
          _.sortBy(
            _.filter(files, file => _.includes(preferredExtensions, path.extname(file))),
            a => _.size(a)
          ),
          files
        )
      );

      if (_.size(sortedFiles) > 1) {
        this.serverless.cli.log(`WARNING: More than one matching handlers found for '${fileName}'. Using '${_.first(sortedFiles)}'.`);
      }
      return path.extname(_.first(sortedFiles));
    };

    const getEntryForFunction = (name, serverlessFunction) => {
      const handler = serverlessFunction.handler;

      const handlerFile = getHandlerFile(handler);
      if (!handlerFile) {
        _.get(this.serverless, 'service.provider.name') !== 'google' &&
          this.serverless.cli.log(`\nWARNING: Entry for ${name}@${handler} could not be retrieved.\nPlease check your service config if you want to use lib.entries.`);
        return {};
      }
      const ext = getEntryExtension(handlerFile);

      // Create a valid entry key
      return {
        [handlerFile]: `./${handlerFile}${ext}`
      };
    };

    // Initialize plugin configuration
    this.configuration = new Configuration(this.serverless.service.custom);
    this.options.verbose && this.serverless.cli.log(`Using configuration:\n${JSON.stringify(this.configuration, null, 2)}`);
    if (this.configuration.hasLegacyConfig) {
      this.serverless.cli.log('Legacy configuration detected. Consider to use "custom.webpack" as object (see README).');
    }

    this.webpackConfig = this.configuration.config || this.configuration.webpackConfig;

    // Expose entries - must be done before requiring the webpack configuration
    const entries = {};

    const functions = this.serverless.service.getAllFunctions();
    if (this.options.function) {
      const serverlessFunction = this.serverless.service.getFunction(this.options.function);
      const entry = getEntryForFunction.call(this, this.options.function, serverlessFunction);
      _.merge(entries, entry);
    } else {
      _.forEach(functions, (func, index) => {
        const entry = getEntryForFunction.call(this, functions[index], this.serverless.service.getFunction(func));
        _.merge(entries, entry);
      });
    }

    // Expose service file and options
    lib.serverless = this.serverless;
    lib.options = this.options;
    lib.entries = entries;

    if (_.isString(this.webpackConfig)) {
      const webpackConfigFilePath = path.join(this.serverless.config.servicePath, this.webpackConfig);
      if (!this.serverless.utils.fileExistsSync(webpackConfigFilePath)) {
        return BbPromise.reject(new this.serverless.classes
          .Error('The webpack plugin could not find the configuration file at: ' + webpackConfigFilePath));
      }
      try {
        this.webpackConfig = require(webpackConfigFilePath);
      } catch (err) {
        this.serverless.cli.log(`Could not load webpack config '${webpackConfigFilePath}'`);
        return BbPromise.reject(err);
      }
    }

    // Intermediate function to handle async webpack config
    const processConfig = _config => {
      this.webpackConfig = _config;
      // Default context
      if (!this.webpackConfig.context) {
        this.webpackConfig.context = this.serverless.config.servicePath;
      }

      // Default target
      if (!this.webpackConfig.target) {
        this.webpackConfig.target = 'node';
      }

      // Default output
      if (!this.webpackConfig.output || _.isEmpty(this.webpackConfig.output)) {
        const outputPath = path.join(this.serverless.config.servicePath, '.webpack');
        this.webpackConfig.output = {
          libraryTarget: 'commonjs2',
          path: outputPath,
          filename: '[name].js',
        };
      }

      // Default node
      if (!this.webpackConfig.node || _.isEmpty(this.webpackConfig.node)) {
        this.webpackConfig.node = false;
      }

      // Custom output path
      if (this.options.out) {
        this.webpackConfig.output.path = path.join(this.serverless.config.servicePath, this.options.out);
      }

      if (this.skipCompile) {
        this.serverless.cli.log('Skipping build and using existing compiled output');
        if (!fse.pathExistsSync(this.webpackConfig.output.path)) {
          return BbPromise.reject(new this.serverless.classes
            .Error('No compiled output found'));
        }
        this.keepOutputDirectory = true;
      }

      if (!this.keepOutputDirectory) {
        this.options.verbose && this.serverless.cli.log(`Removing ${this.webpackConfig.output.path}`);
        fse.removeSync(this.webpackConfig.output.path);
      }
      this.webpackOutputPath = this.webpackConfig.output.path;

      // In case of individual packaging we have to create a separate config for each function
      if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) {
        this.options.verbose && this.serverless.cli.log('Using multi-compile (individual packaging)');
        this.multiCompile = true;

        if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) {
          return BbPromise.reject(new this.serverless.classes
            .Error('Webpack entry must be automatically resolved when package.individually is set to true. ' +
              'In webpack.config.js, remove the entry declaration or set entry to slsw.lib.entries.'));
        }

        // Lookup associated Serverless functions
        const allEntryFunctions = _.map(
          this.serverless.service.getAllFunctions(),
          funcName => {
            const func = this.serverless.service.getFunction(funcName);
            const handler = func.handler;
            const handlerFile = path.relative('.', getHandlerFile(handler));
            return {
              handlerFile,
              funcName,
              func
            };
          }
        );

        this.entryFunctions = _.flatMap(entries, (value, key) => {
          const entry = path.relative('.', value);
          const entryFile = _.replace(entry, new RegExp(`${path.extname(entry)}$`), '');

          const entryFuncs = _.filter(allEntryFunctions, [ 'handlerFile', entryFile ]);
          if (_.isEmpty(entryFuncs)) {
            // We have to make sure that for each entry there is an entry function item.
            entryFuncs.push({});
          }
          _.forEach(entryFuncs, entryFunc => {
            entryFunc.entry = {
              key,
              value
            };
          });
          return entryFuncs;
        });

        this.webpackConfig = _.map(this.entryFunctions, entryFunc => {
          const config = _.cloneDeep(this.webpackConfig);
          config.entry = {
            [entryFunc.entry.key]: entryFunc.entry.value
          };
          const compileName = entryFunc.funcName || _.camelCase(entryFunc.entry.key);
          config.output.path = path.join(config.output.path, compileName);
          return config;
        });
      } else {
        this.webpackConfig.output.path = path.join(this.webpackConfig.output.path, 'service');
      }

      return BbPromise.resolve();
    };

    // Webpack config can be a Promise, If it's a Promise wait for resolved config object.
    if (this.webpackConfig && _.isFunction(this.webpackConfig.then)) {
      return BbPromise.resolve(this.webpackConfig.then(config => processConfig(config)));
    } else {
      return processConfig(this.webpackConfig);
    }
  },
};
<|endoftext|>


<commit_before>'use strict';

var jsonlint = require('jsonlint-lines-primitives');
var reference = require('mapbox-gl-style-spec/reference/v6');
var parseCSSColor = require('csscolorparser').parseCSSColor;
var format = require('util').format;

module.exports = function(str) {
    var style;

    try {
        style = jsonlint.parse(str.toString());
    } catch(e) {
        var match = e.message.match(/line (\d+)/),
            lineNumber = 0;
        if (match) lineNumber = parseInt(match[1], 10);
        return [{
            line: lineNumber - 1,
            message: e.message,
            error: e
        }];
    }

    var constants = style.constants || {},
        layers = {},
        errors = [];

    function error(key, val /*, message, ...*/) {
        errors.push({
            line: val.__line__,
            message: (key ? key + ': ' : '') +
                format.apply(format, Array.prototype.slice.call(arguments, 2))
        });
    }

    // Main recursive validation function. Tracks:
    //
    // - key: string representing location of validation in style tree. Used only
    //   for more informative error reporting.
    // - val: current value from style being evaluated. May be anything from a
    //   high level object that needs to be descended into deeper or a simple
    //   scalar value.
    // - spec: current spec being evaluated. Tracks val.
    //
    function validate(key, val, spec) {
        var type = typeof_(val);

        // Constants
        if (type === 'string' && val[0] === '@') {
            if (!(val in constants)) {
                return error(key, val, 'constant "%s" not found', val);
            }
            val = constants[val];
            type = typeof_(val);
        }

        // Functions
        if (spec.function && type === 'object') {
            return validate.function(key, val, spec);
        }

        if (spec.type) {
            var validator = validate[spec.type];
            if (validator) {
                return validator(key, val, spec);
            }
            spec = reference[spec.type];
        }

        validate.object(key, val, spec);
    }

    validate.constants = function(key, val) {
        var type = typeof_(val);
        if (type !== 'object') {
            return error(key, val, 'object expected, %s found', type);
        }

        for (var k in val) {
            if (k[0] !== '@') {
                error(key + '.' + k, val[k], 'constants must start with "@"');
            }
        }
    };

    validate.layer = function(key, val) {
        if (!val.type && !val.ref) {
            error(key, val, 'either "type" or "ref" is required');
        }

        var type = unbundle(val.type),
            ref = unbundle(val.ref);

        if (val.id) {
            if (layers[val.id]) {
                error(key, val.id, 'duplicate layer id "%s", previously used at line %d', val.id, layers[val.id]);
            } else {
                layers[val.id] = val.id.__line__;
            }
        }

        if ('ref' in val) {
            ['type', 'source', 'source-layer', 'filter', 'layout'].forEach(function (p) {
                if (p in val) {
                    error(key, val[p], '"%s" is prohibited for ref layers', p);
                }
            });

            var parent;

            style.layers.forEach(function(layer) {
                if (layer.id == ref) parent = layer;
            });

            if (parent) {
                type = parent.type;
            } else {
                error(key, val.ref, 'ref layer "%s" not found', ref);
            }
        } else if (type !== 'background') {
            if (!val.source) {
                error(key, val, 'missing required property "source"');
            } else {
                var source = style.sources[val.source];
                if (!source) {
                    error(key, val.source, 'source "%s" not found', val.source);
                } else if (source.type == 'vector' && type == 'raster' && !val.layers) {
                    error(key, val.source, 'layer "%s" requires a raster source', val.id);
                } else if (source.type == 'raster' && type != 'raster') {
                    error(key, val.source, 'layer "%s" requires a vector source', val.id);
                }
            }
        }

        validate.object(key, val, reference.layer, {
            filter: validate.filter,
            layout: function(key, val) {
                return type && validate(key, val, reference['layout_' + type]);
            },
            paint: function(key, val) {
                return type && validate(key, val, reference['paint_' + type]);
            }
        });
    };

    validate.object = function (key, val, spec, validators) {
        validators = validators || {};

        var type = typeof_(val);
        if (type !== 'object') {
            return error(key, val, 'object expected, %s found', type);
        }

        for (var k in val) {
            var speckey = k.split('.')[0]; // treat 'paint.*' as 'paint'
            var def = spec[speckey] || spec['*'];
            if (def) {
                (validators[speckey] || validate)((key ? key + '.' : key) + k, val[k], def);
            } else {
                error(key, val[k], 'unknown property "%s"', k);
            }
        }

        for (var l in spec) {
            if (spec[l].required && spec[l]['default'] === undefined && val[l] === undefined) {
                error(key, val, 'missing required property "%s"', l);
            }
        }
    };

    validate.array = function (key, val, spec, validator) {
        if (typeof_(val) !== 'array') {
            return error(key, val, 'array expected, %s found', typeof_(val));
        }

        if (spec.length && val.length !== spec.length) {
            return error(key, val, 'array length %d expected, length %d found', spec.length, val.length);
        }

        for (var i = 0; i < val.length; i++) {
            (validator || validate)(key + '[' + i + ']', val[i], {
                "type": spec.value,
                "function": spec.function
            });
        }
    };

    validate.filter = function(key, val) {
        var type;

        if (typeof_(val) !== 'array') {
            return error(key, val, 'array expected, %s found', typeof_(val));
        }

        if (val.length < 1) {
            return error(key, val, 'filter array must have at least 1 element');
        }

        validate.enum(key + '[0]', val[0], reference.filter_operator);

        switch (unbundle(val[0])) {
            case '<':
            case '<=':
            case '>':
            case '>=':
                if (val.length >= 2 && val[1] == '$type') {
                    error(key, val, '"$type" cannot be use with operator "%s"', val[0]);
                }
            /* falls through */
            case '==':
            case '!=':
                if (val.length != 3) {
                    error(key, val, 'filter array for operator "%s" must have 3 elements', val[0]);
                }
            /* falls through */
            case 'in':
            case '!in':
                if (val.length >= 2) {
                    type = typeof_(val[1]);
                    if (type !== 'string') {
                        error(key + '[1]', val[1], 'string expected, %s found', type);
                    } else if (val[1][0] === '@') {
                        error(key + '[1]', val[1], 'filter key cannot be a constant');
                    }
                }
                for (var i = 2; i < val.length; i++) {
                    type = typeof_(val[i]);
                    if (val[1] == '$type') {
                        validate.enum(key + '[' + i + ']', val[i], reference.geometry_type);
                    } else if (type === 'string' && val[i][0] === '@') {
                        error(key + '[' + i + ']', val[i], 'filter value cannot be a constant');
                    } else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
                        error(key + '[' + i + ']', val[i], 'string, number, or boolean expected, %s found', type);
                    }
                }
                break;

            case 'any':
            case 'all':
            case 'none':
                for (i = 1; i < val.length; i++) {
                    validate.filter(key + '[' + i + ']', val[i]);
                }
                break;
        }
    };

    validate.function = function(key, val, spec) {
        validate.object(key, val, reference.function, {
            stops: function (key, val, arraySpec) {
                validate.array(key, val, arraySpec, function validateStop(key, val) {
                    if (typeof_(val) !== 'array') {
                        return error(key, val, 'array expected, %s found', typeof_(val));
                    }

                    if (val.length !== 2) {
                        return error(key, val, 'array length %d expected, length %d found', 2, val.length);
                    }

                    validate(key + '[0]', val[0], {type: 'number'});
                    validate(key + '[1]', val[1], spec);
                });
            }
        });
    };

    validate.enum = function (key, val, spec) {
        if (spec.values.indexOf(unbundle(val)) === -1) {
            error(key, val, 'expected one of [%s], %s found', spec.values.join(', '), val);
        }
    };

    validate.color = function(key, val) {
        var type = typeof_(val);
        if (type !== 'string') {
            error(key, val, 'color expected, %s found', type);
        } else if (parseCSSColor(val) === null) {
            error(key, val, 'color expected, "%s" found', val);
        }
    };

    function typeValidator(expected) {
        return function(key, val, spec) {
            var actual = typeof_(val);
            if (actual !== expected) {
                error(key, val, '%s expected, %s found', expected, actual);
            }

            if ('minimum' in spec && val < spec.minimum) {
                error(key, val, '%s is less than the minimum value %s', val, spec.minimum);
            }

            if ('maximum' in spec && val > spec.maximum) {
                error(key, val, '%s is greater than the maximum value %s', val, spec.maximum);
            }
        };
    }

    validate.number = typeValidator('number');
    validate.string = typeValidator('string');
    validate.boolean = typeValidator('boolean');

    validate['*'] = function() {};

    validate('', style, reference.$root);

    return errors;
};

function typeof_(val) {
    if (val instanceof Number)
        return 'number';
    if (val instanceof String)
        return 'string';
    if (val instanceof Boolean)
        return 'boolean';
    if (Array.isArray(val))
        return 'array';
    if (val === 'null')
        return 'null';
    return typeof(val);
}

function unbundle(_) {
    if (_ instanceof Number ||
        _ instanceof String ||
        _ instanceof Boolean) {
        return _.valueOf();
    } else {
        return _;
    }
}
<commit_msg>validate requires<commit_after>'use strict';

var jsonlint = require('jsonlint-lines-primitives');
var reference = require('mapbox-gl-style-spec/reference/v6');
var parseCSSColor = require('csscolorparser').parseCSSColor;
var format = require('util').format;

module.exports = function(str) {
    var style;
    var rawStyle = JSON.parse(str);

    try {
        style = jsonlint.parse(str.toString());
    } catch(e) {
        var match = e.message.match(/line (\d+)/),
            lineNumber = 0;
        if (match) lineNumber = parseInt(match[1], 10);
        return [{
            line: lineNumber - 1,
            message: e.message,
            error: e
        }];
    }

    var constants = style.constants || {},
        layers = {},
        errors = [];

    function error(key, val /*, message, ...*/) {
        errors.push({
            line: val.__line__,
            message: (key ? key + ': ' : '') +
                format.apply(format, Array.prototype.slice.call(arguments, 2))
        });
    }

    // Main recursive validation function. Tracks:
    //
    // - key: string representing location of validation in style tree. Used only
    //   for more informative error reporting.
    // - val: current value from style being evaluated. May be anything from a
    //   high level object that needs to be descended into deeper or a simple
    //   scalar value.
    // - spec: current spec being evaluated. Tracks val.
    //
    function validate(key, val, spec) {
        var type = typeof_(val);

        // Requires
        if (spec.requires) {
            var layer = rawStyle.layers[key.split('.')[0].slice(7, -1)];
            spec.requires.forEach(function(property) {
                validate.requires(layer, property, key, val);
            });
        }

        // Constants
        if (type === 'string' && val[0] === '@') {
            if (!(val in constants)) {
                return error(key, val, 'constant "%s" not found', val);
            }
            val = constants[val];
            type = typeof_(val);
        }

        // Functions
        if (spec.function && type === 'object') {
            return validate.function(key, val, spec);
        }

        if (spec.type) {
            var validator = validate[spec.type];
            if (validator) {
                return validator(key, val, spec);
            }
            spec = reference[spec.type];
        }

        validate.object(key, val, spec);
    }

    validate.requires = function(layer, property, key, val) {
        if (typeof property === 'string') {
            if (!(layer.layout && layer.layout[property]) &&
                !layer.paint[property]) return error(key, val, 'property requires "%s"', property);
        } else {
            if (property['!']) {
                if ((layer.layout && layer.layout[property['!']]) ||
                    layer.paint[property['!']]) return error(key, val, 'property is disabled by "%s"', property['!']);
            } else {
                var requiredProp = Object.keys(property)[0];
                var requiredVal = property[requiredProp];
                if ((layer.layout && layer.layout[requiredProp] !== requiredVal) &&
                    layer.paint[requiredProp] !== requiredVal) return error(key, val, 'property requires "%s" to be "%s"', requiredProp, requiredVal);
            }
        }
    };

    validate.constants = function(key, val) {
        var type = typeof_(val);
        if (type !== 'object') {
            return error(key, val, 'object expected, %s found', type);
        }

        for (var k in val) {
            if (k[0] !== '@') {
                error(key + '.' + k, val[k], 'constants must start with "@"');
            }
        }
    };

    validate.layer = function(key, val) {
        if (!val.type && !val.ref) {
            error(key, val, 'either "type" or "ref" is required');
        }

        var type = unbundle(val.type),
            ref = unbundle(val.ref);

        if (val.id) {
            if (layers[val.id]) {
                error(key, val.id, 'duplicate layer id "%s", previously used at line %d', val.id, layers[val.id]);
            } else {
                layers[val.id] = val.id.__line__;
            }
        }

        if ('ref' in val) {
            ['type', 'source', 'source-layer', 'filter', 'layout'].forEach(function (p) {
                if (p in val) {
                    error(key, val[p], '"%s" is prohibited for ref layers', p);
                }
            });

            var parent;

            style.layers.forEach(function(layer) {
                if (layer.id == ref) parent = layer;
            });

            if (parent) {
                type = parent.type;
            } else {
                error(key, val.ref, 'ref layer "%s" not found', ref);
            }
        } else if (type !== 'background') {
            if (!val.source) {
                error(key, val, 'missing required property "source"');
            } else {
                var source = style.sources[val.source];
                if (!source) {
                    error(key, val.source, 'source "%s" not found', val.source);
                } else if (source.type == 'vector' && type == 'raster' && !val.layers) {
                    error(key, val.source, 'layer "%s" requires a raster source', val.id);
                } else if (source.type == 'raster' && type != 'raster') {
                    error(key, val.source, 'layer "%s" requires a vector source', val.id);
                }
            }
        }

        validate.object(key, val, reference.layer, {
            filter: validate.filter,
            layout: function(key, val) {
                return type && validate(key, val, reference['layout_' + type]);
            },
            paint: function(key, val) {
                return type && validate(key, val, reference['paint_' + type]);
            }
        });
    };

    validate.object = function (key, val, spec, validators) {
        validators = validators || {};

        var type = typeof_(val);
        if (type !== 'object') {
            return error(key, val, 'object expected, %s found', type);
        }

        for (var k in val) {
            var speckey = k.split('.')[0]; // treat 'paint.*' as 'paint'
            var def = spec[speckey] || spec['*'];
            if (def) {
                (validators[speckey] || validate)((key ? key + '.' : key) + k, val[k], def);
            } else {
                error(key, val[k], 'unknown property "%s"', k);
            }
        }

        for (var l in spec) {
            if (spec[l].required && spec[l]['default'] === undefined && val[l] === undefined) {
                error(key, val, 'missing required property "%s"', l);
            }
        }
    };

    validate.array = function (key, val, spec, validator) {
        if (typeof_(val) !== 'array') {
            return error(key, val, 'array expected, %s found', typeof_(val));
        }

        if (spec.length && val.length !== spec.length) {
            return error(key, val, 'array length %d expected, length %d found', spec.length, val.length);
        }

        for (var i = 0; i < val.length; i++) {
            (validator || validate)(key + '[' + i + ']', val[i], {
                "type": spec.value,
                "function": spec.function
            });
        }
    };

    validate.filter = function(key, val) {
        var type;

        if (typeof_(val) !== 'array') {
            return error(key, val, 'array expected, %s found', typeof_(val));
        }

        if (val.length < 1) {
            return error(key, val, 'filter array must have at least 1 element');
        }

        validate.enum(key + '[0]', val[0], reference.filter_operator);

        switch (unbundle(val[0])) {
            case '<':
            case '<=':
            case '>':
            case '>=':
                if (val.length >= 2 && val[1] == '$type') {
                    error(key, val, '"$type" cannot be use with operator "%s"', val[0]);
                }
            /* falls through */
            case '==':
            case '!=':
                if (val.length != 3) {
                    error(key, val, 'filter array for operator "%s" must have 3 elements', val[0]);
                }
            /* falls through */
            case 'in':
            case '!in':
                if (val.length >= 2) {
                    type = typeof_(val[1]);
                    if (type !== 'string') {
                        error(key + '[1]', val[1], 'string expected, %s found', type);
                    } else if (val[1][0] === '@') {
                        error(key + '[1]', val[1], 'filter key cannot be a constant');
                    }
                }
                for (var i = 2; i < val.length; i++) {
                    type = typeof_(val[i]);
                    if (val[1] == '$type') {
                        validate.enum(key + '[' + i + ']', val[i], reference.geometry_type);
                    } else if (type === 'string' && val[i][0] === '@') {
                        error(key + '[' + i + ']', val[i], 'filter value cannot be a constant');
                    } else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
                        error(key + '[' + i + ']', val[i], 'string, number, or boolean expected, %s found', type);
                    }
                }
                break;

            case 'any':
            case 'all':
            case 'none':
                for (i = 1; i < val.length; i++) {
                    validate.filter(key + '[' + i + ']', val[i]);
                }
                break;
        }
    };

    validate.function = function(key, val, spec) {
        validate.object(key, val, reference.function, {
            stops: function (key, val, arraySpec) {
                validate.array(key, val, arraySpec, function validateStop(key, val) {
                    if (typeof_(val) !== 'array') {
                        return error(key, val, 'array expected, %s found', typeof_(val));
                    }

                    if (val.length !== 2) {
                        return error(key, val, 'array length %d expected, length %d found', 2, val.length);
                    }

                    validate(key + '[0]', val[0], {type: 'number'});
                    validate(key + '[1]', val[1], spec);
                });
            }
        });
    };

    validate.enum = function (key, val, spec) {
        if (spec.values.indexOf(unbundle(val)) === -1) {
            error(key, val, 'expected one of [%s], %s found', spec.values.join(', '), val);
        }
    };

    validate.color = function(key, val) {
        var type = typeof_(val);
        if (type !== 'string') {
            error(key, val, 'color expected, %s found', type);
        } else if (parseCSSColor(val) === null) {
            error(key, val, 'color expected, "%s" found', val);
        }
    };

    function typeValidator(expected) {
        return function(key, val, spec) {
            var actual = typeof_(val);
            if (actual !== expected) {
                error(key, val, '%s expected, %s found', expected, actual);
            }

            if ('minimum' in spec && val < spec.minimum) {
                error(key, val, '%s is less than the minimum value %s', val, spec.minimum);
            }

            if ('maximum' in spec && val > spec.maximum) {
                error(key, val, '%s is greater than the maximum value %s', val, spec.maximum);
            }
        };
    }

    validate.number = typeValidator('number');
    validate.string = typeValidator('string');
    validate.boolean = typeValidator('boolean');

    validate['*'] = function() {};

    validate('', style, reference.$root);

    return errors;
};

function typeof_(val) {
    if (val instanceof Number)
        return 'number';
    if (val instanceof String)
        return 'string';
    if (val instanceof Boolean)
        return 'boolean';
    if (Array.isArray(val))
        return 'array';
    if (val === 'null')
        return 'null';
    return typeof(val);
}

function unbundle(_) {
    if (_ instanceof Number ||
        _ instanceof String ||
        _ instanceof Boolean) {
        return _.valueOf();
    } else {
        return _;
    }
}
<|endoftext|>


<commit_before>var through2 = require('through2')

module.exports = function(stream, next) {

  var transform = function(chunk, enc, cb) {

    if (! chunk) return cb(new Error('invalid chunk'))
    chunk = chunk.toString().replace(/\n$/, '')

    try {
      var data = JSON.parse(chunk)
    } catch (err) {
      return next(err)
    }

    for (var key in data) {
      if (key === 'omdb_data') {
        for (var child in data[key]) {
          if (! data[key][child] || data[key][child] === 'N/A') {
            switch (child) {
              case 'Runtime':
              case 'Metascore':
              case 'imdbRating':
              case 'imdbVotes':
                data[key][child] = 0
                break
            }
          }
          if (child === 'Hash') {
            data[key]['Hash_omdb'] = data[key][child]
            delete data[key]['Hash']
          }
        }
      }

      if (key === 'tmdb_data') {
        for (var child in data[key]) {
          switch (child) {
            case 'runtime':
              data[key]['runtime_'] = parseInt(data[key][child], 10)
              delete data[key][child]
              break
            case 'title':
              data[key]['title_'] = data[key][child].toString()
              delete data[key][child]
              break
          }
          if (child === 'Hash') {
            data[key]['Hash_tmdb'] = data[key][child]
            delete data[key]['Hash']
          }
        }
      }
    }

    data = JSON.stringify(data)
    this.push(data +'\n')

    // another chunk..
    cb()
  }

  var flush = function() {
    this.push(null)
  }

  next(null, stream.pipe(through2(transform, flush)))
}

<commit_msg>inject custom yyyymm value into imported data object<commit_after>var through2 = require('through2')

module.exports = function(stream, next) {

  var transform = function(chunk, enc, cb) {

    if (! chunk) return cb(new Error('invalid chunk'))
    chunk = chunk.toString().replace(/\n$/, '')

    try {
      var data = JSON.parse(chunk)
    } catch (err) {
      return next(err)
    }

    for (var key in data) {
      if (key === 'omdb_data') {
        for (var child in data[key]) {
          if (! data[key][child] || data[key][child] === 'N/A') {
            switch (child) {
              case 'Runtime':
              case 'Metascore':
              case 'imdbRating':
              case 'imdbVotes':
                data[key][child] = 0
                break
            }
          }
          if (child === 'Hash') {
            data[key]['Hash_omdb'] = data[key][child]
            delete data[key]['Hash']
          }
        }
      }

      if (key === 'tmdb_data') {
        for (var child in data[key]) {
          switch (child) {
            case 'release_date':
              data['custom'] = {}
              data['custom']['yyyymm'] = data[key][child].substr(0, 7).replace('-', '')
              break
            case 'runtime':
              data[key]['runtime_'] = parseInt(data[key][child], 10)
              delete data[key][child]
              break
            case 'title':
              data[key]['title_'] = data[key][child].toString()
              delete data[key][child]
              break
          }
          if (child === 'Hash') {
            data[key]['Hash_tmdb'] = data[key][child]
            delete data[key]['Hash']
          }
        }
      }
    }

    data = JSON.stringify(data)
    this.push(data +'\n')

    // another chunk..
    cb()
  }

  var flush = function() {
    this.push(null)
  }

  next(null, stream.pipe(through2(transform, flush)))
}

<|endoftext|>


<commit_before>/** This cheap replica of DOM/Builder puts me to shame :-) */
function Element(name, attrs) {
    this.name = name;
    this.parent = null;
    if (attrs)
	this.attrs = attrs;
    else
	this.attrs = {};
    this.children = [];
}

/*** Accessors ***/

Element.prototype.is = function(name, xmlns) {
    return this.getName() == name &&
	(!xmlns || this.getNS() == xmlns);
};

/* without prefix */
Element.prototype.getName = function() {
    if (this.name.indexOf(":") >= 0)
	return this.name.substr(this.name.indexOf(":") + 1);
    else
	return this.name;
};

Element.prototype.getNS = function() {
    if (this.name.indexOf(":") >= 0) {
	var prefix = this.name.substr(0, this.name.indexOf(":"));
	return this.findNS(prefix);
    } else {
	return this.findNS();
    }
};

Element.prototype.findNS = function(prefix) {
    if (!prefix) {
	/* default namespace */
	if (this.attrs.xmlns)
	    return this.attrs.xmlns;
	else
	    return this.parent.findNS();
    } else {
	/* prefixed namespace */
	var attr = 'xmlns:' + prefix;
	if (this.attrs[attr])
	    return this.attrs[attr];
	else
	    return this.parent.findNS(prefix);
    }
};

/** xmlns can be null */
Element.prototype.getChild = function(name, xmlns) {
    return this.getChildren(name, xmlns)[0];
};

Element.prototype.getChildren = function(name, xmlns) {
    var result = [];
    this.children.forEach(function(child) {
	if (child.getName() == name &&
	    (!xmlns || child.getNS() == xmlns))
	    result.push(child);
    });
    return result;
};

Element.prototype.getText = function() {
    var text = "";
    this.children.forEach(function(child) {
	if (typeof child == 'string')
	    text += child;
    });
    return text;
};

Element.prototype.getChildText = function(name) {
    var text = null;
    this.children.forEach(function(el) {
	if (!text && el.name == name)
	{
	    text = el.getText();
	}
    });
    return text;
};

/*** Builder ***/

/** returns uppermost parent */
Element.prototype.root = function() {
    if (this.parent)
	return this.parent.root();
    else
	return this;
};
Element.prototype.tree = Element.prototype.root;

/** just parent or itself */
Element.prototype.up = function() {
    if (this.parent)
	return this.parent;
    else
	return this;
};

/** create child node and return it */
Element.prototype.c = function(name, attrs) {
    return this.cnode(new Element(name, attrs));
};

Element.prototype.cnode = function(child) {
    this.children.push(child);
    child.parent = this;
    return child;
};

/** create text node and return element */
Element.prototype.t = function(text) {
    this.children.push(text);
    return this;
};

/*** Serialization ***/

Element.prototype.toString = function() {
    var s = "";
    this.write(function(c) {
	s += c;
    });
    return s;
};

Element.prototype.write = function(writer) {
    writer("<");
    writer(this.name);
    for(var k in this.attrs) {
	writer(" ");
	writer(k);
	writer("=\"");
	writer(escapeXml(this.attrs[k]));
	writer("\"");
    }
    if (this.children.length == 0) {
	writer("/>");
    } else {
	writer(">");
	this.children.forEach(function(child) {
	    if (typeof child == 'string')
		writer(child);
	    else
		child.write(writer);
	});
	writer("</");
	writer(this.name);
	writer(">");
    }
};

function escapeXml(s) {
    return s.
	replace('&', '&').
	replace('<', '<').
	replace('>', '>').
	replace('"', '"').
	replace('\'', ''');
};

exports.Element = Element;
exports.escapeXml = escapeXml;
<commit_msg>xml: getChildren() ignores string nodes<commit_after>/** This cheap replica of DOM/Builder puts me to shame :-) */
function Element(name, attrs) {
    this.name = name;
    this.parent = null;
    if (attrs)
	this.attrs = attrs;
    else
	this.attrs = {};
    this.children = [];
}

/*** Accessors ***/

Element.prototype.is = function(name, xmlns) {
    return this.getName() == name &&
	(!xmlns || this.getNS() == xmlns);
};

/* without prefix */
Element.prototype.getName = function() {
    if (this.name.indexOf(":") >= 0)
	return this.name.substr(this.name.indexOf(":") + 1);
    else
	return this.name;
};

Element.prototype.getNS = function() {
    if (this.name.indexOf(":") >= 0) {
	var prefix = this.name.substr(0, this.name.indexOf(":"));
	return this.findNS(prefix);
    } else {
	return this.findNS();
    }
};

Element.prototype.findNS = function(prefix) {
    if (!prefix) {
	/* default namespace */
	if (this.attrs.xmlns)
	    return this.attrs.xmlns;
	else
	    return this.parent.findNS();
    } else {
	/* prefixed namespace */
	var attr = 'xmlns:' + prefix;
	if (this.attrs[attr])
	    return this.attrs[attr];
	else
	    return this.parent.findNS(prefix);
    }
};

/** xmlns can be null */
Element.prototype.getChild = function(name, xmlns) {
    return this.getChildren(name, xmlns)[0];
};

Element.prototype.getChildren = function(name, xmlns) {
    var result = [];
    this.children.forEach(function(child) {
	if (child.getName &&
	    child.getName() == name &&
	    (!xmlns || child.getNS() == xmlns))
	    result.push(child);
    });
    return result;
};

Element.prototype.getText = function() {
    var text = "";
    this.children.forEach(function(child) {
	if (typeof child == 'string')
	    text += child;
    });
    return text;
};

Element.prototype.getChildText = function(name) {
    var text = null;
    this.children.forEach(function(el) {
	if (!text && el.name == name)
	{
	    text = el.getText();
	}
    });
    return text;
};

/*** Builder ***/

/** returns uppermost parent */
Element.prototype.root = function() {
    if (this.parent)
	return this.parent.root();
    else
	return this;
};
Element.prototype.tree = Element.prototype.root;

/** just parent or itself */
Element.prototype.up = function() {
    if (this.parent)
	return this.parent;
    else
	return this;
};

/** create child node and return it */
Element.prototype.c = function(name, attrs) {
    return this.cnode(new Element(name, attrs));
};

Element.prototype.cnode = function(child) {
    this.children.push(child);
    child.parent = this;
    return child;
};

/** create text node and return element */
Element.prototype.t = function(text) {
    this.children.push(text);
    return this;
};

/*** Serialization ***/

Element.prototype.toString = function() {
    var s = "";
    this.write(function(c) {
	s += c;
    });
    return s;
};

Element.prototype.write = function(writer) {
    writer("<");
    writer(this.name);
    for(var k in this.attrs) {
	writer(" ");
	writer(k);
	writer("=\"");
	writer(escapeXml(this.attrs[k]));
	writer("\"");
    }
    if (this.children.length == 0) {
	writer("/>");
    } else {
	writer(">");
	this.children.forEach(function(child) {
	    if (typeof child == 'string')
		writer(child);
	    else
		child.write(writer);
	});
	writer("</");
	writer(this.name);
	writer(">");
    }
};

function escapeXml(s) {
    return s.
	replace('&', '&').
	replace('<', '<').
	replace('>', '>').
	replace('"', '"').
	replace('\'', ''');
};

exports.Element = Element;
exports.escapeXml = escapeXml;
<|endoftext|>


<commit_before>;(function(bdgg) {
    CONTRIBUTORS = [ '9inevolt', 'ILiedAboutCake', 'mellipelli' ];

    bdgg.flair = (function() {
        destiny.UserFeatures['BDGG_CONTRIBUTOR'] = 'bdgg_contributor';
        var fnGetFeatureHTML = ChatUser.prototype.getFeatureHTML;
        var bdggGetFeatureHTML = function() {
            var icons = fnGetFeatureHTML.apply(this, arguments);
            if (CONTRIBUTORS.indexOf(this.username) > -1) {
                icons += '<i class="icon-bdgg-contributor" title="Better Destiny.gg Contributor"/>';
            }
            return icons;
        };
        ChatUser.prototype.getFeatureHTML = bdggGetFeatureHTML;
        return {};
    })();
}(window.BetterDGG = window.BetterDGG || {}));
<commit_msg>fix broken flair. Fixes #61<commit_after>;(function(bdgg) {
    CONTRIBUTORS = [ '9inevolt', 'ILiedAboutCake', 'mellipelli' ];

    bdgg.flair = (function() {
        destiny.UserFeatures['BDGG_CONTRIBUTOR'] = 'bdgg_contributor';
        var fnGetFeatureHTML = ChatUserMessage.prototype.getFeatureHTML;
        var bdggGetFeatureHTML = function() {
            var icons = fnGetFeatureHTML.apply(this, arguments);
            if (CONTRIBUTORS.indexOf(this.user.username) > -1) {
                icons += '<i class="icon-bdgg-contributor" title="Better Destiny.gg Contributor"/>';
            }
            return icons;
        };
        ChatUserMessage.prototype.getFeatureHTML = bdggGetFeatureHTML;
        return {};
    })();
}(window.BetterDGG = window.BetterDGG || {}));
<|endoftext|>


<commit_before>/*globals Endpoint*/
/*exported Segment*/
var Segment = (function() {
  'use strict';

  function Segment() {
    var x0 = 0,
        y0 = 0,
        x1 = 0,
        y1 = 0;

    // Set from existing endpoints.
    if ( arguments.length === 2 ) {
      this.p0 = arguments[0];
      this.p1 = arguments[1];
      return this;
    }

    // Set endpoints.
    if ( arguments.length === 4 ) {
      x0 = arguments[0];
      y0 = arguments[1];
      x1 = arguments[2];
      y1 = arguments[3];
    }

    this.p0 = new Endpoint( x0, y0 );
    this.p1 = new Endpoint( x1, y1 );
  }

  Segment.prototype.draw = function( ctx ) {
    ctx.moveTo( this.p0.x, this.p0.y );
    ctx.lineTo( this.p1.x, this.p1.y );
  };

  Segment.prototype.first = function() {
    return this.p0;
  };

  Segment.prototype.last = function() {
    return this.p1;
  };

  Segment.prototype.points = function() {
    return [ this.p0, this.p1 ];
  };

  Segment.prototype.linkTo = function( segment ) {
    this.p0 = segment.last();
    return this;
  };

  Segment.prototype.unlink = function() {
    this.p0 = this.p0.clone();
    return this;
  };

  return Segment;

}) ();
<commit_msg>bezier-curve: Add Segment split/toArray/toJSON methods.<commit_after>/*globals Endpoint*/
/*exported Segment*/
var Segment = (function() {
  'use strict';

  function lerp( a, b, t ) {
    return a + t * ( b - a );
  }

  function Segment() {
    var x0 = 0,
        y0 = 0,
        x1 = 0,
        y1 = 0;

    // Set from existing endpoints.
    if ( arguments.length === 2 ) {
      this.p0 = arguments[0];
      this.p1 = arguments[1];
      return this;
    }

    // Set endpoints.
    if ( arguments.length === 4 ) {
      x0 = arguments[0];
      y0 = arguments[1];
      x1 = arguments[2];
      y1 = arguments[3];
    }

    this.p0 = new Endpoint( x0, y0 );
    this.p1 = new Endpoint( x1, y1 );
  }

  Segment.prototype.draw = function( ctx ) {
    ctx.moveTo( this.p0.x, this.p0.y );
    ctx.lineTo( this.p1.x, this.p1.y );
  };

  Segment.prototype.first = function() {
    return this.p0;
  };

  Segment.prototype.last = function() {
    return this.p1;
  };

  Segment.prototype.points = function() {
    return [ this.p0, this.p1 ];
  };

  Segment.prototype.linkTo = function( segment ) {
    this.p0 = segment.last();
    return this;
  };

  Segment.prototype.unlink = function() {
    this.p0 = this.p0.clone();
    return this;
  };

  /**
   * Returns the coordinate arrays of the segments formed by the split at
   * parameter t.
   */
  Segment.prototype.split = function( t ) {
    var x0 = this.p0.x,
        y0 = this.p0.y,
        x1 = this.p1.x,
        y1 = this.p1.y;

    var xt = lerp( x0, x1, t ),
        yt = lerp( y0, y1, t );

    return [
      [ x0, y0, xt, yt ],
      [ xt, yt, x1, y1 ]
    ];
  };

  Segment.prototype.toArray = function() {
    return [
      this.p0.x, this.p0.y,
      this.p1.x, this.p1.y
    ];
  };

  Segment.prototype.toJSON = Segment.prototype.toArray;

  return Segment;

}) ();
<|endoftext|>


<commit_before>/**
 * Created by micha on 06.12.2016.
 */
//node
const fs = require ('fs')
const path = require ('path')
//own
const Database = require('./database.js').Database
const DO = require('./database.js').DatabaseOperation
let checksum = require('./checksum.js').ChecksumCreator
const urlHandler = require('./urlHandler.js').URLHandler
//other

//consts
const libraryPath = "./DockyLibrary/Zeskanowane"
const overwritePath = "./DockyLibrary/Zeskanowane/Overwrite"

class AddFile {

    static addFile(fpath, collectionId, callback){
        fpath = fpath.toString()

        if (fpath.substring(0,4) ==='http' || fpath.substring(0,5) ==='https') {
            urlHandler.downloadFile(fpath, (err, path) => {
                if (err) {
                    callback && callback({'status': 'error', 'file': err})
                } else {
                    this.libAndDb(path, fpath, collectionId, callback)
                }
            })
        } else {
            this.libAndDb(fpath, '', collectionId, callback)
        }

    }

    static libAndDb(fpath, url, collectionId, callback){
        AddFileHelper.copyFileToLib(fpath,  (err, fileInfo) => {
            if (err){
                callback({'status': 'error', 'file': err})
            } else {
                let currentDate = new Date ()
                fileInfo.Date = currentDate.toLocaleString()
                fileInfo.Url = url
                DO.MultiInsert.InsertAllInfo(collectionId, fileInfo, (err, fid) => {
                    fileInfo.ID_File = fid
                    callback && callback({'status': 'success', 'file': fileInfo})
                })
            }
        })
    }

}
exports.AddFile = AddFile

class AddFileHelper {

    static copyFileToLib (fpath, callback) {
        //console.log('copy ' + fpath)
        let filename = path.basename(fpath, ".pdf")
        checksum.create(fpath, (err, checksum) =>{
            DO.File.GetAllFiles(null, null, null, (err, rows) => {
                if (err){
                    callback && callback({'status': 'error', 'name': filename}, null)
                } else {
                    let checksumInDb = rows.filter(AddFileFinder.isChecksumInDb, checksum)
                    if (checksumInDb.length < 1) {
                        PathHanlder.resolvePath(fpath, rows, (finalpath) => {
                            if (finalpath === fpath){
                                callback && callback ({'status': 'error', 'name': 'mkdir err'}, null)
                            } else {
                                //console.log('resolved' + fpath)
                                PathHanlder.copyFile(fpath, finalpath, ()=> {
                                    let finfo = {'Filename':filename, 'Path':finalpath, 'Checksum':checksum}
                                    //console.log('copied ' + fpath)
                                    callback && callback (null, finfo)
                                })
                            }
                        })
                    } else {
                        callback && callback({'status': 'exist', 'file': checksumInDb[0]}, null)
                    }
                }
            })
        })
    }

}

class PathHanlder {
    static resolvePath(fpath, rows, callback){
        //console.log('resolve ' + fpath)
        let filename = path.basename(fpath, '.pdf')
        let possiblePath = libraryPath + "/" + filename + ".pdf"
        let pathInDb = rows.filter(AddFileFinder.isPathTaken, possiblePath)
        if (pathInDb.length < 1){
            callback && callback(possiblePath)
        } else {
            let ovDir = overwritePath + '/' + filename
            //console.log("Ovdir: " + ovDir)
            let ovs = rows.filter(AddFileFinder.isPathPart, ovDir)
            if (ovs.length < 1) {
                fs.mkdir(ovDir, (err)=> {
                    if (err) {
                        //console.log('error')
                        callback(fpath)
                    } else {
                        let finalPath = ovDir + "/" + filename + "__1.pdf"
                        callback && callback(finalPath)
                    }
                })
            } else {
                let max = 0
                ovs.forEach((ov) => {
                    let oldNumber = (parseInt((ov.Path.split("__").pop())))
                    if (oldNumber > max){
                        max = oldNumber
                    }
                })
                let finalPath = ovDir + "/" + filename + "__" + (max + 1).toString() + ".pdf"
                callback && callback(finalPath)
            }
        }
    }

    static copyFile(source, destination, callback) {
        fs.createReadStream(source).pipe(fs.createWriteStream(destination))
        callback && callback()
    }
}

class AddFileFinder {

    static isPathTaken(element){
        return element.Path === this
    }

    static isChecksumInDb(element){
        return element.Checksum === this
    }

    static isPathPart (element){
        return element.Path.includes(this)
    }

}<commit_msg>status fix<commit_after>/**
 * Created by micha on 06.12.2016.
 */
//node
const fs = require ('fs')
const path = require ('path')
//own
const Database = require('./database.js').Database
const DO = require('./database.js').DatabaseOperation
let checksum = require('./checksum.js').ChecksumCreator
const urlHandler = require('./urlHandler.js').URLHandler
//other

//consts
const libraryPath = "./DockyLibrary/Zeskanowane"
const overwritePath = "./DockyLibrary/Zeskanowane/Overwrite"

class AddFile {

    static addFile(fpath, collectionId, callback){
        fpath = fpath.toString()

        if (fpath.substring(0,4) ==='http' || fpath.substring(0,5) ==='https') {
            urlHandler.downloadFile(fpath, (err, path) => {
                if (err) {
                    callback && callback({'status': 'error', 'file': err})
                } else {
                    this.libAndDb(path, fpath, collectionId, callback)
                }
            })
        } else {
            this.libAndDb(fpath, '', collectionId, callback)
        }

    }

    static libAndDb(fpath, url, collectionId, callback){
        AddFileHelper.copyFileToLib(fpath,  (err, fileInfo) => {
            if (err){
                if (fileInfo){
                    callback(fileInfo)
                } else {
                    callback({'status': 'error', 'file': err})
                }
            } else {
                let currentDate = new Date ()
                fileInfo.Date = currentDate.toLocaleString()
                fileInfo.Url = url
                DO.MultiInsert.InsertAllInfo(collectionId, fileInfo, (err, fid) => {
                    fileInfo.ID_File = fid
                    callback && callback({'status': 'success', 'file': fileInfo})
                })
            }
        })
    }

}
exports.AddFile = AddFile

class AddFileHelper {

    static copyFileToLib (fpath, callback) {
        //console.log('copy ' + fpath)
        let filename = path.basename(fpath, ".pdf")
        checksum.create(fpath, (err, checksum) =>{
            DO.File.GetAllFiles(null, null, null, (err, rows) => {
                if (err){
                    callback && callback({'status': 'error', 'name': filename}, null)
                } else {
                    let checksumInDb = rows.filter(AddFileFinder.isChecksumInDb, checksum)
                    if (checksumInDb.length < 1) {
                        PathHanlder.resolvePath(fpath, rows, (finalpath) => {
                            if (finalpath === fpath){
                                callback && callback ({'status': 'error', 'name': 'mkdir err'}, null)
                            } else {
                                //console.log('resolved' + fpath)
                                PathHanlder.copyFile(fpath, finalpath, ()=> {
                                    let finfo = {'Filename':filename, 'Path':finalpath, 'Checksum':checksum}
                                    //console.log('copied ' + fpath)
                                    callback && callback (null, finfo)
                                })
                            }
                        })
                    } else {
                        callback && callback({'status': 'exist', 'file': checksumInDb[0]}, {'status': 'exist', 'file': checksumInDb[0]})
                    }
                }
            })
        })
    }

}

class PathHanlder {
    static resolvePath(fpath, rows, callback){
        //console.log('resolve ' + fpath)
        let filename = path.basename(fpath, '.pdf')
        let possiblePath = libraryPath + "/" + filename + ".pdf"
        let pathInDb = rows.filter(AddFileFinder.isPathTaken, possiblePath)
        if (pathInDb.length < 1){
            callback && callback(possiblePath)
        } else {
            let ovDir = overwritePath + '/' + filename
            //console.log("Ovdir: " + ovDir)
            let ovs = rows.filter(AddFileFinder.isPathPart, ovDir)
            if (ovs.length < 1) {
                fs.mkdir(ovDir, (err)=> {
                    if (err) {
                        //console.log('error')
                        callback(fpath)
                    } else {
                        let finalPath = ovDir + "/" + filename + "__1.pdf"
                        callback && callback(finalPath)
                    }
                })
            } else {
                let max = 0
                ovs.forEach((ov) => {
                    let oldNumber = (parseInt((ov.Path.split("__").pop())))
                    if (oldNumber > max){
                        max = oldNumber
                    }
                })
                let finalPath = ovDir + "/" + filename + "__" + (max + 1).toString() + ".pdf"
                callback && callback(finalPath)
            }
        }
    }

    static copyFile(source, destination, callback) {
        fs.createReadStream(source).pipe(fs.createWriteStream(destination))
        callback && callback()
    }
}

class AddFileFinder {

    static isPathTaken(element){
        return element.Path === this
    }

    static isChecksumInDb(element){
        return element.Checksum === this
    }

    static isPathPart (element){
        return element.Path.includes(this)
    }

}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
 *
 * 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'

const settings = require('./settings')

const EventEmitter = require('events')
const util = require('util')
const Hue = require('node-hue-api')

function updateHueApi (obj) {
  if (obj.ip == null) {
    return
  }

  if (settings.config.hue.username == null) {
    return
  }

  if (obj.api) {
    return
  }

  settings.data.hue = obj.ip
  obj.api = new Hue.HueApi(obj.ip, settings.config.hue.username)
  obj.api.setLightState(1, obj.lightstate.off(), (err, lights) => {
    if (err) {
      console.log(err)
    } else {
      console.log(lights)
    }
  })
}

function HueBridge () {
  EventEmitter.call(this)

  this.ip = null
  this.api = null
  this.lightstate = Hue.lightState.create()
}

util.inherits(HueBridge, EventEmitter)

HueBridge.prototype.Search = function () {
  const self = this

  Hue.nupnpSearch((err, bridge) => {
    if (err) {
      console.log(err)
      self.emit('notfound', null)
      return
    }

    if (bridge.length === 0) {
      console.log("can't find hue bridge")
      self.emit('notfound', null)
      return
    }

    console.log('Hue bridge found: ', bridge)
    self.ip = bridge[0].ipaddress
    self.emit('found', self.ip)
    updateHueApi(self)
  })
}

HueBridge.prototype.getUsername = function (cb) {
  if (this.ip == null) {
    cb(new Error("can't find hue bridge"))
    return
  }

  const self = this

  const api = new Hue.HueApi()
  api.registerUser(this.ip, 'demokit').then((result) => {
    console.log(result)
    cb(null, result)
    updateHueApi(self)
  }).catch((err) => {
    console.log(err)
    cb(err)
  })
}

HueBridge.prototype.setOn = function (cb) {
  if (this.api == null) {
    cb(new Error('not ready'))
    return
  }

  this.api.setLightState(1, this.lightstate.on(), (err, lights) => {
    console.log(lights)
    cb(err, lights)
  })
}

HueBridge.prototype.setOff = function (cb) {
  if (this.api == null) {
    cb(new Error('not ready'))
    return
  }

  this.api.setLightState(1, this.lightstate.off(), (err, lights) => {
    console.log(lights)
    cb(err, lights)
  })
}

HueBridge.prototype.getStatus = function (cb) {
  if (this.api == null) {
    cb(new Error('not ready'))
    return
  }

  this.api.lightStatus(1, (err, result) => {
    console.log(result)
    cb(err, result)
  })
}

HueBridge.prototype.setTrigger = function (src) {
  src.on('on', () => {
    hb.setOn((err) => {
      if (err) {
        console.log(err)
      }
    })
  })
}

const hb = new HueBridge()

hb.on('notfound', function () {
  console.log('retry hue search')
  setTimeout(function () {
    hb.Search()
  }, 1000)
})

hb.Search()

module.exports = hb
<commit_msg>Add alert to huectrl<commit_after>/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
 *
 * 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'

const settings = require('./settings')

const EventEmitter = require('events')
const util = require('util')
const Hue = require('node-hue-api')

function updateHueApi (obj) {
  if (obj.ip == null) {
    return
  }

  if (settings.config.hue.username == null) {
    return
  }

  if (obj.api) {
    return
  }

  settings.data.hue = obj.ip
  obj.api = new Hue.HueApi(obj.ip, settings.config.hue.username)
  obj.api.setLightState(1, obj.lightstate.off(), (err, lights) => {
    if (err) {
      console.log(err)
    } else {
      console.log(lights)
    }
  })
}

function HueBridge () {
  EventEmitter.call(this)

  this.ip = null
  this.api = null
  this.lightstate = Hue.lightState.create()
}

util.inherits(HueBridge, EventEmitter)

HueBridge.prototype.Search = function () {
  const self = this

  Hue.nupnpSearch((err, bridge) => {
    if (err) {
      console.log(err)
      self.emit('notfound', null)
      return
    }

    if (bridge.length === 0) {
      console.log("can't find hue bridge")
      self.emit('notfound', null)
      return
    }

    console.log('Hue bridge found: ', bridge)
    self.ip = bridge[0].ipaddress
    self.emit('found', self.ip)
    updateHueApi(self)
  })
}

HueBridge.prototype.getUsername = function (cb) {
  if (this.ip == null) {
    cb(new Error("can't find hue bridge"))
    return
  }

  const self = this

  const api = new Hue.HueApi()
  api.registerUser(this.ip, 'demokit').then((result) => {
    console.log(result)
    cb(null, result)
    updateHueApi(self)
  }).catch((err) => {
    console.log(err)
    cb(err)
  })
}

HueBridge.prototype.setAlert = function (cb) {
  if (this.api == null) {
    cb(new Error('not ready'))
    return
  }

  this.api.setLightState(1, {"on": true, "bri": 64, "alert": "lselect"}, (err, lights) => {
    console.log(lights)
    cb(err, lights)
  })
}

HueBridge.prototype.setOn = function (cb) {
  if (this.api == null) {
    cb(new Error('not ready'))
    return
  }

//  this.api.setLightState(1, this.lightstate.on(), (err, lights) => {
  this.api.setLightState(1, {"on": true, "bri": 64, "alert": "none"}, (err, lights) => {
    console.log(lights)
    cb(err, lights)
  })
}

HueBridge.prototype.setOff = function (cb) {
  if (this.api == null) {
    cb(new Error('not ready'))
    return
  }

  this.api.setLightState(1, this.lightstate.off(), (err, lights) => {
    console.log(lights)
    cb(err, lights)
  })
}

HueBridge.prototype.getStatus = function (cb) {
  if (this.api == null) {
    cb(new Error('not ready'))
    return
  }

  this.api.lightStatus(1, (err, result) => {
    console.log(result)
    cb(err, result)
  })
}

HueBridge.prototype.setTrigger = function (src) {
  src.on('on', () => {
    hb.setAlert((err) => {
      if (err) {
        console.log(err)
      }
    })
  })
}

const hb = new HueBridge()

hb.on('notfound', function () {
  console.log('retry hue search')
  setTimeout(function () {
    hb.Search()
  }, 1000)
})

hb.Search()

module.exports = hb
<|endoftext|>