<commit_before>var UserAgentParser = require('ua-parser-js');
var languageMessages = require('./languages.json');
var deepExtend = require('deep-extend');

var DEFAULTS = {
	'Chrome': 57, // Includes Chrome for mobile devices
	'Edge': 39,
	'Safari': 10,
	'Mobile Safari': 10,
	'Opera': 50,
	'Firefox': 50,
	'Vivaldi': 1,
	'IE': false
};

var EDGEHTML_VS_EDGE_VERSIONS = {
	12: 0.1,
	13: 21,
	14: 31,
	15: 39,
	16: 41,
	17: 42
};

var updateDefaults = function(defaults, updatedValues) {
	for (var key in updatedValues) {
		if (defaults.hasOwnProperty(key)) {
			defaults[key] = updatedValues[key];
		}
	}

	return defaults;
};

module.exports = function (options) {

	var main = function () {

		// Despite the docs, UA needs to be provided to constructor explicitly:
		// https://github.com/faisalman/ua-parser-js/issues/90
		var parsedUserAgent = new UserAgentParser(window.navigator.userAgent).getResult();

		// Variable definition (before ajax)
		var outdatedUI = document.getElementById('outdated');

		options = options || {};

		var browserLocale = window.navigator.language || window.navigator.userLanguage; // Everyone else, IE

		// Set default options
		var browserSupport = options.browserSupport ? updateDefaults(DEFAULTS, options.browserSupport) : DEFAULTS;
		// CSS property to check for. You may also like 'borderSpacing', 'boxShadow', 'transform', 'borderImage';
		var	requiredCssProperty = options.requiredCssProperty || false;
		var	backgroundColor = options.backgroundColor || '#f25648'; // Salmon
		var	textColor = options.textColor || 'white';
		var fullscreen = options.fullscreen || false; //Defaulting fullscreen to false.
		var	language = options.language || browserLocale.slice(0, 2); // Language code

		var updateSource = 'web'; // Other possible values are 'googlePlay' or 'appStore'. Determines where we tell users to go for upgrades.

		// Chrome mobile is still Chrome (unlike Safari which is 'Mobile Safari')
		var isAndroid = parsedUserAgent.os.name === 'Android';
		if ( isAndroid ) {
			updateSource = 'googlePlay';
		}

		var isAndroidButNotChrome;
		if (options.requireChromeOnAndroid) {
			isAndroidButNotChrome = (isAndroid) && (parsedUserAgent.browser.name !== 'Chrome');
		}

		if (parsedUserAgent.os.name === 'iOS') {
			updateSource = 'appStore';
		}

		var done = true;

		var changeOpacity = function (opacityValue) {
			outdatedUI.style.opacity = opacityValue / 100;
			outdatedUI.style.filter = 'alpha(opacity=' + opacityValue + ')';
		};

		var fadeIn = function (opacityValue) {
			changeOpacity(opacityValue);
			if (opacityValue === 1) {
				outdatedUI.style.display = 'table';
			}
			if (opacityValue === 100) {
				done = true;
			}
		};

		var isBrowserOutOfDate = function () {
			var browserName = parsedUserAgent.browser.name;
			var browserMajorVersion = parsedUserAgent.browser.major;
			if ( browserName === 'Edge' ) {
				browserMajorVersion = EDGEHTML_VS_EDGE_VERSIONS[browserMajorVersion]
			}
			var isOutOfDate = false;
			if ( ! browserSupport[browserName] ) {
				if ( ! options.isUnknownBrowserOK ) {
					isOutOfDate = true;
				}
			} else if (browserMajorVersion < browserSupport[browserName]) {
				isOutOfDate = true;
			}
			return isOutOfDate;
		};

		// Returns true if a browser supports a css3 property
		var isPropertySupported = function (property) {
			if ( ! property ) {
				return true;
			}
			var div = document.createElement('div');
			var vendorPrefixes = ['khtml', 'ms', 'o', 'moz', 'webkit'];
			var count = vendorPrefixes.length;

			if ( div.style.hasOwnProperty(property) ) {
				return true;
			}

			property = property.replace(/^[a-z]/, function (val) {
				return val.toUpperCase();
			});

			while (count--) {
				var prefixedProperty = vendorPrefixes[count] + property
				if ( div.style.hasOwnProperty(prefixedProperty) ) {
					return true;
				}
			}
			return false;
		};

		var makeFadeInFunction = function(opacityValue) {
			return function () {
				fadeIn(opacityValue);
			};
		};

		// Style element explicitly - TODO: investigate and delete if not needed
		var startStylesAndEvents = function () {
			var buttonClose = document.getElementById('buttonCloseUpdateBrowser');
			var buttonUpdate = document.getElementById('buttonUpdateBrowser');

			//check settings attributes
			outdatedUI.style.backgroundColor = backgroundColor;
			//way too hard to put !important on IE6
			outdatedUI.style.color = textColor;
			outdatedUI.children[0].children[0].style.color = textColor;
			outdatedUI.children[0].children[1].style.color = textColor;

			// Update button is desktop only
			if (buttonUpdate) {
				buttonUpdate.style.color = textColor;
				if (buttonUpdate.style.borderColor) {
					buttonUpdate.style.borderColor = textColor;
				}

				// Override the update button color to match the background color
				buttonUpdate.onmouseover = function () {
					this.style.color = backgroundColor;
					this.style.backgroundColor = textColor;
				};

				buttonUpdate.onmouseout = function () {
					this.style.color = textColor;
					this.style.backgroundColor = backgroundColor;
				};
			}

			buttonClose.style.color = textColor;

			buttonClose.onmousedown = function () {
				outdatedUI.style.display = 'none';
				return false;
			};
		};

		var getmessage = function (lang) {
			var defaultMessages = languageMessages[lang] || languageMessages.en;
			var customMessages = options.messages && options.messages[lang];
			var messages = deepExtend({}, defaultMessages, customMessages);

			var updateMessages = {
				'web': '
' + messages.update.web + '' + messages.callToAction + '
',
				'googlePlay': '
' + messages.update.googlePlay +
				'' + messages.callToAction + '
',
				'appStore': '
' + messages.update[updateSource] + '
'
			};

			var updateMessage = updateMessages[updateSource];

			return '

' + messages.outOfDate + '
' + updateMessage +
				'
×

';
		};

		// Check if browser is supported
		if ( isBrowserOutOfDate() || ! isPropertySupported(requiredCssProperty) || isAndroidButNotChrome ) {

			// This is an outdated browser
			if (done && outdatedUI.style.opacity !== '1') {
				done = false;

				for (var opacity = 1; opacity <= 100; opacity++) {
					setTimeout(makeFadeInFunction(opacity), opacity * 8);
				}
			}

			var insertContentHere = document.getElementById('outdated');
			if(fullscreen){
				insertContentHere.classList.add("fullscreen");
			}
			insertContentHere.innerHTML = getmessage(language);
			startStylesAndEvents();
		}
	};

	// Load main when DOM ready.
	var oldOnload = window.onload;
	if (typeof window.onload !== 'function') {
		window.onload = main;
	}
	else {
		window.onload = function () {
			if ( oldOnload ) {
				oldOnload();
			}
			main();
		};
	}
};
<commit_msg>Use an old-style constant for colors<commit_after>var UserAgentParser = require('ua-parser-js');
var languageMessages = require('./languages.json');
var deepExtend = require('deep-extend');

var DEFAULTS = {
	'Chrome': 57, // Includes Chrome for mobile devices
	'Edge': 39,
	'Safari': 10,
	'Mobile Safari': 10,
	'Opera': 50,
	'Firefox': 50,
	'Vivaldi': 1,
	'IE': false
};

var EDGEHTML_VS_EDGE_VERSIONS = {
	12: 0.1,
	13: 21,
	14: 31,
	15: 39,
	16: 41,
	17: 42
};

var COLORS = {
	salmon: '#f25648',
	white: 'white'
}

var updateDefaults = function(defaults, updatedValues) {
	for (var key in updatedValues) {
		if (defaults.hasOwnProperty(key)) {
			defaults[key] = updatedValues[key];
		}
	}

	return defaults;
};

module.exports = function (options) {

	var main = function () {

		// Despite the docs, UA needs to be provided to constructor explicitly:
		// https://github.com/faisalman/ua-parser-js/issues/90
		var parsedUserAgent = new UserAgentParser(window.navigator.userAgent).getResult();

		// Variable definition (before ajax)
		var outdatedUI = document.getElementById('outdated');

		options = options || {};

		var browserLocale = window.navigator.language || window.navigator.userLanguage; // Everyone else, IE

		// Set default options
		var browserSupport = options.browserSupport ? updateDefaults(DEFAULTS, options.browserSupport) : DEFAULTS;
		// CSS property to check for. You may also like 'borderSpacing', 'boxShadow', 'transform', 'borderImage';
		var	requiredCssProperty = options.requiredCssProperty || false;
		var	backgroundColor = options.backgroundColor || '#f25648'; // Salmon
		var	textColor = options.textColor || 'white';
		var fullscreen = options.fullscreen || false; //Defaulting fullscreen to false.
		var	language = options.language || browserLocale.slice(0, 2); // Language code

		var updateSource = 'web'; // Other possible values are 'googlePlay' or 'appStore'. Determines where we tell users to go for upgrades.

		// Chrome mobile is still Chrome (unlike Safari which is 'Mobile Safari')
		var isAndroid = parsedUserAgent.os.name === 'Android';
		if ( isAndroid ) {
			updateSource = 'googlePlay';
		}

		var isAndroidButNotChrome;
		if (options.requireChromeOnAndroid) {
			isAndroidButNotChrome = (isAndroid) && (parsedUserAgent.browser.name !== 'Chrome');
		}

		if (parsedUserAgent.os.name === 'iOS') {
			updateSource = 'appStore';
		}

		var done = true;

		var changeOpacity = function (opacityValue) {
			outdatedUI.style.opacity = opacityValue / 100;
			outdatedUI.style.filter = 'alpha(opacity=' + opacityValue + ')';
		};

		var fadeIn = function (opacityValue) {
			changeOpacity(opacityValue);
			if (opacityValue === 1) {
				outdatedUI.style.display = 'table';
			}
			if (opacityValue === 100) {
				done = true;
			}
		};

		var isBrowserOutOfDate = function () {
			var browserName = parsedUserAgent.browser.name;
			var browserMajorVersion = parsedUserAgent.browser.major;
			if ( browserName === 'Edge' ) {
				browserMajorVersion = EDGEHTML_VS_EDGE_VERSIONS[browserMajorVersion]
			}
			var isOutOfDate = false;
			if ( ! browserSupport[browserName] ) {
				if ( ! options.isUnknownBrowserOK ) {
					isOutOfDate = true;
				}
			} else if (browserMajorVersion < browserSupport[browserName]) {
				isOutOfDate = true;
			}
			return isOutOfDate;
		};

		// Returns true if a browser supports a css3 property
		var isPropertySupported = function (property) {
			if ( ! property ) {
				return true;
			}
			var div = document.createElement('div');
			var vendorPrefixes = ['khtml', 'ms', 'o', 'moz', 'webkit'];
			var count = vendorPrefixes.length;

			if ( div.style.hasOwnProperty(property) ) {
				return true;
			}

			property = property.replace(/^[a-z]/, function (val) {
				return val.toUpperCase();
			});

			while (count--) {
				var prefixedProperty = vendorPrefixes[count] + property
				if ( div.style.hasOwnProperty(prefixedProperty) ) {
					return true;
				}
			}
			return false;
		};

		var makeFadeInFunction = function(opacityValue) {
			return function () {
				fadeIn(opacityValue);
			};
		};

		// Style element explicitly - TODO: investigate and delete if not needed
		var startStylesAndEvents = function () {
			var buttonClose = document.getElementById('buttonCloseUpdateBrowser');
			var buttonUpdate = document.getElementById('buttonUpdateBrowser');

			//check settings attributes
			outdatedUI.style.backgroundColor = backgroundColor;
			//way too hard to put !important on IE6
			outdatedUI.style.color = textColor;
			outdatedUI.children[0].children[0].style.color = textColor;
			outdatedUI.children[0].children[1].style.color = textColor;

			// Update button is desktop only
			if (buttonUpdate) {
				buttonUpdate.style.color = textColor;
				if (buttonUpdate.style.borderColor) {
					buttonUpdate.style.borderColor = textColor;
				}

				// Override the update button color to match the background color
				buttonUpdate.onmouseover = function () {
					this.style.color = backgroundColor;
					this.style.backgroundColor = textColor;
				};

				buttonUpdate.onmouseout = function () {
					this.style.color = textColor;
					this.style.backgroundColor = backgroundColor;
				};
			}

			buttonClose.style.color = textColor;

			buttonClose.onmousedown = function () {
				outdatedUI.style.display = 'none';
				return false;
			};
		};

		var getmessage = function (lang) {
			var defaultMessages = languageMessages[lang] || languageMessages.en;
			var customMessages = options.messages && options.messages[lang];
			var messages = deepExtend({}, defaultMessages, customMessages);

			var updateMessages = {
				'web': '
' + messages.update.web + '' + messages.callToAction + '
',
				'googlePlay': '
' + messages.update.googlePlay +
				'' + messages.callToAction + '
',
				'appStore': '
' + messages.update[updateSource] + '
'
			};

			var updateMessage = updateMessages[updateSource];

			return '

' + messages.outOfDate + '
' + updateMessage +
				'
×

';
		};

		// Check if browser is supported
		if ( isBrowserOutOfDate() || ! isPropertySupported(requiredCssProperty) || isAndroidButNotChrome ) {

			// This is an outdated browser
			if (done && outdatedUI.style.opacity !== '1') {
				done = false;

				for (var opacity = 1; opacity <= 100; opacity++) {
					setTimeout(makeFadeInFunction(opacity), opacity * 8);
				}
			}

			var insertContentHere = document.getElementById('outdated');
			if(fullscreen){
				insertContentHere.classList.add("fullscreen");
			}
			insertContentHere.innerHTML = getmessage(language);
			startStylesAndEvents();
		}
	};

	// Load main when DOM ready.
	var oldOnload = window.onload;
	if (typeof window.onload !== 'function') {
		window.onload = main;
	}
	else {
		window.onload = function () {
			if ( oldOnload ) {
				oldOnload();
			}
			main();
		};
	}
};
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var writeFile = require('broccoli-file-creator');

