<commit_before>var fs = require("fs-extra"),
  findParentDir = require('find-parent-dir'),
  _            = require("lodash"),
  spawn        = require("cross-spawn"),
  chalk = require("chalk"),
  path = require("path");

function readExposing(filePath) {
  return new Promise(function(resolve, reject) {
    // Read ~60 characters at a time, since many module names + exposing (..) will fit in that chunk.
    var readStream = fs.createReadStream(filePath, {encoding: 'utf8', highWaterMark: 8 * 60});
    var data = "";
    var matches = null;
    var exposedValues = [];
    var state = "NO_MATCHES_YET"

    readStream.on('data', function (chunk) {
      data += chunk;

      switch (state) {
        case "NO_MATCHES_YET":
          // Search for "module Foo exposing ("
          matches = data.match(/^module\s+\S+\s+exposing\s+\((.*)/);

          if (matches) {
            // Discard everything up to and including the "(" in "exposing ("
            data = matches[1];
            state = "INSIDE_EXPOSES";
          } else {
            break;
          }

          // NOTE: break intentionally omitted here! We want to keep going if it matched.

        case "INSIDE_EXPOSES":
          // Search for exposed modules followed by )

          // Like so many regular expressions, this is "write once, read never"
          // Basically looking for one of these four:
          //
          // 1) ..
          // 2) foo
          // 3) Foo
          // 4) Foo(..)
          //
          // ...followed by a ")" indicating we've found the end of "exposes"
          while (matches = data.match(/^(\s*..\s*|(?:\s*(?:[a-z][^\),\s]*))|(?:\s*(?:[A-Z][^\_,\s]*[^\(]*(?:\(?:[^\)]+\))?)[,]?\s*))([,\)])(.*)/)) {
            var exposedValue = matches[1].trim();

            if (exposedValue === "..") {
              // An "exposedValues" of null means "everything was exposed"
              exposedValues = null;

              // exposing (..) means we're done! No more exposed values to consume.
              state = "FINISHED";
              break;
            }

            // We only care about lowercase values. Exposed types can't be tests.
            if (exposedValue[0].toLowerCase() === exposedValue[0]) {
              exposedValues.push(exposedValue);
            }

            // If we found the ")" ending the "exposes", we're done.
            // (This value might also be "," - indicating we have further to go.)
            if (matches[2] === ")") {
              state = "FINISHED";
              break;
            }

            // Detect an infinite loop and bail out.
            if (matches[3] === data) {
              reject("Unable to parse \"" + data + "\" - this should never happen. Please report this issue on https://github.com/rtfeldman/node-test-runner - and include the full `module` declaration (including the `exposing`) part of this file: " + filePath);
            }

            // Before the next iteration, set data to be the remainder of the string.
            data = matches[3];
          }

          break;

        case "FINISHED":
          readStream.close();
          break;

        default:
          reject("Invalid module parser state: " + state);
      }
    }).on('close', function () {
      if (matches === null) {
        reject(filePath + " is missing a module declaration.");
      } else {
        resolve(exposedValues);
      }
    }).on('error', function (err) {
      reject(err);
    });
  });
}

function copyNativeSrcFiles(newPackageName, srcPath, dest) {
  fs.readdirSync(srcPath).forEach(function(filename) {
    var filePath = path.join(srcPath, filename);
    var newDest = path.join(dest, filename);
    var stats = fs.lstatSync(filePath);

    if (stats.isDirectory()) {
      fs.mkdirpSync(newDest);

      copyNativeSrcFiles(newPackageName, filePath, newDest);
    } else if ((stats.isFile() || stats.isSymbolicLink()) && isJsFile(filename)) {
      var contents = fs.readFileSync(filePath, "utf8");

      // These Native files need to use the local package name,
      // because of how we're hacking them in.
      var newContents = contents.replace(
        /rtfeldman\$node_test_runner([\.=\s]*)/gm,
        newPackageName + "$1"
      );

      fs.writeFileSync(newDest, newContents);
    }
  });
}

function isJsFile(filename) {
  return /\.js$/.test(filename);
}

function isElmFile(filename) {
  return /\.elm$/.test(filename);
}

function repositoryToNativePackageName(repository) {
  // https://github.com/rtfeldman/node-test-runner.git
  //
  // matches[1] = "rtfeldman"
  // matches[2] = "node-test-runner"
  var matches = repository.match(/\/([^\/]+)\/([^\/\.]+)\.git/);

  // From the above example, return "rtfeldman$node_test_runner"
  return [
    matches[1].replace(/-/g, "_"),
    matches[2].replace(/-/g, "_")
  ].join("$");
}

function findNearestElmPackageDir(filePaths) {
  // For each of the given files, try to find an ancestor elm-package.json
  // As soon as we find one, return it.
  for (var index=0; index < filePaths.length; index++) {
    var currentDir = path.dirname(filePaths[index]);
    var result = findParentDir.sync(currentDir, "elm-package.json");

    if (result !== null) {
      return result;
    }
  }

  // If we didn't find any, fall back on the current working directory.
  return process.cwd();
}

function evalElmCode (args, report, compiledCode) {
  // Apply Node polyfills as necessary.
  var window = {Date: Date, addEventListener: function() {}, removeEventListener: function() {}};
  var document = {body: {}, createTextNode: function() {}};
  if (typeof XMLHttpRequest === 'undefined') { XMLHttpRequest = function() { return { addEventListener: function() {}, open: function() {}, send: function() {} }; }; }
  if (typeof FormData === 'undefined') { FormData = function () { this._data = []; }; FormData.prototype.append = function () { this._data.push(Array.prototype.slice.call(arguments)); }; }

  var Elm = function(module) { eval(compiledCode); return module.exports; }({});

  // Make sure necessary things are defined.
  if (typeof Elm === 'undefined') { throw 'test runner config error: Elm is not defined. Make sure you provide a file compiled by Elm!'; }

  var potentialModuleNames = Object.keys(Elm.Test.Generated);

  if (potentialModuleNames.length !== 1) {
    console.error("Multiple potential generated modules to run in the Elm.Test.Generated namespace: ", potentialModuleNames, " - this should never happen!");
    process.exit(1);
  }

  var testModule = Elm.Test.Generated[potentialModuleNames[0]];
  var initialSeed = null;

  if (args.seed !== undefined) {
    initialSeed = args.seed;
  }

  pathToMake = args.compiler;

  // Fix Windows Unicode problems. Credit to https://github.com/sindresorhus/figures for the Windows compat idea!
  var windowsSubstitutions = [[/[↓✗►]/g, '>'], [/╵│╷╹┃╻/g, '|'], [/═/g, '='],, [/▔/g, '-'], [/✔/g, '√']];

  function windowsify(str) {
    return windowsSubstitutions.reduce(
      function(result, sub) { return result.replace(sub[0], sub[1]); }, str);
  }

  function chalkify(messages) {
    return messages.map(function(msg) {
      var path = msg.styles;
      var text = process.platform === 'win32' ? windowsify(msg.text) : msg.text;

      if (path.length === 0) {
        return text;
      } else {
        var fn = chalk;

        path.forEach(function(nextPath) { fn = fn[nextPath]; });

        return fn(text);
      }
    }).join('');
  }

  // Run the Elm app.
  var app = testModule.worker({seed: initialSeed, report: report});

  // Receive messages from ports and translate them into appropriate JS calls.
  app.ports.emit.subscribe(function(msg) {
    var msgType = msg[0];
    var data = msg[1];

    if (msgType === 'FINISHED') {
      if (data.format === "CHALK") {
        console.log(chalkify(data.message));
      } else if (data.format === "JUNIT") {
        console.log(builder.create(data.message).end());
      } else {
        console.log(JSON.stringify(data.message));
      }

      if (!args.watch) {
        process.exit(data.exitCode);
      }
    } else if (msgType === "STARTED" || msgType === "TEST_COMPLETED")  {
        if (data.format === "CHALK") {
          console.log(chalkify(data.message));
        } else if (data.format === "JSON") {
          console.log(JSON.stringify(data.message));
        }

    }
  });
}

var binaryExtension = process.platform === "win32" ? ".exe" : "";
var readElmiPath = path.join(__dirname, "..", "bin", "elm-interface-to-json") + binaryExtension;

function moduleFromFilePath(filePathArg) {
  var parsed = path.parse(path.normalize(filePathArg));
  var basename = path.basename(parsed.base, ".elm");

  // Turn these into module name checks to be performed, in order.
  // e.g. 'tests/All/Passing.elm' ===> ['Passing', 'All', 'tests']
  // This way, if we're given 'All.Passing' as a module name, we can also
  // flip it into ['Passing', 'All'], and see if the first N elements line up.
  return _.compact(parsed.dir.split(path.sep).concat([basename])).reverse();
}

function moduleFromTestName(testName) {
  return testName.split(".").reverse();
}

function toPathsAndModules(testFilePaths) {
  var paths = testFilePaths.map(function(filePath) {
    return {filePath: filePath, module: moduleFromFilePath(filePath)};
  });

  return function(testModule) {
    var testModulePaths = moduleFromTestName(testModule.name);
    var results = [];

    // Must have at least one matching module path.
    paths.forEach(function(currentPath) {
      // A module path matches if it lines up completely with a known one.
      if (testModulePaths.every(function(testModulePath, index) {
        return testModulePath === currentPath.module[index];
      })) {
        results.push({
          name: testModule.name,
          tests: testModule.tests,
          path: currentPath.filePath
        });
      }
    });

    return results;
  };
}

function findTests(elmPackageJsonPath, testFilePaths) {
  return new Promise(function(resolve, reject) {
    var process = spawn(readElmiPath, ["--path", elmPackageJsonPath]);
    var jsonStr = "";
    var stderrStr = "";

    process.stdout.on('data', function(data) {
      jsonStr += data;
    });

    process.stderr.on('data', function(data) {
      stderrStr += data;
    });

    process.on('close', function(code) {
      if (stderrStr !== "") {
        reject(stderrStr);
      } else if (code !== 0) {
        reject("Finding test interfaces failed, exiting with code " + code);
      }

      var modules;

      try {
        modules = JSON.parse(jsonStr);
      } catch(err) {
        reject("Received invalid JSON from test interface search: " + err);
      }

      var filteredModules = _.flatMap(modules, function(mod) {
        var eligible = _.flatMap(mod.types, function(typ) {
          if (typ.signature === "Test.Test") {
            return typ.name;
          } else {
            return [];
          }
        });

        // Must have at least 1 value of type Test. Otherwise ignore this module.
        if (eligible.length > 0) {
          return [{name: mod.moduleName, tests: eligible}];
        } else {
          return [];
        }
      });

      return Promise.all(
        _.map(_.flatMap(filteredModules, toPathsAndModules(testFilePaths)), filterExposing)
      ).then(resolve).catch(reject);
    });
  });
}

function filterExposing(pathAndModule) {
  return new Promise(function(resolve, reject) {
    return readExposing(pathAndModule.path).then(function(exposedValues) {
      var newTests =
        exposedValues === null
          // null exposedValues means "the module was exposing (..), so keep everything"
          ? pathAndModule.tests

          // Only keep the tests that were exposed.
          : _.intersection(exposedValues, pathAndModule.tests);

      if (newTests.length < pathAndModule.tests.length) {
        return reject(
          "\n`" + pathAndModule.name + "` is a module with top-level Test values which it does not expose:\n\n" +
          _.difference(pathAndModule.tests, newTests).map(function(test){ return test + " : Test"; }).join("\n") +
          "\n\nThese tests will not get run. Please either expose them or move them out of the top level.");
      } else {
        return resolve({name: pathAndModule.name, tests: newTests});
      }
    }).catch(reject);
  });
}

