<commit_before>var debug = require('debug')('metalsmith-spellcheck'),
    path = require('path'),
    fs = require('fs'),
    async = require('async'),
    _ = require('underscore'),
    nodehun = require('nodehun'),
    validator = require('validator'),
    cheerio = require('cheerio'),
    jsonfile = require('jsonfile'),
    minimatch = require('minimatch'),
    MD5 = require('md5'),
    object_hash = require('object-hash');
jsonfile.spaces = 4;

var defaults = {
  'verbose': true,
  'failErrors': true,
  'cacheChecks': true,
  'checkedPart': "*",
  'exceptionFile': 'spelling_exceptions.json',
  'checkFile': '.spelling_check.json',
  'failFile': 'spelling_failed.json',
  'exceptions': [],
}

function processConfig(config, src) {
  config = config || {};
  config = _.extend(_.clone(defaults), config);
  if (src) {
    config.exceptionFile = path.join(src, config.exceptionFile);
    config.failFile = path.join(src, config.failFile);
    config.checkFile = path.join(src, config.checkFile);
  }
  return config;
}

function removeFiles(files, config) {
  if (files[config.checkFile]) {
    delete(files[config.checkFile]);
  }
  if (files[config.failFile]) {
    delete(files[config.failFile]);
  }
  if (files[config.exceptionFile]) {
    delete(files[config.exceptionFile]);
  }
  if (files[config.affFile]) {
    delete(files[config.affFile]);
  }
  if (files[config.dicFile]) {
    delete(files[config.dicFile]);
  }
};