module.exports = {
  name: 'ember-cli-new-version',

  /*
  Store config from `ember-cli-build.js`
   */
  included: function(app/*, parentAddon*/) {
    this.options = app.options.newVersion || {};

    if (this.options.enabled === true) {
      this.options.fileName = this.options.fileName || 'VERSION.txt';
      this.options.prepend  = this.options.prepend  || '';
    }
  },

  /*
  Set options on the environment configuration object so they can
  be accessed via `import config from '../config/environment';`
   */
  config: function(/*env, baseConfig*/) {
    if (this.options && this.options.enabled) {
      return { newVersion: this.options };
    }
  },

  /*
  Generate version file automatically
  based on package.json of consuming application.
   */
  treeForPublic: function() {
    var content  = this.parent.pkg.version || '';
    var fileName = this.options.fileName;

    if (this.options.enabled) {
      this.ui.writeLine('Created ' + fileName);
      return writeFile(fileName, content);
    }
  }
};<commit_msg>fix: this.options is used be ember-cli, use an alternate name<commit_after>/* jshint node: true */
'use strict';

var writeFile = require('broccoli-file-creator');

module.exports = {
  name: 'ember-cli-new-version',

  /*
  Store config from `ember-cli-build.js`
   */
  included: function(app/*, parentAddon*/) {
    this._options = app.options.newVersion || {};

    if (this._options.enabled === true) {
      this._options.fileName = this._options.fileName || 'VERSION.txt';
      this._options.prepend  = this._options.prepend  || '';
    }
  },

  /*
  Set options on the environment configuration object so they can
  be accessed via `import config from '../config/environment';`
   */
  config: function(/*env, baseConfig*/) {
    if (this._options && this._options.enabled) {
      return { newVersion: this._options };
    }
  },

  /*
  Generate version file automatically
  based on package.json of consuming application.
   */
  treeForPublic: function() {
    var content  = this.parent.pkg.version || '';
    var fileName = this._options.fileName;

    if (this._options.enabled) {
      this.ui.writeLine('Created ' + fileName);
      return writeFile(fileName, content);
    }
  }
};<|endoftext|>


<commit_before>'use strict';

var bitcore = module.exports;

// module information
bitcore.version = 'v' + require('./package.json').version;
bitcore.versionGuard = function(version) {
  if (version !== undefined) {
    var message = 'More than one instance of bitcore-lib found. ' +
      'Please make sure to require bitcore-lib and check that submodules do' +
      ' not also include their own bitcore-lib dependency.';
    throw new Error(message);
  }
};
bitcore.versionGuard(global._bitcore);
global._bitcore = bitcore.version;

// crypto
bitcore.crypto = {};
bitcore.crypto.BN = require('./lib/crypto/bn');
bitcore.crypto.ECDSA = require('./lib/crypto/ecdsa');
bitcore.crypto.Hash = require('./lib/crypto/hash');
bitcore.crypto.Random = require('./lib/crypto/random');
bitcore.crypto.Point = require('./lib/crypto/point');
bitcore.crypto.Signature = require('./lib/crypto/signature');

// encoding
bitcore.encoding = {};
bitcore.encoding.Base58 = require('./lib/encoding/base58');
bitcore.encoding.Base58Check = require('./lib/encoding/base58check');
bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader');
bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter');
bitcore.encoding.Varint = require('./lib/encoding/varint');

// utilities
bitcore.util = {};
bitcore.util.buffer = require('./lib/util/buffer');
bitcore.util.js = require('./lib/util/js');
bitcore.util.preconditions = require('./lib/util/preconditions');

// errors thrown by the library
bitcore.errors = require('./lib/errors');

// main bitcoin library
bitcore.Address = require('./lib/address');
bitcore.Block = require('./lib/block');
bitcore.MerkleBlock = require('./lib/block/merkleblock');
bitcore.BlockHeader = require('./lib/block/blockheader');
bitcore.HDPrivateKey = require('./lib/hdprivatekey.js');
bitcore.HDPublicKey = require('./lib/hdpublickey.js');
bitcore.Networks = require('./lib/networks');
bitcore.Opcode = require('./lib/opcode');
bitcore.PrivateKey = require('./lib/privatekey');
bitcore.PublicKey = require('./lib/publickey');
bitcore.Script = require('./lib/script');
bitcore.Transaction = require('./lib/transaction');
bitcore.URI = require('./lib/uri');
bitcore.Unit = require('./lib/unit');

// dependencies, subject to change
bitcore.deps = {};
bitcore.deps.bnjs = require('bn.js');
bitcore.deps.bs58 = require('bs58');
bitcore.deps.Buffer = Buffer;
bitcore.deps.elliptic = require('elliptic');
bitcore.deps._ = require('lodash');

// Internal usage, exposed for testing/advanced tweaking
bitcore.Transaction.sighash = require('./lib/transaction/sighash');
<commit_msg>refactor(initialization): remove version guard<commit_after>'use strict';

var bitcore = module.exports;

// module information
bitcore.version = 'v' + require('./package.json').version;

// crypto
bitcore.crypto = {};
bitcore.crypto.BN = require('./lib/crypto/bn');
bitcore.crypto.ECDSA = require('./lib/crypto/ecdsa');
bitcore.crypto.Hash = require('./lib/crypto/hash');
bitcore.crypto.Random = require('./lib/crypto/random');
bitcore.crypto.Point = require('./lib/crypto/point');
bitcore.crypto.Signature = require('./lib/crypto/signature');

// encoding
bitcore.encoding = {};
bitcore.encoding.Base58 = require('./lib/encoding/base58');
bitcore.encoding.Base58Check = require('./lib/encoding/base58check');
bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader');
bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter');
bitcore.encoding.Varint = require('./lib/encoding/varint');

// utilities
bitcore.util = {};
bitcore.util.buffer = require('./lib/util/buffer');
bitcore.util.js = require('./lib/util/js');
bitcore.util.preconditions = require('./lib/util/preconditions');

// errors thrown by the library
bitcore.errors = require('./lib/errors');

// main bitcoin library
bitcore.Address = require('./lib/address');
bitcore.Block = require('./lib/block');
bitcore.MerkleBlock = require('./lib/block/merkleblock');
bitcore.BlockHeader = require('./lib/block/blockheader');
bitcore.HDPrivateKey = require('./lib/hdprivatekey.js');
bitcore.HDPublicKey = require('./lib/hdpublickey.js');
bitcore.Networks = require('./lib/networks');
bitcore.Opcode = require('./lib/opcode');
bitcore.PrivateKey = require('./lib/privatekey');
bitcore.PublicKey = require('./lib/publickey');
bitcore.Script = require('./lib/script');
bitcore.Transaction = require('./lib/transaction');
bitcore.URI = require('./lib/uri');
bitcore.Unit = require('./lib/unit');

// dependencies, subject to change
bitcore.deps = {};
bitcore.deps.bnjs = require('bn.js');
bitcore.deps.bs58 = require('bs58');
bitcore.deps.Buffer = Buffer;
bitcore.deps.elliptic = require('elliptic');
bitcore.deps._ = require('lodash');

// Internal usage, exposed for testing/advanced tweaking
bitcore.Transaction.sighash = require('./lib/transaction/sighash');
<|endoftext|>


<commit_before>'use strict';
<commit_msg>Get data from cdx server and parse into webarchive urls<commit_after>'use strict';

const http = require('http'),
      _    = require('lodash');

// Object -> Array
function createSiteRequestUrl(timestamps) {
  let responseTimestamps = JSON.parse(timestamps);

  let webUrls = [];
  _.map(responseTimestamps, (timestamp) => {
    if (timestamp[0] !== 'timestamp') {
      webUrls.push(`http://web.archive.org/web/${timestamp}/http://www.bbc.com/news`);
    }
  });
  return webUrls;
}

let timestamps = "",
  url  = 'http://web.archive.org/cdx/search/cdx?url=bbc.com/news&fl=timestamp&filter=statuscode:200&from=20160612070000&output=json';

http.get(url, (res) => {
  res.on('data', (d) => {
    timestamps += d;
  });
  res.on('end', () => {
    let archiveUrls = createSiteRequestUrl(timestamps);
    console.log(archiveUrls);
  });
}).on('error', (e) => {
  console.error(e);
});
<|endoftext|>


<commit_before>var durableJsonLint = require('durable-json-lint'),
    needle = require('needle'),

    stream = require('stream');

var HOST = 'http://www.omdbapi.com/',
    TYPES = [ 'movie', 'series', 'episode' ];

// Series have a different format to describe years, so account for that
// when we format it. For example,
// "1989" == 1998
// "1989-" == { from: 1989, to: undefined }
// "1989-2014" == { from: 1989, to: 2014 }
function formatYear(year) {
    var from, to;

    year = year.split('–');

    if (year.length === 2) {
        from = +year[0];

        if (year[1]) {
            to = +year[1];
        }

        return { from: from, to: to };
    }

    return +year;
}

function formatAwards(raw) {
    var wins, nominations;

    if (!raw) {
        return { wins: 0, nominations: 0, text: '' };
    }

    wins = raw.match(/(\d+) wins?/i);
    nominations = raw.match(/(\d+) nominations?/i);

    return {
        wins: wins ? +wins[1] : 0,
        nominations: nominations ? +nominations[1] : 0,
        text: raw
    };
}