module.exports = {
  findTests: findTests,
  evalElmCode: evalElmCode,
  isElmFile: isElmFile,
  copyNativeSrcFiles: copyNativeSrcFiles,
  repositoryToNativePackageName: repositoryToNativePackageName,
  findNearestElmPackageDir: findNearestElmPackageDir
};
<commit_msg>:skull: whitespace<commit_after>var fs = require("fs-extra"),
  findParentDir = require('find-parent-dir'),
  _            = require("lodash"),
  spawn        = require("cross-spawn"),
  chalk = require("chalk"),
  path = require("path");

function readExposing(filePath) {
  return new Promise(function(resolve, reject) {
    // Read ~60 characters at a time, since many module names + exposing (..) will fit in that chunk.
    var readStream = fs.createReadStream(filePath, {encoding: 'utf8', highWaterMark: 8 * 60});
    var data = "";
    var matches = null;
    var exposedValues = [];
    var state = "NO_MATCHES_YET"

    readStream.on('data', function (chunk) {
      data += chunk;

      switch (state) {
        case "NO_MATCHES_YET":
          // Search for "module Foo exposing ("
          matches = data.match(/^module\s+\S+\s+exposing\s+\((.*)/);

          if (matches) {
            // Discard everything up to and including the "(" in "exposing ("
            data = matches[1];
            state = "INSIDE_EXPOSES";
          } else {
            break;
          }

          // NOTE: break intentionally omitted here! We want to keep going if it matched.

        case "INSIDE_EXPOSES":
          // Search for exposed modules followed by )

          // Like so many regular expressions, this is "write once, read never"
          // Basically looking for one of these four:
          //
          // 1) ..
          // 2) foo
          // 3) Foo
          // 4) Foo(..)
          //
          // ...followed by a ")" indicating we've found the end of "exposes"
          while (matches = data.match(/^(\s*..\s*|(?:\s*(?:[a-z][^\),\s]*))|(?:\s*(?:[A-Z][^\_,\s]*[^\(]*(?:\(?:[^\)]+\))?)[,]?\s*))([,\)])(.*)/)) {
            var exposedValue = matches[1].trim();

            if (exposedValue === "..") {
              // An "exposedValues" of null means "everything was exposed"
              exposedValues = null;

              // exposing (..) means we're done! No more exposed values to consume.
              state = "FINISHED";
              break;
            }

            // We only care about lowercase values. Exposed types can't be tests.
            if (exposedValue[0].toLowerCase() === exposedValue[0]) {
              exposedValues.push(exposedValue);
            }

            // If we found the ")" ending the "exposes", we're done.
            // (This value might also be "," - indicating we have further to go.)
            if (matches[2] === ")") {
              state = "FINISHED";
              break;
            }

            // Detect an infinite loop and bail out.
            if (matches[3] === data) {
              reject("Unable to parse \"" + data + "\" - this should never happen. Please report this issue on https://github.com/rtfeldman/node-test-runner - and include the full `module` declaration (including the `exposing`) part of this file: " + filePath);
            }

            // Before the next iteration, set data to be the remainder of the string.
            data = matches[3];
          }

          break;

        case "FINISHED":
          readStream.close();
          break;

        default:
          reject("Invalid module parser state: " + state);
      }
    }).on('close', function () {
      if (matches === null) {
        reject(filePath + " is missing a module declaration.");
      } else {
        resolve(exposedValues);
      }
    }).on('error', function (err) {
      reject(err);
    });
  });
}

function copyNativeSrcFiles(newPackageName, srcPath, dest) {
  fs.readdirSync(srcPath).forEach(function(filename) {
    var filePath = path.join(srcPath, filename);
    var newDest = path.join(dest, filename);
    var stats = fs.lstatSync(filePath);

    if (stats.isDirectory()) {
      fs.mkdirpSync(newDest);

      copyNativeSrcFiles(newPackageName, filePath, newDest);
    } else if ((stats.isFile() || stats.isSymbolicLink()) && isJsFile(filename)) {
      var contents = fs.readFileSync(filePath, "utf8");

      // These Native files need to use the local package name,
      // because of how we're hacking them in.
      var newContents = contents.replace(
        /rtfeldman\$node_test_runner([\.=\s]*)/gm,
        newPackageName + "$1"
      );

      fs.writeFileSync(newDest, newContents);
    }
  });
}

function isJsFile(filename) {
  return /\.js$/.test(filename);
}

function isElmFile(filename) {
  return /\.elm$/.test(filename);
}

function repositoryToNativePackageName(repository) {
  // https://github.com/rtfeldman/node-test-runner.git
  //
  // matches[1] = "rtfeldman"
  // matches[2] = "node-test-runner"
  var matches = repository.match(/\/([^\/]+)\/([^\/\.]+)\.git/);

  // From the above example, return "rtfeldman$node_test_runner"
  return [
    matches[1].replace(/-/g, "_"),
    matches[2].replace(/-/g, "_")
  ].join("$");
}

function findNearestElmPackageDir(filePaths) {
  // For each of the given files, try to find an ancestor elm-package.json
  // As soon as we find one, return it.
  for (var index=0; index < filePaths.length; index++) {
    var currentDir = path.dirname(filePaths[index]);
    var result = findParentDir.sync(currentDir, "elm-package.json");

    if (result !== null) {
      return result;
    }
  }

  // If we didn't find any, fall back on the current working directory.
  return process.cwd();
}

function evalElmCode (args, report, compiledCode) {
  // Apply Node polyfills as necessary.
  var window = {Date: Date, addEventListener: function() {}, removeEventListener: function() {}};
  var document = {body: {}, createTextNode: function() {}};
  if (typeof XMLHttpRequest === 'undefined') { XMLHttpRequest = function() { return { addEventListener: function() {}, open: function() {}, send: function() {} }; }; }
  if (typeof FormData === 'undefined') { FormData = function () { this._data = []; }; FormData.prototype.append = function () { this._data.push(Array.prototype.slice.call(arguments)); }; }

  var Elm = function(module) { eval(compiledCode); return module.exports; }({});

  // Make sure necessary things are defined.
  if (typeof Elm === 'undefined') { throw 'test runner config error: Elm is not defined. Make sure you provide a file compiled by Elm!'; }

  var potentialModuleNames = Object.keys(Elm.Test.Generated);

  if (potentialModuleNames.length !== 1) {
    console.error("Multiple potential generated modules to run in the Elm.Test.Generated namespace: ", potentialModuleNames, " - this should never happen!");
    process.exit(1);
  }

  var testModule = Elm.Test.Generated[potentialModuleNames[0]];
  var initialSeed = null;

  if (args.seed !== undefined) {
    initialSeed = args.seed;
  }

  pathToMake = args.compiler;

  // Fix Windows Unicode problems. Credit to https://github.com/sindresorhus/figures for the Windows compat idea!
  var windowsSubstitutions = [[/[↓✗►]/g, '>'], [/╵│╷╹┃╻/g, '|'], [/═/g, '='],, [/▔/g, '-'], [/✔/g, '√']];

  function windowsify(str) {
    return windowsSubstitutions.reduce(
      function(result, sub) { return result.replace(sub[0], sub[1]); }, str);
  }

  function chalkify(messages) {
    return messages.map(function(msg) {
      var path = msg.styles;
      var text = process.platform === 'win32' ? windowsify(msg.text) : msg.text;

      if (path.length === 0) {
        return text;
      } else {
        var fn = chalk;

        path.forEach(function(nextPath) { fn = fn[nextPath]; });

        return fn(text);
      }
    }).join('');
  }

  // Run the Elm app.
  var app = testModule.worker({seed: initialSeed, report: report});

  // Receive messages from ports and translate them into appropriate JS calls.
  app.ports.emit.subscribe(function(msg) {
    var msgType = msg[0];
    var data = msg[1];

    if (msgType === 'FINISHED') {
      if (data.format === "CHALK") {
        console.log(chalkify(data.message));
      } else if (data.format === "JUNIT") {
        console.log(builder.create(data.message).end());
      } else {
        console.log(JSON.stringify(data.message));
      }

      if (!args.watch) {
        process.exit(data.exitCode);
      }
    } else if (msgType === "STARTED" || msgType === "TEST_COMPLETED")  {
        if (data.format === "CHALK") {
          console.log(chalkify(data.message));
        } else if (data.format === "JSON") {
          console.log(JSON.stringify(data.message));
        }

    }
  });
}

var binaryExtension = process.platform === "win32" ? ".exe" : "";
var readElmiPath = path.join(__dirname, "..", "bin", "elm-interface-to-json") + binaryExtension;

function moduleFromFilePath(filePathArg) {
  var parsed = path.parse(path.normalize(filePathArg));
  var basename = path.basename(parsed.base, ".elm");

  // Turn these into module name checks to be performed, in order.
  // e.g. 'tests/All/Passing.elm' ===> ['Passing', 'All', 'tests']
  // This way, if we're given 'All.Passing' as a module name, we can also
  // flip it into ['Passing', 'All'], and see if the first N elements line up.
  return _.compact(parsed.dir.split(path.sep).concat([basename])).reverse();
}

function moduleFromTestName(testName) {
  return testName.split(".").reverse();
}

function toPathsAndModules(testFilePaths) {
  var paths = testFilePaths.map(function(filePath) {
    return {filePath: filePath, module: moduleFromFilePath(filePath)};
  });

  return function(testModule) {
    var testModulePaths = moduleFromTestName(testModule.name);
    var results = [];

    // Must have at least one matching module path.
    paths.forEach(function(currentPath) {
      // A module path matches if it lines up completely with a known one.
      if (testModulePaths.every(function(testModulePath, index) {
        return testModulePath === currentPath.module[index];
      })) {
        results.push({
          name: testModule.name,
          tests: testModule.tests,
          path: currentPath.filePath
        });
      }
    });

    return results;
  };
}

function findTests(elmPackageJsonPath, testFilePaths) {
  return new Promise(function(resolve, reject) {
    var process = spawn(readElmiPath, ["--path", elmPackageJsonPath]);
    var jsonStr = "";
    var stderrStr = "";

    process.stdout.on('data', function(data) {
      jsonStr += data;
    });

    process.stderr.on('data', function(data) {
      stderrStr += data;
    });

    process.on('close', function(code) {
      if (stderrStr !== "") {
        reject(stderrStr);
      } else if (code !== 0) {
        reject("Finding test interfaces failed, exiting with code " + code);
      }

      var modules;

      try {
        modules = JSON.parse(jsonStr);
      } catch(err) {
        reject("Received invalid JSON from test interface search: " + err);
      }

      var filteredModules = _.flatMap(modules, function(mod) {
        var eligible = _.flatMap(mod.types, function(typ) {
          if (typ.signature === "Test.Test") {
            return typ.name;
          } else {
            return [];
          }
        });

        // Must have at least 1 value of type Test. Otherwise ignore this module.
        if (eligible.length > 0) {
          return [{name: mod.moduleName, tests: eligible}];
        } else {
          return [];
        }
      });

      return Promise.all(
        _.map(_.flatMap(filteredModules, toPathsAndModules(testFilePaths)), filterExposing)
      ).then(resolve).catch(reject);
    });
  });
}

function filterExposing(pathAndModule) {
  return new Promise(function(resolve, reject) {
    return readExposing(pathAndModule.path).then(function(exposedValues) {
      var newTests =
        exposedValues === null
          // null exposedValues means "the module was exposing (..), so keep everything"
          ? pathAndModule.tests

          // Only keep the tests that were exposed.
          : _.intersection(exposedValues, pathAndModule.tests);

      if (newTests.length < pathAndModule.tests.length) {
        return reject(
          "\n`" + pathAndModule.name + "` is a module with top-level Test values which it does not expose:\n\n" +
          _.difference(pathAndModule.tests, newTests).map(function(test){ return test + " : Test"; }).join("\n") +
          "\n\nThese tests will not get run. Please either expose them or move them out of the top level.");
      } else {
        return resolve({name: pathAndModule.name, tests: newTests});
      }
    }).catch(reject);
  });
}