function cleanText(text) {
  var words = text.trim()
    .replace(/[\u2018\u2019]/g, "'")
    .replace(/\.\.\./g, ".")
    .replace(/[^a-zA-Z0-9'\.@]+/g, " ").trim().split(/\s+/);

  words = _.map(words, function (word) {
    if (((word.match(/\./g) || []).length == 1 && /^.*\.$/.test(word)) ||
        (/^.*:$/.test(word))) {
      word = word.substring(0, word.length - 1);
    }
    if (/^.*'$/.test(word)) {
      return word.substring(0, word.length - 1);
    } else if (/^.*'s/.test(word)) {
      return word.substring(0, word.length - 2);
    } else {
      return word;
    }
  });
  words = _.reject(words, function (word) {
    return (word === "") ||
      (word === "'s") ||
      /^\d{2}:\d{2}/.test(word) ||
      validator.isNumeric(word) ||
      validator.isEmail(word) ||
      validator.isURL(word) ||
      validator.isDate(word);
  });
  return _.toArray(words);
};

var regexPattern = /^\/(.*?)\/([gim]*)$/;
var startBoundary = "(?:^|[^a-zA-Z0-9'@])";
var endBoundary = "(?=$|[^a-zA-Z0-9'\.@])";

function exceptionToPatterns(pattern, files) {
  var parts = pattern.match(regexPattern);
  if (parts) {
    var newPattern = parts[1];
    var flags = parts[2];
    if (flags.indexOf("g") === -1) {
      flags += "g";
    }
    return [{'files': files, 'pattern': new RegExp(startBoundary + newPattern + endBoundary, flags)}];
  } else {
    return _.map(cleanText(pattern), function (word) {
      return {'files': files, 'pattern': new RegExp(startBoundary + word + endBoundary, "g") }
    });
  }
}

function spellcheck(config) {

  return function(files, metalsmith, done) {

    config = processConfig(config);

    var realDone = function(err) {
      removeFiles(files, config);
      done(err)
    };

    if (!config.dict && (!(config.dicFile) || !(config.affFile))) {
      realDone(new Error("must provide either a dict or dicFile and affFile options to metalsmith-spellcheck"));
      return;
    }

    var dict, exceptions = {};
    try {
      dict = config.dict || new nodehun(files[config.affFile].contents, files[config.dicFile].contents);

      if (config.exceptionFile && files[config.exceptionFile]) {
        exceptions = JSON.parse(files[config.exceptionFile].contents);
      }
    } catch (err) {
      realDone(err);
      return;
    }

    if (config.cacheChecks) {
      var checked_files = { 'files': {}, 'exceptions': {}};
      try {
        checked_files = JSON.parse(files[config.checkFile].contents);
      } catch (err) {};
      var aff_hash = MD5(files[config.affFile].contents);
      var dic_hash = MD5(files[config.dicFile].contents);

      var can_cache = ((checked_files.files[config.affFile] == aff_hash) &&
          (checked_files.files[config.dicFile] == dic_hash));
      checked_files.files[config.affFile] = aff_hash;
      checked_files.files[config.dicFile] = dic_hash;
    }
    var examined_files = [];

    var metadata = metalsmith.metadata();
    var metadata_exceptions;
    try {
      metadata_exceptions = metadata['spelling_exceptions'];
    } catch (err) {};
    metadata_exceptions = _.union(config.exceptions, metadata_exceptions);

    var htmlfiles = _.pick(files, function(file, filename) {
      return (path.extname(filename) === '.html');
    });

    var filenamewords = {}, wordstofilenames = {}, uniqwords = [];
    var pattern_exceptions = {};

    _.each(htmlfiles, function (file, filename) {
      pattern_exceptions[filename] = [];
    });

    async.series([
        function (callback) {
          function addException(info) {
            if (info.files === true) {
              _.each(pattern_exceptions, function (patterns) {
                patterns.push(info.pattern);
              });
            } else {
              _.each(info.files, function (filepattern) {
                if (pattern_exceptions[filepattern]) {
                  pattern_exceptions[filepattern].push(info.pattern);
                }
                _.each(pattern_exceptions, function (patterns, filename) {
                  if (minimatch(filename, filepattern)) {
                    patterns.push(info.pattern);
                  }
                });
              });
            }
          };
          _.each(metadata_exceptions, function (exception) {
            _.map(exceptionToPatterns(exception, true), addException);
          });
          _.each(exceptions, function (info, exception) {
            _.map(exceptionToPatterns(exception, info), addException);
          });
          _.each(htmlfiles, function (file, filename) {
            if (file.spelling_exceptions) {
              _.each(file.spelling_exceptions, function (exception) {
                _.map(exceptionToPatterns(exception, [filename]), addException);
              });
            }
          });
          callback();
        },
        function (callback) {
          async.forEachOf(htmlfiles, function(file, filename, finished) {
            var $ = cheerio.load(file.contents);

            if (config.cacheChecks) {
              var file_hash = MD5($(config.checkedPart).html());
              var exception_hash = object_hash(pattern_exceptions[filename].sort());

              if (can_cache &&
                  (checked_files.files[filename] == file_hash) &&
                  (checked_files.exceptions[filename] == exception_hash)) {
                finished();
                return;
              }
            }
            examined_files.push(filename);
            var allwords = [];
            $(config.checkedPart).contents().filter(function (index, element) {
              return (element.type === 'text' &&
                  $(element).parents('.spelling_exception').length == 0 &&
                  $(element).parents('script').length == 0 &&
                  $(element).parents('code').length == 0 &&
                  element.data.trim().length > 0);
            }).each(function (index, element) {
              var cleaned = cleanText(element.data).join(" ");
              _.each(pattern_exceptions[filename], function(pattern) {
                cleaned = cleaned.replace(pattern, " ");
              });
              allwords = _.union(allwords, cleaned.split(/\s+/));
            });
            if (config.cacheChecks) {
              checked_files.files[filename] = file_hash;
              checked_files.exceptions[filename] = exception_hash;
            }
            filenamewords[filename] = allwords;
            finished();
          },
          function() {
            _.each(filenamewords, function (allwords) {
              uniqwords = _.union(uniqwords, allwords);
            });
            _.each(uniqwords, function (word) {
              wordstofilenames[word] = [];
            });
            _.each(filenamewords, function (allwords, filename) {
              _.each(allwords, function (word) {
                wordstofilenames[word].push(filename);
              });
            });
            callback();
          });
        },
        function (callback) {
          async.filter(uniqwords, function (word, innerCallback) {
            dict.isCorrect(word, function (err, correct) {
              innerCallback(!correct);
            });
          }, function (results) {
            if (config.cacheChecks) {
              jsonfile.writeFileSync(path.join(metalsmith.source(), config.checkFile), checked_files);
            }
            var misspellings = {};
            try {
              misspellings = JSON.parse(files[config.failFile].contents);
            } catch (err) {};
            results = results.sort(function (a, b) {
              return a.toLowerCase().localeCompare(b.toLowerCase());
            });
            _.each(results, function (word) {
              if (misspellings[word]) {
                var bad_files = _.filter(misspellings[word], function (filename) {
                  return ((examined_files.indexOf(filename) === -1) ||
                          (wordstofilenames[word].indexOf(filename) !== -1));
                });
                if (bad_files.length == 0) {
                  delete(misspellings[word]);
                }
              } else {
                misspellings[word] = wordstofilenames[word];
              }
            });
            if (_.keys(misspellings).length == 0) {
              try {
                fs.unlinkSync(path.join(metalsmith.source(), config.failFile));
              } catch (err) {};
              realDone();
            } else {
              if (config.verbose) {
                console.log("There were spelling errors. See " + config.failFile);
              }
              jsonfile.writeFileSync(path.join(metalsmith.source(), config.failFile), misspellings);
              if (config.failErrors) {
                realDone(new Error("fail spelling check. See " + config.failFile));
              } else {
                realDone();
              }
            }
          });
        }
    ]);
  }
}
exports = module.exports = spellcheck;
exports.defaults = defaults;
exports.processConfig = processConfig;
<commit_msg>Extra verbosity.<commit_after>var debug = require('debug')('metalsmith-spellcheck'),
    path = require('path'),
    fs = require('fs'),
    async = require('async'),
    _ = require('underscore'),
    nodehun = require('nodehun'),
    validator = require('validator'),
    cheerio = require('cheerio'),
    jsonfile = require('jsonfile'),
    minimatch = require('minimatch'),
    MD5 = require('md5'),
    object_hash = require('object-hash');
jsonfile.spaces = 4;

var defaults = {
  'verbose': true,
  'veryVerbose': false,
  'failErrors': true,
  'cacheChecks': true,
  'checkedPart': "*",
  'exceptionFile': 'spelling_exceptions.json',
  'checkFile': '.spelling_check.json',
  'failFile': 'spelling_failed.json',
  'exceptions': [],
}

function processConfig(config, src) {
  config = config || {};
  config = _.extend(_.clone(defaults), config);
  if (src) {
    config.exceptionFile = path.join(src, config.exceptionFile);
    config.failFile = path.join(src, config.failFile);
    config.checkFile = path.join(src, config.checkFile);
  }
  return config;
}

function removeFiles(files, config) {
  if (files[config.checkFile]) {
    delete(files[config.checkFile]);
  }
  if (files[config.failFile]) {
    delete(files[config.failFile]);
  }
  if (files[config.exceptionFile]) {
    delete(files[config.exceptionFile]);
  }
  if (files[config.affFile]) {
    delete(files[config.affFile]);
  }
  if (files[config.dicFile]) {
    delete(files[config.dicFile]);
  }
};

function cleanText(text) {
  var words = text.trim()
    .replace(/[\u2018\u2019]/g, "'")
    .replace(/\.\.\./g, ".")
    .replace(/[^a-zA-Z0-9'\.@]+/g, " ").trim().split(/\s+/);

  words = _.map(words, function (word) {
    if (((word.match(/\./g) || []).length == 1 && /^.*\.$/.test(word)) ||
        (/^.*:$/.test(word))) {
      word = word.substring(0, word.length - 1);
    }
    if (/^.*'$/.test(word)) {
      return word.substring(0, word.length - 1);
    } else if (/^.*'s/.test(word)) {
      return word.substring(0, word.length - 2);
    } else {
      return word;
    }
  });
  words = _.reject(words, function (word) {
    return (word === "") ||
      (word === "'s") ||
      /^\d{2}:\d{2}/.test(word) ||
      validator.isNumeric(word) ||
      validator.isEmail(word) ||
      validator.isURL(word) ||
      validator.isDate(word);
  });
  return _.toArray(words);
};

var regexPattern = /^\/(.*?)\/([gim]*)$/;
var startBoundary = "(?:^|[^a-zA-Z0-9'@])";
var endBoundary = "(?=$|[^a-zA-Z0-9'\.@])";

function exceptionToPatterns(pattern, files) {
  var parts = pattern.match(regexPattern);
  if (parts) {
    var newPattern = parts[1];
    var flags = parts[2];
    if (flags.indexOf("g") === -1) {
      flags += "g";
    }
    return [{'files': files, 'pattern': new RegExp(startBoundary + newPattern + endBoundary, flags)}];
  } else {
    return _.map(cleanText(pattern), function (word) {
      return {'files': files, 'pattern': new RegExp(startBoundary + word + endBoundary, "g") }
    });
  }
}

function spellcheck(config) {

  return function(files, metalsmith, done) {

    config = processConfig(config);

    var realDone = function(err) {
      removeFiles(files, config);
      done(err)
    };

    if (!config.dict && (!(config.dicFile) || !(config.affFile))) {
      realDone(new Error("must provide either a dict or dicFile and affFile options to metalsmith-spellcheck"));
      return;
    }

    var dict, exceptions = {};
    try {
      dict = config.dict || new nodehun(files[config.affFile].contents, files[config.dicFile].contents);

      if (config.exceptionFile && files[config.exceptionFile]) {
        exceptions = JSON.parse(files[config.exceptionFile].contents);
      }
    } catch (err) {
      realDone(err);
      return;
    }

    if (config.cacheChecks) {
      var checked_files = { 'files': {}, 'exceptions': {}};
      try {
        checked_files = JSON.parse(files[config.checkFile].contents);
      } catch (err) {};
      var aff_hash = MD5(files[config.affFile].contents);
      var dic_hash = MD5(files[config.dicFile].contents);

      var can_cache = ((checked_files.files[config.affFile] == aff_hash) &&
          (checked_files.files[config.dicFile] == dic_hash));
      if (config.veryVerbose) {
        if (can_cache) {
          console.log("Using cached data for this spell check.");
        } else {
          console.log("No cached data for this spell check.");
        }
      }
      checked_files.files[config.affFile] = aff_hash;
      checked_files.files[config.dicFile] = dic_hash;
    }
    var examined_files = [];

    var metadata = metalsmith.metadata();
    var metadata_exceptions;
    try {
      metadata_exceptions = metadata['spelling_exceptions'];
    } catch (err) {};
    metadata_exceptions = _.union(config.exceptions, metadata_exceptions);

    var htmlfiles = _.pick(files, function(file, filename) {
      return (path.extname(filename) === '.html');
    });

    var filenamewords = {}, wordstofilenames = {}, uniqwords = [];
    var pattern_exceptions = {};

    _.each(htmlfiles, function (file, filename) {
      pattern_exceptions[filename] = [];
    });

    async.series([
        function (callback) {
          function addException(info) {
            if (info.files === true) {
              _.each(pattern_exceptions, function (patterns) {
                patterns.push(info.pattern);
              });
            } else {
              _.each(info.files, function (filepattern) {
                if (pattern_exceptions[filepattern]) {
                  pattern_exceptions[filepattern].push(info.pattern);
                }
                _.each(pattern_exceptions, function (patterns, filename) {
                  if (minimatch(filename, filepattern)) {
                    patterns.push(info.pattern);
                  }
                });
              });
            }
          };
          _.each(metadata_exceptions, function (exception) {
            _.map(exceptionToPatterns(exception, true), addException);
          });
          _.each(exceptions, function (info, exception) {
            _.map(exceptionToPatterns(exception, info), addException);
          });
          _.each(htmlfiles, function (file, filename) {
            if (file.spelling_exceptions) {
              _.each(file.spelling_exceptions, function (exception) {
                _.map(exceptionToPatterns(exception, [filename]), addException);
              });
            }
          });
          callback();
        },
        function (callback) {
          async.forEachOf(htmlfiles, function(file, filename, finished) {
            var $ = cheerio.load(file.contents);

            if (config.cacheChecks) {
              var file_hash = MD5($(config.checkedPart).html());
              var exception_hash = object_hash(pattern_exceptions[filename].sort());

              if (can_cache &&
                  (checked_files.files[filename] == file_hash) &&
                  (checked_files.exceptions[filename] == exception_hash)) {
                if (config.veryVerbose) {
                  console.log(filename + " and its exceptions are unchanged. Not rechecking.");
                }
                finished();
                return;
              }
            }
            if (config.veryVerbose) {
              console.log(filename + " or its exceptions have changed. Rechecking.");
            }
            examined_files.push(filename);
            var allwords = [];
            $(config.checkedPart).contents().filter(function (index, element) {
              return (element.type === 'text' &&
                  $(element).parents('.spelling_exception').length == 0 &&
                  $(element).parents('script').length == 0 &&
                  $(element).parents('code').length == 0 &&
                  element.data.trim().length > 0);
            }).each(function (index, element) {
              var cleaned = cleanText(element.data).join(" ");
              _.each(pattern_exceptions[filename], function(pattern) {
                cleaned = cleaned.replace(pattern, " ");
              });
              allwords = _.union(allwords, cleaned.split(/\s+/));
            });
            if (config.cacheChecks) {
              checked_files.files[filename] = file_hash;
              checked_files.exceptions[filename] = exception_hash;
            }
            filenamewords[filename] = allwords;
            finished();
          },
          function() {
            _.each(filenamewords, function (allwords) {
              uniqwords = _.union(uniqwords, allwords);
            });
            _.each(uniqwords, function (word) {
              wordstofilenames[word] = [];
            });
            _.each(filenamewords, function (allwords, filename) {
              _.each(allwords, function (word) {
                wordstofilenames[word].push(filename);
              });
            });
            callback();
          });
        },
        function (callback) {
          async.filter(uniqwords, function (word, innerCallback) {
            dict.isCorrect(word, function (err, correct) {
              innerCallback(!correct);
            });
          }, function (results) {
            if (config.cacheChecks) {
              jsonfile.writeFileSync(path.join(metalsmith.source(), config.checkFile), checked_files);
            }
            var misspellings = {};
            try {
              misspellings = JSON.parse(files[config.failFile].contents);
            } catch (err) {};
            results = results.sort(function (a, b) {
              return a.toLowerCase().localeCompare(b.toLowerCase());
            });
            _.each(results, function (word) {
              if (misspellings[word]) {
                var bad_files = _.filter(misspellings[word], function (filename) {
                  return ((examined_files.indexOf(filename) === -1) ||
                          (wordstofilenames[word].indexOf(filename) !== -1));
                });
                if (bad_files.length == 0) {
                  delete(misspellings[word]);
                }
              } else {
                misspellings[word] = wordstofilenames[word];
              }
            });
            if (_.keys(misspellings).length == 0) {
              try {
                fs.unlinkSync(path.join(metalsmith.source(), config.failFile));
              } catch (err) {};
              realDone();
            } else {
              if (config.verbose) {
                console.log("There were spelling errors. See " + config.failFile);
              }
              jsonfile.writeFileSync(path.join(metalsmith.source(), config.failFile), misspellings);
              if (config.failErrors) {
                realDone(new Error("fail spelling check. See " + config.failFile));
              } else {
                realDone();
              }
            }
          });
        }
    ]);
  }
}
exports = module.exports = spellcheck;
exports.defaults = defaults;
exports.processConfig = processConfig;
<|endoftext|>


<commit_before>var async = require('async');
var _ = require('underscore');
var path = require('path');

var config = {
    cookie:{
        secret:'ninja_face'
    },
    callback:{
        uri:'/callbacks'
    },
    iframe:{
        uri:'/iframe'
    },
    app_dir:path.join(__dirname, '..', '..'),
    port:3000,
    api:{
        protocol:'https',
        host:'api.localhost:3000'
    },
    core:{
        host:'localhost:3030',
        api:{
            protocol:'https'
        }
    }
};
var njax_util = require('njax-util');
var njax_app = function(options){

    options = _.extend(config, options)
    if(!options.core.api.host){
        options.core.api.host = 'api.' + options.core.host;
    }
    var app = njax_util.app(options);

    app.njax.config.njax_dir = path.join(__dirname, '..');

    app.njax.config.njax_tpl_dir = path.join(app.njax.config.njax_dir, 'public', 'templates');
    app.locals.partials = {};
    app.locals.partials._header = app.njax.config.njax_util_tpl_dir + '/_header';
    app.locals.partials._footer = app.njax.config.njax_util_tpl_dir + '/_footer';
    app.njax.config.tpl_dir = path.join(app.njax.config.app_dir, 'public', 'templates');

    require('./modules')(app);

    require('./routes')(app);

    return app;

}

module.exports = njax_app;<commit_msg>Code flying from the fingertips<commit_after>var async = require('async');
var _ = require('underscore');
var path = require('path');

var config = {
    cookie:{
        secret:'ninja_face'
    },
    callback:{
        uri:'/callbacks'
    },
    iframe:{
        uri:'/iframe'
    },
    app_dir:path.join(__dirname, '..', '..'),
    port:3000,
    api:{
        protocol:'https',
        host:'api.localhost:3000'
    },
    core:{
        host:'localhost:3030',
        api:{
            protocol:'https'
        }
    }
};
var njax_util = require('njax-util');
var njax_app = function(options){

    options = _.extend(config, options)
    if(!options.core.api.host){
        options.core.api.host = 'api.' + options.core.host;
    }
    var app = njax_util.app(options);

    app.njax.config.njax_dir = path.join(__dirname, '..');

    app.njax.config.njax_tpl_dir = path.join(app.njax.config.njax_dir, 'public', 'templates');
    app.locals.partials = {};
    app.locals.partials._header = app.njax.config.njax_util_tpl_dir + '/_header';
    app.locals.partials._footer = app.njax.config.njax_util_tpl_dir + '/_footer';
    app.njax.config.tpl_dir = path.join(app.njax.config.app_dir, 'public', 'templates');
	app.njax.addTemplateDir('');
	app.njax.addAssetDir(path.join(app.njax.config.njax_dir, 'public'));
	app.njax.addTemplateDir(app.njax.config.njax_tpl_dir);

    require('./modules')(app);

    require('./routes')(app);
	var _start = _.bind(app.start, app);
	app.start = _.bind(function(){
		app.njax.addTemplateDir(app.njax.config.tpl_dir);
		_start();
	}, app);
	return app;
    return app;

}

module.exports = njax_app;<|endoftext|>


<commit_before>// ==UserScript==
// @name        ExtPlug
// @description <%= description %>
// @version     <%= version %>
// @match       https://plug.dj/*
// @namespace   https://extplug.github.io/
// @downloadURL https://extplug.github.io/ExtPlug/extplug.user.js
// @updateURL   https://extplug.github.io/ExtPlug/extplug.user.js
// @grant       none
// ==/UserScript==
<commit_msg>userscript: add icon link<commit_after>// ==UserScript==
// @name        ExtPlug
// @description <%= description %>
// @version     <%= version %>
// @icon        https://extplug.com/icon.png
// @match       https://plug.dj/*
// @namespace   https://extplug.github.io/
// @downloadURL https://extplug.github.io/ExtPlug/extplug.user.js
// @updateURL   https://extplug.github.io/ExtPlug/extplug.user.js
// @grant       none
// ==/UserScript==
<|endoftext|>


<commit_before>"use strict";
exports.ISO8601_FORMAT = "yyyy-MM-dd hh:mm:ss.SSS";
exports.ISO8601_WITH_TZ_OFFSET_FORMAT = "yyyy-MM-ddThh:mm:ssO";
exports.DATETIME_FORMAT = "dd MM yyyy hh:mm:ss.SSS";
exports.ABSOLUTETIME_FORMAT = "hh:mm:ss.SSS";

function padWithZeros(vNumber, width) {
  var numAsString = vNumber + "";
  while (numAsString.length < width) {
    numAsString = "0" + numAsString;
  }
  return numAsString;
}

function addZero(vNumber) {
  return padWithZeros(vNumber, 2);
}

/**
 * Formats the TimeOffest
 * Thanks to http://www.svendtofte.com/code/date_format/
 * @private
 */
function offset(date) {
  // Difference to Greenwich time (GMT) in hours
  var os = Math.abs(date.getTimezoneOffset());
  var h = String(Math.floor(os/60));
  var m = String(os%60);
  if (h.length == 1) {
    h = "0" + h;
  }
  if (m.length == 1) {
    m = "0" + m;
  }
  return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
}

exports.asString = function(/*format,*/ date) {
  var format = exports.ISO8601_FORMAT;
  if (typeof(date) === "string") {
    format = arguments[0];
    date = arguments[1];
  }

  var vDay = addZero(date.getDate());
  var vMonth = addZero(date.getMonth()+1);
  var vYearLong = addZero(date.getFullYear());
  var vYearShort = addZero(date.getFullYear().toString().substring(2,4));
  var vYear = (format.indexOf("yyyy") > -1 ? vYearLong : vYearShort);
  var vHour  = addZero(date.getHours());
  var vMinute = addZero(date.getMinutes());
  var vSecond = addZero(date.getSeconds());
  var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
  var vTimeZone = offset(date);
  var formatted = format
    .replace(/dd/g, vDay)
    .replace(/MM/g, vMonth)
    .replace(/y{1,4}/g, vYear)
    .replace(/hh/g, vHour)
    .replace(/mm/g, vMinute)
    .replace(/ss/g, vSecond)
    .replace(/SSS/g, vMillisecond)
    .replace(/O/g, vTimeZone);
  return formatted;

};
<commit_msg>Export `asString` directly<commit_after>"use strict";

module.exports = asString
asString.asString = asString

asString.ISO8601_FORMAT = "yyyy-MM-dd hh:mm:ss.SSS";
asString.ISO8601_WITH_TZ_OFFSET_FORMAT = "yyyy-MM-ddThh:mm:ssO";
asString.DATETIME_FORMAT = "dd MM yyyy hh:mm:ss.SSS";
asString.ABSOLUTETIME_FORMAT = "hh:mm:ss.SSS";

function padWithZeros(vNumber, width) {
  var numAsString = vNumber + "";
  while (numAsString.length < width) {
    numAsString = "0" + numAsString;
  }
  return numAsString;
}

function addZero(vNumber) {
  return padWithZeros(vNumber, 2);
}

/**
 * Formats the TimeOffest
 * Thanks to http://www.svendtofte.com/code/date_format/
 * @private
 */
function offset(date) {
  // Difference to Greenwich time (GMT) in hours
  var os = Math.abs(date.getTimezoneOffset());
  var h = String(Math.floor(os/60));
  var m = String(os%60);
  if (h.length == 1) {
    h = "0" + h;
  }
  if (m.length == 1) {
    m = "0" + m;
  }
  return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
}

function asString(/*format,*/ date) {
  var format = exports.ISO8601_FORMAT;
  if (typeof(date) === "string") {
    format = arguments[0];
    date = arguments[1];
  }

  var vDay = addZero(date.getDate());
  var vMonth = addZero(date.getMonth()+1);
  var vYearLong = addZero(date.getFullYear());
  var vYearShort = addZero(date.getFullYear().toString().substring(2,4));
  var vYear = (format.indexOf("yyyy") > -1 ? vYearLong : vYearShort);
  var vHour  = addZero(date.getHours());
  var vMinute = addZero(date.getMinutes());
  var vSecond = addZero(date.getSeconds());
  var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
  var vTimeZone = offset(date);
  var formatted = format
    .replace(/dd/g, vDay)
    .replace(/MM/g, vMonth)
    .replace(/y{1,4}/g, vYear)
    .replace(/hh/g, vHour)
    .replace(/mm/g, vMinute)
    .replace(/ss/g, vSecond)
    .replace(/SSS/g, vMillisecond)
    .replace(/O/g, vTimeZone);
  return formatted;

};
<|endoftext|>


<commit_before>'use strict';

var Upspeed = function(clientId) {
    SC.initialize({
        client_id: clientId
    });
    this.currentTrackUrl = '';
    this.timerHandle = 0;
    this.playBackRate = 1;
    this.trackHowl = undefined;
    this.clientId = clientId;
}

Upspeed.prototype.playSong = function(song_url, dontPushState) {
    var regexp = /^https?:\/\/(soundcloud.com|snd.sc)\/(.*)$/;
    if(!(song_url.match(regexp) && song_url.match(regexp)[2])) return;
    if(!dontPushState) {
        var relativeUrl = song_url.match(/(http[s]?:\/\/)?([^\/\s]+\/)(.*)/)[3];
        history.pushState({songUrl: song_url}, "", "/Upspeed/" + relativeUrl);
    }
    var that = this;
    this.currentTrackUrl = song_url;
    $('#thaSpin').show();
    $('#rqurl').val(this.currentTrackUrl);

    // Get the URL
    SC.resolve(song_url).then(function(track) {
        $('#coverArt').attr('src', track.artwork_url);
        $('#songName').text(track.title);
        $('#songArtist').text(track.user.username).attr('href', track.user.permalink_url);
        $('#songSpeed').text('0%');
        $('#nowPlaying').show();
        that.process(track);
    });
}

Upspeed.prototype.process = function(track) {
    if (this.trackHowl) {
        clearInterval(this.timerHandle);
        this.playBackRate = 1;
        this.trackHowl.stop();
    }
    var that = this;
    var howl = new Howl({ src: [track.stream_url+'?client_id='+this.clientId], format:'mp3', loop: true,
    onloaderror:function(err){
        console.log(err);
        var ta = false;
    }, onload: function() { that.startPlaying(); } });
    this.trackHowl = howl;
}

Upspeed.prototype.startPlaying = function() {
    var that = this;
    this.trackHowl.play();
    $('#thaSpin').hide();
    $('#songSpeed').text('100%');
    this.timerHandle = setInterval(function(){
        that.playBackRate += 0.01;
        that.trackHowl.rate(that.playBackRate);
        $('#songSpeed').text(Math.floor(that.playBackRate * 100) + '%');
    }, 500);
}

var upspeed = new Upspeed('b2568f1fd1ca4d61013a8102c9526ae8');

if(document.location.pathname != '/Upspeed/')
{
    upspeed.playSong('https://www.soundcloud.com/'+ document.location.pathname.match(/\/Upspeed\/([^?]+)(?:\??.+)?/)[1], true);
}<commit_msg>I need to sleep...<commit_after>'use strict';

var Upspeed = function(clientId) {
    SC.initialize({
        client_id: clientId
    });
    this.currentTrackUrl = '';
    this.timerHandle = 0;
    this.playBackRate = 1;
    this.trackHowl = undefined;
    this.clientId = clientId;
}

Upspeed.prototype.playSong = function(song_url, dontPushState) {
    var regexp = /^https?:\/\/(soundcloud.com|snd.sc)\/(.*)$/;
    if(!(song_url.match(regexp) && song_url.match(regexp)[2])) return;
    if(!dontPushState) {
        var relativeUrl = song_url.match(/(http[s]?:\/\/)?([^\/\s]+\/)(.*)/)[3];
        history.pushState({songUrl: song_url}, "", "/Upspeed/" + relativeUrl);
    }
    var that = this;
    this.currentTrackUrl = song_url;
    $('#thaSpin').show();
    $('#rqurl').val(this.currentTrackUrl);

    // Get the URL
    SC.resolve(song_url).then(function(track) {
        $('#coverArt').attr('src', track.artwork_url);
        $('#songName').text(track.title);
        $('#songArtist').text(track.user.username).attr('href', track.user.permalink_url);
        $('#songSpeed').text('0%');
        $('#nowPlaying').show();
        that.process(track);
    });
}

Upspeed.prototype.process = function(track) {
    if (this.trackHowl) {
        clearInterval(this.timerHandle);
        this.playBackRate = 1;
        this.trackHowl.stop();
    }
    var that = this;
    var howl = new Howl({ src: [track.stream_url+'?client_id='+this.clientId], format:'mp3', loop: true,
    onloaderror:function(err){
        console.log(err);
        var ta = false;
    }, onload: function() { that.startPlaying(); } });
    this.trackHowl = howl;
}

Upspeed.prototype.startPlaying = function() {
    var that = this;
    this.trackHowl.play();
    $('#thaSpin').hide();
    $('#songSpeed').text('100%');
    this.timerHandle = setInterval(function(){
        that.playBackRate += 0.01;
        that.trackHowl.rate(that.playBackRate);
        $('#songSpeed').text(Math.floor(that.playBackRate * 100) + '%');
    }, 500);
}

var upspeed = new Upspeed('b2568f1fd1ca4d61013a8102c9526ae8');

if(document.location.pathname != '/Upspeed/')
{
    upspeed.playSong('https://soundcloud.com/'+ document.location.pathname.match(/\/Upspeed\/([^?]+)(?:\??.+)?/)[1], true);
}<|endoftext|>


<commit_before>var fos = require('filter-objects');
var _ = require('lodash');

function makeIsAuthorized(getRules, getAuthzdAclIds, propsToTest, defaultOptions) {

  getMatchedRules = makeGetMatchedRulesFn(propsToTest, defaultOptions);
  var ia = isAuthorized(getMatchedRules, getRules, getAuthzdAclIds);
  return ia;
}

function setOptionsOnProps(propsToTest, myDefaultOptions) {
  /* Sets all options on propsToTest
     Option value will be determined for *each option value* if that option value
     exists in (in order; ie, first found sets the value) :
      1. propsToTest by propsToTest property (eg; 'method', 'path')
      2. defaultPropOptions by propsToTest property (eg; 'method', 'path')
          (cascaded to all nested props; eq query.filter will be set to query option)
      3. myDefaultOptions parameter
      4. globalDefaultOptions

      Example:
      propsToTest = ['method','baseUrl','query.sort',{'query.filter':{regExpMatch: false}]
      myDefaultOptions = {variablesInTObj: true}

      method = {
        regExpMatch: false            // defaultPropOptions
        regExpIgnoreCase: false       // defaultPropOptions
        variablesInTObj: false        // defaultPropOptions
      }

      baseUrl = {
        regExpMatch: true             // globalDefaulOptions
        regExpIgnoreCase: true        // globalDefaulOptions
        variablesInTObj: true         // myDefaultOptions
      }

      query.sort = {
        regExpMatch: true             // defaultPropOptions
        regExpIgnoreCase: false       // defaultPropOptions
        variablesInTObj: false        // defaultPropOptions
      }

      query.sort = {
        regExpMatch: false            // propsToTest
        regExpIgnoreCase: false       // defaultPropOptions
        variablesInTObj: false        // defaultPropOptions
      }

  */

  var defaultPropOptions =
    {'method': {
       'regExpMatch': false,
       'regExpIgnoreCase': false,
       'variablesInTObj': false},
     'query': {
       'regExpMatch': true,
       'regExpIgnoreCase': false,
       'variablesInTObj': false},
    };

  // set each property option and their nested property options (eg; query.filter)
  //   to defaultPropOptions if it isn't set in propsToTest
  fos.setNestedPropOptions(propsToTest, defaultPropOptions);

  // options when no options are stipulated for a given property
  var globalDefaultOptions = {
      matchIfTObjPropMissing: true,
      matchIfPObjPropMissing: false,
      matchIfBothPropMissing: true,
      regExpMatch: true,
      regExpReverse: true,
      regExpIgnoreCase: true,
      regExpAnchorStart: true,
      regExpAnchorEnd: true,
      variables: {},
      variablesInTObj: false,
      variablesStartStr: '~',
      variablesEndStr: '#',
    };

  //set options to myDefaultOptions where properties are set to globalDefaultOptions
  //   property value if that property doesn't exist on myDefaultOptions
  // var options = setOptionsDefault(myDefaultOptions, globalDefaultOptions);
  options = {};
  _.defaultsDeep(options,myDefaultOptions, globalDefaultOptions);

  fos.setOptionsOnProps(propsToTest, options);

  return propsToTest;

}

function makeGetMatchedRulesFn(propsToTest, myDefaultOptions) {

  var defaultPropsToTest = ['path', 'baseUrl', 'method'];

  propsToTest = propsToTest && Object.keys(propsToTest).length > 0 ?
    propsToTest : defaultPropsToTest;

  setOptionsOnProps(propsToTest,myDefaultOptions);

  var getMatchedRules = fos.makeFilterFn(propsToTest, options);

  return function(req, getRules, callback) {
    getRules(function(err, rules) {
      var matchedRules = getMatchedRules(req, rules);
      return callback(err, matchedRules);
    });
  };

}

function isAuthorized(getMatchedRules, getRules, getAuthzdAclIds) {

  return function(req, callback) {
    var ids;
    var matchedRules;

    var checkAuthzdIdsWithRules = function(err) {
      // allows getMatchedRules and getAuthzdAclIds to be called in parallel
      // getMatchedRules and getAuthzdAclIds each call this function in their cb
      //    but the overall callback is only executed after both are complete
      if(err) return callback(err);
      if(ids !== undefined && matchedRules !== undefined) {
        // have both ids & rules so can now process results
        // console.log(matchedRules);
        var isAuthorized =
          matchedRules && _.isArray(matchedRules) && matchedRules.length > 0 &&
          ids && _.isArray(ids) && ids.length > 0 &&
          matchedRules.every(function(rule) {
            return ids.some(function(inCode) {
              var re = new RegExp('^'+inCode+'$');
              var idMatchesRule = re.test(rule.id);
              return idMatchesRule;
            });
        });
        if(isAuthorized) {
          return callback(null, true);
        } else {
          return callback(new Error('Not authorized'));
        }
      }
    };

    getMatchedRules(req, getRules, getMatchedRulesCb);
    getAuthzdAclIds(req, getAuthzdAclIdsCb);

    function getMatchedRulesCb(err, returnedRules) {
      matchedRules = returnedRules || null;
      checkAuthzdIdsWithRules(err);
    }

    function getAuthzdAclIdsCb(err, returnedIds) {
      ids = returnedIds || null;
      checkAuthzdIdsWithRules(err);
    }
  };
}

function setOptionsDefault(options, optionsDefault) {
  //if a property doesn't exist on options object, that property is set to
  //  the value of that property on optionsDefault
  //Allows an options object to be passed in with only those properties that
  //  are wanted to over-ride the default option properties
  if (options) {
    var optionsDefaultKeys = Object.keys(optionsDefault);
    // set each property on options to default for those that aren't set; eg,
    //  options.checkMethod = options.checkMethod || optionsDefault.checkMethod
    for (var i = optionsDefaultKeys.length - 1; i >= 0; i--) {
      options[optionsDefaultKeys[i]] =
        options.hasOwnProperty(optionsDefaultKeys[i]) ?
          options[optionsDefaultKeys[i]] :
          optionsDefault[optionsDefaultKeys[i]];
    }
  } else {
    options = optionsDefault;
  }

  return options;
}

function getPropsFromRules(rules, keysToIgnore) {
  // return an array of strings that are the keys of rules objects
  // in dot notation form.  Do not return any strings that are in keysToIgnore
  // keysToIgnore = array of strings.
  // eg; rules = [{method:'POST', query:{sort:'ASC'}},'pathname':'/api/blah']
  //   would return ['method', 'query.sort', 'pathname']
  keysToIgnore = keysToIgnore && _.isArray(keysToIgnore) ? keysToIgnore : [];
  // always ignore 'id' property which is reserved property name
  keysToIgnore.push('id');
  var props = getKeysFromArrayOfObjs(rules, keysToIgnore);
  return props;
}

function getKeysFromArrayOfObjs(arrayOfObjs, keysToIgnore) {
  // returns an array of strings that is a unique list of object keys
  //   in dot notation across all objects in an array
  // keysToIgnore is an optional.  Is an array of strings.
  //   Any key in arrayOfObjs will not be included in return array
  //   if that string is in keysToIgnore
  arrayOfObjs = arrayOfObjs ? arrayOfObjs : [];
  arrayOfObjs = _.isArray(arrayOfObjs) ? arrayOfObjs : [arrayOfObjs];

  var keys = [];
  // get all props being tested in rules and de-dupe
  arrayOfObjs.forEach(function(obj){
    // var ps = fos.getObjectProperties(rule);
    var objKeys = fos.getObjectProperties(obj);
    keys = keys.concat(objKeys);
  });

  keys = uniq(keys);

  keys = _.difference(keys,keysToIgnore);

  return keys;

  function uniq(a) {
      var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

      return a.filter(function(item) {
          var type = typeof item;
          if(type in prims)
              return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
          else
              return objs.indexOf(item) >= 0 ? false : objs.push(item);
      });
  }

} // end of getKeysFromArrayOfObjs

module.exports = {
  makeGetMatchedRulesFn: makeGetMatchedRulesFn,
  makeIsAuthorized: makeIsAuthorized,
  getPropsFromRules: getPropsFromRules,
  setOptionsOnProps: setOptionsOnProps
};
<commit_msg>Minor - update code function names for readability<commit_after>var fos = require('filter-objects');
var _ = require('lodash');

function makeIsAuthorized(getAclRules, getAuthzdAclIds, propsToTest, defaultOptions) {

  getMatchedRules = makeGetMatchedRulesFn(propsToTest, defaultOptions);
  var ia = isAuthorized(getMatchedRules, getAclRules, getAuthzdAclIds);
  return ia;
}

function setOptionsOnProps(propsToTest, myDefaultOptions) {
  /* Sets all options on propsToTest
     Option value will be determined for *each option value* if that option value
     exists in (in order; ie, first found sets the value) :
      1. propsToTest by propsToTest property (eg; 'method', 'path')
      2. defaultPropOptions by propsToTest property (eg; 'method', 'path')
          (cascaded to all nested props; eq query.filter will be set to query option)
      3. myDefaultOptions parameter
      4. globalDefaultOptions

      Example:
      propsToTest = ['method','baseUrl','query.sort',{'query.filter':{regExpMatch: false}]
      myDefaultOptions = {variablesInTObj: true}

      method = {
        regExpMatch: false            // defaultPropOptions
        regExpIgnoreCase: false       // defaultPropOptions
        variablesInTObj: false        // defaultPropOptions
      }

      baseUrl = {
        regExpMatch: true             // globalDefaulOptions
        regExpIgnoreCase: true        // globalDefaulOptions
        variablesInTObj: true         // myDefaultOptions
      }

      query.sort = {
        regExpMatch: true             // defaultPropOptions
        regExpIgnoreCase: false       // defaultPropOptions
        variablesInTObj: false        // defaultPropOptions
      }

      query.sort = {
        regExpMatch: false            // propsToTest
        regExpIgnoreCase: false       // defaultPropOptions
        variablesInTObj: false        // defaultPropOptions
      }

  */

  var defaultPropOptions =
    {'method': {
       'regExpMatch': false,
       'regExpIgnoreCase': false,
       'variablesInTObj': false},
     'query': {
       'regExpMatch': true,
       'regExpIgnoreCase': false,
       'variablesInTObj': false},
    };

  // set each property option and their nested property options (eg; query.filter)
  //   to defaultPropOptions if it isn't set in propsToTest
  fos.setNestedPropOptions(propsToTest, defaultPropOptions);

  // options when no options are stipulated for a given property
  var globalDefaultOptions = {
      matchIfTObjPropMissing: true,
      matchIfPObjPropMissing: false,
      matchIfBothPropMissing: true,
      regExpMatch: true,
      regExpReverse: true,
      regExpIgnoreCase: true,
      regExpAnchorStart: true,
      regExpAnchorEnd: true,
      variables: {},
      variablesInTObj: false,
      variablesStartStr: '~',
      variablesEndStr: '#',
    };

  //set options to myDefaultOptions where properties are set to globalDefaultOptions
  //   property value if that property doesn't exist on myDefaultOptions
  // var options = setOptionsDefault(myDefaultOptions, globalDefaultOptions);
  options = {};
  _.defaultsDeep(options,myDefaultOptions, globalDefaultOptions);

  fos.setOptionsOnProps(propsToTest, options);

  return propsToTest;

}

function makeGetMatchedRulesFn(propsToTest, myDefaultOptions) {

  var defaultPropsToTest = ['path', 'baseUrl', 'method'];

  propsToTest = propsToTest && Object.keys(propsToTest).length > 0 ?
    propsToTest : defaultPropsToTest;

  setOptionsOnProps(propsToTest,myDefaultOptions);

  var filterRules = fos.makeFilterFn(propsToTest, options);

  return function(req, getAclRules, callback) {
    getAclRules(function(err, rules) {
      var matchedRules = filterRules(req, rules);
      return callback(err, matchedRules);
    });
  };

}

function isAuthorized(getMatchedRules, getAclRules, getAuthzdAclIds) {

  return function(req, callback) {
    var ids;
    var matchedRules;

    var checkAuthzdIdsWithRules = function(err) {
      // allows getMatchedRules and getAuthzdAclIds to be called in parallel
      // getMatchedRules and getAuthzdAclIds each call this function in their cb
      //    but the overall callback is only executed after both are complete
      if(err) return callback(err);
      if(ids !== undefined && matchedRules !== undefined) {
        // have both ids & rules so can now process results
        // console.log(matchedRules);
        var isAuthorized =
          matchedRules && _.isArray(matchedRules) && matchedRules.length > 0 &&
          ids && _.isArray(ids) && ids.length > 0 &&
          matchedRules.every(function(rule) {
            return ids.some(function(inCode) {
              var re = new RegExp('^'+inCode+'$');
              var idMatchesRule = re.test(rule.id);
              return idMatchesRule;
            });
        });
        if(isAuthorized) {
          return callback(null, true);
        } else {
          return callback(new Error('Not authorized'));
        }
      }
    };

    getMatchedRules(req, getAclRules, getMatchedRulesCb);
    getAuthzdAclIds(req, getAuthzdAclIdsCb);

    function getMatchedRulesCb(err, returnedRules) {
      matchedRules = returnedRules || null;
      checkAuthzdIdsWithRules(err);
    }

    function getAuthzdAclIdsCb(err, returnedIds) {
      ids = returnedIds || null;
      checkAuthzdIdsWithRules(err);
    }
  };
}

function setOptionsDefault(options, optionsDefault) {
  //if a property doesn't exist on options object, that property is set to
  //  the value of that property on optionsDefault
  //Allows an options object to be passed in with only those properties that
  //  are wanted to over-ride the default option properties
  if (options) {
    var optionsDefaultKeys = Object.keys(optionsDefault);
    // set each property on options to default for those that aren't set; eg,
    //  options.checkMethod = options.checkMethod || optionsDefault.checkMethod
    for (var i = optionsDefaultKeys.length - 1; i >= 0; i--) {
      options[optionsDefaultKeys[i]] =
        options.hasOwnProperty(optionsDefaultKeys[i]) ?
          options[optionsDefaultKeys[i]] :
          optionsDefault[optionsDefaultKeys[i]];
    }
  } else {
    options = optionsDefault;
  }

  return options;
}

function getPropsFromRules(rules, keysToIgnore) {
  // return an array of strings that are the keys of rules objects
  // in dot notation form.  Do not return any strings that are in keysToIgnore
  // keysToIgnore = array of strings.
  // eg; rules = [{method:'POST', query:{sort:'ASC'}},'pathname':'/api/blah']
  //   would return ['method', 'query.sort', 'pathname']
  keysToIgnore = keysToIgnore && _.isArray(keysToIgnore) ? keysToIgnore : [];
  // always ignore 'id' property which is reserved property name
  keysToIgnore.push('id');
  var props = getKeysFromArrayOfObjs(rules, keysToIgnore);
  return props;
}

function getKeysFromArrayOfObjs(arrayOfObjs, keysToIgnore) {
  // returns an array of strings that is a unique list of object keys
  //   in dot notation across all objects in an array
  // keysToIgnore is an optional.  Is an array of strings.
  //   Any key in arrayOfObjs will not be included in return array
  //   if that string is in keysToIgnore
  arrayOfObjs = arrayOfObjs ? arrayOfObjs : [];
  arrayOfObjs = _.isArray(arrayOfObjs) ? arrayOfObjs : [arrayOfObjs];

  var keys = [];
  // get all props being tested in rules and de-dupe
  arrayOfObjs.forEach(function(obj){
    // var ps = fos.getObjectProperties(rule);
    var objKeys = fos.getObjectProperties(obj);
    keys = keys.concat(objKeys);
  });

  keys = uniq(keys);

  keys = _.difference(keys,keysToIgnore);

  return keys;

  function uniq(a) {
      var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

      return a.filter(function(item) {
          var type = typeof item;
          if(type in prims)
              return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
          else
              return objs.indexOf(item) >= 0 ? false : objs.push(item);
      });
  }

} // end of getKeysFromArrayOfObjs

module.exports = {
  makeGetMatchedRulesFn: makeGetMatchedRulesFn,
  makeIsAuthorized: makeIsAuthorized,
  getPropsFromRules: getPropsFromRules,
  setOptionsOnProps: setOptionsOnProps
};
<|endoftext|>


<commit_before>/**
 *
 * sends auth token to uppy client
 */
const tokenService = require('../helpers/jwt')
const parseUrl = require('url').parse
const { hasMatch, sanitizeHtml } = require('../helpers/utils')
const oAuthState = require('../helpers/oauth-state')

/**
 *
 * @param {object} req
 * @param {object} res
 * @param {function} next
 */
module.exports = function sendToken (req, res, next) {
  const uppyAuthToken = req.uppy.authToken
  // add the token to cookies for thumbnail/image requests
  tokenService.addToCookies(res, uppyAuthToken, req.uppy.options, req.uppy.provider.authProvider)

  const state = (req.session.grant || {}).state
  if (state) {
    const origin = oAuthState.getFromState(state, 'origin', req.uppy.options.secret)
    const clientVersion = oAuthState.getFromState(
      state,
      'clientVersion',
      req.uppy.options.secret
    )
    const allowedClients = req.uppy.options.clients
    // if no preset clients then allow any client
    if (!allowedClients || hasMatch(origin, allowedClients) || hasMatch(parseUrl(origin).host, allowedClients)) {
      return res.send(clientVersion ? htmlContent(uppyAuthToken, origin) : oldHtmlContent(uppyAuthToken, origin))
    }
  }
  next()
}

/**
 *
 * @param {string} token uppy auth token
 * @param {string} origin url string
 */
const htmlContent = (token, origin) => {
  return `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
}

/**
 * @todo remove this function in next major release
 * @param {string} token uppy auth token
 * @param {string} origin url string
 */
const oldHtmlContent = (token, origin) => {
  return `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
}
<commit_msg>companion: add todo<commit_after>/**
 *
 * sends auth token to uppy client
 */
const tokenService = require('../helpers/jwt')
const parseUrl = require('url').parse
const { hasMatch, sanitizeHtml } = require('../helpers/utils')
const oAuthState = require('../helpers/oauth-state')

/**
 *
 * @param {object} req
 * @param {object} res
 * @param {function} next
 */
module.exports = function sendToken (req, res, next) {
  const uppyAuthToken = req.uppy.authToken
  // add the token to cookies for thumbnail/image requests
  tokenService.addToCookies(res, uppyAuthToken, req.uppy.options, req.uppy.provider.authProvider)

  const state = (req.session.grant || {}).state
  if (state) {
    const origin = oAuthState.getFromState(state, 'origin', req.uppy.options.secret)
    const clientVersion = oAuthState.getFromState(
      state,
      'clientVersion',
      req.uppy.options.secret
    )
    const allowedClients = req.uppy.options.clients
    // if no preset clients then allow any client
    if (!allowedClients || hasMatch(origin, allowedClients) || hasMatch(parseUrl(origin).host, allowedClients)) {
      // @todo do a more secure client version check, see https://www.npmjs.com/package/semver
      return res.send(clientVersion ? htmlContent(uppyAuthToken, origin) : oldHtmlContent(uppyAuthToken, origin))
    }
  }
  next()
}

/**
 *
 * @param {string} token uppy auth token
 * @param {string} origin url string
 */
const htmlContent = (token, origin) => {
  return `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
}

/**
 * @todo remove this function in next major release
 * @param {string} token uppy auth token
 * @param {string} origin url string
 */
const oldHtmlContent = (token, origin) => {
  return `
    <!DOCTYPE html>

        <meta charset="utf-8" />

    `
}
<|endoftext|>


<commit_before>var btc = require('blockchain.info/exchange');
var stats = require('blockchain.info/statistics');
var apiCode = require('./apiCode');

exports.getCurrentPrice = (req, res) => {
  btc.getTicker({ currency: 'USD', apiCode: apiCode ? apiCode : null })
    .then((resp) => {
      res.send(resp);
    });
};

exports.getHistoricalPriceChart = (req, res) => {
  stats.getChartData('market-price', { timespan: req.query.timespan, apiCode: apiCode ? apiCode : null })
    .then((resp) => {
      res.send(resp);
  })
};<commit_msg>documenting endpoints<commit_after>// dependencies
var btc = require('blockchain.info/exchange');
var stats = require('blockchain.info/statistics');
var apiCode = require('./apiCode');

// fetches current BTC price in USD
// example request ==> https://api.blockchain.info/ticker
exports.getCurrentPrice = (req, res) => {
  btc.getTicker({ currency: 'USD', apiCode: apiCode ? apiCode : null })
    .then((resp) => {
      res.send(resp);
    });
};

// fetches historical BTC with given timespan
// example timespan's ==> '14d' (14 days), '90d' (90 days), '1y' (1 year), 'all' (all time)
// example request ==> https://api.blockchain.info/charts/market-price?timespan=1y
exports.getHistoricalPriceChart = (req, res) => {
  stats.getChartData('market-price', { timespan: req.query.timespan, apiCode: apiCode ? apiCode : null })
    .then((resp) => {
      res.send(resp);
  })
};<|endoftext|>


<commit_before>/* global RTCPeerConnection */
// jshint unused:false

var cordova = window.cordova;

// Expose WebRTC Globals
if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
  cordova.plugins.iosrtc.registerGlobals();
  //cordova.plugins.iosrtc.debug.disable('*', true);
  //cordova.plugins.iosrtc.debug.enable('*', true);
  cordova.plugins.iosrtc.turnOnSpeaker(true);
  cordova.plugins.iosrtc.requestPermission(true, true, function (result) {
    console.log('requestPermission.result', result);
  });
}

//
// Container
//

document.body.innerHTML = "";
var appContainer = document.body;

//
// getUserMedia
//

var localStream;
var localVideoEl;
function TestGetUserMedia() {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (localStream) {

    // Close local Stream if already connected
    localStream.stop();

    // Clear local video element
    if (localVideoEl.srcObject) {
      localVideoEl.srcObject = null;
      if (localVideoEl.parentNode === appContainer) {
        appContainer.removeChild(localVideoEl);
      }
    }
  }

  localVideoEl = document.createElement('video');
  localVideoEl.setAttribute('autoplay', 'autoplay');
  localVideoEl.setAttribute('playsinline', 'playsinline');

  // Note: Test CSS positioning
  localVideoEl.style.backgroundColor = 'purple'; // Cause zIndex - 1 failure
  localVideoEl.style.position = 'absolute';
  localVideoEl.style.top = 0;
  localVideoEl.style.left = 0;
  localVideoEl.style.width = "100px";
  localVideoEl.style.height = "100px";
  localVideoEl.style.transform = "scaleX(-1)";
  appContainer.appendChild(localVideoEl);

  navigator.mediaDevices.enumerateDevices().then(function (devices) {
      console.log('getMediaDevices.ok', devices);
      devices.forEach(function (device, idx) {
        console.log('getMediaDevices.devices', idx, device.label, device.kind, device.deviceId);
      });
  }, function (err) {
      console.log('getMediaDevices.err', err);
  });

  return navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
    /*
    video: {
      // Test Back Camera
      //deviceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      //sourceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      deviceId: {
        exact: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      }
    },
    audio: {
      exact: 'Built-In Microphone'
    }*/
  }).then(function (stream) {

    console.log('getUserMedia.stream', stream);
    console.log('getUserMedia.stream.getTracks', stream.getTracks());

    // Note: Expose for debug
    localStream = stream;

    // Attach local stream to video element
    localVideoEl.srcObject = localStream;

    // Test HTML over Video element
    TestPluginMediaStreamRenderer(localVideoEl);

    return localStream;

  }).catch(function (err) {
    console.log('getUserMediaError', err, err.stack);
  });
}

var useAnimateVideo = false;
function TestPluginMediaStreamRenderer(localVideoEl) {

  // Animate video position
  var currentPosition = {
    x: 0,
    y: 0
  };

  var animateTimer;
  function animateVideo() {

    currentPosition.x = currentPosition.x < (window.innerWidth - parseInt(localVideoEl.style.width, 10)) ? currentPosition.x + 1 : 0;
    currentPosition.y = currentPosition.y < (window.innerHeight - parseInt(localVideoEl.style.height, 10)) ? currentPosition.y + 1 : 0;

    localVideoEl.style.top = currentPosition.y + 'px';
    localVideoEl.style.left = currentPosition.x + 'px';

    if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
      //cordova.plugins.iosrtc.refreshVideos();
    }

    return (animateTimer = requestAnimationFrame(animateVideo));
  }

  if (useAnimateVideo) {
    animateTimer = animateVideo();
  }

  //
  // Test Video behind Element
  //

  // Note: Test HTML over video requiring Z-Index -1 and transparent <html> and <body>
  document.body.style.background = "transparent";
  document.documentElement.style.background = "transparent";
  localVideoEl.style.backgroundColor = '';
  localVideoEl.style.zIndex = -1;

  var overEl = document.createElement('button');
  overEl.style.backgroundColor = 'red';
  overEl.style.position = 'absolute';
  overEl.style.left = 0;
  overEl.style.top = 0;
  overEl.style.width = "100px";
  overEl.style.height = "100px";

  overEl.addEventListener('click', function () {
    overEl.style.backgroundColor = overEl.style.backgroundColor === 'red' ? 'green' : 'red';

    if (overEl.style.backgroundColor === 'red') {
      animateTimer = animateVideo();
    } else {
      cancelAnimationFrame(animateTimer);
    }
  });

  appContainer.appendChild(overEl);

  overEl.style.left = ((window.innerWidth / 2)  - parseInt(overEl.style.width, 10)) + 'px';
  overEl.style.top  = ((window.innerHeight / 2) - parseInt(overEl.style.height, 10)) + 'px';

}

//
// Test RTCPeerConnection
//

var peerConnectionConfig = {
    offerToReceiveVideo: true,
    //iceTransportPolicy: 'relay',
    sdpSemantics: 'unified-plan',
    offerToReceiveAudio: true,
    //sdpSemantics: 'plan-b',
    //bundlePolicy: 'max-compat',
    //rtcpMuxPolicy: 'negotiate',
    iceServers: [
        {
            url: "stun:stun.stunprotocol.org"
        }
    ]
};
var pc1 = new RTCPeerConnection(peerConnectionConfig),
    pc2 = new RTCPeerConnection(peerConnectionConfig);

var sendChannel, receiveChannel;
function TestPeerDataChannel() {
  sendChannel = pc1.createDataChannel("sendChannel");

  sendChannel.addEventListener('message',  function (event) {
    console.log('sendChannel.message', event, event.data);
  });

  sendChannel.addEventListener('open', function (event) {
      console.log('sendChannel.open', event);
      sendChannel.send("data message Date: " + new Date());
  });

  sendChannel.addEventListener('close', function (event) {
      console.log('sendChannel.close', event);
  });

  pc2.addEventListener('datachannel', function (event) {
    receiveChannel = event.channel;
    receiveChannel.addEventListener('message',  function (event) {
      console.log('receiveChannel.message', event, event.data);
    });
    receiveChannel.addEventListener('open',  function (event) {
      console.log('receiveChannel.open', event);
    });
    receiveChannel.addEventListener('close',  function (event) {
      console.log('receiveChannel.close', event);
    });
  });
}

var peerVideoEl;
var peerStream;
function TestRTCPeerConnection(localStream) {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (peerStream) {

    // Close peer Stream if already connected
    peerStream.stop();

    // Clear peer video element
    if (peerVideoEl.srcObject) {
      peerVideoEl.srcObject = null;
      appContainer.removeChild(peerVideoEl);
    }

    // Disconnect peer
    if (pc1.iceConnectionState === 'completed') {
      pc1.close();

      // Current you cannot reuse previous RTCPeerConnection
      pc1 = new RTCPeerConnection();
      pc2 = new RTCPeerConnection();
    }
  }

  // Note: Deprecated but supported
  //pc1.addStream(localStream);

  // Note: Deprecated Test removeStream
  // pc1.removeStream(pc1.getLocalStreams()[0])

  // Note: Chrome Version 77.0.3865.90 (Official Build) still
  // require to use addStream without webrtc-adapter.
  localStream.getTracks().forEach(function (track) {
    console.log('addTrack', track);
    pc1.addTrack(track);
  });

  function onAddIceCandidate(pc, can) {
    console.log('addIceCandidate', pc, can);
    return can && pc.addIceCandidate(can).catch(function (err) {
      console.log('addIceCandidateError', err);
    });
  }

  pc1.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc2, e.candidate);
  });

  pc2.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc1, e.candidate);
  });

  pc2.addEventListener('track', function (e) {
    console.log('pc2.track', e);
  });

  pc2.addEventListener('removetrack', function (e) {
    console.log('pc2.removeTrack', e);
  });

  pc2.addEventListener('addstream', function (e) {
    console.log('pc2.addStream', e);
    peerVideoEl = document.createElement('video');
    peerVideoEl.setAttribute('autoplay', 'autoplay');
    peerVideoEl.setAttribute('playsinline', 'playsinline');

    // Note: Test Object-fix
    peerVideoEl.style.objectFit = "cover";

    // Note: Test CSS positioning
    peerVideoEl.style.backgroundColor = 'blue';
    peerVideoEl.style.position = 'fixed';
    peerVideoEl.style.width = "100px";
    peerVideoEl.style.height = "100px";
    peerVideoEl.style.top = 0;
    peerVideoEl.style.left = (window.innerWidth - parseInt(peerVideoEl.style.width, 10)) + 'px';
    appContainer.appendChild(peerVideoEl);

    // Note: Expose for debug
    peerStream = e.stream;

    // Attach peer stream to video element
    peerVideoEl.srcObject = peerStream;
  });

  pc1.addEventListener('iceconnectionstatechange', function (e) {
    console.log('pc1.iceConnectionState', e, pc1.iceConnectionState);

    if (pc1.iceConnectionState === 'completed') {
      console.log('pc1.getSenders', pc1.getSenders());
      console.log('pc2.getReceivers', pc2.getReceivers());
    }
  });

  pc1.addEventListener('icegatheringstatechange', function (e) {
    console.log('pc1.iceGatheringStateChange', e);
  });

  // https://stackoverflow.com/questions/48963787/failed-to-set-local-answer-sdp-called-in-wrong-state-kstable
  // https://bugs.chromium.org/p/chromium/issues/detail?id=740501
  var isNegotiating = false;
  pc1.addEventListener('signalingstatechange', function (e) {
    console.log('pc1.signalingstatechange',  e);
    isNegotiating = (pc1.signalingState !== "stable");
  });

  pc1.addEventListener('negotiationneeded', function (e) {

    if (isNegotiating) {
      // Should not trigger on iosrtc cause of PluginRTCPeerConnection.swift fix
      console.log("pc1.negotiatioNeeded", "SKIP nested negotiations");
      return;
    }
    isNegotiating = true;

    console.log('pc1.negotiatioNeeded', e);

    return pc1.createOffer().then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc1.setLocalDescription', desc);
      return pc1.setLocalDescription(desc);
    }).then(function () {
      var desc = {
        type: pc1.localDescription.type,
        sdp: pc1.localDescription.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setRemoteDescription(desc);
    }).then(function () {
      console.log('pc2.createAnswer');
      return pc2.createAnswer();
    }).then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setLocalDescription(d);
    }).then(function () {
      var desc = {
        type: pc2.localDescription.type,
        sdp: pc2.localDescription.sdp
      };
      console.log('pc1.setRemoteDescription', desc);
      return pc1.setRemoteDescription(desc);
    }).then(function () {
      TestMediaRenderCatpure(peerVideoEl);
      TestMediaRenderCatpure(localVideoEl);
      TestPeerDataChannel();
    }).catch(function (err) {
      console.log('pc1.createOfferError', err);
    });
  });
}

var canvasEl;
function TestMediaRenderCatpure(videoEl) {

  if (!canvasEl) {
    canvasEl = document.createElement('canvas');
  }

  var ctx = canvasEl.getContext("2d");
  canvasEl.style.position = 'absolute';
  canvasEl.style.left = 0;
  canvasEl.style.bottom = 0;
  appContainer.appendChild(canvasEl);
  var image = new Image();
  image.addEventListener('load', function() {
    canvasEl.width = image.width;
    canvasEl.height = image.height;
    ctx.drawImage(image, 0, 0);
  });
  localVideoEl.render.save(function (data) {
    image.src = "data:image/jpg;base64," + data;
  });
}

var testMediaRenderCatpureAnimateFrame;
function TestMediaRenderCatpureAnimate() {
  TestMediaRenderCatpure(peerVideoEl);
  testMediaRenderCatpureAnimateFrame = requestAnimationFrame(TestMediaRenderCatpureAnimate);
}

// Disabled to avoid confusion with remoteStream
var cloneStream;
var cloneVideoEl;
function TestPluginMediaStreamClone(mediaStream) {
  cloneVideoEl = document.createElement('video');
  cloneVideoEl.setAttribute('autoplay', 'autoplay');
  cloneVideoEl.setAttribute('playsinline', 'playsinline');
  cloneVideoEl.style.backgroundColor = 'purple';
  cloneVideoEl.style.position = 'absolute';
  cloneVideoEl.style.bottom = 0;
  cloneVideoEl.style.left = 0;
  cloneVideoEl.style.width = "100px";
  cloneVideoEl.style.height = "100px";
  cloneVideoEl.style.transform = "scaleX(-1)";

  cloneStream = mediaStream.clone();
  cloneVideoEl.srcObject = cloneStream;

  appContainer.appendChild(cloneVideoEl);
}

var useWebRTCAdapter = false;

// Expose webrtc-adapter
if (useWebRTCAdapter && typeof window.adapter === 'undefined') {

    // load adapter.js
    var version = 'latest';
    var script = document.createElement("script");
    script.type = "text/javascript";
    //script.src = "adapter-latest.js";
    script.src = "https://webrtc.github.io/adapter/adapter-" + version + ".js";
    script.async = false;
    document.getElementsByTagName("head")[0].appendChild(script);
    script.addEventListener('load', function () {
      console.log('useWebRTCAdapter.loaded', script.src);
      TestGetUserMedia().then(function (localStream) {
        TestRTCPeerConnection(localStream);
      });
    });
} else {
  TestGetUserMedia().then(function (localStream) {
    TestRTCPeerConnection(localStream);
  });
}

<commit_msg>Update renderer-and-libwebrtc-tests.js<commit_after>/* global RTCPeerConnection */
// jshint unused:false

var cordova = window.cordova;

// Expose WebRTC Globals
if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
  cordova.plugins.iosrtc.registerGlobals();
  //cordova.plugins.iosrtc.debug.disable('*', true);
  //cordova.plugins.iosrtc.debug.enable('*', true);
  cordova.plugins.iosrtc.turnOnSpeaker(true);
  cordova.plugins.iosrtc.requestPermission(true, true, function (result) {
    console.log('requestPermission.result', result);
  });
}

//
// Container
//

document.body.innerHTML = "";
var appContainer = document.body;

//
// getUserMedia
//

var localStream;
var localVideoEl;
function TestGetUserMedia() {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (localStream) {

    // Close local Stream if already connected
    localStream.stop();

    // Clear local video element
    if (localVideoEl.srcObject) {
      localVideoEl.srcObject = null;
      if (localVideoEl.parentNode === appContainer) {
        appContainer.removeChild(localVideoEl);
      }
    }
  }

  localVideoEl = document.createElement('video');
  localVideoEl.setAttribute('autoplay', 'autoplay');
  localVideoEl.setAttribute('playsinline', 'playsinline');

  // Note: Test CSS positioning
  localVideoEl.style.backgroundColor = 'purple'; // Cause zIndex - 1 failure
  localVideoEl.style.position = 'absolute';
  localVideoEl.style.top = 0;
  localVideoEl.style.left = 0;
  localVideoEl.style.width = "100px";
  localVideoEl.style.height = "100px";
  localVideoEl.style.transform = "scaleX(-1)";
  appContainer.appendChild(localVideoEl);

  navigator.mediaDevices.enumerateDevices().then(function (devices) {
      console.log('getMediaDevices.ok', devices);
      devices.forEach(function (device, idx) {
        console.log('getMediaDevices.devices', idx, device.label, device.kind, device.deviceId);
      });
  }, function (err) {
      console.log('getMediaDevices.err', err);
  });

  return navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
    /*
    video: {
      // Test Back Camera
      //deviceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      //sourceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      deviceId: {
        exact: 'com.apple.avfoundation.avcapturedevice.built-in_video:0'
      }
    },
    audio: {
      exact: 'Built-In Microphone'
    }*/
  }).then(function (stream) {

    console.log('getUserMedia.stream', stream);
    console.log('getUserMedia.stream.getTracks', stream.getTracks());

    // Note: Expose for debug
    localStream = stream;

    // Attach local stream to video element
    localVideoEl.srcObject = localStream;

    // Test HTML over Video element
    TestPluginMediaStreamRenderer(localVideoEl);

    return localStream;

  }).catch(function (err) {
    console.log('getUserMediaError', err, err.stack);
  });
}

var useAnimateVideo = false;
function TestPluginMediaStreamRenderer(localVideoEl) {

  // Animate video position
  var currentPosition = {
    x: 0,
    y: 0
  };

  var animateTimer;
  function animateVideo() {

    currentPosition.x = currentPosition.x < (window.innerWidth - parseInt(localVideoEl.style.width, 10)) ? currentPosition.x + 1 : 0;
    currentPosition.y = currentPosition.y < (window.innerHeight - parseInt(localVideoEl.style.height, 10)) ? currentPosition.y + 1 : 0;

    localVideoEl.style.top = currentPosition.y + 'px';
    localVideoEl.style.left = currentPosition.x + 'px';

    if (cordova && cordova.plugins && cordova.plugins.iosrtc) {
      //cordova.plugins.iosrtc.refreshVideos();
    }

    return (animateTimer = requestAnimationFrame(animateVideo));
  }

  if (useAnimateVideo) {
    animateTimer = animateVideo();
  }

  //
  // Test Video behind Element
  //

  // Note: Test HTML over video requiring Z-Index -1 and transparent <html> and <body>
  document.body.style.background = "transparent";
  document.documentElement.style.background = "transparent";
  localVideoEl.style.backgroundColor = '';
  localVideoEl.style.zIndex = -1;

  var overEl = document.createElement('button');
  overEl.style.backgroundColor = 'red';
  overEl.style.position = 'absolute';
  overEl.style.left = 0;
  overEl.style.top = 0;
  overEl.style.width = "100px";
  overEl.style.height = "100px";

  overEl.addEventListener('click', function () {
    overEl.style.backgroundColor = overEl.style.backgroundColor === 'red' ? 'green' : 'red';

    if (overEl.style.backgroundColor === 'red') {
      animateTimer = animateVideo();
    } else {
      cancelAnimationFrame(animateTimer);
    }
  });

  appContainer.appendChild(overEl);

  overEl.style.left = ((window.innerWidth / 2)  - parseInt(overEl.style.width, 10)) + 'px';
  overEl.style.top  = ((window.innerHeight / 2) - parseInt(overEl.style.height, 10)) + 'px';

}

//
// Test RTCPeerConnection
//

var peerConnectionConfig = {
    offerToReceiveVideo: true,
    //iceTransportPolicy: 'relay',
    sdpSemantics: 'unified-plan',
    offerToReceiveAudio: true,
    //sdpSemantics: 'plan-b',
    //bundlePolicy: 'max-compat',
    //rtcpMuxPolicy: 'negotiate',
    iceServers: [
        {
            url: "stun:stun.stunprotocol.org"
        }
    ]
};
var pc1 = new RTCPeerConnection(peerConnectionConfig),
    pc2 = new RTCPeerConnection(peerConnectionConfig);

var sendChannel, receiveChannel;
function TestPeerDataChannel() {
  sendChannel = pc1.createDataChannel("sendChannel");

  sendChannel.addEventListener('message',  function (event) {
    console.log('sendChannel.message', event, event.data);
  });

  sendChannel.addEventListener('open', function (event) {
      console.log('sendChannel.open', event);
      sendChannel.send("data message Date: " + new Date());
  });

  sendChannel.addEventListener('close', function (event) {
      console.log('sendChannel.close', event);
  });

  pc2.addEventListener('datachannel', function (event) {
    receiveChannel = event.channel;
    receiveChannel.addEventListener('message',  function (event) {
      console.log('receiveChannel.message', event, event.data);
    });
    receiveChannel.addEventListener('open',  function (event) {
      console.log('receiveChannel.open', event);
    });
    receiveChannel.addEventListener('close',  function (event) {
      console.log('receiveChannel.close', event);
    });
  });
}

var peerVideoEl;
var peerStream;
function TestRTCPeerConnection(localStream) {

  // Note: Support for Multiple TestRTCPeerConnection calls
  if (peerStream) {

    // Close peer Stream if already connected
    peerStream.stop();

    // Clear peer video element
    if (peerVideoEl.srcObject) {
      peerVideoEl.srcObject = null;
      appContainer.removeChild(peerVideoEl);
    }

    // Disconnect peer
    if (pc1.iceConnectionState === 'completed') {
      pc1.close();

      // Current you cannot reuse previous RTCPeerConnection
      pc1 = new RTCPeerConnection();
      pc2 = new RTCPeerConnection();
    }
  }

  // Note: Deprecated but supported
  //pc1.addStream(localStream);

  // Note: Deprecated Test removeStream
  // pc1.removeStream(pc1.getLocalStreams()[0])

  // Note: Chrome Version 77.0.3865.90 (Official Build) still
  // require to use addStream without webrtc-adapter.
  localStream.getTracks().forEach(function (track) {
    console.log('addTrack', track);
    pc1.addTrack(track);
  });

  function onAddIceCandidate(pc, can) {
    console.log('addIceCandidate', pc, can);
    return can && pc.addIceCandidate(can).catch(function (err) {
      console.log('addIceCandidateError', err);
    });
  }

  pc1.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc2, e.candidate);
  });

  pc2.addEventListener('icecandidate', function (e) {
    onAddIceCandidate(pc1, e.candidate);
  });

  pc2.addEventListener('track', function (e) {
    console.log('pc2.track', e);
  });

  pc2.addEventListener('removestream', function (e) {
    console.log('pc2.removeStream', e);
  });

  pc2.addEventListener('addstream', function (e) {
    console.log('pc2.addStream', e);
    peerVideoEl = document.createElement('video');
    peerVideoEl.setAttribute('autoplay', 'autoplay');
    peerVideoEl.setAttribute('playsinline', 'playsinline');

    // Note: Test Object-fix
    peerVideoEl.style.objectFit = "cover";

    // Note: Test CSS positioning
    peerVideoEl.style.backgroundColor = 'blue';
    peerVideoEl.style.position = 'fixed';
    peerVideoEl.style.width = "100px";
    peerVideoEl.style.height = "100px";
    peerVideoEl.style.top = 0;
    peerVideoEl.style.left = (window.innerWidth - parseInt(peerVideoEl.style.width, 10)) + 'px';
    appContainer.appendChild(peerVideoEl);

    // Note: Expose for debug
    peerStream = e.stream;

    // Attach peer stream to video element
    peerVideoEl.srcObject = peerStream;
  });

  pc1.addEventListener('iceconnectionstatechange', function (e) {
    console.log('pc1.iceConnectionState', e, pc1.iceConnectionState);

    if (pc1.iceConnectionState === 'completed') {
      console.log('pc1.getSenders', pc1.getSenders());
      console.log('pc2.getReceivers', pc2.getReceivers());
    }
  });

  pc1.addEventListener('icegatheringstatechange', function (e) {
    console.log('pc1.iceGatheringStateChange', e);
  });

  // https://stackoverflow.com/questions/48963787/failed-to-set-local-answer-sdp-called-in-wrong-state-kstable
  // https://bugs.chromium.org/p/chromium/issues/detail?id=740501
  var isNegotiating = false;
  pc1.addEventListener('signalingstatechange', function (e) {
    console.log('pc1.signalingstatechange',  e);
    isNegotiating = (pc1.signalingState !== "stable");
  });

  pc1.addEventListener('negotiationneeded', function (e) {

    if (isNegotiating) {
      // Should not trigger on iosrtc cause of PluginRTCPeerConnection.swift fix
      console.log("pc1.negotiatioNeeded", "SKIP nested negotiations");
      return;
    }
    isNegotiating = true;

    console.log('pc1.negotiatioNeeded', e);

    return pc1.createOffer().then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc1.setLocalDescription', desc);
      return pc1.setLocalDescription(desc);
    }).then(function () {
      var desc = {
        type: pc1.localDescription.type,
        sdp: pc1.localDescription.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setRemoteDescription(desc);
    }).then(function () {
      console.log('pc2.createAnswer');
      return pc2.createAnswer();
    }).then(function (d) {
      var desc = {
        type: d.type,
        sdp: d.sdp
      };
      console.log('pc2.setLocalDescription', desc);
      return pc2.setLocalDescription(d);
    }).then(function () {
      var desc = {
        type: pc2.localDescription.type,
        sdp: pc2.localDescription.sdp
      };
      console.log('pc1.setRemoteDescription', desc);
      return pc1.setRemoteDescription(desc);
    }).then(function () {
      TestMediaRenderCatpure(peerVideoEl);
      TestMediaRenderCatpure(localVideoEl);
      TestPeerDataChannel();
    }).catch(function (err) {
      console.log('pc1.createOfferError', err);
    });
  });
}

var canvasEl;
function TestMediaRenderCatpure(videoEl) {

  if (!canvasEl) {
    canvasEl = document.createElement('canvas');
  }

  var ctx = canvasEl.getContext("2d");
  canvasEl.style.position = 'absolute';
  canvasEl.style.left = 0;
  canvasEl.style.bottom = 0;
  appContainer.appendChild(canvasEl);
  var image = new Image();
  image.addEventListener('load', function() {
    canvasEl.width = image.width;
    canvasEl.height = image.height;
    ctx.drawImage(image, 0, 0);
  });
  localVideoEl.render.save(function (data) {
    image.src = "data:image/jpg;base64," + data;
  });
}

var testMediaRenderCatpureAnimateFrame;
function TestMediaRenderCatpureAnimate() {
  TestMediaRenderCatpure(peerVideoEl);
  testMediaRenderCatpureAnimateFrame = requestAnimationFrame(TestMediaRenderCatpureAnimate);
}

// Disabled to avoid confusion with remoteStream
var cloneStream;
var cloneVideoEl;
function TestPluginMediaStreamClone(mediaStream) {
  cloneVideoEl = document.createElement('video');
  cloneVideoEl.setAttribute('autoplay', 'autoplay');
  cloneVideoEl.setAttribute('playsinline', 'playsinline');
  cloneVideoEl.style.backgroundColor = 'purple';
  cloneVideoEl.style.position = 'absolute';
  cloneVideoEl.style.bottom = 0;
  cloneVideoEl.style.left = 0;
  cloneVideoEl.style.width = "100px";
  cloneVideoEl.style.height = "100px";
  cloneVideoEl.style.transform = "scaleX(-1)";

  cloneStream = mediaStream.clone();
  cloneVideoEl.srcObject = cloneStream;

  appContainer.appendChild(cloneVideoEl);
}

var useWebRTCAdapter = false;

// Expose webrtc-adapter
if (useWebRTCAdapter && typeof window.adapter === 'undefined') {

    // load adapter.js
    var version = 'latest';
    var script = document.createElement("script");
    script.type = "text/javascript";
    //script.src = "adapter-latest.js";
    script.src = "https://webrtc.github.io/adapter/adapter-" + version + ".js";
    script.async = false;
    document.getElementsByTagName("head")[0].appendChild(script);
    script.addEventListener('load', function () {
      console.log('useWebRTCAdapter.loaded', script.src);
      TestGetUserMedia().then(function (localStream) {
        TestRTCPeerConnection(localStream);
      });
    });
} else {
  TestGetUserMedia().then(function (localStream) {
    TestRTCPeerConnection(localStream);
  });
}

<|endoftext|>


<commit_before>define(function (require) {
    'use strict';

    var GameEngine = require('scripts/Controllers/GameEngine.js'),
        Background = require('scripts/Models/Background.js'),
        GameSettings = require('scripts/Models/GameSettings.js');

    var gameEngine = null;
    var audio = new Audio('sounds/gong.mp3');

    function onButtonStart() {
        if (!gameEngine) {
            gameEngine = new GameEngine(GameSettings);
            gameEngine.startGame();
            audio.play();
        }
    }

    document.getElementById("start").addEventListener("click", onButtonStart);

    $("#fullscreen").on('click', function () {
        var docElement, request;

        docElement = document.documentElement;
        request = docElement.requestFullScreen || docElement.webkitRequestFullScreen || docElement.mozRequestFullScreen || docElement.msRequestFullScreen;

        if (typeof request != "undefined" && request) {
            request.call(docElement);
        }

        if (!gameEngine) {
            gameEngine = new GameEngine(stage, gameFieldOptions, fruitLayerOptions);
            gameEngine.startGame();
            audio.play();
        }

        $('#game-field').css('padding-top', '240px');
        // $('#fruit-layer').css('margin-top', '120px');
        $('#background-layer').css('margin-top', '-120px');

        $('html').css('height', '100%');
        $('body').css('height', '100%');

        $('#exit-fullscreen').show();
        $(this).hide();
    });

    $("#exit-fullscreen").on('click', function () {
        function exitFullscreen() {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            }
        }

        // Cancel fullscreen for browsers that support it!
        exitFullscreen();

        $('#game-field').css('padding-top', '0');
        $('#background-layer').css('margin-top', '0');

        $('html').css('height', '');
        $('body').css('height', '');

        $('#fullscreen').show();
        $(this).hide();
    });

    var background = new Background(GameSettings.stage, GameSettings.gameFieldOptions);
    background.draw();
});<commit_msg>main.js gong.mp3 changed with gong.wav<commit_after>define(function (require) {
    'use strict';

    var GameEngine = require('scripts/Controllers/GameEngine.js'),
        Background = require('scripts/Models/Background.js'),
        GameSettings = require('scripts/Models/GameSettings.js');

    var gameEngine = null;
    var audio = new Audio('sounds/gong.wav');

    function onButtonStart() {
        if (!gameEngine) {
            gameEngine = new GameEngine(GameSettings);
            gameEngine.startGame();
            audio.play();
        }
    }

    document.getElementById("start").addEventListener("click", onButtonStart);

    $("#fullscreen").on('click', function () {
        var docElement, request;

        docElement = document.documentElement;
        request = docElement.requestFullScreen || docElement.webkitRequestFullScreen || docElement.mozRequestFullScreen || docElement.msRequestFullScreen;

        if (typeof request != "undefined" && request) {
            request.call(docElement);
        }

        if (!gameEngine) {
            gameEngine = new GameEngine(stage, gameFieldOptions, fruitLayerOptions);
            gameEngine.startGame();
            audio.play();
        }

        $('#game-field').css('padding-top', '240px');
        // $('#fruit-layer').css('margin-top', '120px');
        $('#background-layer').css('margin-top', '-120px');

        $('html').css('height', '100%');
        $('body').css('height', '100%');

        $('#exit-fullscreen').show();
        $(this).hide();
    });

    $("#exit-fullscreen").on('click', function () {
        function exitFullscreen() {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            }
        }

        // Cancel fullscreen for browsers that support it!
        exitFullscreen();

        $('#game-field').css('padding-top', '0');
        $('#background-layer').css('margin-top', '0');

        $('html').css('height', '');
        $('body').css('height', '');

        $('#fullscreen').show();
        $(this).hide();
    });

    var background = new Background(GameSettings.stage, GameSettings.gameFieldOptions);
    background.draw();
});<|endoftext|>