// Search for movies by titles.
module.exports.search = function (terms, done) {
    var query = {};

    if (typeof terms === 'string') {
        query.s = terms;
    } else {
        query.s = terms.terms || terms.s;
        query.y = terms.year || terms.y;
        query.type = terms.type;
    }

    if (!query.s) {
        return done(new Error('No search terms specified.'));
    }

    if (query.type) {
        if (TYPES.indexOf(query.type) < 0) {
            return done(new Error(
                'Invalid type specified. Valid types are: ' + TYPES.join(', ') +
                '.'
            ));
        }
    }

    if (query.y) {
        query.y = parseInt(query.y, 10);

        if (isNaN(query.y)) {
            return done(new Error('Year is not an integer.'));
        }
    }

    needle.request('get', HOST, query, function (err, res, movies) {
        if (err) {
            return done(err);
        }

        if (res.statusCode !== 200) {
            return done(new Error('status code: ' + res.statusCode));
        }

        // If no movies are found, the API returns
        // "{"Response":"False","Error":"Movie not found!"}" instead of an
        // empty array. So in this case, return an empty array to be consistent.
        if (movies.Response === 'False') {
            return done(null, []);
        }

        // Fix the ugly capitalized naming and cast the year as a Number.
        done(null, movies.Search.map(function (movie) {
            return {
                title: movie.Title,
                year: formatYear(movie.Year),
                imdb: movie.imdbID,
                type: movie.Type
            };
        }));
    });
};

// Find a movie by title, title & year or IMDB ID. The second argument is
// optional and determines whether or not to return an extended plot synopsis.
module.exports.get = (function () {
    var formatRuntime, formatVotes;

    // Format strings of hours & minutes into minutes. For example,
    // "1 h 30 min" == 90.
    formatRuntime = function (runtime) {
        var hours = runtime.match(/(\d+) h/),
            minutes = runtime.match(/(\d+) min/);

        hours = hours ? hours[1] : 0;
        minutes = minutes ? +minutes[1] : 0;

        return (hours * 60) + minutes;
    };

    // Strip foreign characters from the string and return a casted Number.
    formatVotes = function (votes) {
        return +votes.match(/\d/g).join('');
    };

    return function (show, fullPlot, done) {
        var query = {};

        // If the third argument is omitted, treat the second argument as the
        // callback.
        if (!done) {
            done = fullPlot;
            fullPlot = false;
        }

        query.plot = fullPlot ? 'full' : 'short';

        // Select query based on explicit IMDB ID, explicit title, title & year,
        // IMDB ID and title, respectively.
        if (show.imdb) {
            query.i = show.imdb;
        } else if (show.title) {
            query.t = show.title;

            // In order to search with a year, a title must be present.
            if (show.year) {
                query.y = show.year;
            }

        // Assume anything beginning with "tt" and ending with digits is an
        // IMDB ID.
        } else if (/^tt\d+$/.test(show)) {
            query.i = show;

        // Finally, assume options is a string repesenting the title.
        } else {
            query.t = show;
        }

        needle.request('get', HOST, query, function (err, res, movie) {
            if (err) {
                return done(err);
            }

            if (res.statusCode !== 200) {
                return done(new Error('status code: ' + res.statusCode));
            }

            // Needle was unable to parse the JSON. Try durable-json-lint.
            if (typeof movie === 'string') {
                try {
                    movie = JSON.parse(durableJsonLint(movie).json);
                } catch (e) {
                    return done(new Error('Malformed JSON.'));
                }
            }

            // The movie being searched for could not be found.
            if (movie.Response === 'False') {
                return done(null, null);
            }

            // Replace 'N/A' strings with null for simple checks in the return
            // value.
            Object.keys(movie).forEach(function (key) {
                if (movie[key] === 'N/A') {
                    movie[key] = null;
                }
            });

            // Beautify and normalize the ugly results the API returns.
            done(null, {
                title: movie.Title,
                year: formatYear(movie.Year),
                rated: movie.Rated,

                // Cast the API's release date as a native JavaScript Date type.
                released: movie.Released ? new Date(movie.Released) : null,

                // Return runtime as minutes casted as a Number instead of an
                // arbitrary string.
                runtime: movie.Runtime ? formatRuntime(movie.Runtime) : null,

                countries: movie.Country ? movie.Country.split(', ') : null,
                genres: movie.Genre ? movie.Genre.split(', ') : null,
                director: movie.Director,
                writers: movie.Writer ? movie.Writer.split(', ') : null,
                actors: movie.Actors ? movie.Actors.split(', ') : null,
                plot: movie.Plot,

                // A hotlink to a JPG of the movie poster on IMDB.
                poster: movie.Poster,

                imdb: {
                    id: movie.imdbID,
                    rating: movie.imdbRating ? +movie.imdbRating : null,

                    // Convert votes from a US formatted string of a number to
                    // a JavaScript Number.
                    votes: movie.imdbVotes ? formatVotes(movie.imdbVotes) : null
                },

                metacritic: movie.Metascore ? +movie.Metascore : null,

                awards: formatAwards(movie.Awards),

                type: movie.Type
            });
        });
    };
}());

// Get a Readable Stream with the jpg image data of the poster to the movie,
// identified by title, title & year or IMDB ID.
module.exports.poster = function (show) {
    var out = new stream.PassThrough(),
        req;

    module.exports.get(show, false, function (err, res) {
        if (err) {
            out.emit('error', err);
        } else if (!res) {
            out.emit('error', new Error('Movie not found'));
        } else {
            req = needle.get(res.poster);

            req.on('error', function (err) {
                out.emit('error', err);
            });

            req.pipe(out);
        }
    });

    return out;
};
<commit_msg>Add Rotten Tomatoes rating to movie get<commit_after>var durableJsonLint = require('durable-json-lint'),
    needle = require('needle'),

    stream = require('stream');

var HOST = 'http://www.omdbapi.com/',
    TYPES = [ 'movie', 'series', 'episode' ];

// Series have a different format to describe years, so account for that
// when we format it. For example,
// "1989" == 1998
// "1989-" == { from: 1989, to: undefined }
// "1989-2014" == { from: 1989, to: 2014 }
function formatYear(year) {
    var from, to;

    year = year.split('–');

    if (year.length === 2) {
        from = +year[0];

        if (year[1]) {
            to = +year[1];
        }

        return { from: from, to: to };
    }

    return +year;
}

function formatAwards(raw) {
    var wins, nominations;

    if (!raw) {
        return { wins: 0, nominations: 0, text: '' };
    }

    wins = raw.match(/(\d+) wins?/i);
    nominations = raw.match(/(\d+) nominations?/i);

    return {
        wins: wins ? +wins[1] : 0,
        nominations: nominations ? +nominations[1] : 0,
        text: raw
    };
}

// Search for movies by titles.
module.exports.search = function (terms, done) {
    var query = {};

    if (typeof terms === 'string') {
        query.s = terms;
    } else {
        query.s = terms.terms || terms.s;
        query.y = terms.year || terms.y;
        query.type = terms.type;
    }

    if (!query.s) {
        return done(new Error('No search terms specified.'));
    }

    if (query.type) {
        if (TYPES.indexOf(query.type) < 0) {
            return done(new Error(
                'Invalid type specified. Valid types are: ' + TYPES.join(', ') +
                '.'
            ));
        }
    }

    if (query.y) {
        query.y = parseInt(query.y, 10);

        if (isNaN(query.y)) {
            return done(new Error('Year is not an integer.'));
        }
    }

    needle.request('get', HOST, query, function (err, res, movies) {
        if (err) {
            return done(err);
        }

        if (res.statusCode !== 200) {
            return done(new Error('status code: ' + res.statusCode));
        }

        // If no movies are found, the API returns
        // "{"Response":"False","Error":"Movie not found!"}" instead of an
        // empty array. So in this case, return an empty array to be consistent.
        if (movies.Response === 'False') {
            return done(null, []);
        }

        // Fix the ugly capitalized naming and cast the year as a Number.
        done(null, movies.Search.map(function (movie) {
            return {
                title: movie.Title,
                year: formatYear(movie.Year),
                imdb: movie.imdbID,
                type: movie.Type
            };
        }));
    });
};

// Find a movie by title, title & year or IMDB ID. The second argument is
// optional and determines whether or not to return an extended plot synopsis.
module.exports.get = (function () {
    var formatRuntime, formatVotes;

    // Format strings of hours & minutes into minutes. For example,
    // "1 h 30 min" == 90.
    formatRuntime = function (runtime) {
        var hours = runtime.match(/(\d+) h/),
            minutes = runtime.match(/(\d+) min/);

        hours = hours ? hours[1] : 0;
        minutes = minutes ? +minutes[1] : 0;

        return (hours * 60) + minutes;
    };

    // Strip foreign characters from the string and return a casted Number.
    formatVotes = function (votes) {
        return +votes.match(/\d/g).join('');
    };

    return function (show, options, done) {
        var query = {};

        // If the third argument is omitted, treat the second argument as the
        // callback.
        if (!done) {
            done = options;
            options = {};

        // If options is given, but is not an object, assume fullPlot: true
        // for backwards compatibility
        } else if (typeof options != "object" && options) {
            options = { fullPlot: true };
        }

        query.plot = options.fullPlot ? 'full' : 'short';

        // Include Rotten Tomatoes rating, if requested
        if (options.tomatoes) {
            query.tomatoes = true;
        }

        // Select query based on explicit IMDB ID, explicit title, title & year,
        // IMDB ID and title, respectively.
        if (show.imdb) {
            query.i = show.imdb;
        } else if (show.title) {
            query.t = show.title;

            // In order to search with a year, a title must be present.
            if (show.year) {
                query.y = show.year;
            }

        // Assume anything beginning with "tt" and ending with digits is an
        // IMDB ID.
        } else if (/^tt\d+$/.test(show)) {
            query.i = show;

        // Finally, assume options is a string repesenting the title.
        } else {
            query.t = show;
        }

        needle.request('get', HOST, query, function (err, res, movie) {
            if (err) {
                return done(err);
            }

            if (res.statusCode !== 200) {
                return done(new Error('status code: ' + res.statusCode));
            }

            // Needle was unable to parse the JSON. Try durable-json-lint.
            if (typeof movie === 'string') {
                try {
                    movie = JSON.parse(durableJsonLint(movie).json);
                } catch (e) {
                    return done(new Error('Malformed JSON.'));
                }
            }

            // The movie being searched for could not be found.
            if (movie.Response === 'False') {
                return done(null, null);
            }

            // Replace 'N/A' strings with null for simple checks in the return
            // value.
            Object.keys(movie).forEach(function (key) {
                if (movie[key] === 'N/A') {
                    movie[key] = null;
                }
            });

            // Beautify and normalize the ugly results the API returns.
            done(null, {
                title: movie.Title,
                year: formatYear(movie.Year),
                rated: movie.Rated,

                // Cast the API's release date as a native JavaScript Date type.
                released: movie.Released ? new Date(movie.Released) : null,

                // Return runtime as minutes casted as a Number instead of an
                // arbitrary string.
                runtime: movie.Runtime ? formatRuntime(movie.Runtime) : null,

                countries: movie.Country ? movie.Country.split(', ') : null,
                genres: movie.Genre ? movie.Genre.split(', ') : null,
                director: movie.Director,
                writers: movie.Writer ? movie.Writer.split(', ') : null,
                actors: movie.Actors ? movie.Actors.split(', ') : null,
                plot: movie.Plot,

                // A hotlink to a JPG of the movie poster on IMDB.
                poster: movie.Poster,

                imdb: {
                    id: movie.imdbID,
                    rating: movie.imdbRating ? +movie.imdbRating : null,

                    // Convert votes from a US formatted string of a number to
                    // a JavaScript Number.
                    votes: movie.imdbVotes ? formatVotes(movie.imdbVotes) : null
                },

                // Determine tomatoRatings existance by the presense of tomatoMeter
                tomato: !movie.tomatoMeter ? null : {
                    // Convert numeric values to numeric form
                    meter: +movie.tomatoMeter,
                    image: movie.tomatoImage,
                    rating: +movie.tomatoRating,
                    reviews: +movie.tomatoReviews,
                    fresh: +movie.tomatoFresh,
                    consensus: movie.tomatoConsensus,
                    userMeter: +movie.tomatoUserMeter,
                    userRating: +movie.tomatoUserRating,
                    userReviews: +movie.tomatoUserReviews
                },

                metacritic: movie.Metascore ? +movie.Metascore : null,

                awards: formatAwards(movie.Awards),

                type: movie.Type
            });
        });
    };
}());