module.exports = {
  findTests: findTests,
  evalElmCode: evalElmCode,
  isElmFile: isElmFile,
  copyNativeSrcFiles: copyNativeSrcFiles,
  repositoryToNativePackageName: repositoryToNativePackageName,
  findNearestElmPackageDir: findNearestElmPackageDir
};
<|endoftext|>


<commit_before>// Global variables

var hours = ['6:00am - 7:00am', '7:00am - 8:00am', '8:00am - 9:00am', '9:00am - 10:00am', '10:00am - 11:00am', '11:00am - 12:00pm', '12:00pm - 1:00pm', '1:00pm - 2:00pm', '2:00pm - 3:00pm', '3:00pm - 4:00pm', '4:00pm - 5:00pm', '5:00pm - 6:00pm','6:00pm - 7:00pm', '7:00pm - 8:00pm'];

// Constructor to generate patCookiesLocation instances
function PatCookiesLocation (locationName, minCust, maxCust, avgCookiesPerCust, iDPat) {
  this.locationName = locationName;
  this.minCust = minCust;
  this.maxCust = maxCust;
  this.avgCookiesPerCust = avgCookiesPerCust;
  this.iDPat = iDPat;
  this.hourlyCustomersArray = [];
  this.hourlySalesArray = [];
  this.totalSales = 0;
};

// Prototype to generate hourly customers
PatCookiesLocation.prototype.calcHourlyCustomers = function() {
  for(var i = 0; i < hours.length; i++) {
    var randomCust = Math.floor(Math.random() * (this.maxCust - this.minCust + 1)) + this.minCust;
    this.hourlyCustomersArray.push(randomCust);
  }
};

// Prototype to generate hourly sales
PatCookiesLocation.prototype.calcHourlySales = function() {
  for(var i = 0; i < hours.length; i++) {
    var cookiesSoldThatHour = this.hourlyCustomersArray[i] * this.avgCookiesPerCust;
    this.hourlySalesArray.push(cookiesSoldThatHour);
    this.totalSales += cookiesSoldThatHour;
  }
};

// Prototype to trigger render of unordered list
makeHeaderRow = function() {
  var cookieTable = document.getElementById('patCookiesLocationTable');
  var trEl = document.createElement('tr');
  var thEl = document.createElement('th');
  thEl.textContent = ' ';
  trEl.appendChild(thEl);
  // cookieTable.appendChild(trEl);

  var thEl = document.createElement('th');
  thEl.textContent = 'Daily Location Total';
  trEl.appendChild(thEl);

  for (var i = 0; i < hours.length; i++) {
    var thEl = document.createElement('th');
    thEl.textContent = hours[i];
    trEl.appendChild(thEl);
  };

  cookieTable.appendChild(trEl);
};
makeHeaderRow();

PatCookiesLocation.prototype.render = function() {
  this.calcHourlyCustomers();
  this.calcHourlySales();
  var cookieTable = document.getElementById('patCookiesLocationTable');
  var trEl = document.createElement('tr');
  var tdEl = document.createElement('td');
  tdEl.textContent = this.locationName;
  trEl.appendChild(tdEl);
  // cookieTable.appendChild(trEl);

  var tdEl = document.createElement('td');
  tdEl.textContent = Math.round(this.totalSales);
  trEl.appendChild(tdEl);

  for (var i = 0; i < hours.length; i++) {
    var tdEl = document.createElement('td');
    tdEl.textContent = Math.round(this.hourlySalesArray[i]);
    trEl.appendChild(tdEl);
  };

  cookieTable.appendChild(trEl);
};

  // for(var i = 0; i < hours.length; i++) {
  //   var listItem = document.createElement('li');
  //   listItem.textContent = hours[i] + ': ' + Math.round(this.hourlySalesArray[i]) + ' cookies';
  //   var patCookieLocationList = document.getElementById(this.iDPat);
  //   document.getElementById(this.iDPat).appendChild(listItem);
  // }
  // var totalListItem = document.createElement('li');
  // totalListItem.textContent = 'Total: ' + Math.round(this.totalSales) + ' cookies';
  // patCookieLocationList.appendChild(totalListItem);
// };

// All instances and calls of prototypes to calculate hourly customers, hourly sales, and then render on the page
var firstAndPike = new PatCookiesLocation('First and Pike', 23, 65, 6.3, 'pikeID');
firstAndPike.render();

var seaTac = new PatCookiesLocation('SeaTac', 3, 24, 1.2, 'seaTacID');
seaTac.render();

var seaCenter = new PatCookiesLocation('Seattle Center', 11, 38, 3.7, 'seaCenterID');
seaCenter.render();

var capHill = new PatCookiesLocation('Capitol Hill', 20, 38, 2.3, 'capHillID');
capHill.render();

var alki = new PatCookiesLocation('Alki', 2, 16, 4.6, 'alkiID');
alki.render();

// Instead of rendering each individually, add each instance to an array (like allStoresArray) and create a function that generates sales numbers by calling the array. This call requires a for loop that calls allStoresArray[i].render(i); Then, call the 'generate sales numbers' function directly below makeHeaderRow at the bottom of the document

// to color alternating lines, add ID to alternating trEL
<commit_msg>changed function to push carts to array<commit_after>// Global variables

var hours = ['6:00am - 7:00am', '7:00am - 8:00am', '8:00am - 9:00am', '9:00am - 10:00am', '10:00am - 11:00am', '11:00am - 12:00pm', '12:00pm - 1:00pm', '1:00pm - 2:00pm', '2:00pm - 3:00pm', '3:00pm - 4:00pm', '4:00pm - 5:00pm', '5:00pm - 6:00pm','6:00pm - 7:00pm', '7:00pm - 8:00pm'];
var cookieStandsArray = [];

// Constructor to generate patCookiesLocation instances
function PatCookiesLocation (locationName, minCust, maxCust, avgCookiesPerCust, iDPat) {
  this.locationName = locationName;
  this.minCust = minCust;
  this.maxCust = maxCust;
  this.avgCookiesPerCust = avgCookiesPerCust;
  this.iDPat = iDPat;
  this.hourlyCustomersArray = [];
  this.hourlySalesArray = [];
  this.totalSales = 0;
  cookieStandsArray.push(this);
};

// Prototype to generate hourly customers
PatCookiesLocation.prototype.calcHourlyCustomers = function() {
  for(var i = 0; i < hours.length; i++) {
    var randomCust = Math.floor(Math.random() * (this.maxCust - this.minCust + 1)) + this.minCust;
    this.hourlyCustomersArray.push(randomCust);
  }
};

// Prototype to generate hourly sales
PatCookiesLocation.prototype.calcHourlySales = function() {
  for(var i = 0; i < hours.length; i++) {
    var cookiesSoldThatHour = this.hourlyCustomersArray[i] * this.avgCookiesPerCust;
    this.hourlySalesArray.push(cookiesSoldThatHour);
    this.totalSales += cookiesSoldThatHour;
  }
};

// Prototype to trigger render of unordered list
var makeHeaderRow = function() {
  var cookieTable = document.getElementById('patCookiesLocationTable');
  var trEl = document.createElement('tr');
  var thEl = document.createElement('th');
  thEl.textContent = ' ';
  trEl.appendChild(thEl);
  // cookieTable.appendChild(trEl);

  var thEl = document.createElement('th');
  thEl.textContent = 'Daily Location Total';
  trEl.appendChild(thEl);

  for (var i = 0; i < hours.length; i++) {
    var thEl = document.createElement('th');
    thEl.textContent = hours[i];
    trEl.appendChild(thEl);
  };

  cookieTable.appendChild(trEl);
};

PatCookiesLocation.prototype.render = function() {
  this.calcHourlyCustomers();
  this.calcHourlySales();
  var cookieTable = document.getElementById('patCookiesLocationTable');
  var trEl = document.createElement('tr');
  var tdEl = document.createElement('td');
  tdEl.textContent = this.locationName;
  trEl.appendChild(tdEl);
  // cookieTable.appendChild(trEl);

  var tdEl = document.createElement('td');
  tdEl.textContent = Math.round(this.totalSales);
  trEl.appendChild(tdEl);

  for (var i = 0; i < hours.length; i++) {
    var tdEl = document.createElement('td');
    tdEl.textContent = Math.round(this.hourlySalesArray[i]);
    trEl.appendChild(tdEl);
  };

  cookieTable.appendChild(trEl);
};

var wholeTable = function() {
  makeHeaderRow();
  for(var i = 0; i < cookieStandsArray.length; i++) {
    cookieStandsArray[i].render();
    console.log(cookieStandsArray[i]);
  }
};
// pushed carts into array
var firstAndPike = new PatCookiesLocation('First and Pike', 23, 65, 6.3, 'pikeID');
var seaTac = new PatCookiesLocation('SeaTac', 3, 24, 1.2, 'seaTacID');
var seaCenter = new PatCookiesLocation('Seattle Center', 11, 38, 3.7, 'seaCenterID');
var capHill = new PatCookiesLocation('Capitol Hill', 20, 38, 2.3, 'capHillID');
var alki = new PatCookiesLocation('Alki', 2, 16, 4.6, 'alkiID');
//appended to table
wholeTable();
<|endoftext|>


<commit_before>var fs = require("fs-extra"),
  findParentDir = require('find-parent-dir'),
  _            = require("lodash"),
  spawn        = require("cross-spawn"),
  chalk = require("chalk"),
  path = require("path");

function toModuleName(filePath) {
  return new Promise(function(resolve, reject) {
    // Read ~60 characters at a time, since most module names will fit in that chunk.
    var readStream = fs.createReadStream(filePath, {encoding: 'utf8', highWaterMark: 8 * 60});
    var data = "";
    var matches = null;

    readStream.on('data', function (chunk) {
      data += chunk;
      matches = data.match(/^module\s+(\S+)\s/);

      if (matches !== null) {
        readStream.close();
      }
    }).on('close', function () {
      if (matches === null) {
        reject(filePath + " is missing a module declaration.");
      } else {
        resolve(matches[1]);
      }
    }).on('error', function (err) {
      reject(err);
    });
  });
}

function copyNativeSrcFiles(newPackageName, srcPath, dest) {
  fs.readdirSync(srcPath).forEach(function(filename) {
    var filePath = path.join(srcPath, filename);
    var newDest = path.join(dest, filename);
    var stats = fs.lstatSync(filePath);

    if (stats.isDirectory()) {
      fs.mkdirpSync(newDest);

      copyNativeSrcFiles(newPackageName, filePath, newDest);
    } else if ((stats.isFile() || stats.isSymbolicLink()) && isJsFile(filename)) {
      var contents = fs.readFileSync(filePath, "utf8");

      // These Native files need to use the local package name,
      // because of how we're hacking them in.
      var newContents = contents.replace(
        /rtfeldman\$node_test_runner([\.=\s]*)/gm,
        newPackageName + "$1"
      );

      fs.writeFileSync(newDest, newContents);
    }
  });
}

function isJsFile(filename) {
  return /\.js$/.test(filename);
}

function isElmFile(filename) {
  return /\.elm$/.test(filename);
}

function repositoryToNativePackageName(repository) {
  // https://github.com/rtfeldman/node-test-runner.git
  //
  // matches[1] = "rtfeldman"
  // matches[2] = "node-test-runner"
  var matches = repository.match(/\/([^\/]+)\/([^\/\.]+)\.git/);

  // From the above example, return "rtfeldman$node_test_runner"
  return [
    matches[1].replace(/-/g, "_"),
    matches[2].replace(/-/g, "_")
  ].join("$");
}

function findNearestElmPackageDir(filePaths) {
  // For each of the given files, try to find an ancestor elm-package.json
  // As soon as we find one, return it.
  for (var index=0; index < filePaths.length; index++) {
    var currentDir = path.dirname(filePaths[index]);
    var result = findParentDir.sync(currentDir, "elm-package.json");

    if (result !== null) {
      return result;
    }
  }

  // If we didn't find any, fall back on the current working directory.
  return process.cwd();
}

function evalElmCode (args, report, compiledCode) {
  // Apply Node polyfills as necessary.
  var window = {Date: Date, addEventListener: function() {}, removeEventListener: function() {}};
  var document = {body: {}, createTextNode: function() {}};
  if (typeof XMLHttpRequest === 'undefined') { XMLHttpRequest = function() { return { addEventListener: function() {}, open: function() {}, send: function() {} }; }; }
  if (typeof FormData === 'undefined') { FormData = function () { this._data = []; }; FormData.prototype.append = function () { this._data.push(Array.prototype.slice.call(arguments)); }; }

  var Elm = function(module) { eval(compiledCode); return module.exports; }({});

  // Make sure necessary things are defined.
  if (typeof Elm === 'undefined') { throw 'test runner config error: Elm is not defined. Make sure you provide a file compiled by Elm!'; }

  var potentialModuleNames = Object.keys(Elm.Test.Generated);

  if (potentialModuleNames.length !== 1) {
    console.error("Multiple potential generated modules to run in the Elm.Test.Generated namespace: ", potentialModuleNames, " - this should never happen!");
    process.exit(1);
  }

  var testModule = Elm.Test.Generated[potentialModuleNames[0]];
  var initialSeed = null;

  if (args.seed !== undefined) {
    initialSeed = args.seed;
  }

  pathToMake = args.compiler;

  // Fix Windows Unicode problems. Credit to https://github.com/sindresorhus/figures for the Windows compat idea!
  var windowsSubstitutions = [[/[↓✗►]/g, '>'], [/╵│╷╹┃╻/g, '|'], [/═/g, '='],, [/▔/g, '-'], [/✔/g, '√']];

  function windowsify(str) {
    return windowsSubstitutions.reduce(
      function(result, sub) { return result.replace(sub[0], sub[1]); }, str);
  }

  function chalkify(messages) {
    return messages.map(function(msg) {
      var path = msg.styles;
      var text = process.platform === 'win32' ? windowsify(msg.text) : msg.text;

      if (path.length === 0) {
        return text;
      } else {
        var fn = chalk;

        path.forEach(function(nextPath) { fn = fn[nextPath]; });

        return fn(text);
      }
    }).join('');
  }

  // Run the Elm app.
  var app = testModule.worker({seed: initialSeed, report: report});

  // Receive messages from ports and translate them into appropriate JS calls.
  app.ports.emit.subscribe(function(msg) {
    var msgType = msg[0];
    var data = msg[1];

    if (msgType === 'FINISHED') {
      if (data.format === "CHALK") {
        console.log(chalkify(data.message));
      } else if (data.format === "JUNIT") {
        console.log(builder.create(data.message).end());
      } else {
        console.log(JSON.stringify(data.message));
      }

      if (!args.watch) {
        process.exit(data.exitCode);
      }
    } else if (msgType === "STARTED" || msgType === "TEST_COMPLETED")  {
        if (data.format === "CHALK") {
          console.log(chalkify(data.message));
        } else if (data.format === "JSON") {
          console.log(JSON.stringify(data.message));
        }

    }
  });
}

var binaryExtension = process.platform === "win32" ? ".exe" : "";
var readElmiPath = path.join(__dirname, "..", "bin", "elm-interface-to-json") + binaryExtension;

function findTests(elmPackageJsonPath) {
  return new Promise(function(resolve, reject) {
    var process = spawn(readElmiPath, ["--path", elmPackageJsonPath]);
    var jsonStr = "";
    var stderrStr = "";

    process.stdout.on('data', function(data) {
      jsonStr += data;
    });

    process.stderr.on('data', function(data) {
      stderrStr += data;
    });

    process.on('close', function(code) {
      if (stderrStr !== "") {
        reject(stderrStr);
      } else if (code !== 0) {
        reject("Finding test interfaces failed, exiting with code " + code);
      }

      var modules;

      try {
        modules = JSON.parse(jsonStr);
      } catch(err) {
        reject("Received invalid JSON from test interface search: " + err);
      }

      var filteredModules = _.flatMap(modules, function(mod) {
        var eligible = _.flatMap(mod.types, function(typ) {
          if (typ.signature === "Test.Test") {
            return typ.name;
          } else {
            return [];
          }
        });

        // Must have at least 1 value of type Test. Otherwise ignore this module.
        if (eligible.length > 0) {
          return [{name: mod.moduleName, tests: eligible}];
        } else {
          return [];
        }
      });

      return resolve(filteredModules);
    });
  });
}

module.exports = {
  toModuleName: toModuleName,
  findTests: findTests,
  evalElmCode: evalElmCode,
  isElmFile: isElmFile,
  copyNativeSrcFiles: copyNativeSrcFiles,
  repositoryToNativePackageName: repositoryToNativePackageName,
  findNearestElmPackageDir: findNearestElmPackageDir
};
<commit_msg>:skull: obsolete function<commit_after>var fs = require("fs-extra"),
  findParentDir = require('find-parent-dir'),
  _            = require("lodash"),
  spawn        = require("cross-spawn"),
  chalk = require("chalk"),
  path = require("path");

function copyNativeSrcFiles(newPackageName, srcPath, dest) {
  fs.readdirSync(srcPath).forEach(function(filename) {
    var filePath = path.join(srcPath, filename);
    var newDest = path.join(dest, filename);
    var stats = fs.lstatSync(filePath);

    if (stats.isDirectory()) {
      fs.mkdirpSync(newDest);

      copyNativeSrcFiles(newPackageName, filePath, newDest);
    } else if ((stats.isFile() || stats.isSymbolicLink()) && isJsFile(filename)) {
      var contents = fs.readFileSync(filePath, "utf8");

      // These Native files need to use the local package name,
      // because of how we're hacking them in.
      var newContents = contents.replace(
        /rtfeldman\$node_test_runner([\.=\s]*)/gm,
        newPackageName + "$1"
      );

      fs.writeFileSync(newDest, newContents);
    }
  });
}

function isJsFile(filename) {
  return /\.js$/.test(filename);
}

function isElmFile(filename) {
  return /\.elm$/.test(filename);
}

function repositoryToNativePackageName(repository) {
  // https://github.com/rtfeldman/node-test-runner.git
  //
  // matches[1] = "rtfeldman"
  // matches[2] = "node-test-runner"
  var matches = repository.match(/\/([^\/]+)\/([^\/\.]+)\.git/);

  // From the above example, return "rtfeldman$node_test_runner"
  return [
    matches[1].replace(/-/g, "_"),
    matches[2].replace(/-/g, "_")
  ].join("$");
}

function findNearestElmPackageDir(filePaths) {
  // For each of the given files, try to find an ancestor elm-package.json
  // As soon as we find one, return it.
  for (var index=0; index < filePaths.length; index++) {
    var currentDir = path.dirname(filePaths[index]);
    var result = findParentDir.sync(currentDir, "elm-package.json");

    if (result !== null) {
      return result;
    }
  }

  // If we didn't find any, fall back on the current working directory.
  return process.cwd();
}

function evalElmCode (args, report, compiledCode) {
  // Apply Node polyfills as necessary.
  var window = {Date: Date, addEventListener: function() {}, removeEventListener: function() {}};
  var document = {body: {}, createTextNode: function() {}};
  if (typeof XMLHttpRequest === 'undefined') { XMLHttpRequest = function() { return { addEventListener: function() {}, open: function() {}, send: function() {} }; }; }
  if (typeof FormData === 'undefined') { FormData = function () { this._data = []; }; FormData.prototype.append = function () { this._data.push(Array.prototype.slice.call(arguments)); }; }

  var Elm = function(module) { eval(compiledCode); return module.exports; }({});

  // Make sure necessary things are defined.
  if (typeof Elm === 'undefined') { throw 'test runner config error: Elm is not defined. Make sure you provide a file compiled by Elm!'; }

  var potentialModuleNames = Object.keys(Elm.Test.Generated);

  if (potentialModuleNames.length !== 1) {
    console.error("Multiple potential generated modules to run in the Elm.Test.Generated namespace: ", potentialModuleNames, " - this should never happen!");
    process.exit(1);
  }

  var testModule = Elm.Test.Generated[potentialModuleNames[0]];
  var initialSeed = null;

  if (args.seed !== undefined) {
    initialSeed = args.seed;
  }

  pathToMake = args.compiler;

  // Fix Windows Unicode problems. Credit to https://github.com/sindresorhus/figures for the Windows compat idea!
  var windowsSubstitutions = [[/[↓✗►]/g, '>'], [/╵│╷╹┃╻/g, '|'], [/═/g, '='],, [/▔/g, '-'], [/✔/g, '√']];

  function windowsify(str) {
    return windowsSubstitutions.reduce(
      function(result, sub) { return result.replace(sub[0], sub[1]); }, str);
  }

  function chalkify(messages) {
    return messages.map(function(msg) {
      var path = msg.styles;
      var text = process.platform === 'win32' ? windowsify(msg.text) : msg.text;

      if (path.length === 0) {
        return text;
      } else {
        var fn = chalk;

        path.forEach(function(nextPath) { fn = fn[nextPath]; });

        return fn(text);
      }
    }).join('');
  }

  // Run the Elm app.
  var app = testModule.worker({seed: initialSeed, report: report});

  // Receive messages from ports and translate them into appropriate JS calls.
  app.ports.emit.subscribe(function(msg) {
    var msgType = msg[0];
    var data = msg[1];

    if (msgType === 'FINISHED') {
      if (data.format === "CHALK") {
        console.log(chalkify(data.message));
      } else if (data.format === "JUNIT") {
        console.log(builder.create(data.message).end());
      } else {
        console.log(JSON.stringify(data.message));
      }

      if (!args.watch) {
        process.exit(data.exitCode);
      }
    } else if (msgType === "STARTED" || msgType === "TEST_COMPLETED")  {
        if (data.format === "CHALK") {
          console.log(chalkify(data.message));
        } else if (data.format === "JSON") {
          console.log(JSON.stringify(data.message));
        }

    }
  });
}

var binaryExtension = process.platform === "win32" ? ".exe" : "";
var readElmiPath = path.join(__dirname, "..", "bin", "elm-interface-to-json") + binaryExtension;

function findTests(elmPackageJsonPath) {
  return new Promise(function(resolve, reject) {
    var process = spawn(readElmiPath, ["--path", elmPackageJsonPath]);
    var jsonStr = "";
    var stderrStr = "";

    process.stdout.on('data', function(data) {
      jsonStr += data;
    });

    process.stderr.on('data', function(data) {
      stderrStr += data;
    });

    process.on('close', function(code) {
      if (stderrStr !== "") {
        reject(stderrStr);
      } else if (code !== 0) {
        reject("Finding test interfaces failed, exiting with code " + code);
      }

      var modules;

      try {
        modules = JSON.parse(jsonStr);
      } catch(err) {
        reject("Received invalid JSON from test interface search: " + err);
      }

      var filteredModules = _.flatMap(modules, function(mod) {
        var eligible = _.flatMap(mod.types, function(typ) {
          if (typ.signature === "Test.Test") {
            return typ.name;
          } else {
            return [];
          }
        });

        // Must have at least 1 value of type Test. Otherwise ignore this module.
        if (eligible.length > 0) {
          return [{name: mod.moduleName, tests: eligible}];
        } else {
          return [];
        }
      });

      return resolve(filteredModules);
    });
  });
}

module.exports = {
  findTests: findTests,
  evalElmCode: evalElmCode,
  isElmFile: isElmFile,
  copyNativeSrcFiles: copyNativeSrcFiles,
  repositoryToNativePackageName: repositoryToNativePackageName,
  findNearestElmPackageDir: findNearestElmPackageDir
};
<|endoftext|>