// Get a Readable Stream with the jpg image data of the poster to the movie,
// identified by title, title & year or IMDB ID.
module.exports.poster = function (show) {
    var out = new stream.PassThrough(),
        req;

    module.exports.get(show, false, function (err, res) {
        if (err) {
            out.emit('error', err);
        } else if (!res) {
            out.emit('error', new Error('Movie not found'));
        } else {
            req = needle.get(res.poster);

            req.on('error', function (err) {
                out.emit('error', err);
            });

            req.pipe(out);
        }
    });

    return out;
};
<|endoftext|>


<commit_before>function r(strings) {
	var str = strings.raw[0];

	var tabs = str.match(/^[\t]*/)[0];

	return str.substr(tabs.length).replace(new RegExp('\n'+tabs, 'g'), '\n');
}

module.exports = r;<commit_msg>Support top-tagged way.<commit_after>function r(strings) {
	var str = strings.raw[0];

	str = str.replace(/\r\n/g, '\n');

	var newlineAndTabs = str.match(/^\n[\t]*/);

	if( newlineAndTabs != null ) {
		var matched = newlineAndTabs[0];

		str = str.replace(new RegExp(matched, 'g'), '\n').substr(1);
	}

	else {
		var matched = str.match(/^[\t]*/)[0];

		str = str.substr(matched.length).replace(new RegExp('\n'+matched, 'g'), '\n');
	}

	return str;
}

module.exports = r;<|endoftext|>


<commit_before>var postcss = require('postcss'),
    colorObject = require('color-name'),
    parserColor = require('parse-color'),
    nearestColor = require('nearest-color');