<commit_before>if (Meteor.isServer) {
  // This code only runs on the server

    Meteor.publish("singleProject", function (projectId) {
          return Projects.find({ _id: projectId });
    });
}
<commit_msg>removed unneccesary code and commented<commit_after>//The single singleProject publication return a cursors with a single project using the projectId as an argument
Meteor.publish("singleProject", function (projectId) {
      return Projects.find({ _id: projectId });
});
<|endoftext|>


<commit_before>'use strict';

// Imports
const childProcess = require('child_process');
const stream = require('stream');
const utils = require('./utils');

// Variables
let aliasNames;

// Exports
const runner = module.exports = {
  /**
   * A configuration object, specifying the behavior of {@link runner#run run()}.
   * @typedef {Object} RunConfig
   * @property {boolean} debug - If true, produce verbose, debug-friendly output.
   *     (Default: false)
   * @property {boolean} dryrun - If true, print the command instead of actually running it.
   *     (Default: false)
   *     NOTE: This is still an experimental feature and not guaranteed to work as expected.
   * @property {boolean|Number} returnOutput - If true, return the output of the command instead of printing it to
   *     stdout. If a number (`n`), print the output to stdout, but also return the `n` last lines (ignoring trailing
   *     whitespace).
   *     (Default: false)
   */

  /**
   * @function preprocessArgs
   *
   * @description
   * Preprocess a list of input arguments (e.g. `process.argv.slice(2)`) into a list of arguments that can be used for
   * substituting into commands (i.e. filtering out `--al-` arguments and wrapping remaining argument in double-quotes,
   * if necessary). Also, derive a {@link runner#RunConfig configuration object} (based on `--al-` arguments) to modify
   * the behavior of {@link runner#run run()} (e.g. enable debug output).
   *
   * @param {string[]} rawArgs - The input arguments that will be preprocessed.
   *
   * @return {{args: string[], config: RunConfig}} result - An object contaning a list of arguments that can be used for
   *     substituting and a {@link runner#RunConfig configuration object}.
   */
  preprocessArgs: _preprocessArgs,

  /**
   * @function run
   *
   * @description
   * Run a command. Could be a complex command with `|`, `&&` and `||` (but not guaranteed to work if too complex :)).
   *
   * It supports argument substitution (independently of the underlying OS) and default/fallback arguments (specified
   * either as static values or as commands to execute and use the output). The following rules apply:
   * - `$*`, `${*}`: Substitute with all arguments (if any).
   * - `$n`, `${n}`: Substitute with the nth argument (if specified), where `n` is a positive integer.
   * - `${*:value}`, `${n:value}`: Substitute with all arguments (`*`) or the nth argument (`n`). If not specified,
   *   substitute with `value`.
   * - `${*:\`command\`}`, `${n:\`command\`}`: Substitute with all arguments (`*`) or the nth argument (`n`). If not
   *   specified, run `command` and substitute with its trimmed output.
   *
   * Hint: `${0:\`command\`}` will always be substituted with the output of `command`. This is useful when you want to
   *       always use the output of `command` in an OS-independent way.
   *
   * You can use {@link runner#preprocessArgs preprocessArgs()} to obtain the basic `runtimeArgs` and `config` values.
   * For example: `preprocessArgs(process.argv.slice(2))`.
   *
   * @param {string} cmd - The command to run. Could be a complex command with `|`, `&&` and `||` (but not guaranteed to
   *     work if too complex :)).
   * @param {string[]} [runtimeArgs=[]] - The runtime arguments that will be used for substituting.
   * @param {RunConfig} [config={}] - A configuration object. See {@link runner#RunConfig} for more details.
   *
   * @return {Promise<string>} - A promise that resolves once the command has been executed. The resolved value is
   *     either an empty string or the output of the command (if `returnOutput` is true).
   */
  run: _run,

  /** Exposed for testing purposes only. */
  _expandCmd: expandCmd,

  /** Exposed for testing purposes only. */
  _spawnAsPromised: spawnAsPromised,
};

// Functions - Definitions
function _preprocessArgs(rawArgs) {
  const alArgRe = /^--al-(?=[a-z])/;
  const quoteIfNecessary = arg => /\s/.test(arg) ? `"${arg}"` : arg;

  const config = Object.create(null);
  const args = rawArgs.
    filter(arg => !(alArgRe.test(arg) && (config[arg.replace(alArgRe, '')] = true))).
    map(quoteIfNecessary);

  return {args, config};
}

function _run(cmd, runtimeArgs, config) {
  return doRun(cmd, runtimeArgs || [], config || {}).catch(utils.onError);
}

function checkInsertAt(newItem, idx, arr) {
  if (arr[idx] === '(') {
    ++idx;
  }

  if (arr[idx] !== newItem) {
    if (aliasNames.indexOf(arr[idx]) === -1) {
      arr.splice(idx, 0, newItem);
    } else {
      arr.splice(idx + 1, 0, '--al-dryrun');
    }
  }
}

function doRun(cmd, runtimeArgs, config) {
  return runner._expandCmd(cmd, runtimeArgs, config).then(expandedCmd => {
    if (config.debug) {
      console.log(`Input command: '${cmd}'`);
      console.log(`Expanded command: '${expandedCmd}'`);
    }
    return runner._spawnAsPromised(expandedCmd, config);
  });
}

function expandCmd(cmd, runtimeArgs, config) {
  // 1: leading \s
  // 2, 4: $*
  // 3, 5: $\d+
  // 6: default/fallback value (possibly with `returnOutput` limit)
  const re = /(\s{0,1})\$(?:(\*)|(\d+)|{(?:(?:(\*)|(\d+))(?::([^}]*))?)})/g;
  const cmdPromises = {};

  let expandedCmd = cmd.replace(re, (_, g1, g2, g3, g4, g5, g6) => {
    const valToReplacement = val => !val ? '' : `${g1}${val}`;

    // Value based on the supplied arguments.
    let value = (g2 || g4) ? runtimeArgs.join(' ') : runtimeArgs[(g3 || g5) - 1];

    // No argument(s), fall back to default.
    if (!value && g6) {
      const match = /^`(.+)`$/.exec(g6);

      if (!match) {
        // It is a plain ol' fallback value.
        value = g6;
      } else {
        // It is a command.
        let returnOutput = true;
        const cmd = match[1].replace(/ --al-returnOutput=(\d+)$/, (_, g) => {
          returnOutput = Number(g);
          return '';
        });
        const placeholder = Math.random();
        const runConfig = Object.assign({}, config, {returnOutput});

        cmdPromises[cmd] = (cmdPromises[cmd] || doRun(cmd, runtimeArgs, runConfig)).
          then(result => result.trim()).
          then(result => {
            const repl = valToReplacement(runConfig.dryrun ? `{{${result.replace(/\s/g, '_')}}}` : result);
            expandedCmd = expandedCmd.replace(placeholder, repl);
            return result;
          });

        return placeholder;
      }
    }

    return valToReplacement(value);
  });

  return Promise.
    all(Object.keys(cmdPromises).map(cmd => cmdPromises[cmd])).
    then(() => expandedCmd);
}

function insertAfter(newItem, afterItem, arr) {
  for (let i = 0; i < arr.length; ++i) {
    if (arr[i] === afterItem) {
      checkInsertAt(newItem, i + 1, arr);
    }
  }
}

function parseSingleCmd(cmd, dryrun) {
  const tokens = cmd.
    split('"').
    reduce((arr, str, idx) => {
      const newTokens = (idx % 2) ? [`"${str}"`] : str.split(' ');
      const lastToken = arr[arr.length - 1];

      if (lastToken) arr[arr.length - 1] += newTokens.shift();

      return arr.concat(newTokens);
    }, []).
    filter(Boolean).
    reduce((arr, str) => {
      if (str[0] === '(') {
        arr.push('(', str.slice(1));
      } else {
        arr.push(str);
      }
      return arr;
    }, []);

  if (dryrun) {
    transformForDryrun(tokens);
  }

  return {
    executable: tokens.shift(),
    args: tokens,
  };
}

function spawnAsPromised(rawCmd, {debug, dryrun, returnOutput}) {
  return new Promise((resolve, reject) => {
    let data = '';

    const getReturnData = (typeof returnOutput !== 'number') ?
      () => data :
      () => data.trim().split('\n').slice(-returnOutput).join('\n');

    const pipedCmdSpecs = rawCmd.
      split(/\s+\|\s+/).
      map(cmd => parseSingleCmd(cmd, dryrun));

    const lastStdout = pipedCmdSpecs.reduce((prevStdout, cmdSpec, idx, arr) => {
      const isLast = idx === arr.length - 1;
      const pipeOuput = !isLast || returnOutput;

      const executable = cmdSpec.executable;
      const args = cmdSpec.args;
      const options = {
        shell: true,
        stdio: [
          prevStdout ? 'pipe' : 'inherit',
          pipeOuput ? 'pipe' : 'inherit',
          'inherit',
        ],
      };

      if (debug) {
        console.log(`  Running ${idx + 1}/${arr.length}: '${executable}', '${args}', (stdio: ${options.stdio})`);
      }

      const proc = childProcess.spawn(executable, args, options).
        on('error', reject).
        on('exit', (code, signal) => {
          if (code !== 0) return reject(code || signal);
          if (isLast) return resolve(getReturnData());
        });

      if (prevStdout) prevStdout.pipe(proc.stdin);

      return proc.stdout;
    }, null);

    if (returnOutput) {
      const outputStream = new stream.PassThrough();
      outputStream.on('data', d => data += d);
      lastStdout.pipe(outputStream);

      if (returnOutput !== true) {
        outputStream.pipe(process.stdout);
      }
    }
  });
}

function transformForDryrun(tokens) {
  if (!aliasNames) {
    const aliases = require('./constants').ALIASES;
    aliasNames = Object.keys(aliases).
      map(category => Object.keys(aliases[category])).
      reduce((aggr, arr) => aggr.concat(arr)).
      sort();
  }

  checkInsertAt('echo', 0, tokens);
  insertAfter('echo', '&&', tokens);
  insertAfter('echo', '||', tokens);
}
<commit_msg>feat(runner): restore the output style on exit (to fix misbehaving commands)<commit_after>'use strict';

// Imports
const childProcess = require('child_process');
const stream = require('stream');
const utils = require('./utils');

// Variables
let aliasNames;

// Exports
const runner = module.exports = {
  /**
   * A configuration object, specifying the behavior of {@link runner#run run()}.
   * @typedef {Object} RunConfig
   * @property {boolean} debug - If true, produce verbose, debug-friendly output.
   *     (Default: false)
   * @property {boolean} dryrun - If true, print the command instead of actually running it.
   *     (Default: false)
   *     NOTE: This is still an experimental feature and not guaranteed to work as expected.
   * @property {boolean|Number} returnOutput - If true, return the output of the command instead of printing it to
   *     stdout. If a number (`n`), print the output to stdout, but also return the `n` last lines (ignoring trailing
   *     whitespace).
   *     (Default: false)
   */

  /**
   * @function preprocessArgs
   *
   * @description
   * Preprocess a list of input arguments (e.g. `process.argv.slice(2)`) into a list of arguments that can be used for
   * substituting into commands (i.e. filtering out `--al-` arguments and wrapping remaining argument in double-quotes,
   * if necessary). Also, derive a {@link runner#RunConfig configuration object} (based on `--al-` arguments) to modify
   * the behavior of {@link runner#run run()} (e.g. enable debug output).
   *
   * @param {string[]} rawArgs - The input arguments that will be preprocessed.
   *
   * @return {{args: string[], config: RunConfig}} result - An object contaning a list of arguments that can be used for
   *     substituting and a {@link runner#RunConfig configuration object}.
   */
  preprocessArgs: _preprocessArgs,

  /**
   * @function run
   *
   * @description
   * Run a command. Could be a complex command with `|`, `&&` and `||` (but not guaranteed to work if too complex :)).
   *
   * It supports argument substitution (independently of the underlying OS) and default/fallback arguments (specified
   * either as static values or as commands to execute and use the output). The following rules apply:
   * - `$*`, `${*}`: Substitute with all arguments (if any).
   * - `$n`, `${n}`: Substitute with the nth argument (if specified), where `n` is a positive integer.
   * - `${*:value}`, `${n:value}`: Substitute with all arguments (`*`) or the nth argument (`n`). If not specified,
   *   substitute with `value`.
   * - `${*:\`command\`}`, `${n:\`command\`}`: Substitute with all arguments (`*`) or the nth argument (`n`). If not
   *   specified, run `command` and substitute with its trimmed output.
   *
   * Hint: `${0:\`command\`}` will always be substituted with the output of `command`. This is useful when you want to
   *       always use the output of `command` in an OS-independent way.
   *
   * You can use {@link runner#preprocessArgs preprocessArgs()} to obtain the basic `runtimeArgs` and `config` values.
   * For example: `preprocessArgs(process.argv.slice(2))`.
   *
   * @param {string} cmd - The command to run. Could be a complex command with `|`, `&&` and `||` (but not guaranteed to
   *     work if too complex :)).
   * @param {string[]} [runtimeArgs=[]] - The runtime arguments that will be used for substituting.
   * @param {RunConfig} [config={}] - A configuration object. See {@link runner#RunConfig} for more details.
   *
   * @return {Promise<string>} - A promise that resolves once the command has been executed. The resolved value is
   *     either an empty string or the output of the command (if `returnOutput` is true).
   */
  run: _run,

  /** Exposed for testing purposes only. */
  _expandCmd: expandCmd,

  /** Exposed for testing purposes only. */
  _spawnAsPromised: spawnAsPromised,
};

// Functions - Definitions
function _preprocessArgs(rawArgs) {
  const alArgRe = /^--al-(?=[a-z])/;
  const quoteIfNecessary = arg => /\s/.test(arg) ? `"${arg}"` : arg;

  const config = Object.create(null);
  const args = rawArgs.
    filter(arg => !(alArgRe.test(arg) && (config[arg.replace(alArgRe, '')] = true))).
    map(quoteIfNecessary);

  return {args, config};
}

function _run(cmd, runtimeArgs, config) {
  return doRun(cmd, runtimeArgs || [], config || {}).catch(utils.onError);
}

function checkInsertAt(newItem, idx, arr) {
  if (arr[idx] === '(') {
    ++idx;
  }

  if (arr[idx] !== newItem) {
    if (aliasNames.indexOf(arr[idx]) === -1) {
      arr.splice(idx, 0, newItem);
    } else {
      arr.splice(idx + 1, 0, '--al-dryrun');
    }
  }
}

function doRun(cmd, runtimeArgs, config) {
  return runner._expandCmd(cmd, runtimeArgs, config).then(expandedCmd => {
    if (config.debug) {
      console.log(`Input command: '${cmd}'`);
      console.log(`Expanded command: '${expandedCmd}'`);
    }
    return runner._spawnAsPromised(expandedCmd, config);
  });
}

function expandCmd(cmd, runtimeArgs, config) {
  // 1: leading \s
  // 2, 4: $*
  // 3, 5: $\d+
  // 6: default/fallback value (possibly with `returnOutput` limit)
  const re = /(\s{0,1})\$(?:(\*)|(\d+)|{(?:(?:(\*)|(\d+))(?::([^}]*))?)})/g;
  const cmdPromises = {};

  let expandedCmd = cmd.replace(re, (_, g1, g2, g3, g4, g5, g6) => {
    const valToReplacement = val => !val ? '' : `${g1}${val}`;

    // Value based on the supplied arguments.
    let value = (g2 || g4) ? runtimeArgs.join(' ') : runtimeArgs[(g3 || g5) - 1];

    // No argument(s), fall back to default.
    if (!value && g6) {
      const match = /^`(.+)`$/.exec(g6);

      if (!match) {
        // It is a plain ol' fallback value.
        value = g6;
      } else {
        // It is a command.
        let returnOutput = true;
        const cmd = match[1].replace(/ --al-returnOutput=(\d+)$/, (_, g) => {
          returnOutput = Number(g);
          return '';
        });
        const placeholder = Math.random();
        const runConfig = Object.assign({}, config, {returnOutput});

        cmdPromises[cmd] = (cmdPromises[cmd] || doRun(cmd, runtimeArgs, runConfig)).
          then(result => result.trim()).
          then(result => {
            const repl = valToReplacement(runConfig.dryrun ? `{{${result.replace(/\s/g, '_')}}}` : result);
            expandedCmd = expandedCmd.replace(placeholder, repl);
            return result;
          });

        return placeholder;
      }
    }

    return valToReplacement(value);
  });

  return Promise.
    all(Object.keys(cmdPromises).map(cmd => cmdPromises[cmd])).
    then(() => expandedCmd);
}

function insertAfter(newItem, afterItem, arr) {
  for (let i = 0; i < arr.length; ++i) {
    if (arr[i] === afterItem) {
      checkInsertAt(newItem, i + 1, arr);
    }
  }
}

function parseSingleCmd(cmd, dryrun) {
  const tokens = cmd.
    split('"').
    reduce((arr, str, idx) => {
      const newTokens = (idx % 2) ? [`"${str}"`] : str.split(' ');
      const lastToken = arr[arr.length - 1];

      if (lastToken) arr[arr.length - 1] += newTokens.shift();

      return arr.concat(newTokens);
    }, []).
    filter(Boolean).
    reduce((arr, str) => {
      if (str[0] === '(') {
        arr.push('(', str.slice(1));
      } else {
        arr.push(str);
      }
      return arr;
    }, []);

  if (dryrun) {
    transformForDryrun(tokens);
  }

  return {
    executable: tokens.shift(),
    args: tokens,
  };
}

function spawnAsPromised(rawCmd, {debug, dryrun, returnOutput}) {
  return new Promise((resolve, reject) => {
    let data = '';

    const getReturnData = (typeof returnOutput !== 'number') ?
      () => data :
      () => data.trim().split('\n').slice(-returnOutput).join('\n');

    const pipedCmdSpecs = rawCmd.
      split(/\s+\|\s+/).
      map(cmd => parseSingleCmd(cmd, dryrun));

    const lastStdout = pipedCmdSpecs.reduce((prevStdout, cmdSpec, idx, arr) => {
      const isLast = idx === arr.length - 1;
      const pipeOuput = !isLast || returnOutput;

      const executable = cmdSpec.executable;
      const args = cmdSpec.args;
      const options = {
        shell: true,
        stdio: [
          prevStdout ? 'pipe' : 'inherit',
          pipeOuput ? 'pipe' : 'inherit',
          'inherit',
        ],
      };

      if (debug) {
        console.log(`  Running ${idx + 1}/${arr.length}: '${executable}', '${args}', (stdio: ${options.stdio})`);
      }

      const proc = childProcess.spawn(executable, args, options).
        on('error', reject).
        on('exit', (code, signal) => {
          if (isLast && (returnOutput !== true)) {
            // We have been piping output to `process.stdout`.
            // Restore the output style in case a command didn't play nice (e.g. `yarn`).
            process.stdout.write('\u001b[0m');
          }

          if (code !== 0) return reject(code || signal);
          if (isLast) return resolve(getReturnData());
        });

      if (prevStdout) prevStdout.pipe(proc.stdin);

      return proc.stdout;
    }, null);

    if (returnOutput) {
      const outputStream = new stream.PassThrough();
      outputStream.on('data', d => data += d);
      lastStdout.pipe(outputStream);

      if (returnOutput !== true) {
        outputStream.pipe(process.stdout);
      }
    }
  });
}

function transformForDryrun(tokens) {
  if (!aliasNames) {
    const aliases = require('./constants').ALIASES;
    aliasNames = Object.keys(aliases).
      map(category => Object.keys(aliases[category])).
      reduce((aggr, arr) => aggr.concat(arr)).
      sort();
  }

  checkInsertAt('echo', 0, tokens);
  insertAfter('echo', '&&', tokens);
  insertAfter('echo', '||', tokens);
}
<|endoftext|>


<commit_before>var express = require('express'),
  fs = require('fs'),
  http = require('http'),
  moment = require('moment'),
  events = require('./events')
  moreEvents = require('./events/more_events'),
  request = require('request'),
  jf = require('jsonfile'),
  githubFeed = require('./jobs/github_feed'),
  app = express();

var githubJson = { repos: [] },
  eventsJson = [];

app.configure(function(){
  app.set('port', process.env.PORT || 4000);
  app.use(express.compress());
  app.use('/public', express.static(__dirname + '/public'));
  app.use(express.favicon(__dirname + '/public/favicon.ico'));

  app.use(express.errorHandler());
  app.locals.pretty = true;
  app.locals.moment = require('moment');

  app.use(express.bodyParser());
  app.use(express.methodOverride());
});

function timeComparer(a, b) {
  function momentcast(x) {
    return x.time ? moment(new Date(x.time))
                  : moment(x.formatted_time, 'DD MMM, ddd, h:mm a');
  }
  return (momentcast(a).valueOf() - momentcast(b).valueOf());
}

function updateEventsJson() {
  console.log('Updating the events feed...');
  return events.getMeetupEvents()
  .then(function(events) {
    eventsJson = events.concat(moreEvents);
    eventsJson.sort(timeComparer);
    console.log('The events feed has been updated!');
  })
  .catch(function(err) {
    console.error(err);
  })
}

app.get('/', function(req, res) {
  res.render('index.jade', {
    github: githubJson.repos.slice(0, 10),
    events: eventsJson.slice(0, 10)
  });
});

app.get('/api/events', function(req, res) {
  res.send(eventsJson);
});

app.get('/api/github', function(req, res) {
  res.send(githubJson);
});

app.post('/api/events/update', function(req, res) {
  if (req.param('secret') !== process.env.WEBUILD_API_SECRET) {
    res.send(503, 'Incorrect secret key');
  }
  updateEventsJson()
  .then(function() {
    res.send(200, 'Events feed updated');
  })
  .catch(function() {
    res.send(500, 'Failed to update feed');
  });
})

app.post('/api/github/update', function(req, res) {
  if (req.param('secret') !== process.env.WEBUILD_API_SECRET) {
    res.send(503, 'Incorrect secret key');
  }
  githubFeed.update()
    .then(function(feed) {
      console.log('GitHub feed generated');
      githubJson = feed;
      jf.writeFile(__dirname + '/github.json', feed);
    });
  res.send(200, 'Updating the repos feed; sit tight!');
});

fs.exists(__dirname + '/github.json', function(exists) {
  if (exists) {
    jf.readFile(__dirname + '/github.json', function(err, feed) {
      if (!err) {
        githubJson = feed;
      }
    });
  } else {
    console.log('Fetching public repos feed...');
    request('http://webuild.sg/github.json', function(err, res, body) {
      if (!err && res.statusCode === 200) {
        console.log('Cached public repos feed');
        githubJson = body;
        jf.writeFile(__dirname + '/github.json', body);
      } else {
        console.warn('Failed to retrieve data (Status code: %s)', res.statusCode);
      }
    });
  }
});
updateEventsJson();

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});
<commit_msg>More console logging<commit_after>var express = require('express'),
  fs = require('fs'),
  http = require('http'),
  moment = require('moment'),
  events = require('./events')
  moreEvents = require('./events/more_events'),
  request = require('request'),
  jf = require('jsonfile'),
  githubFeed = require('./jobs/github_feed'),
  app = express();

var githubJson = { repos: [] },
  eventsJson = [];

app.configure(function(){
  app.set('port', process.env.PORT || 4000);
  app.use(express.compress());
  app.use('/public', express.static(__dirname + '/public'));
  app.use(express.favicon(__dirname + '/public/favicon.ico'));

  app.use(express.errorHandler());
  app.locals.pretty = true;
  app.locals.moment = require('moment');

  app.use(express.bodyParser());
  app.use(express.methodOverride());
});