module.exports = postcss.plugin('postcss-extract-value', function (opts) {
    opts = opts || {};

    var colorNameList = Object.keys(colorObject);

    // Cache RegExp
    var reColorKeywords = new RegExp(colorNameList.join('|'));
    var reCSSVariable = /^var\(-{2}\w{1}[\w+-]*/;

    var reHex = /#(\w{6}|\w{3})/;
    var reRgb = /rgba?\([\d,.\s]+\)/;
    var reHsl = /hsla?\(\s?[0-9]{1,3},\s?([0-9]{1,3}%,?\s?){2}([0-9.]+)?\)/;

    var reExtract = new RegExp(reHex.source + '|' + reRgb.source + '|' +
        reHsl.source + '|' + reColorKeywords.source, 'g');

    // Options
    var filterByProps = opts.filterByProps,
        onlyColor = opts.onlyColor,
        scope = opts.scope || ':root',
        templateVariableName = opts.templateVariableName || '';

    var colorList = {};
    colorNameList.forEach(function (key) {
        colorList[key] = {
            r: colorObject[key][0],
            g: colorObject[key][1],
            b: colorObject[key][2]
        };
    });
    var findColor = nearestColor.from(colorList);
    var variablesListCounter = {};

    function isColor(value) {
        var reCheck =  new RegExp(/#\w+|rgba?|hsla?/.source +
            '|' + reColorKeywords.source, 'g');
        return reCheck.test(value);
    }

    function extractColor(value) {
        var resultArray = [];
        var result = [];

        while ((result = reExtract.exec(value)) !== null) {
            resultArray.push(result[0]);
        }
        return resultArray;
    }

    function checkProp(filter, prop) {
        return filter.indexOf(prop) > -1;
    }

    function colorNameVariable(value) {
        var variable = {},
            nearestColorValue = {},
            parsedColor = parserColor(value);

        if (parsedColor.hex) {
            nearestColorValue = parserColor(findColor(parsedColor.hex).value);
        }

        if (nearestColorValue) {
            variable.colorKeyword = nearestColorValue.keyword;

            if (templateVariableName.indexOf('[tint]') > -1) {
                if (nearestColorValue.hsl[2] > parsedColor.hsl[2]) {
                    variable.tint = 'dark';
                } else if (nearestColorValue.hsl[2] < parsedColor.hsl[2]) {
                    variable.tint = 'light';
                } else {
                    variable.tint = '';
                }

                if (variable.tint) {
                    if (templateVariableName.indexOf('[tint]') > 0) {
                        variable.tint = '-' + variable.tint;
                    }
                }
            }
            if (templateVariableName.indexOf('[colorKeyword]') > 0 &&
                !(templateVariableName.indexOf('[tint]') === 0 && !variable.tint)) {
                variable.colorKeyword = '-' + variable.colorKeyword;
            }
        }

        return variable;
    }

    function makeNameByTemplate(value, prop) {
        var nameVariables = [],
            result = templateVariableName;

        if (onlyColor) {
            nameVariables = colorNameVariable(value);
        } else if (templateVariableName.indexOf('[propertyName]')) {
            nameVariables.propertyName = prop;
        }
        for (var key in nameVariables) {
            result = result.replace('[' + key + ']', nameVariables[key]);
        }
        return result;
    }

    function makeCSSVariable(prop, num, value) {
        var variableName = '',
            result = '';

        if (templateVariableName) {
            variableName = makeNameByTemplate(value, prop);
            result = variableName;

            if (!variablesListCounter[variableName]) {
                variablesListCounter[variableName] = 1;
            }

            result += '-' + variablesListCounter[variableName];
            variablesListCounter[variableName]++;
        } else {
            variableName = prop + '-' + num;
            result = variableName;
        }

        return '--' + result;
    }

    function addCSSVariable(currentScope, value, variableName) {
        currentScope.append(variableName + ': ' + value);
    }

    return function (css) {
        var root = css.root(),
            rootSel,
            storeProps = {},
            checkColorFilter = true,
            checkPropFilter = true,
            filteredValueList = [],
            filteredValue = '',
            variableName = '',
            variablesList = {},
            positionValue = 0;

        css.walkRules(function (rule) {

            if (rule.selector === scope) {
                rootSel = rule;
            } else {
                rule.walkDecls(function (decl) {
                    if (!reCSSVariable.test(decl.value)) {

                        checkColorFilter = !onlyColor ||
                            onlyColor && isColor(decl.value);

                        checkPropFilter = !filterByProps ||
                            filterByProps &&
                            checkProp(filterByProps, decl.prop);

                        if (checkColorFilter && checkPropFilter) {

                            if (!storeProps[decl.prop]) {
                                storeProps[decl.prop] = [];
                            }

                            if (onlyColor) {
                                filteredValueList = extractColor(decl.value);
                            } else {
                                filteredValueList = new Array(decl.value);
                            }

                            for (var value in filteredValueList) {
                                filteredValue = filteredValueList[value];

                                positionValue = storeProps[decl.prop].indexOf(filteredValue);

                                if (positionValue === -1) {
                                    storeProps[decl.prop].push(filteredValue);
                                }
                                if (variablesList.hasOwnProperty(filteredValue)) {
                                    variableName = variablesList[filteredValue];
                                } else {
                                    positionValue = storeProps[decl.prop].indexOf(filteredValue);
                                    variableName = makeCSSVariable(decl.prop, ++positionValue, filteredValue);
                                    variablesList[filteredValue] = variableName;
                                }

                                decl.value = decl.value.replace(filteredValue, 'var(' + variableName + ')');
                            }
                        }
                    }
                });
            }
        });

        if (!rootSel) {
            rootSel = postcss.rule({ selector: scope });
            root.prepend(rootSel);
        }
        for (var value in variablesList) {
            addCSSVariable(rootSel, value, variablesList[value]);
        }
    };
});
<commit_msg>Add ES6 syntax<commit_after>'use strict';

const postcss = require('postcss');
const colorObject = require('color-name');
const parserColor = require('parse-color');
const nearestColor = require('nearest-color');

module.exports = postcss.plugin('postcss-extract-value', (opts) => {
    // Fix for Node 4
    const params = opts || {};

    // Options
    const filterByProps = params.filterByProps;
    const onlyColor = params.onlyColor;
    const scope = params.scope || ':root';
    const templateVariableName = params.templateVariableName || '';

    const colorList = {};
    const colorNameList = Object.keys(colorObject);

    colorNameList.forEach((key) => {
        colorList[key] = {
            r: colorObject[key][0],
            g: colorObject[key][1],
            b: colorObject[key][2],
        };
    });
    const findColor = nearestColor.from(colorList);
    const variablesListCounter = {};

    // Cache RegExp
    const reColorKeywords = new RegExp(colorNameList.join('|'));
    const reCSSVariable = /^var\(-{2}\w{1}[\w+-]*/;
    const reHex = /#(\w{6}|\w{3})/;
    const reRgb = /rgba?\([\d,.\s]+\)/;
    const reHsl = /hsla?\(\s?[0-9]{1,3},\s?([0-9]{1,3}%,?\s?){2}([0-9.]+)?\)/;
    const reExtract = new RegExp(`${reHex.source}|${reRgb.source}|${reHsl.source}|${reColorKeywords.source}`, 'g');

    function isColor(value) {
        const reCheck = new RegExp(`${/#\w+|rgba?|hsla?/.source}|${reColorKeywords.source}`, 'g');
        return reCheck.test(value);
    }

    function extractColor(value) {
        const resultArray = [];
        let result = reExtract.exec(value);

        while (result) {
            resultArray.push(result[0]);
            result = reExtract.exec(value);
        }
        return resultArray;
    }

    function checkProp(filter, prop) {
        return filter.indexOf(prop) > -1;
    }

    function colorNameVariable(value) {
        const variable = {};
        let nearestColorValue = {};
        const parsedColor = parserColor(value);

        if (parsedColor.hex) {
            nearestColorValue = parserColor(findColor(parsedColor.hex).value);
        }

        if (nearestColorValue) {
            variable.colorKeyword = nearestColorValue.keyword;

            if (templateVariableName.indexOf('[tint]') > -1) {
                if (nearestColorValue.hsl[2] > parsedColor.hsl[2]) {
                    variable.tint = 'dark';
                } else if (nearestColorValue.hsl[2] < parsedColor.hsl[2]) {
                    variable.tint = 'light';
                } else {
                    variable.tint = '';
                }

                if (variable.tint) {
                    if (templateVariableName.indexOf('[tint]') > 0) {
                        variable.tint = `-${variable.tint}`;
                    }
                }
            }
            if (templateVariableName.indexOf('[colorKeyword]') > 0 &&
                !(templateVariableName.indexOf('[tint]') === 0 &&
                !variable.tint)) {
                variable.colorKeyword = `-${variable.colorKeyword}`;
            }
        }

        return variable;
    }

    function makeNameByTemplate(value, prop) {
        let nameVariables = [];
        let result = templateVariableName;

        if (onlyColor) {
            nameVariables = colorNameVariable(value);
        } else if (templateVariableName.indexOf('[propertyName]')) {
            nameVariables.propertyName = prop;
        }
        Object.keys(nameVariables).forEach((key) => {
            result = result.replace(`[${key}]`, nameVariables[key]);
        });
        return result;
    }

    function makeCSSVariable(prop, num, value) {
        let variableName = '';
        let result = '';

        if (templateVariableName) {
            variableName = makeNameByTemplate(value, prop);
            result = variableName;

            if (!variablesListCounter[variableName]) {
                variablesListCounter[variableName] = 1;
            }

            result += `-${variablesListCounter[variableName]}`;
            variablesListCounter[variableName] += 1;
        } else {
            variableName = `${prop}-${num}`;
            result = variableName;
        }

        return `--${result}`;
    }

    function addCSSVariable(currentScope, value, variableName) {
        currentScope.append(`${variableName}: ${value}`);
    }

    return function parser(css) {
        const root = css.root();
        let rootSel = {};
        const storeProps = {};
        let checkColorFilter = true;
        let checkPropFilter = true;
        let filteredValueList = [];
        let variableName = '';
        const variablesList = {};
        let positionValue = 0;

        css.walkRules((rule) => {
            if (rule.selector === scope) {
                rootSel = rule;
            } else {
                rule.walkDecls((decl) => {
                    if (!reCSSVariable.test(decl.value)) {
                        checkColorFilter = !onlyColor || onlyColor && isColor(decl.value);

                        checkPropFilter = (!filterByProps || filterByProps
                            && checkProp(filterByProps, decl.prop));

                        if (checkColorFilter && checkPropFilter) {
                            if (!storeProps[decl.prop]) {
                                storeProps[decl.prop] = [];
                            }

                            if (onlyColor) {
                                filteredValueList = extractColor(decl.value);
                            } else {
                                filteredValueList = new Array(decl.value);
                            }

                            filteredValueList.forEach((filteredValue) => {
                                positionValue = storeProps[decl.prop].indexOf(filteredValue);

                                if (positionValue === -1) {
                                    storeProps[decl.prop].push(filteredValue);
                                }
                                if ({}.hasOwnProperty.call(variablesList, filteredValue)) {
                                    variableName = variablesList[filteredValue];
                                } else {
                                    positionValue = storeProps[decl.prop].indexOf(filteredValue) + 1;
                                    variableName = makeCSSVariable(decl.prop, positionValue, filteredValue);
                                    variablesList[filteredValue] = variableName;
                                }
                                decl.value = decl.value.replace(filteredValue,
                                    `var(${variableName})`);
                            });
                        }
                    }
                });
            }
        });

        if (Object.keys(rootSel).length === 0) {
            rootSel = postcss.rule({ selector: scope });
            root.prepend(rootSel);
        }

        Object.keys(variablesList).forEach((value) => {
            addCSSVariable(rootSel, value, variablesList[value]);
        });
    };
});
<|endoftext|>


<commit_before>'use strict'
/*
 * cdn-uploader
 * https://github.com/teambition/cdn-uploader
 *
 * Copyright (c) 2016 Teambition
 * Licensed under the MIT license.
 */

var fs = require('fs')
var ftp = require('vinyl-ftp')
var through = require('through2')

var defaultOptions = {
  cache: '.cdnUploaderCache'
}

module.exports = function cdnUploader (remoteFolder, ftpList, options) {
  if (!remoteFolder || typeof remoteFolder !== 'string') throw new Error('remoteFolder required!')
  if (!ftpList) throw new Error('ftps required!')
  if (!Array.isArray(ftpList)) ftpList = [ftpList]

  var config = Object.assign({}, defaultOptions, options)

  if (config.cache) {   // Prepare cache
    var cacheFd = fs.openSync(config.cache, 'a+')
    var cachedConent = fs.readFileSync(cacheFd, { encoding: 'utf-8' })
    try {
      var cachedObject = JSON.parse(cachedConent)
    } catch (e) {
      var cachedObject = {}
    }
  }

  var uploaderStreams = ftpList.map(function (ftpConfig) {
    if (!ftpConfig || !ftpConfig.host) throw new Error(String(ftpConfig) + ' error!')
    ftpConfig.log = ftpConfig.log || log(ftpConfig.host)

    var integrityChecker = function (file, remote, cb) {
      if (!remote ||
          file.stat.mtime > remote.ftp.date ||
          file.stat.size !== remote.ftp.size) {
        checker.failed = true
        console.log('File', file.path, 'was corrupted')
      } else if (config.cache) {
        cachedObject[file.path] = { mtime: file.stat.mtime, size: file.stat.size }
      }
      cb(null, false)
    }

    var conn = ftp.create(ftpConfig)
    var ftpFolder = ftpConfig.remoteFolder || remoteFolder
    var checker = conn.filter(ftpFolder, integrityChecker)
    var uploader = conn.dest(ftpFolder)

    uploader.on('data', function (chunk) { checker.write(chunk) })
    uploader.once('finish', function () { checker.end() })

    return { uploader: uploader, checker: checker, uploaded: 0 }
  })

  var pending = uploaderStreams.length

  return through.obj(function (file, encoding, cb) {
    uploaderStreams.forEach(function (stream) {
      if (config.cache &&
          file.path in cachedObject &&
          file.stat.size === cachedObject[file.path].size &&
          new Date(file.stat.mtime).valueOf() ===
          new Date(cachedObject[file.path].mtime).valueOf()) {
        console.log('Cache hit: ' + file.path)
        return
      }
      ++stream.uploaded
      stream.uploader.write(file)
    })
    cb(null, file)
  }, function (cb) {
    var failed = false
    uploaderStreams.forEach(function (stream) {
      stream.checker.once('finish', function () {
        if (stream.checker.failed) { failed = true }
        if (!--pending) {
          if (config.cache) {
            fs.writeFileSync(cacheFd, JSON.stringify(cachedObject, null, '  '))
            fs.closeSync(cacheFd)
          }
          setTimeout(function () {
            cb(failed ? new Error('File corrupted during upload, please try again') : null)
          }, 500)
        }
      })
      stream.uploader.on('data', function () {
        if(!--stream.uploaded) { stream.uploader.end() }
      })
    })
  })
}

function log (host) {
  return function (action, message) {
    if (/UP/.test(action)) console.log(host, action.trim(), message)
  }
}
<commit_msg>Mode change: Check only after all uploaded<commit_after>'use strict'
/*
 * cdn-uploader
 * https://github.com/teambition/cdn-uploader
 *
 * Copyright (c) 2016 Teambition
 * Licensed under the MIT license.
 */

var fs = require('fs')
var ftp = require('vinyl-ftp')
var crypto = require('crypto')
var through = require('through2')

var defaultOptions = {
  cache: '.cdnUploaderCache'
}

var md5 = function (data) {
  var hash = crypto.createHash('md5')
  hash.update(data)
  return hash.digest('hex')
}

module.exports = function cdnUploader (remoteFolder, ftpList, options) {
  if (!remoteFolder || typeof remoteFolder !== 'string') throw new Error('remoteFolder required!')
  if (!ftpList) throw new Error('ftps required!')
  if (!Array.isArray(ftpList)) ftpList = [ftpList]

  var config = Object.assign({}, defaultOptions, options)

  if (config.cache) {   // Prepare cache
    fs.closeSync(fs.openSync(config.cache, 'a+'))
    var cachedConent = fs.readFileSync(config.cache, { encoding: 'utf-8' })
    try {
      var cachedObject = JSON.parse(cachedConent)
    } catch (e) {
      cachedObject = {}
    }
  }

  var uploaderStreams = ftpList.map(function (ftpConfig) {
    if (!ftpConfig || !ftpConfig.host) throw new Error(String(ftpConfig) + ' error!')
    ftpConfig.log = ftpConfig.log || log(ftpConfig.host)

    if (!(id in cachedObject)) { cachedObject[id] = {} }
    var ftpFolder = ftpConfig.remoteFolder || remoteFolder
    var id = ftpConfig.host + '>' + ftpConfig.user + '<' + ftpFolder

    var integrityChecker = function (file, remote, cb) {
      if (!remote ||
          file.stat.mtime > remote.ftp.date ||
          file.stat.size !== remote.ftp.size) {
        ++stream.failed
        console.log(ftpConfig.host + ':', 'File', remote.path, 'was corrupted')
      } else if (config.cache) {
        cachedObject[id][file.path] = { md5: md5(file.contents) }
      }
      cb(null, false)
    }

    var conn = ftp.create(ftpConfig)
    var uploader = conn.dest(ftpFolder)
    var checker = conn.filter(ftpFolder, integrityChecker)
    var stream = { uploader: uploader, checker: checker, buffer: [], id: id,
                   failed: 0, uploaded: 0, hit: 0, host: ftpConfig.host }

    uploader.on('data', function (chunk) { stream.buffer.push(chunk) })

    return stream
  })

  var pending = uploaderStreams.length

  return through.obj(function (file, encoding, cb) {
    uploaderStreams.forEach(function (stream) {
      if (config.cache &&
          file.path in cachedObject[stream.id] &&
          md5(file.contents) === cachedObject[stream.id][file.path].md5) {
        // console.log('Cache hit: ' + file.path)
        ++stream.hit
        return
      }
      ++stream.uploaded
      stream.uploader.write(file)
    })
    cb(null, file)
  }, function (cb) {
    uploaderStreams.forEach(function (stream) {
      stream.uploader.once('finish', function () {
        setTimeout(function () {
          while (stream.buffer.length) {
            stream.checker.write(stream.buffer.shift())
          }
          stream.checker.end()
        }, 2000)
      })

      var failed = false
      stream.checker.once('finish', function () {
        setTimeout(function () {
          console.log('Host:', stream.host, 'Uploaded:', stream.uploaded,
                      'Cache Hit:', stream.hit, 'Failed:', stream.failed)
          if (stream.failed) { failed = true }
          if (!--pending) {
            if (config.cache) {
              fs.writeFileSync(config.cache, JSON.stringify(cachedObject, null, '  '))
            }
            cb(failed ? new Error('File corrupted during upload, please try again') : null)
          }
        }, 1000)
      })
      stream.uploader.end()
    })
  })
}

function log (host) {
  return function (action, message) {
    if (/UP/.test(action)) console.log(host, action.trim(), message)
  }
}
<|endoftext|>


<commit_before>/*!
 * file-morgan
 * Copyright(c) 2017 Peter Rietveld
 * MIT Licensed
 */

'use strict'

/**
 * Module exports.
 * @public
 */

module.exports = fileMorgan
module.exports.on = module.exports.addListener = addListener
module.exports.compile = compile
module.exports.token = token
module.exports.format = format

/**
 * Module dependencies.
 * @private
 */

var fs = require('fs')
var path = require('path')
var morgan = require('morgan')
var fileStreamRotator = require('file-stream-rotator')
var objectAssign = require('object-assign')
var chokidar = require('chokidar')
var events = require('events')

/**
 * Default log filename.
 * @private
 */

var DEFAULT_LOG_FILENAME = 'access.log'

/**
 * Default log directory.
 * @private
 */

var DEFAULT_LOG_DIRECTORY = 'logs'

/**
 * Force production mode used for testing.
 * @private
 */

var FORCE_PRODUCTION_MODE = false

/**
 * Watch files for changes.
 * @private
 */

var WATCH_FILES = false

/**
 * Use stream rotator.
 * @private
 */

var USE_STREAM_ROTATOR = false

/**
 * Date format used with file stream rotator.
 * @private
 */

var DATE_FORMAT = ('YYYYMMDD')

/**
 * Placeholder for EventEmitter.
 * @private
 */

var EVENT_EMITTER = new events.EventEmitter()

/**
 * Array of possible events.
 * @private
 */

var SUPPORTED_EVENTS = [
	'change'
]

/**
 * Create a logger middleware.
 *
 * @public
 * @param {String|Function} format
 * @param {Object} [options]
 * @return {Function} middleware
 */

function fileMorgan(format, options) {
	var opts = options || {},
		forceProductionMode = opts.forceProductionMode !== 'undefined' ? opts.forceProductionMode : FORCE_PRODUCTION_MODE,
		watchFiles = opts.watchFiles !== 'undefined' ? opts.watchFiles : WATCH_FILES,
		useStreamRotator = opts.useStreamRotator !== 'undefined' ? opts.useStreamRotator : USE_STREAM_ROTATOR,
		dateFormat = opts.dateFormat || DATE_FORMAT,
		fileName = opts.fileName || DEFAULT_LOG_FILENAME,
		directory = path.resolve(opts.directory || DEFAULT_LOG_DIRECTORY),
		filePath = path.join(directory, fileName),
		env = process.env.NODE_ENV || 'development',
		skip,
		stream

	if(typeof format !== 'string') {
		throw new TypeError('argument format must be a string')
	}

	if(useStreamRotator && typeof dateFormat !== 'string') {
		throw new TypeError('option dateFormat must be a string')
	}

	if(env === 'production' || forceProductionMode) {
		try {
			// Ensure log directory exists
			fs.existsSync(directory) || fs.mkdirSync(directory)

			// Default skip to requests with error code 400 or higher
			skip = typeof opts.skip !== 'undefined' ? opts.skip : function(req, res) {
					return res.statusCode < 400
				}

			if(useStreamRotator === true) {
				filePath = formatFileName(filePath, '%DATE%')

				// Create a rotating write stream
				stream = fileStreamRotator.getStream({
					date_format: dateFormat,
					filename: filePath,
					frequency: 'daily',
					verbose: false
				})
			}
			else {
				// Create a write stream (in append mode)
				stream = fs.createWriteStream(filePath, {
					flags: 'a'
				})
			}

			// Create file watcher
			if(watchFiles === true) {
				addFileWatcher(useStreamRotator === true ? directory : filePath)
			}

			// Merge options
			opts = objectAssign(opts, {
				skip: skip,
				stream: stream
			})

			return morgan(format, opts)
		}
		catch(err) {
			throw err
		}
	}
	else/* if(env === 'dev' || env === 'development' || !env) */{
		return morgan('dev')
	}
}

/**
 * Format file name.
 *
 * @private
 * @param {String} fileName
 * @param {String} dateFormat
 * @return {String}
 */

function formatFileName(filePath, dateFormat) {
	var parsedFilePath = path.parse(filePath),
		dir = parsedFilePath.dir,
		name = parsedFilePath.name,
		ext = parsedFilePath.ext,
		fileName = name + '-' + dateFormat + ext

	return path.join(dir, fileName)
}

/**
 * Create file watcher.
 *
 * @private
 * @param {String} file or directory
 */

function addFileWatcher(filePathOrDirectory) {
	var watcher = chokidar.watch(filePathOrDirectory, {
		alwaysStat: true
	})

	watcher.on('change', function(path, stats) {
		if (stats) {
			EVENT_EMITTER.emit('change', path, stats)
		}
	})
}

/**
 * Wrapper for EventEmitter.on function.
 *
 * @public
 * @param {String} type
 * @param {Function} listener
 */

function addListener(event, listener) {
	if(SUPPORTED_EVENTS.indexOf(event) !== -1) {
		try {
			EVENT_EMITTER.on(event, listener)
		}
		catch(err) {
			throw err
		}
	}
	else {
		throw new Error('Unsupported event.')
	}
}

/**
 * Compile a format string into a function.
 *
 * @param {string} format
 * @return {function}
 * @public
 */

function compile(format) {
	return morgan.compile(format)
}

/**
 * Define a token function with the given name,
 * and callback fn(req, res).
 *
 * @param {string} name
 * @param {function} fn
 * @public
 */

function token(name, fn) {
	if(typeof name !== 'string') {
		throw new TypeError('argument name must be a string')
	}

	if(typeof fn !== 'function') {
		throw new TypeError('argument fn must be a function')
	}

	return morgan.token.call(this, name, fn)
}

/**
 * Define a format with the given name.
 *
 * @param {string} name
 * @param {string|function} fmt
 * @public
 */

function format(name, fmt) {
	if(typeof name !== 'string') {
		throw new TypeError('argument name must be a string')
	}

	if(typeof fmt !== 'string' && typeof fmt !== 'function') {
		throw new TypeError('argument fmt must be a string or a function')
	}

	return morgan.format.call(this, name, fmt)
}<commit_msg>Format code<commit_after>/*!
 * file-morgan
 * Copyright(c) 2017 Peter Rietveld
 * MIT Licensed
 */

'use strict'

/**
 * Module exports.
 * @public
 */

module.exports = fileMorgan
module.exports.on = module.exports.addListener = addListener
module.exports.compile = compile
module.exports.token = token
module.exports.format = format

/**
 * Module dependencies.
 * @private
 */

var fs = require('fs')
var path = require('path')
var morgan = require('morgan')
var fileStreamRotator = require('file-stream-rotator')
var objectAssign = require('object-assign')
var chokidar = require('chokidar')
var events = require('events')

/**
 * Default log filename.
 * @private
 */

var DEFAULT_LOG_FILENAME = 'access.log'

/**
 * Default log directory.
 * @private
 */

var DEFAULT_LOG_DIRECTORY = 'logs'

/**
 * Force production mode used for testing.
 * @private
 */

var FORCE_PRODUCTION_MODE = false

/**
 * Watch files for changes.
 * @private
 */

var WATCH_FILES = false

/**
 * Use stream rotator.
 * @private
 */

var USE_STREAM_ROTATOR = false

/**
 * Date format used with file stream rotator.
 * @private
 */

var DATE_FORMAT = ('YYYYMMDD')

/**
 * Placeholder for EventEmitter.
 * @private
 */

var EVENT_EMITTER = new events.EventEmitter()

/**
 * Array of possible events.
 * @private
 */

var SUPPORTED_EVENTS = [
	'change'
]

/**
 * Create a logger middleware.
 *
 * @public
 * @param {String|Function} format
 * @param {Object} [options]
 * @return {Function} middleware
 */

function fileMorgan(format, options) {
	var opts = options || {},
		forceProductionMode = opts.forceProductionMode !== 'undefined' ? opts.forceProductionMode : FORCE_PRODUCTION_MODE,
		watchFiles = opts.watchFiles !== 'undefined' ? opts.watchFiles : WATCH_FILES,
		useStreamRotator = opts.useStreamRotator !== 'undefined' ? opts.useStreamRotator : USE_STREAM_ROTATOR,
		dateFormat = opts.dateFormat || DATE_FORMAT,
		fileName = opts.fileName || DEFAULT_LOG_FILENAME,
		directory = path.resolve(opts.directory || DEFAULT_LOG_DIRECTORY),
		filePath = path.join(directory, fileName),
		env = process.env.NODE_ENV || 'development',
		skip,
		stream

	if(typeof format !== 'string') {
		throw new TypeError('argument format must be a string')
	}

	if(useStreamRotator && typeof dateFormat !== 'string') {
		throw new TypeError('option dateFormat must be a string')
	}

	if(env === 'production' || forceProductionMode) {
		try {
			// Ensure log directory exists
			fs.existsSync(directory) || fs.mkdirSync(directory)

			// Default skip to requests with error code 400 or higher
			skip = typeof opts.skip !== 'undefined' ? opts.skip : function(req, res) {
				return res.statusCode < 400
			}

			if(useStreamRotator === true) {
				filePath = formatFileName(filePath, '%DATE%')

				// Create a rotating write stream
				stream = fileStreamRotator.getStream({
					date_format: dateFormat,
					filename: filePath,
					frequency: 'daily',
					verbose: false
				})
			}
			else {
				// Create a write stream (in append mode)
				stream = fs.createWriteStream(filePath, {
					flags: 'a'
				})
			}

			// Create file watcher
			if(watchFiles === true) {
				addFileWatcher(useStreamRotator === true ? directory : filePath)
			}

			// Merge options
			opts = objectAssign(opts, {
				skip: skip,
				stream: stream
			})

			return morgan(format, opts)
		}
		catch(err) {
			throw err
		}
	}
	else/* if(env === 'dev' || env === 'development' || !env) */{
		return morgan('dev')
	}
}

/**
 * Format file name.
 *
 * @private
 * @param {String} fileName
 * @param {String} dateFormat
 * @return {String}
 */

function formatFileName(filePath, dateFormat) {
	var parsedFilePath = path.parse(filePath),
		dir = parsedFilePath.dir,
		name = parsedFilePath.name,
		ext = parsedFilePath.ext,
		fileName = name + '-' + dateFormat + ext

	return path.join(dir, fileName)
}

/**
 * Create file watcher.
 *
 * @private
 * @param {String} file or directory
 */

function addFileWatcher(filePathOrDirectory) {
	var watcher = chokidar.watch(filePathOrDirectory, {
		alwaysStat: true
	})

	watcher.on('change', function(path, stats) {
		if(stats) {
			EVENT_EMITTER.emit('change', path, stats)
		}
	})
}

/**
 * Wrapper for EventEmitter.on function.
 *
 * @public
 * @param {String} type
 * @param {Function} listener
 */

function addListener(event, listener) {
	if(SUPPORTED_EVENTS.indexOf(event) !== -1) {
		try {
			EVENT_EMITTER.on(event, listener)
		}
		catch(err) {
			throw err
		}
	}
	else {
		throw new Error('Unsupported event.')
	}
}

/**
 * Compile a format string into a function.
 *
 * @param {string} format
 * @return {function}
 * @public
 */

function compile(format) {
	return morgan.compile(format)
}

/**
 * Define a token function with the given name,
 * and callback fn(req, res).
 *
 * @param {string} name
 * @param {function} fn
 * @public
 */

function token(name, fn) {
	if(typeof name !== 'string') {
		throw new TypeError('argument name must be a string')
	}

	if(typeof fn !== 'function') {
		throw new TypeError('argument fn must be a function')
	}

	return morgan.token.call(this, name, fn)
}

/**
 * Define a format with the given name.
 *
 * @param {string} name
 * @param {string|function} fmt
 * @public
 */

function format(name, fmt) {
	if(typeof name !== 'string') {
		throw new TypeError('argument name must be a string')
	}

	if(typeof fmt !== 'string' && typeof fmt !== 'function') {
		throw new TypeError('argument fmt must be a string or a function')
	}

	return morgan.format.call(this, name, fmt)
}<|endoftext|>


<commit_before>'use strict';

/**
 * Simplified http request.
 * (C) 2013-2014 MediaSmart Mobile.
 */

// requires
var http = require('http');
var https = require('https');
var urlLib = require('url');

/**
 * Access a URL, send to callback. Parameters:
 *	- url: the URL to access.
 *	- params: optional additional parameters, currently supported:
 *		- retries: number of times to retry in case of error, default none.
 *	- callback(error, body): error is null only if result is 200.
 *		If there is an error, the body can contain the following attributes:
 *		- statusCode: if status code is not 200.
 *		- readingResponse: if response could not be read.
 */
exports.get = function(url, params, callback)
{
	if (typeof params == 'function')
	{
		callback = params;
		params = {};
	}
	params = params || {};
	var options = urlLib.parse(url);
	send(options, params, callback);
};

/**
 * Post to a URL, send to callback. Parameters:
 *	- url: the URL to access.
 *	- json: the object to send, can be a JSON string.
 *	- params: optional additional parameters, currently supported:
 *		- retries: number of times to retry in case of error, default none.
 *	- callback(error, body): error is null only if result is 200.
 *		If there is an error, the body can contain the following attributes:
 *		- statusCode: if status code is not 200.
 *		- readingResponse: if response could not be read.
 */
exports.post = function(url, json, params, callback)
{
	if (typeof params == 'function')
	{
		callback = params;
		params = {};
	}
	params = params || {};
	var options = urlLib.parse(url);
	options.method = 'POST';
	if (typeof json == 'object')
	{
		params.body = JSON.stringify(json);
		options.headers = {
			'Content-Type': 'application/json',
			'Content-Length': json.length,
		};
	}
	else
	{
		params.body = json;
		options.headers = {
			'Content-Type': 'text/plain',
			'Content-Length': json.length,
		};
	}
	send(options, params, callback);
};

function send(options, params, callback)
{
	callback = callback || function() {};
	options.headers = options.headers || {};
	options.headers['user-agent'] = 'node.js basic-request bot';
	options.agent = null;
	sendWithRetries(params.retries, options, params, callback);
}

function sendWithRetries(retries, options, params, callback)
{
	var finished = false;
	var protocol = http;
	if (options.protocol == 'https:')
	{
		protocol = https;
	}
	var request = protocol.get(options, function(response)
	{
		if (response.statusCode == 301 || response.statusCode == 302)
		{
			// follow redirection
			var location = response.headers.location;
			request.abort();
			return exports.get(location, callback);
		}
		if (response.statusCode != 200)
		{
			finished = true;
			request.abort();
			return callback('Invalid status code ' + response.statusCode, {statusCode: response.statusCode});
		}
		var body = '';
		response.on('data', function (chunk)
		{
			body += chunk;
		});
		response.on('error', function(error)
		{
			finished = true;
			return callback('Error reading response: ' + error, {readingResponse: true});
		});
		response.on('end', function()
		{
			if (finished)
			{
				return;
			}
			request.end();
			return callback(null, body);
		});
	});
	request.on('error', function(error)
	{
		finished = true;
		return callback('Error sending request: ' + error, {sendingRequest: true});
	});
	if (params.body)
	{
		request.write(params.body);
	}
	request.end();
}

// show API if invoked directly
if (__filename == process.argv[1])
{
	console.log('Use in your code as:');
	console.log('  request.get(url, function(error, body) {});');
}

<commit_msg>Set correct content length.<commit_after>'use strict';

/**
 * Simplified http request.
 * (C) 2013-2014 MediaSmart Mobile.
 */

// requires
var http = require('http');
var https = require('https');
var urlLib = require('url');

/**
 * Access a URL, send to callback. Parameters:
 *	- url: the URL to access.
 *	- params: optional additional parameters, currently supported:
 *		- retries: number of times to retry in case of error, default none.
 *	- callback(error, body): error is null only if result is 200.
 *		If there is an error, the body can contain the following attributes:
 *		- statusCode: if status code is not 200.
 *		- readingResponse: if response could not be read.
 */
exports.get = function(url, params, callback)
{
	if (typeof params == 'function')
	{
		callback = params;
		params = {};
	}
	params = params || {};
	var options = urlLib.parse(url);
	send(options, params, callback);
};

/**
 * Post to a URL, send to callback. Parameters:
 *	- url: the URL to access.
 *	- json: the object to send, can be a JSON string.
 *	- params: optional additional parameters, currently supported:
 *		- retries: number of times to retry in case of error, default none.
 *	- callback(error, body): error is null only if result is 200.
 *		If there is an error, the body can contain the following attributes:
 *		- statusCode: if status code is not 200.
 *		- readingResponse: if response could not be read.
 */
exports.post = function(url, json, params, callback)
{
	if (typeof params == 'function')
	{
		callback = params;
		params = {};
	}
	params = params || {};
	var options = urlLib.parse(url);
	options.method = 'POST';
	if (typeof json == 'object')
	{
		params.body = JSON.stringify(json);
		options.headers = {
			'Content-Type': 'application/json',
			'Content-Length': options.body.length,
		};
	}
	else
	{
		params.body = json;
		options.headers = {
			'Content-Type': 'text/plain',
			'Content-Length': options.body.length,
		};
	}
	send(options, params, callback);
};

function send(options, params, callback)
{
	callback = callback || function() {};
	options.headers = options.headers || {};
	options.headers['user-agent'] = 'node.js basic-request bot';
	options.agent = null;
	sendWithRetries(params.retries, options, params, callback);
}

function sendWithRetries(retries, options, params, callback)
{
	var finished = false;
	var protocol = http;
	if (options.protocol == 'https:')
	{
		protocol = https;
	}
	var request = protocol.get(options, function(response)
	{
		if (response.statusCode == 301 || response.statusCode == 302)
		{
			// follow redirection
			var location = response.headers.location;
			request.abort();
			return exports.get(location, callback);
		}
		if (response.statusCode != 200)
		{
			finished = true;
			request.abort();
			return callback('Invalid status code ' + response.statusCode, {statusCode: response.statusCode});
		}
		var body = '';
		response.on('data', function (chunk)
		{
			body += chunk;
		});
		response.on('error', function(error)
		{
			finished = true;
			return callback('Error reading response: ' + error, {readingResponse: true});
		});
		response.on('end', function()
		{
			if (finished)
			{
				return;
			}
			request.end();
			return callback(null, body);
		});
	});
	request.on('error', function(error)
	{
		finished = true;
		return callback('Error sending request: ' + error, {sendingRequest: true});
	});
	if (params.body)
	{
		request.write(params.body);
	}
	request.end();
}

// show API if invoked directly
if (__filename == process.argv[1])
{
	console.log('Use in your code as:');
	console.log('  request.get(url, function(error, body) {});');
}

<|endoftext|>


<commit_before>const pnut = require('lib/pnut');
<commit_msg>Fix required path<commit_after>const pnut = require('./lib/pnut');
<|endoftext|>


<commit_before>var gulpUtil = require( 'gulp-util' );
var through2 = require( 'through2' );

/**
 * CSS nesting by directory gulp plugin
 */
module.exports = function ()
{
	return through2.obj(
		function ( data, encoding, callback )
		{
			if ( data.isNull() )
			{
				callback( null, data );
				return;
			}

			if ( data.isStream() )
			{
				this.emit(
					'error',
					new gulpUtil.PluginError(
						'gulp-css-nbd',
						'Streams are not supported!'
					)
				);
				callback();
				return;
			}

			if ( data.isBuffer() )
			{
				if ( isSkipFile( data ) )
				{
					callback();
					return;
				}

				data.contents = new Buffer(
					getPathSelector( data ) + '\n{\n'
					+ String( data.contents )
					+ '\n}\n'
				);

				callback( null, data );
			}
		}
	);
};

/**
 * Checks whether the file should be skipped
 *
 * @param data Through2 file data
 * @returns Skip file?
 */
function isSkipFile( data )
{
	return /\/_[^\/]*$/.test( data.path );
}

/**
 * Build CSS selector based on file path
 *
 * @param data Through2 file data
 * @returns CSS selector
 */
function getPathSelector( data )
{
	var selectors = [''];
	var firstEntry = true;

	pathWithoutExtension( data.path )
		.substr( data.base.length )
		.split( '/' )
		.forEach(
			function ( name )
			{
				if ( isNotForSelector( name ) )
				{
					return;
				}

				var descendant = isDescendantSelector( name );
				var combinator = (
					( selectors[0].length === 0 )
					? ''
					: ( descendant ? ' ' : ' > ' )
				);
				var parts = splitSelectors(
					descendant
					? name.substr( 1 )
					: name
				);
				var currentSelectors = selectors.slice();

				for ( var i = 0, n = parts.length; i < n; i++ )
				{
					var selector = combinator + parts[i];

					if ( i > 0 )
					{
						selectors = selectors.concat(
							appendToStrings( currentSelectors.slice(), selector )
						);
					}
					else
					{
						appendToStrings( selectors, selector );
					}
				}
			}
		);

	return selectors.join( ', ' );
}

/**
 * Append given string to every string in array (mutates original array)
 *
 * @param strings Array of strings
 * @param addition String to append
 * @returns Array of strings
 */
function appendToStrings( strings, addition )
{
	for ( var i = 0, n = strings.length; i < n; i++ )
	{
		strings[i] += addition;
	}

	return strings;
}

/**
 * Split string of selectors separated by comma
 *
 * @param selectors String of selectors
 * @returns Array of selectors
 */
function splitSelectors( selectors )
{
	var parts = [];
	var inParentheses = false;
	var lastPos = 0;

	for ( var i = 0, n = selectors.length; i < n; i++ )
	{
		if ( inParentheses )
		{
			if ( selectors[i] === ')' )
			{
				inParentheses = false;
			}
		}
		else if ( selectors[i] === '(' )
		{
			inParentheses = true;
		}
		else if ( selectors[i] === ',' )
		{
			parts.push( selectors.slice( lastPos, i ) );
			lastPos = i + 1;
		}
	}

	parts.push( selectors.slice( lastPos ) );

	return parts;
}

/**
 * Returns path without file extension
 *
 * @param path File path
 * @returns Path without extension
 */
function pathWithoutExtension( path )
{
	return path.replace( /\.\w+$/, '' );
}

/**
 * Checks whether it is descendant selector
 *
 * @param name File or directory name
 * @returns Descendant selector?
 */
function isDescendantSelector( name )
{
	return ( name.charAt( 0 ) === '!' );
}

/**
 * Checks that it should not be a part of the selector
 *
 * @param name File or directory name
 * @returns Skip from selector?
 */
function isNotForSelector( name )
{
	return (
		( name.charAt( 0 ) === '_' )
		|| ( name.indexOf( '&' ) !== -1 )
	);
}
<commit_msg>Add support of directory as selector modifier<commit_after>var gulpUtil = require( 'gulp-util' );
var through2 = require( 'through2' );

/**
 * CSS nesting by directory gulp plugin
 */
module.exports = function ()
{
	return through2.obj(
		function ( data, encoding, callback )
		{
			if ( data.isNull() )
			{
				callback( null, data );
				return;
			}

			if ( data.isStream() )
			{
				this.emit(
					'error',
					new gulpUtil.PluginError(
						'gulp-css-nbd',
						'Streams are not supported!'
					)
				);
				callback();
				return;
			}

			if ( data.isBuffer() )
			{
				if ( isSkipFile( data ) )
				{
					callback();
					return;
				}

				data.contents = new Buffer(
					getPathSelector( data ) + '\n{\n'
					+ String( data.contents )
					+ '\n}\n'
				);

				callback( null, data );
			}
		}
	);
};

/**
 * Checks whether the file should be skipped
 *
 * @param data Through2 file data
 * @returns Skip file?
 */
function isSkipFile( data )
{
	return /\/_[^\/]*$/.test( data.path );
}

/**
 * Build CSS selector based on file path
 *
 * @param data Through2 file data
 * @returns CSS selector
 */
function getPathSelector( data )
{
	var selectors = [''];
	var firstEntry = true;

	pathWithoutExtension( data.path )
		.substr( data.base.length )
		.split( '/' )
		.forEach(
			function ( name )
			{
				if ( isNotForSelector( name ) )
				{
					return;
				}

				var descendant = isDescendantSelector( name );
				var modifier = isModifier( name );
				var combinator = (
					(
						modifier
						|| ( selectors[0].length === 0 )
					)
					? ''
					: ( descendant ? ' ' : ' > ' )
				);
				var parts = splitSelectors( name );
				var currentSelectors = selectors.slice();

				for ( var i = 0, n = parts.length; i < n; i++ )
				{
					var selector = combinator
						+ (
							( descendant || modifier )
							? parts[i].substr( 1 )
							: parts[i]
						);

					if ( i > 0 )
					{
						selectors = selectors.concat(
							appendToStrings( currentSelectors.slice(), selector )
						);
					}
					else
					{
						appendToStrings( selectors, selector );
					}
				}
			}
		);

	return selectors.join( ', ' );
}

/**
 * Append given string to every string in array (mutates original array)
 *
 * @param strings Array of strings
 * @param addition String to append
 * @returns Array of strings
 */
function appendToStrings( strings, addition )
{
	for ( var i = 0, n = strings.length; i < n; i++ )
	{
		strings[i] += addition;
	}

	return strings;
}

/**
 * Split string of selectors separated by comma
 *
 * @param selectors String of selectors
 * @returns Array of selectors
 */
function splitSelectors( selectors )
{
	var parts = [];
	var inParentheses = false;
	var lastPos = 0;

	for ( var i = 0, n = selectors.length; i < n; i++ )
	{
		if ( inParentheses )
		{
			if ( selectors[i] === ')' )
			{
				inParentheses = false;
			}
		}
		else if ( selectors[i] === '(' )
		{
			inParentheses = true;
		}
		else if ( selectors[i] === ',' )
		{
			parts.push( selectors.slice( lastPos, i ) );
			lastPos = i + 1;
		}
	}

	parts.push( selectors.slice( lastPos ) );

	return parts;
}

/**
 * Returns path without file extension
 *
 * @param path File path
 * @returns Path without extension
 */
function pathWithoutExtension( path )
{
	return path.replace( /\.\w+$/, '' );
}

/**
 * Checks whether it is descendant selector
 *
 * @param name File or directory name
 * @returns Descendant selector?
 */
function isDescendantSelector( name )
{
	return ( name.charAt( 0 ) === '!' );
}

/**
 * Checks whether it is modifier of selector
 *
 * @param name File or directory name
 * @returns Modifier of selector?
 */
function isModifier( name )
{
	return ( name.charAt( 0 ) === '&' );
}

/**
 * Checks that it should not be a part of the selector
 *
 * @param name File or directory name
 * @returns Skip from selector?
 */
function isNotForSelector( name )
{
	return (
		// Partial
		( name.charAt( 0 ) === '_' )
		// Same selector
		|| ( name === '&' )
	);
}
<|endoftext|>


<commit_before>var WS = require('multiserver/plugins/ws')
var http = require('http')
var pull = require('pull-stream')
var JSONApi = require('./json-api')
var scopes = require('multiserver-scopes')

var READ_AND_ADD = [ //except for add, of course
  'get',
  'getLatest',
  'createLogStream',
  'createUserStream',

  'createHistoryStream',
  'getAddress',

  'links',

  'blobs.add',
  'blobs.size',
  'blobs.has',
  'blobs.get',
  'blobs.changes',
  'blobs.createWants',

  'add',

  'query.read',
  'links2.read'
]

exports.name = 'ws'
exports.version = require('./package.json').version
exports.manifest = {}

exports.init = function (sbot, config) {
  var port, host
  if(config.ws) {
    port = config.ws.port
    host = config.ws.host || config.host
  }
  if(!port)
    port = 1024+(~~(Math.random()*(65536-1024)))

  var layers = []

  var handlers = JSONApi(sbot, layers)
  function no_handler (req, res, next) {
    next(new Error('ssb-ws:web sockets only'))
  }
  sbot.auth.hook(function (fn, args) {
    var id = args[0]
    var cb = args[1]
    fn(id, function (err, value) {
      if(value === true)
        sbot.friends.get({source: sbot.id, dest: toId(id)}, function (err, follows) {
          if(err) return cb(err)
          else if(follows) cb(null, {allow: READ_AND_ADD, deny: null})
          else cb(null, true)
        })
      else
        cb(err, value)
    })
  })
  var c = 0
  sbot.multiserver.transport({
    name: 'ws',
    create: function (config) {
      var _host = config.host || 'localhost'
      var _port = config.port || port
      //debug('listening on host=%s port=%d', _host, _port)
      var server = http.createServer(config.web !== false ? handlers : no_handler).listen(_port, _host, function(err) {
        if (err) console.error('ssb-ws failed to listen on ' + _host + ':' + _port, err)
        else console.log('Listening on ' + _host + ':' + _port, '(ssb-ws)')
      })
      return WS(Object.assign({
        server: server, port: _port, host: _host
      }, config))
    }
  })

  return {
    use: function (handler) {
      layers.push(handler)
    }
  }
}

<commit_msg>simplify by moving support for a handler function option into multiserver/plugins/ws<commit_after>var WS = require('multiserver/plugins/ws')
var http = require('http')
var pull = require('pull-stream')
var JSONApi = require('./json-api')
var scopes = require('multiserver-scopes')

var READ_AND_ADD = [ //except for add, of course
  'get',
  'getLatest',
  'createLogStream',
  'createUserStream',

  'createHistoryStream',
  'getAddress',

  'links',

  'blobs.add',
  'blobs.size',
  'blobs.has',
  'blobs.get',
  'blobs.changes',
  'blobs.createWants',

  'add',

  'query.read',
  'links2.read'
]

exports.name = 'ws'
exports.version = require('./package.json').version
exports.manifest = {}

exports.init = function (sbot, config) {
  var port, host
  if(config.ws) {
    port = config.ws.port
    host = config.ws.host || config.host
  }
  if(!port)
    port = 1024+(~~(Math.random()*(65536-1024)))

  var layers = []

  var handlers = JSONApi(sbot, layers)
  function no_handler (req, res, next) {
    next(new Error('ssb-ws:web sockets only'))
  }
  sbot.auth.hook(function (fn, args) {
    var id = args[0]
    var cb = args[1]
    fn(id, function (err, value) {
      if(value === true)
        sbot.friends.get({source: sbot.id, dest: toId(id)}, function (err, follows) {
          if(err) return cb(err)
          else if(follows) cb(null, {allow: READ_AND_ADD, deny: null})
          else cb(null, true)
        })
      else
        cb(err, value)
    })
  })
  var c = 0
  sbot.multiserver.transport({
    name: 'ws',
    create: function (config) {
      var _host = config.host || 'localhost'
      var _port = config.port || port
      //debug('listening on host=%s port=%d', _host, _port)
      return WS(Object.assign({
        port: _port, host: _host,
        handler: config.web !== false ? handlers : no_handler
      }, config))
    }
  })

  return {
    use: function (handler) {
      layers.push(handler)
    }
  }
}

<|endoftext|>


<commit_before>;(function (root) {
  'use strict'

  var _ = {

    util: {

      asc  (a, b) { return a > b },
      desc (a, b) { return a < b },
      truthy (value) { return value === true },
      firstOr (arr, value) { return arr.length ? arr[0] : value }

    },

    chain (arr) {
      function chainer (collection) {
        var self = {
          get () {
            return collection
          }
        }

        for( var method in _ ) {
          if (typeof _[method] === 'function') {
            (function (oldMethod) {
              self[method] = function () {
                var args = _.toArray(arguments)
                args.unshift(collection)

                return chainer(oldMethod.apply(null, args))
              }
            })(_[method])
          } else {
            self[method] = _[method]
          }

        }

        return self
      }

      return chainer(arr)
    },

    contains (arr, item) {
      return Boolean(~arr.indexOf(value))
    },

    reduce (arr, callback, initalValue) {
      var args = _.toArray(arguments)

      if (args.length === 2)
        return arr.reduce(callback)

      return arr.reduce(callback, initalValue)
    },

    each (arr, callback) {
      return _.reduce(arr, function (collection, value, index, arr) {
        callback(value, index, arr)
      }, undefined)
    },

    map (arr, callback) {
      return _.reduce(arr, function (collection, value, index, arr) {
        collection.push(callback(value, index, arr))

        return collection
      }, [])
    },

    filter (arr, callback) {
      return _.reduce(arr, function (collection, value, index, arr) {

        if (_.util.truthy(callback(value, index, arr)))
          collection.push(value)

        return collection
      }, [])
    },

    some (arr, callback) {
      return _.chain(arr)
        .map(callback)
        .filter(_.util.truthy)
        .get()
        .length > 0
    },

    every (arr, callback) {
      return _.chain(arr)
        .map(callback)
        .filter(_.util.truthy)
        .get()
        .length === arr.length
    },

    flatten (arr) {
      return _.reduce(arr, function (collection, value) {
        return collection.concat(value)
      }, [])
    },

    unique (arr) {
      return _.reduce(arr, function (collection, value) {

        if (!_.contains(collection, value))
          collection.push(value)

        return collection
      }, [])
    },

    toArray (arrlike) {
      return Array.prototype.slice.call(arrlike)
    },

    groupBy (arr, key) {
      return _.chain(arr)
        .extract(key)
        .unique()
        .map(function (group) {
          return _.filter(arr, function (item) {
            return item[key] === group
          })
        })
        .get()
    },

    indexes (arr) {
      return _.map(arr, function (_, index) {
        return index
      })
    },

    extract (arr, key) {
      return _.map(arr, function (item) {
        return item[key]
      })
    },

    head (arr) {
      return _.filter(arr, function (_, i) {
        return i < 0
      })
    },

    tail (arr) {
      return _.filter(arr, function (_, i) {
        return i > 0
      })
    },

    fill (arr, target) {
      return _.map(arr, function (value, index, arr) {
        if (typeof target === 'function') return target(value, index, arr)
        return target
      })
    },

    reverse (arr) {
      return _.chain(arr)
        .indexes()
        .sort(_.util.desc)
        .map(function (index) {
          return arr[index]
        })
        .get()
    },

    sort (arr, callback) {
      return arr.sort(callback)
    },

    max (arr) {
      return _.reduce(arr, function (current, value) {
        if (current < value) return value
        return current
      }, _.util.firstOr(arr, -Infinity))
    },

    min (arr) {
      return _.reduce(arr, function (current, value) {
        if (current > value) return value
        return current
      }, _.util.firstOr(arr, Infinity))
    },

  }

  // If it's a nodejs enviroment, export it. Othewise assume enviroment is a browser.
  if (module && module.exports) {
    module.exports = _
  } else {
    root._ = root.reduceIt = _
  }

}(this));<commit_msg>Refactoring duplicated statements<commit_after>;(function (root) {
  'use strict'

  var _ = {

    util: {

      asc  (a, b) { return a > b },
      desc (a, b) { return a < b },
      truthy (value) { return value === true },
      firstOr (arr, value) { return arr.length ? arr[0] : value }

    },

    chain (arr) {
      function chainer (collection) {
        var self = {
          get () {
            return collection
          }
        }

        for( var method in _ ) {
          if (typeof _[method] === 'function') {
            (function (oldMethod) {
              self[method] = function () {
                var args = _.toArray(arguments)
                args.unshift(collection)

                return chainer(oldMethod.apply(null, args))
              }
            })(_[method])
          } else {
            self[method] = _[method]
          }

        }

        return self
      }

      return chainer(arr)
    },

    contains (arr, item) {
      return Boolean(~arr.indexOf(value))
    },

    reduce (arr, callback, initalValue) {
      return (arguments.length > 2)
        ? arr.reduce(callback, initalValue)
        : arr.reduce(callback)
    },

    each (arr, callback) {
      return _.reduce(arr, function (collection, value, index, arr) {
        callback(value, index, arr)
      }, undefined)
    },

    map (arr, callback) {
      return _.reduce(arr, function (collection, value, index, arr) {
        collection.push(callback(value, index, arr))

        return collection
      }, [])
    },

    filter (arr, callback) {
      return _.reduce(arr, function (collection, value, index, arr) {

        if (_.util.truthy(callback(value, index, arr)))
          collection.push(value)

        return collection
      }, [])
    },

    some (arr, callback) {
      return _.chain(arr)
        .map(callback)
        .filter(_.util.truthy)
        .get()
        .length > 0
    },

    every (arr, callback) {
      return _.chain(arr)
        .map(callback)
        .filter(_.util.truthy)
        .get()
        .length === arr.length
    },

    flatten (arr) {
      return _.reduce(arr, function (collection, value) {
        return collection.concat(value)
      }, [])
    },

    unique (arr) {
      return _.reduce(arr, function (collection, value) {

        if (!_.contains(collection, value))
          collection.push(value)

        return collection
      }, [])
    },

    toArray (arrlike) {
      return Array.prototype.slice.call(arrlike)
    },

    groupBy (arr, key) {
      return _.chain(arr)
        .extract(key)
        .unique()
        .map(function (group) {
          return _.filter(arr, function (item) {
            return item[key] === group
          })
        })
        .get()
    },

    indexes (arr) {
      return _.map(arr, function (_, index) {
        return index
      })
    },

    extract (arr, key) {
      return _.map(arr, function (item) {
        return item[key]
      })
    },

    head (arr) {
      return _.filter(arr, function (_, i) {
        return i < 0
      })
    },

    tail (arr) {
      return _.filter(arr, function (_, i) {
        return i > 0
      })
    },

    fill (arr, target) {
      return _.map(arr, function (value, index, arr) {
        return (typeof target === 'function')
          ? target(value, index, arr)
          : target
      })
    },

    reverse (arr) {
      return _.chain(arr)
        .indexes()
        .sort(_.util.desc)
        .map(function (index) {
          return arr[index]
        })
        .get()
    },

    sort (arr, callback) {
      return arr.sort(callback)
    },

    max (arr) {
      return _.reduce(arr, function (current, value) {
        return (current < value)
          ? value
          : current
      }, _.util.firstOr(arr, -Infinity))
    },

    min (arr) {
      return _.reduce(arr, function (current, value) {
        return (current > value)
          ? value
          : current
      }, _.util.firstOr(arr, Infinity))
    },

  }

  // If it's a nodejs enviroment, export it. Othewise assume enviroment is a browser.
  if (module && module.exports) {
    module.exports = _
  } else {
    root._ = root.reduceIt = _
  }

}(this));<|endoftext|>