function timeComparer(a, b) {
  function momentcast(x) {
    return x.time ? moment(new Date(x.time))
                  : moment(x.formatted_time, 'DD MMM, ddd, h:mm a');
  }
  return (momentcast(a).valueOf() - momentcast(b).valueOf());
}

function updateEventsJson() {
  console.log('Updating the events feed...');
  return events.getMeetupEvents()
  .then(function(events) {
    events.concat(moreEvents).forEach(function(e) {
      eventsJson.push(e)
    })
    eventsJson.sort(timeComparer);
    console.log('The events feed has been updated! ' + eventsJson.length);
  })
  .catch(function(err) {
    console.error(err);
  })
}

app.get('/', function(req, res) {
  res.render('index.jade', {
    github: githubJson.repos.slice(0, 10),
    events: eventsJson.slice(0, 10)
  });
});

app.get('/api/events', function(req, res) {
  res.send(eventsJson);
});

app.get('/api/github', function(req, res) {
  res.send(githubJson);
});

app.post('/api/events/update', function(req, res) {
  if (req.param('secret') !== process.env.WEBUILD_API_SECRET) {
    res.send(503, 'Incorrect secret key');
  }
  updateEventsJson()
  .then(function() {
    res.send(200, 'Events feed updated');
  })
  .catch(function() {
    res.send(500, 'Failed to update feed');
  });
})

app.post('/api/github/update', function(req, res) {
  if (req.param('secret') !== process.env.WEBUILD_API_SECRET) {
    res.send(503, 'Incorrect secret key');
  }
  githubFeed.update()
    .then(function(feed) {
      console.log('GitHub feed generated');
      githubJson = feed;
      jf.writeFile(__dirname + '/github.json', feed);
    });
  res.send(200, 'Updating the repos feed; sit tight!');
});

fs.exists(__dirname + '/github.json', function(exists) {
  if (exists) {
    jf.readFile(__dirname + '/github.json', function(err, feed) {
      if (!err) {
        githubJson = feed;
      }
    });
  } else {
    console.log('Fetching public repos feed...');
    request('http://webuild.sg/github.json', function(err, res, body) {
      if (!err && res.statusCode === 200) {
        console.log('Cached public repos feed');
        githubJson = body;
        jf.writeFile(__dirname + '/github.json', body);
      } else {
        console.warn('Failed to retrieve data (Status code: %s)', res.statusCode);
      }
    });
  }
});
updateEventsJson();

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});
<|endoftext|>


<commit_before>var Queue        = require( './utils/queue' );
var WPT          = require( 'webpagetest' );
var _            = require( 'lodash' );
var EventEmitter = require( 'events' ).EventEmitter;
var util         = require( 'util' );

var Runner = function( options ) {
  this.emit(
    'msg',
    'Initialized Runner'
  );

  this.options = options;
  this.wpt = new WPT( this.options.wpt.server );

  this.data  = {};
  this.queue = new Queue();

  EventEmitter.call( this );
};

util.inherits( Runner, EventEmitter );

/**
 * [run description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
Runner.prototype.run = function( callback ) {
  // store the callback to not pass it around the whole time
  this.done = callback;

  this.emit(
    'msg',
    ' (╯°□°)╯  Starting to call WPT to evaluate all 3rd party requests '
  );

  this.emit(
    'msg',
    'Running with following configuration options:' +
    JSON.stringify( this.options, null, 2 )
  );

  // evaluate all 3rd parties
  this._get3rdParties( function( err, src, thirdParties ) {
    if ( err ) {
      this.done( err );

      return;
    }

    var numberOfRequests = thirdParties.length;

    thirdParties = _.reduce( thirdParties, function( thirdParties, domain ) {
      if ( thirdParties.indexOf( domain ) === -1 ) {
        thirdParties.push( domain );
      }

      return thirdParties;
    }, [] );

    this.thirdPartyDomains = thirdParties;

    this.emit( 'evaluated3rdParties', thirdParties );

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

Runner.prototype._emitData = function( data ) {
  this.emit( 'data', {
    allowedUrls : '*',
    blockedUrls : 'none',
    firstView   : {
      bytesDocComplete : data.response.data.median.firstView.bytesInDoc,
      bytesDocLoad     : data.response.data.median.firstView.bytesIn,
      domElements      : data.response.data.median.firstView.domElements,
      loadEnd          : data.response.data.median.firstView.domContentLoadedEventEnd,
      loadTime         : data.response.data.median.firstView.loadTime,
      render           : data.response.data.median.firstView.render,
      requests         : data.response.data.median.firstView.requests[ 0 ]

    },
    repeatView  : {
      bytesDocComplete : data.response.data.median.repeatView.bytesInDoc,
      bytesDocLoad     : data.response.data.median.repeatView.bytesIn,
      domElements      : data.response.data.median.repeatView.domElements,
      loadEnd          : data.response.data.median.repeatView.domContentLoadedEventEnd,
      loadTime         : data.response.data.median.repeatView.loadTime,
      render           : data.response.data.median.repeatView.render,
      requests         : data.response.data.median.repeatView.requests[ 0 ]
    },
    summary : data.response.data.summary
  } );
}

/**
 * [_get3rdParties description]
 * @param  {Function} callback [description]
 */
Runner.prototype._get3rdParties = function( callback ) {
  var options = _.clone( this.options.wpt );

  // set number of runs to 1
  options.runs = 1;

  this.emit(
    'msg',
    'Calling api with following options : ' + JSON.stringify( this.options.wpt, null, 2 )
  );
  this.wpt.runTest(
    this.options.runner.url,
    options,
    function( error, data ) {
      if ( error ) {
        this.emit(
          'error',
          error
        );
      }

      this._emitData( data );

      // reduce and filter third parties
      var thirdParties = _.reduce(
        data.response.data.median.firstView.requests[ 1 ].request,
        function( thirdParties, request ) {
          // console.log( request );
          var isAllowed    = false;
          var i            = 0;
          var length       = this.options.runner.allowedDomains.length;

          for( ; i < length; ++ i ) {
            // TODO put a regex thing in here
            if (
              !isAllowed &&
              request.host.indexOf( this.options.runner.allowedDomains[ i ] ) !== -1
            ) {
              isAllowed = true;
            }
          }

          if ( !isAllowed ) {
            thirdParties.push( request.host );
          }

          return thirdParties;
        },
        [],
        this
      );

      callback( error, data.response.data.summary, thirdParties );
    }.bind( this )
  );
};

Runner.prototype._run = function( options ) {
  options = options || {};

  this.emit(
    'msg',
    options.allowedThirdPartyDomain ?
    ' -> Starting to evaluate metrics for included ' + options.allowedThirdPartyDomain :
    ' -> Starting to evaluate metrics for all blocked 3rd parties'
  );

  var wptOptions = _.clone( this.options.wpt );

  wptOptions.block = _.reduce( this.thirdPartyDomains, function( block, domain ) {
    if ( domain !== options.allowedThirdPartyDomain ) {
      block.push( domain );
    }

    return block;
  }, [] ).join( ' ' );

  this.emit(
    'msg',
    'Calling api with following options : ' + JSON.stringify( wptOptions, null, 2 )
  );

  this.wpt.runTest(
    this.options.runner.url,
    wptOptions,
    function( error, data ) {
      if ( error ) {
        this.emit( 'error', error );
      } else {
        this._emitData( data );
      }

      this.queue.pop();

      // yeah we're done!!! 8-)
      if ( this.queue.isEmpty() ) {
        this.done();
      }
    }.bind( this )
  );
};

/**
 * done
 * @return {[type]} [description]
 */
Runner.prototype._runAll = function() {
  this.emit(
    'msg',
    ' (╯°□°)╯  Starting to call WPT to evaluate load times and request counts '
  );

  var i      = 0;
  var length = this.thirdPartyDomains.length;

  this.queue.push( function( i ) {
    this._run();
  }.bind( this, [ i ] ) );

  for ( ; i < length; ++i ) {
    this.queue.push( function( i ) {
      this._run( {
        allowedThirdPartyDomain : this.thirdPartyDomains[ i ]
      } );
    }.bind( this, [ i ] ) );
  }
};

module.exports = Runner;
<commit_msg>fixed allowedUrls and blockedUrls in emitted data<commit_after>var Queue        = require( './utils/queue' );
var WPT          = require( 'webpagetest' );
var _            = require( 'lodash' );
var EventEmitter = require( 'events' ).EventEmitter;
var util         = require( 'util' );

var Runner = function( options ) {
  this.emit(
    'msg',
    'Initialized Runner'
  );

  this.options = options;
  this.wpt = new WPT( this.options.wpt.server );

  this.data  = {};
  this.queue = new Queue();

  EventEmitter.call( this );
};

util.inherits( Runner, EventEmitter );

/**
 * [run description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
Runner.prototype.run = function( callback ) {
  // store the callback to not pass it around the whole time
  this.done = callback;

  this.emit(
    'msg',
    ' (╯°□°)╯  Starting to call WPT to evaluate all 3rd party requests '
  );

  this.emit(
    'msg',
    'Running with following configuration options:' +
    JSON.stringify( this.options, null, 2 )
  );

  // evaluate all 3rd parties
  this._get3rdParties( function( err, src, thirdParties ) {
    if ( err ) {
      this.done( err );

      return;
    }

    var numberOfRequests = thirdParties.length;

    thirdParties = _.reduce( thirdParties, function( thirdParties, domain ) {
      if ( thirdParties.indexOf( domain ) === -1 ) {
        thirdParties.push( domain );
      }

      return thirdParties;
    }, [] );

    this.thirdPartyDomains = thirdParties;

    this.emit( 'evaluated3rdParties', thirdParties );

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

Runner.prototype._emitData = function( data ) {
  this.emit( 'data', {
    allowedUrls : data.allowedUrls,
    blockedUrls : data.blockedUrls,
    firstView   : {
      bytesDocComplete : data.response.data.median.firstView.bytesInDoc,
      bytesDocLoad     : data.response.data.median.firstView.bytesIn,
      domElements      : data.response.data.median.firstView.domElements,
      loadEnd          : data.response.data.median.firstView.domContentLoadedEventEnd,
      loadTime         : data.response.data.median.firstView.loadTime,
      render           : data.response.data.median.firstView.render,
      requests         : data.response.data.median.firstView.requests[ 0 ]

    },
    repeatView  : {
      bytesDocComplete : data.response.data.median.repeatView.bytesInDoc,
      bytesDocLoad     : data.response.data.median.repeatView.bytesIn,
      domElements      : data.response.data.median.repeatView.domElements,
      loadEnd          : data.response.data.median.repeatView.domContentLoadedEventEnd,
      loadTime         : data.response.data.median.repeatView.loadTime,
      render           : data.response.data.median.repeatView.render,
      requests         : data.response.data.median.repeatView.requests[ 0 ]
    },
    summary : data.response.data.summary
  } );
}

/**
 * [_get3rdParties description]
 * @param  {Function} callback [description]
 */
Runner.prototype._get3rdParties = function( callback ) {
  var options = _.clone( this.options.wpt );

  // set number of runs to 1
  options.runs = 1;

  this.emit(
    'msg',
    'Calling api with following options : ' + JSON.stringify( this.options.wpt, null, 2 )
  );
  this.wpt.runTest(
    this.options.runner.url,
    options,
    function( error, data ) {
      if ( error ) {
        this.emit(
          'error',
          error
        );
      }

      data.allowedUrls = '*';
      data.blockedUrls = 'none';

      this._emitData( data );

      // reduce and filter third parties
      var thirdParties = _.reduce(
        data.response.data.median.firstView.requests[ 1 ].request,
        function( thirdParties, request ) {
          // console.log( request );
          var isAllowed    = false;
          var i            = 0;
          var length       = this.options.runner.allowedDomains.length;

          for( ; i < length; ++ i ) {
            // TODO put a regex thing in here
            if (
              !isAllowed &&
              request.host.indexOf( this.options.runner.allowedDomains[ i ] ) !== -1
            ) {
              isAllowed = true;
            }
          }

          if ( !isAllowed ) {
            thirdParties.push( request.host );
          }

          return thirdParties;
        },
        [],
        this
      );

      callback( error, data.response.data.summary, thirdParties );
    }.bind( this )
  );
};

Runner.prototype._run = function( options ) {
  options = options || {};

  this.emit(
    'msg',
    options.allowedThirdPartyDomain ?
    ' -> Starting to evaluate metrics for included ' + options.allowedThirdPartyDomain :
    ' -> Starting to evaluate metrics for all blocked 3rd parties'
  );

  var wptOptions = _.clone( this.options.wpt );

  wptOptions.block = _.reduce( this.thirdPartyDomains, function( block, domain ) {
    if ( domain !== options.allowedThirdPartyDomain ) {
      block.push( domain );
    }

    return block;
  }, [] ).join( ' ' );

  this.emit(
    'msg',
    'Calling api with following options : ' + JSON.stringify( wptOptions, null, 2 )
  );

  this.wpt.runTest(
    this.options.runner.url,
    wptOptions,
    function( error, data ) {
      if ( error ) {
        this.emit( 'error', error );
      } else {
        data.allowedUrls = options.allowedThirdPartyDomain;
        data.blockedUrls = wptOptions.block;

        this._emitData( data );
      }

      this.queue.pop();

      // yeah we're done!!! 8-)
      if ( this.queue.isEmpty() ) {
        this.done();
      }
    }.bind( this )
  );
};

/**
 * done
 * @return {[type]} [description]
 */
Runner.prototype._runAll = function() {
  this.emit(
    'msg',
    ' (╯°□°)╯  Starting to call WPT to evaluate load times and request counts '
  );

  var i      = 0;
  var length = this.thirdPartyDomains.length;

  this.queue.push( function( i ) {
    this._run();
  }.bind( this, [ i ] ) );

  for ( ; i < length; ++i ) {
    this.queue.push( function( i ) {
      this._run( {
        allowedThirdPartyDomain : this.thirdPartyDomains[ i ]
      } );
    }.bind( this, [ i ] ) );
  }
};

module.exports = Runner;
<|endoftext|>


<commit_before>var gulp = require('gulp');
var coffee = require('gulp-coffee');
var plumber = require('gulp-plumber');
var clean = require('gulp-clean');
var nodemon = require('gulp-nodemon');
var mocha = require('gulp-mocha');
var k, input;

var namespaces = require('ks-npm');
var bundle = Object.keys(namespaces);
var tasks = [];
var tasks_ignore = [''];

bundle.forEach(function (taskName) {
    if (tasks_ignore.indexOf(taskName) < 0) {
        tasks.push(taskName);
        gulp.task(taskName, function () {
            var req = namespaces[taskName];
            var ext = req + '**/*.coffee'
            return gulp.src(ext)
                .pipe(plumber({
                    /**
                     * Description
                     * @method errorHandler
                     * @param {} err
                     * @return
                     */
                    errorHandler: function (err) {
                        console.log(err);
                    }}))
                .pipe(coffee({bare: true}))
                .pipe(gulp.dest(req));
        });
    }
});

gulp.task('coffee', tasks, function () {
    process.stdin.pause();
    return gulp.src(['src/**/*.coffee'])
        .pipe(plumber({
            /**
             * Description
             * @method errorHandler
             * @param {} err
             * @return
             */
            errorHandler: function (err) {
                console.log(err);
            }}))
        .pipe(coffee({bare: true}))
        .pipe(gulp.dest('src'));
});

gulp.task('kernel', ['coffee'], function () {
    var Kernel = require('konsserto');
    var ArgvInput = use('@Konsserto/Component/Console/Input/ArgvInput');
    var InputOption = use('@Konsserto/Component/Console/Input/InputOption');
    var InputDefinition = use('@Konsserto/Component/Console/Input/InputDefinition');
    var definition = new InputDefinition([new InputOption('--nodemon', '-n'), new InputOption('--keep-js', '-k')]);
    input = new ArgvInput(process.argv, definition, null, true);

    if (input.getOption('nodemon')) {
        nodemon({ script: 'start.js', ext: 'html twig css less coffee', ignore: ['node_modules/*', '*.js'] })
            .on('change', ['coffee'])
            .on('restart', function () {
                console.log('Konsserto restarted !');
            }
        );
    } else {
        k = new Kernel;
        configs = require('./app/config/config');

        port = 3000;
        if (configs.port) {
            port = configs.port;
        }

        k.start(port);
        process.on('SIGINT', function () {
            gulp.start('shutdown');
        });
    }
});

gulp.task('mocha', ['kernel'], function () {
    return gulp.src('./test/**/*.js', {read: false})
        .pipe(mocha({reporter: 'list'}));
});

gulp.task('remove', function () {
    if (input.getOption('keep-js'))
        return true;
    return gulp.src([
        'src/**/*.js',
        //require('ks-npm')['Konsserto']+'**/*.js',
        '!src/**/Resources/**/*.js'
    ], {read: false}).pipe(clean());
});

gulp.task('shutdown', ['remove'], function () {
    return k.shutdown(0);
});

gulp.start('mocha');
<commit_msg>Code review<commit_after>var gulp = require('gulp');
var coffee = require('gulp-coffee');
var plumber = require('gulp-plumber');
var clean = require('gulp-clean');
var nodemon = require('gulp-nodemon');
var mocha = require('gulp-mocha');
var k, input;

var namespaces = require('ks-npm');
var bundle = Object.keys(namespaces);
var tasks = [];
var tasks_ignore = [''];

bundle.forEach(function (taskName) {
    if (tasks_ignore.indexOf(taskName) < 0) {
        tasks.push(taskName);
        gulp.task(taskName, function () {
            var req = namespaces[taskName];
            var ext = req + '**/*.coffee'
            return gulp.src(ext)
                .pipe(plumber({
                    errorHandler: function (err) {
                        console.log(err);
                    }}))
                .pipe(coffee({bare: true}))
                .pipe(gulp.dest(req));
        });
    }
});

gulp.task('coffee', tasks, function () {
    process.stdin.pause();
    return gulp.src(['src/**/*.coffee'])
        .pipe(plumber({
            errorHandler: function (err) {
                console.log(err);
            }}))
        .pipe(coffee({bare: true}))
        .pipe(gulp.dest('src'));
});

gulp.task('kernel', ['coffee'], function () {
    var Kernel = require('konsserto');
    var ArgvInput = use('@Konsserto/Component/Console/Input/ArgvInput');
    var InputOption = use('@Konsserto/Component/Console/Input/InputOption');
    var InputDefinition = use('@Konsserto/Component/Console/Input/InputDefinition');
    var definition = new InputDefinition([new InputOption('--nodemon', '-n'), new InputOption('--keep-js', '-k')]);
    input = new ArgvInput(process.argv, definition, null, true);

    if (input.getOption('nodemon')) {
        nodemon({ script: 'start.js', ext: 'html twig css less coffee', ignore: ['node_modules/*', '*.js'] })
            .on('change', ['coffee'])
            .on('restart', function () {
                console.log('Konsserto restarted !');
            }
        );
    } else {
        k = new Kernel;
        configs = require('./app/config/config');

        port = 3000;
        if (configs.port) {
            port = configs.port;
        }

        k.start(port);
        process.on('SIGINT', function () {
            gulp.start('shutdown');
        });
    }
});

gulp.task('mocha', ['kernel'], function () {
    return gulp.src('./test/**/*.js', {read: false})
        .pipe(mocha({reporter: 'list'}));
});

gulp.task('remove', function () {
    if (input.getOption('keep-js'))
        return true;
    return gulp.src([
        'src/**/*.js',
        //require('ks-npm')['Konsserto']+'**/*.js',
        '!src/**/Resources/**/*.js'
    ], {read: false}).pipe(clean());
});

gulp.task('shutdown', ['remove'], function () {
    return k.shutdown(0);
});

gulp.start('mocha');
<|endoftext|>


<commit_before>//Main app file for HackerJobs PubSub
//Scott Hasbrouck <hello@scotthasbrouck> (C) 2014
//License CC0

'use strict';

var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var _ = require('underscore');
var app = express();

app.get('/', function(req, res) {
	res.type('text/plain');
	var url = 'http://jobs.smashingmagazine.com/all/programming';
	var jobs = {};

	request(url, function(err, resp, html) {
		if(!err) {
			var $ = cheerio.load(html);
			var titles = [];
			var engagements = [];
			var locations = [];
			var links = [];
			$('article.entry h2').each(function(i) {
				titles.push({'title': $(this).text()});
			});
			$('article.entry .entry-type').each(function(i) {
				engagements.push({'engagement': $(this).text()});
			});
			$('article.entry .entry-company').each(function(i) {
				locations.push({'location': $(this).text()});
			});
			$('.entry-list li a').each(function(i) {
				links.push({'link': $(this).attr('href')});
			});
			jobs = _.zip(titles, engagements, locations, links);
		}
		res.json(jobs);
		res.end();
	});
});

app.listen(9999);<commit_msg>Adds 4 jobs sites<commit_after>//Main app file for HackerJobs PubSub
//Scott Hasbrouck <hello@scotthasbrouck> (C) 2014
//License CC0

'use strict';

var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var _ = require('underscore');
var app = express();

//JSON of scrape sites with elements
var scrapes = [
	{
		'url': 'http://jobs.smashingmagazine.com/all/programming',
		'titles': 'article.entry h2',
		'engagements': 'article.entry .entry-type',
		'locations': 'article.entry .entry-company',
		'company': '',
		'links': 'entry-list li a',
		'linkprefix': '',
		'timeout': 300,
		'pageindex': '',
		'maxpage': ''
	},
	{
		'url': 'https://news.ycombinator.com/jobs',
		'titles': '.title a',
		'engagements': '',
		'locations': '.title .comhead',
		'company': '',
		'links': '.title a',
		'linkprefix': '',
		'timeout': 300,
		'pageindex': '',
		'maxpage': ''
	},
	{
		'url': 'http://careers.stackoverflow.com/jobs',
		'titles': '.-title a',
		'engagements': '',
		'locations': '.-employer',
		'company': '',
		'links': '.-title a',
		'linkprefix': 'http://careers.stackoverflow.com',
		'timeout': 300,
		'pageindex': 'pg',
		'maxpage': '9'
	},
	{
		'url': 'https://jobs.github.com/positions',
		'titles': '.title a',
		'engagements': '',
		'locations': 'span.location',
		'company': '.company',
		'links': 'h4 a',
		'linkprefix': 'https://jobs.github.com',
		'timeout': 300,
		'pageindex': '',
		'maxpage': ''
	}
];

app.get('/', function(req, res) {
	res.type('text/plain');
	var jobs = [];
	var siteindex = 3;

	request(scrapes[siteindex]['url'], function(err, resp, html) {
		if(!err) {
			var $ = cheerio.load(html);
			var titles = [];
			var engagements = [];
			var locations = [];
			var links = [];
			$(scrapes[siteindex]['titles']).each(function(i) {
				titles.push({'title': $(this).text()});
			});
			$(scrapes[siteindex]['engagements']).each(function(i) {
				engagements.push({'engagement': $(this).text()});
			});
			$(scrapes[siteindex]['locations']).each(function(i) {
				locations.push({'location': $(this).text()});
			});
			$(scrapes[siteindex]['links']).each(function(i) {
				links.push({'link': scrapes[siteindex]['linkprefix'] + $(this).attr('href')});
			});
			jobs = jobs.concat(_.zip(titles, engagements, locations, links));
		}
		res.json(jobs);
		res.end();
	});
});

app.listen(9999);<|endoftext|>