<commit_before>const path = require('path')
const R = require('ramda')
const B = require('bufx')
const { splitEquations } = require('./Helpers')

let preprocessModel = (mdlFilename, spec, profile = 'genc', writeRemovals = false) => {
  const MACROS_FILENAME = 'macros.txt'
  const REMOVALS_FILENAME = 'removals.txt'
  const INSERTIONS_FILENAME = 'mdl-edits.txt'
  const ENCODING = '{UTF-8}'
  let profiles = {
    // simplified but still runnable model
    genc: {
      emitEncoding: true,
      emitCommentMarkers: true,
      joinFormulaLines: false
    },
    // even simpler model that does not run
    analysis: {
      emitEncoding: false,
      emitCommentMarkers: false,
      joinFormulaLines: true
    }
  }
  let opts = profiles[profile]
  let mdl, eqns
  // Equations that contain a string in the removalKeys list in the spec file will be removed.
  let removalKeys = (spec && spec.removalKeys) || []
  // Optional insertions can be used to add expanded macros back into the model.
  let insertions = ''
  // Get the first line of an equation.
  let firstLine = s => {
    let i = s.indexOf('\n')
    if (i < 0) {
      return s.trim()
    } else {
      return s.slice(0, i).trim()
    }
  }
  let getMdlFromPPBuf = () => {
    // Reset the mdl string from the preprocessor buffer.
    mdl = B.getBuf('pp')
    B.clearBuf('pp')
  }
  let emitPP = str => {
    if (str) {
      B.emit(str, 'pp')
    }
  }
  // Open output channels.
  B.open('rm')
  B.open('macros')
  B.open('pp')
  // Read the optional insertions file.
  try {
    insertions = B.read(INSERTIONS_FILENAME)
  } catch (error) {
  }
  // Read the model file.
  try {
    mdl = B.read(mdlFilename)
  } catch (error) {
    console.error(error.message)
    return
  }
  // Remove the macro section.
  let inMacroSection = false
  for (let line of B.lines(mdl)) {
    if (!inMacroSection && R.contains(':MACRO:', line)) {
      B.emitLine(line, 'macros')
      inMacroSection = true
    } else if (inMacroSection) {
      B.emitLine(line, 'macros')
      if (R.contains(':END OF MACRO:', line)) {
        B.emit('\n', 'macros')
        inMacroSection = false
      }
    } else {
      B.emitLine(line, 'pp')
    }
  }
  getMdlFromPPBuf()

  // Split the model into an array of equations and groups.
  eqns = splitEquations(mdl)
  // Remove some equations into the removals channel.
  for (let eqn of eqns) {
    if (R.contains('\\---/// Sketch', eqn)) {
      // Skip everything starting with the first sketch section.
      break
    } else if (R.contains('********************************************************', eqn)) {
      // Skip groups
    } else if (R.contains('TABBED ARRAY', eqn) || R.any(x => R.contains(x, eqn), removalKeys)) {
      // Remove tabbed arrays and equations containing removal key strings from the spec.
      B.emit(eqn, 'rm')
      B.emit('|', 'rm')
    } else if (!R.isEmpty(eqn)) {
      // Emit the equation.
      emitPP(eqn)
      emitPP('|')
    }
  }
  getMdlFromPPBuf()

  // Join lines continued with trailing backslash characters.
  let prevLine = ''
  for (let line of B.lines(mdl)) {
    // Join a previous line with a backslash ending to the current line.
    if (!R.isEmpty(prevLine)) {
      line = prevLine + line.trim()
      prevLine = ''
    }
    let continuation = line.match(/\\\s*$/)
    if (continuation) {
      // If there is a backslash ending on this line, save it without the backslash.
      prevLine = line.substr(0, continuation.index).replace(/\s+$/, ' ')
    } else {
      // With no continuation on this line, go ahead and emit it.
      B.emitLine(line, 'pp')
    }
  }
  getMdlFromPPBuf()

  // Emit the encoding line and optional insertions.
  if (opts.emitEncoding) {
    B.emitLine(ENCODING, 'pp')
  }
  if (insertions) {
    B.emitLine(insertions, 'pp')
  }
  // Emit formula lines without comment contents.
  eqns = splitEquations(mdl)
  for (let eqn of eqns) {
    let iComment = eqn.indexOf('~')
    if (iComment >= 0) {
      let formula = B.lines(eqn.substr(0, iComment))
      for (let i = 0; i < formula.length; i++) {
        if (i === 0) {
          if (formula[i] !== ENCODING) {
            emitPP(formula[i])
          }
        } else {
          if (opts.joinFormulaLines) {
            emitPP(formula[i].replace(/^\t+/, ''))
          } else {
            B.emitLine('', 'pp')
            emitPP(formula[i])
          }
        }
      }
      if (opts.emitCommentMarkers) {
        emitPP('~~|')
      } else {
        B.emitLine('', 'pp')
      }
    }
  }
  getMdlFromPPBuf()

  // Write removals to a file in the model directory.
  if (writeRemovals) {
    if (B.getBuf('macros')) {
      let macrosPathname = path.join(path.dirname(mdlFilename), MACROS_FILENAME)
      B.writeBuf(macrosPathname, 'macros')
    }
    if (B.getBuf('rm')) {
      let rmPathname = path.join(path.dirname(mdlFilename), REMOVALS_FILENAME)
      B.writeBuf(rmPathname, 'rm')
    }
  }

  // Return the preprocessed model as a string.
  return mdl
}

module.exports = { preprocessModel }
<commit_msg>only insert mdl-edits.txt when generating code<commit_after>const path = require('path')
const R = require('ramda')
const B = require('bufx')
const { splitEquations } = require('./Helpers')

let preprocessModel = (mdlFilename, spec, profile = 'genc', writeFiles = false) => {
  const MACROS_FILENAME = 'macros.txt'
  const REMOVALS_FILENAME = 'removals.txt'
  const INSERTIONS_FILENAME = 'mdl-edits.txt'
  const ENCODING = '{UTF-8}'
  let profiles = {
    // simplified but still runnable model
    genc: {
      emitEncoding: true,
      emitCommentMarkers: true,
      joinFormulaLines: false
    },
    // even simpler model that does not run
    analysis: {
      emitEncoding: false,
      emitCommentMarkers: false,
      joinFormulaLines: true
    }
  }
  let opts = profiles[profile]
  let mdl, eqns
  // Equations that contain a string in the removalKeys list in the spec file will be removed.
  let removalKeys = (spec && spec.removalKeys) || []
  // Optional insertions can be used to add expanded macros back into the model.
  let insertions = ''
  let getMdlFromPPBuf = () => {
    // Reset the mdl string from the preprocessor buffer.
    mdl = B.getBuf('pp')
    B.clearBuf('pp')
  }
  let emitPP = str => {
    if (str) {
      B.emit(str, 'pp')
    }
  }
  // Open output channels.
  B.open('rm')
  B.open('macros')
  B.open('pp')
  // Read the optional insertions file into the model unless we are doing a pass that writes removals.
  try {
    if (!writeFiles) {
      let insPathname = path.join(path.dirname(mdlFilename), INSERTIONS_FILENAME)
      insertions = B.read(insPathname)
    }
  } catch (error) {}
  // Read the model file.
  try {
    mdl = B.read(mdlFilename)
  } catch (error) {
    console.error(error.message)
    return
  }
  // Remove the macro section.
  let inMacroSection = false
  for (let line of B.lines(mdl)) {
    if (!inMacroSection && R.contains(':MACRO:', line)) {
      B.emitLine(line, 'macros')
      inMacroSection = true
    } else if (inMacroSection) {
      B.emitLine(line, 'macros')
      if (R.contains(':END OF MACRO:', line)) {
        B.emit('\n', 'macros')
        inMacroSection = false
      }
    } else {
      B.emitLine(line, 'pp')
    }
  }
  getMdlFromPPBuf()

  // Split the model into an array of equations and groups.
  eqns = splitEquations(mdl)
  // Remove some equations into the removals channel.
  for (let eqn of eqns) {
    if (R.contains('\\---/// Sketch', eqn)) {
      // Skip everything starting with the first sketch section.
      break
    } else if (R.contains('********************************************************', eqn)) {
      // Skip groups
    } else if (R.contains('TABBED ARRAY', eqn) || R.any(x => R.contains(x, eqn), removalKeys)) {
      // Remove tabbed arrays and equations containing removal key strings from the spec.
      B.emit(eqn, 'rm')
      B.emit('|', 'rm')
    } else if (!R.isEmpty(eqn)) {
      // Emit the equation.
      emitPP(eqn)
      emitPP('|')
    }
  }
  getMdlFromPPBuf()

  // Join lines continued with trailing backslash characters.
  let prevLine = ''
  for (let line of B.lines(mdl)) {
    // Join a previous line with a backslash ending to the current line.
    if (!R.isEmpty(prevLine)) {
      line = prevLine + line.trim()
      prevLine = ''
    }
    let continuation = line.match(/\\\s*$/)
    if (continuation) {
      // If there is a backslash ending on this line, save it without the backslash.
      prevLine = line.substr(0, continuation.index).replace(/\s+$/, ' ')
    } else {
      // With no continuation on this line, go ahead and emit it.
      B.emitLine(line, 'pp')
    }
  }
  getMdlFromPPBuf()

  // Emit the encoding line and optional insertions.
  if (opts.emitEncoding) {
    B.emitLine(ENCODING, 'pp')
  }
  if (insertions) {
    B.emitLine(insertions, 'pp')
  }
  // Emit formula lines without comment contents.
  eqns = splitEquations(mdl)
  for (let eqn of eqns) {
    let iComment = eqn.indexOf('~')
    if (iComment >= 0) {
      let formula = B.lines(eqn.substr(0, iComment))
      for (let i = 0; i < formula.length; i++) {
        if (i === 0) {
          if (formula[i] !== ENCODING) {
            emitPP(formula[i])
          }
        } else {
          if (opts.joinFormulaLines) {
            emitPP(formula[i].replace(/^\t+/, ''))
          } else {
            B.emitLine('', 'pp')
            emitPP(formula[i])
          }
        }
      }
      if (opts.emitCommentMarkers) {
        emitPP('~~|')
      } else {
        B.emitLine('', 'pp')
      }
    }
  }
  getMdlFromPPBuf()

  // Write removals to a file in the model directory.
  if (writeFiles) {
    if (B.getBuf('macros')) {
      let macrosPathname = path.join(path.dirname(mdlFilename), MACROS_FILENAME)
      B.writeBuf(macrosPathname, 'macros')
    }
    if (B.getBuf('rm')) {
      let rmPathname = path.join(path.dirname(mdlFilename), REMOVALS_FILENAME)
      B.writeBuf(rmPathname, 'rm')
    }
  }

  // Return the preprocessed model as a string.
  return mdl
}

module.exports = { preprocessModel }
<|endoftext|>


<commit_before>const ghGot = require('../platform/github/gh-got-wrapper');
const semver = require('semver');

module.exports = {
  getRepoTags,
  getRepoReleases,
};

function semverSort(a, b) {
  return semver.compare(a, b);
}

async function getRepoTags(repo) {
  const url = `repos/${repo}/git/refs?per_page=100`;
  const res = (await ghGot(url, { paginate: true })).body;
  const tagPrefix = 'refs/tags/';
  return res
    .filter(o => o.ref.startsWith(tagPrefix))
    .map(o => o.ref.replace(tagPrefix, ''))
    .filter(o => semver.valid(o))
    .sort(semverSort);
}

async function getRepoReleases(repo) {
  const url = `repos/${repo}/releases?per_page=100`;
  const res = (await ghGot(url, { paginate: true })).body;
  return res
    .map(o => o.tag_name)
    .filter(semver.valid)
    .sort(semverSort);
}
<commit_msg>fix: add try/catch to github datasource functions<commit_after>const ghGot = require('../platform/github/gh-got-wrapper');
const semver = require('semver');

module.exports = {
  getRepoTags,
  getRepoReleases,
};

function semverSort(a, b) {
  return semver.compare(a, b);
}

async function getRepoTags(repo) {
  try {
    const url = `repos/${repo}/git/refs?per_page=100`;
    const res = (await ghGot(url, { paginate: true })).body;
    const tagPrefix = 'refs/tags/';
    return res
      .filter(o => o.ref.startsWith(tagPrefix))
      .map(o => o.ref.replace(tagPrefix, ''))
      .filter(o => semver.valid(o))
      .sort(semverSort);
  } catch (err) /* istanbul ignore next */ {
    logger.warn({ repo }, 'Could not fetch repo tags');
    return [];
  }
}

async function getRepoReleases(repo) {
  try {
    const url = `repos/${repo}/releases?per_page=100`;
    const res = (await ghGot(url, { paginate: true })).body;
    return res
      .map(o => o.tag_name)
      .filter(semver.valid)
      .sort(semverSort);
  } catch (err) /* istanbul ignore next */ {
    logger.warn({ repo }, 'Could not fetch repo releases');
    return [];
  }
}
<|endoftext|>


<commit_before>
var createClient = require('./swf').createClient;

/**
 * This class makes it easier to build decision responses.
 * http://docs.aws.amazon.com/amazonswf/latest/apireference/API_Decision.html
 * @constructor
 */
var DecisionResponse = exports.DecisionResponse = function (swfClient, taskToken, defaultTaskList) {

   this.swfClient = swfClient || createClient();
   this.taskToken = taskToken;
   this.defaultTaskList = defaultTaskList;

   // For sending response
   this.responseSent = false;
   this.decisions = null;

};

DecisionResponse.prototype = {

   /**
    * sends the decision response to SWF
    */
   respondCompleted: function (decisions, cb) {

      if (this.responseSent) {
         throw "Response has already been sent for this decision task !";
      }
      this.responseSent = true;

      this.swfClient.client.respondDecisionTaskCompleted({
         "taskToken": this.taskToken,
         "decisions": decisions
      }, function (err, result) {

         if (err) { console.error("RespondDecisionTaskCompleted error : ", err, result);  }

         if (cb) {
            cb(err, result);
         } else {
            console.log(decisions.length + " decisions sent !");
            console.log(JSON.stringify(decisions, null, 3));
         }
      });
   },

   /**
    * Add a decision
    */
   addDecision: function(decision) {

      if (!this.decisions) {
         this.decisions = [];
      }

      this.decisions.push(decision);
   },

   /**
    * Add a "CompleteWorkflowExecution" decision
    */
   stop: function (stopAttributes, swfAttributes) {

      var sa = swfAttributes || {};

      // Result
      if(stopAttributes.result) {
         if (typeof stopAttributes.result === 'function') {
            sa.result = stopAttributes.result();
         }
         else {
            sa.result = stopAttributes.result;
         }
      }
      if(typeof sa.result !== 'string') {
         sa.result = JSON.stringify(sa.result);
      }

      this.addDecision({
         "decisionType": "CompleteWorkflowExecution",
         "completeWorkflowExecutionDecisionAttributes": sa
      });

    },

   /**
    * Add a "FailWorkflowExecution" decision
    */
   fail_workflow_execution: function (reason, details, cb) {
      this.respondCompleted([{
         "decisionType": "FailWorkflowExecution",
         "failWorkflowExecutionDecisionAttributes": {
            "reason": reason,
            "details": details || "" /* || JSON.stringify(this.getSimpleWorkflowHistory())*/
         }
      }], cb || function (err) {
         if (err) { console.error(err); return; }
         console.log("Workflow marked as failed ! (decision task)");
      });
   },

   /**
    * alias for fail_workflow_execution
    */
   fail: function (reason, details, cb) {
      this.fail_workflow_execution(reason, details, cb);
   },

   /**
    * Add a new ScheduleActivityTask decision
    */
    schedule: function (scheduleAttributes, swfAttributes) {

      var ta = swfAttributes || {};

      ta.activityId = scheduleAttributes.name; // scheduleAttributes.name required

      // Activity Type
      if(scheduleAttributes.activity) {
         ta.activityType = scheduleAttributes.activity;
      }
      if (typeof ta.activityType === "string") {
         ta.activityType = { name: ta.activityType, version: "1.0" };
      }

      // Activity Input
      if (scheduleAttributes.input) {
         if (typeof scheduleAttributes.input === 'function') {
            ta.input = scheduleAttributes.input();
         }
         else {
            ta.input = scheduleAttributes.input;
         }
      }
      else {
         ta.input = "";
      }

      if (typeof ta.input !== "string") {
         ta.input = JSON.stringify(ta.input);
      }

      // Task list (if not set, use the default taskList)
      if (!ta.taskList) {
         ta.taskList = this.defaultTaskList;
      }
      if (typeof ta.taskList === "string") {
         ta.taskList = { name: ta.taskList};
      }

      // TODO: we should be able to override these defaults :
      if (!ta.scheduleToStartTimeout) { ta.scheduleToStartTimeout = "60"; }
      if (!ta.scheduleToCloseTimeout) { ta.scheduleToCloseTimeout = "360"; }
      if (!ta.startToCloseTimeout) { ta.startToCloseTimeout = "300"; }
      if (!ta.heartbeatTimeout) { ta.heartbeatTimeout = "60"; }

      this.addDecision({
         "decisionType": "ScheduleActivityTask",
         "scheduleActivityTaskDecisionAttributes": ta
      });
   },

   /**
    * Add a StartChildWorkflowExecution decision
    */
   start_childworkflow: function(startAttributes, swfAttributes) {

      var sa = swfAttributes || {};

      // control
      sa.control = startAttributes.name;

      // workflowType
      if(startAttributes.workflow) {
         sa.workflowType = startAttributes.workflow;
      }
      if(typeof sa.workflowType === 'string') {
         sa.workflowType = {
            name: sa.workflowType,
            version: "1.0"
         };
      }

      if (typeof sa.input !== "string") {
         sa.input = JSON.stringify(sa.input);
      }

      if(!sa.workflowId) {
         sa.workflowId = String(Math.random()).substr(2);
      }

      this.addDecision({
         "decisionType": "StartChildWorkflowExecution",
         "startChildWorkflowExecutionDecisionAttributes": sa
      });
   },

   /**
    * Add a new StartTimer decision
    */
   start_timer: function(startAttributes, swfAttributes) {

      var sa = swfAttributes || {};

      // control
      sa.control = startAttributes.name;

      if(startAttributes.delay) {
         sa.startToFireTimeout = String(startAttributes.delay);
      }
      if(!sa.startToFireTimeout) {
         sa.startToFireTimeout = "1";
      }

      if(!sa.timerId) {
         sa.timerId = String(Math.random()).substr(2);
      }

      this.addDecision({
         "decisionType": "StartTimer",
         "startTimerDecisionAttributes": sa
      });
   }
};
<commit_msg>Add a wait method to differentiate no decisions from waiting...<commit_after>
var createClient = require('./swf').createClient;

/**
 * This class makes it easier to build decision responses.
 * http://docs.aws.amazon.com/amazonswf/latest/apireference/API_Decision.html
 * @constructor
 */
var DecisionResponse = exports.DecisionResponse = function (swfClient, taskToken, defaultTaskList) {

   this.swfClient = swfClient || createClient();
   this.taskToken = taskToken;
   this.defaultTaskList = defaultTaskList;

   // For sending response
   this.responseSent = false;
   this.decisions = null;

};

DecisionResponse.prototype = {

  send: function(cb) {
    this.respondCompleted(this.decisions, cb);
  },

   /**
    * sends the decision response to SWF
    */
   respondCompleted: function (decisions, cb) {

      if (this.responseSent) {
         throw "Response has already been sent for this decision task !";
      }
      this.responseSent = true;

      this.swfClient.client.respondDecisionTaskCompleted({
         "taskToken": this.taskToken,
         "decisions": decisions
      }, function (err, result) {
         if (cb) {
            cb(err, result);
         }
      });
   },

   /**
    * Add a decision
    */
   addDecision: function(decision) {

      if (!this.decisions) {
         this.decisions = [];
      }

      this.decisions.push(decision);
   },

   wait: function() {

      // TODO: check arguments to see if the tasks waiting for are not failed or not started...

      if (!this.decisions) {
         this.decisions = [];
      }

   },

   /**
    * Add a "CompleteWorkflowExecution" decision
    */
   stop: function (stopAttributes, swfAttributes) {

      var sa = swfAttributes || {};

      // Result
      if(stopAttributes.result) {
         if (typeof stopAttributes.result === 'function') {
            sa.result = stopAttributes.result();
         }
         else {
            sa.result = stopAttributes.result;
         }
      }
      if(typeof sa.result !== 'string') {
         sa.result = JSON.stringify(sa.result);
      }

      this.addDecision({
         "decisionType": "CompleteWorkflowExecution",
         "completeWorkflowExecutionDecisionAttributes": sa
      });

    },

   /**
    * Add a "FailWorkflowExecution" decision
    */
   fail_workflow_execution: function (reason, details, cb) {
      this.respondCompleted([{
         "decisionType": "FailWorkflowExecution",
         "failWorkflowExecutionDecisionAttributes": {
            "reason": reason,
            "details": details || "" /* || JSON.stringify(this.getSimpleWorkflowHistory())*/
         }
      }], cb || function (err) {
         if (err) { console.error(err); return; }
         console.log("Workflow marked as failed ! (decision task)");
      });
   },

   /**
    * alias for fail_workflow_execution
    */
   fail: function (reason, details, cb) {
      this.fail_workflow_execution(reason, details, cb);
   },

   /**
    * Add a new ScheduleActivityTask decision
    */
    schedule: function (scheduleAttributes, swfAttributes) {

      var ta = swfAttributes || {};

      ta.activityId = scheduleAttributes.name; // scheduleAttributes.name required

      // Activity Type
      if(scheduleAttributes.activity) {
         ta.activityType = scheduleAttributes.activity;
      }
      if (typeof ta.activityType === "string") {
         ta.activityType = { name: ta.activityType, version: "1.0" };
      }

      // Activity Input
      if (scheduleAttributes.input) {
         if (typeof scheduleAttributes.input === 'function') {
            ta.input = scheduleAttributes.input();
         }
         else {
            ta.input = scheduleAttributes.input;
         }
      }
      else {
         ta.input = "";
      }

      if (typeof ta.input !== "string") {
         ta.input = JSON.stringify(ta.input);
      }

      // Task list (if not set, use the default taskList)
      if (!ta.taskList) {
         ta.taskList = this.defaultTaskList;
      }
      if (typeof ta.taskList === "string") {
         ta.taskList = { name: ta.taskList};
      }

      // TODO: we should be able to override these defaults :
      if (!ta.scheduleToStartTimeout) { ta.scheduleToStartTimeout = "60"; }
      if (!ta.scheduleToCloseTimeout) { ta.scheduleToCloseTimeout = "360"; }
      if (!ta.startToCloseTimeout) { ta.startToCloseTimeout = "300"; }
      if (!ta.heartbeatTimeout) { ta.heartbeatTimeout = "60"; }

      this.addDecision({
         "decisionType": "ScheduleActivityTask",
         "scheduleActivityTaskDecisionAttributes": ta
      });
   },

   /**
    * Add a StartChildWorkflowExecution decision
    */
   start_childworkflow: function(startAttributes, swfAttributes) {

      var sa = swfAttributes || {};

      // control
      sa.control = startAttributes.name;

      // workflowType
      if(startAttributes.workflow) {
         sa.workflowType = startAttributes.workflow;
      }
      if(typeof sa.workflowType === 'string') {
         sa.workflowType = {
            name: sa.workflowType,
            version: "1.0"
         };
      }

      if( !sa.input ) {
        sa.input = "";
      }

      if (typeof sa.input !== "string") {
         sa.input = JSON.stringify(sa.input);
      }

      if(!sa.workflowId) {
         sa.workflowId = String(Math.random()).substr(2);
      }

      this.addDecision({
         "decisionType": "StartChildWorkflowExecution",
         "startChildWorkflowExecutionDecisionAttributes": sa
      });
   },

   /**
    * Add a new StartTimer decision
    */
   start_timer: function(startAttributes, swfAttributes) {

      var sa = swfAttributes || {};

      // control
      sa.control = startAttributes.name;

      if(startAttributes.delay) {
         sa.startToFireTimeout = String(startAttributes.delay);
      }
      if(!sa.startToFireTimeout) {
         sa.startToFireTimeout = "1";
      }

      if(!sa.timerId) {
         sa.timerId = String(Math.random()).substr(2);
      }

      this.addDecision({
         "decisionType": "StartTimer",
         "startTimerDecisionAttributes": sa
      });
   }
};
<|endoftext|>


<commit_before>"use strict";

var createBlob = require('./blob.js');
var errors = require('./errors');
var utils = require("../utils");
var hasUpload;

function ajax(options, adapterCallback) {

  var requestCompleted = false;
  var callback = utils.getArguments(function (args) {
    if (requestCompleted) {
      return;
    }
    adapterCallback.apply(this, args);
    requestCompleted = true;
  });

  if (typeof options === "function") {
    callback = options;
    options = {};
  }

  options = utils.clone(options);

  var defaultOptions = {
    method : "GET",
    headers: {},
    json: true,
    processData: true,
    timeout: 10000,
    cache: false
  };

  options = utils.extend(true, defaultOptions, options);

  // cache-buster, specifically designed to work around IE's aggressive caching
  // see http://www.dashbay.com/2011/05/internet-explorer-caches-ajax/
  if (options.method === 'GET' && !options.cache) {
    var hasArgs = options.url.indexOf('?') !== -1;
    options.url += (hasArgs ? '&' : '?') + '_nonce=' + utils.uuid(16);
  }

  function onSuccess(obj, resp, cb) {
    if (!options.binary && !options.json && options.processData &&
      typeof obj !== 'string') {
      obj = JSON.stringify(obj);
    } else if (!options.binary && options.json && typeof obj === 'string') {
      try {
        obj = JSON.parse(obj);
      } catch (e) {
        // Probably a malformed JSON from server
        return cb(e);
      }
    }
    if (Array.isArray(obj)) {
      obj = obj.map(function (v) {
        if (v.error || v.missing) {
          return errors.generateErrorFromResponse(v);
        } else {
          return v;
        }
      });
    }
    cb(null, obj, resp);
  }

  function onError(err, cb) {
    var errParsed, errObj;
    try {
      errParsed = JSON.parse(err.responseText);
      //would prefer not to have a try/catch clause
      errObj = errors.generateErrorFromResponse(errParsed);
    } catch (e) {
      errObj = errors.generateErrorFromResponse(err);
    }
    if (err.withCredentials && err.status === 0) {
      // apparently this is what we get when the method
      // is reported as not allowed by CORS. so fudge it
      errObj.status = 405;
      errObj.statusText = "Method Not Allowed";
    }
    cb(errObj);
  }

  var timer;
  var xhr;
  if (options.xhr) {
    xhr = new options.xhr();
  } else {
    xhr = new XMLHttpRequest();
  }
  xhr.open(options.method, options.url);
  xhr.withCredentials = true;

  if (options.json) {
    options.headers.Accept = 'application/json';
    options.headers['Content-Type'] = options.headers['Content-Type'] ||
      'application/json';
    if (options.body &&
        options.processData &&
        typeof options.body !== "string") {
      options.body = JSON.stringify(options.body);
    }
  }

  if (options.binary) {
    xhr.responseType = 'arraybuffer';
  }

  var createCookie = function (name, value, days) {
    var expires = "";
    if (days) {
      var date = new Date();
      date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
      expires = "; expires=" + date.toGMTString();
    }
    document.cookie = name + "=" + value + expires + "; path=/";
  };

  for (var key in options.headers) {
    if (key === 'Cookie') {
      var cookie = options.headers[key].split('=');
      createCookie(cookie[0], cookie[1], 10);
    } else {
      xhr.setRequestHeader(key, options.headers[key]);
    }
  }

  if (!("body" in options)) {
    options.body = null;
  }

  var abortReq = function () {
    if (requestCompleted) {
      return;
    }
    xhr.abort();
    onError(xhr, callback);
  };

  xhr.onreadystatechange = function () {
    if (xhr.readyState !== 4 || requestCompleted) {
      return;
    }
    clearTimeout(timer);
    if (xhr.status >= 200 && xhr.status < 300) {
      var data;
      if (options.binary) {
        data = createBlob([xhr.response || ''], {
          type: xhr.getResponseHeader('Content-Type')
        });
      } else {
        data = xhr.responseText;
      }
      onSuccess(data, xhr, callback);
    } else {
      onError(xhr, callback);
    }
  };

  if (options.timeout > 0) {
    timer = setTimeout(abortReq, options.timeout);
    xhr.onprogress = function () {
      clearTimeout(timer);
      timer = setTimeout(abortReq, options.timeout);
    };
    if (typeof hasUpload === 'undefined') {
      // IE throws an error if you try to access it directly
      hasUpload = Object.keys(xhr).indexOf('upload') !== -1;
    }
    if (hasUpload) { // does not exist in ie9
      xhr.upload.onprogress = xhr.onprogress;
    }
  }
  if (options.body && (options.body instanceof Blob)) {
    utils.readAsBinaryString(options.body, function (binary) {
      xhr.send(utils.fixBinary(binary));
    });
  } else {
    xhr.send(options.body);
  }
  return {abort: abortReq};
}

module.exports = ajax;
<commit_msg>(#3278) - Add hasOwnProperty check for IE11<commit_after>"use strict";

var createBlob = require('./blob.js');
var errors = require('./errors');
var utils = require("../utils");
var hasUpload;

function ajax(options, adapterCallback) {

  var requestCompleted = false;
  var callback = utils.getArguments(function (args) {
    if (requestCompleted) {
      return;
    }
    adapterCallback.apply(this, args);
    requestCompleted = true;
  });

  if (typeof options === "function") {
    callback = options;
    options = {};
  }

  options = utils.clone(options);

  var defaultOptions = {
    method : "GET",
    headers: {},
    json: true,
    processData: true,
    timeout: 10000,
    cache: false
  };

  options = utils.extend(true, defaultOptions, options);

  // cache-buster, specifically designed to work around IE's aggressive caching
  // see http://www.dashbay.com/2011/05/internet-explorer-caches-ajax/
  if (options.method === 'GET' && !options.cache) {
    var hasArgs = options.url.indexOf('?') !== -1;
    options.url += (hasArgs ? '&' : '?') + '_nonce=' + utils.uuid(16);
  }

  function onSuccess(obj, resp, cb) {
    if (!options.binary && !options.json && options.processData &&
      typeof obj !== 'string') {
      obj = JSON.stringify(obj);
    } else if (!options.binary && options.json && typeof obj === 'string') {
      try {
        obj = JSON.parse(obj);
      } catch (e) {
        // Probably a malformed JSON from server
        return cb(e);
      }
    }
    if (Array.isArray(obj)) {
      obj = obj.map(function (v) {
        if (v.error || v.missing) {
          return errors.generateErrorFromResponse(v);
        } else {
          return v;
        }
      });
    }
    cb(null, obj, resp);
  }

  function onError(err, cb) {
    var errParsed, errObj;
    try {
      errParsed = JSON.parse(err.responseText);
      //would prefer not to have a try/catch clause
      errObj = errors.generateErrorFromResponse(errParsed);
    } catch (e) {
      errObj = errors.generateErrorFromResponse(err);
    }
    if (err.withCredentials && err.status === 0) {
      // apparently this is what we get when the method
      // is reported as not allowed by CORS. so fudge it
      errObj.status = 405;
      errObj.statusText = "Method Not Allowed";
    }
    cb(errObj);
  }

  var timer;
  var xhr;
  if (options.xhr) {
    xhr = new options.xhr();
  } else {
    xhr = new XMLHttpRequest();
  }
  xhr.open(options.method, options.url);
  xhr.withCredentials = true;

  if (options.json) {
    options.headers.Accept = 'application/json';
    options.headers['Content-Type'] = options.headers['Content-Type'] ||
      'application/json';
    if (options.body &&
        options.processData &&
        typeof options.body !== "string") {
      options.body = JSON.stringify(options.body);
    }
  }

  if (options.binary) {
    xhr.responseType = 'arraybuffer';
  }

  var createCookie = function (name, value, days) {
    var expires = "";
    if (days) {
      var date = new Date();
      date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
      expires = "; expires=" + date.toGMTString();
    }
    document.cookie = name + "=" + value + expires + "; path=/";
  };

  for (var key in options.headers) {
    if (options.headers.hasOwnProperty(key)) {
      if (key === 'Cookie') {
        var cookie = options.headers[key].split('=');
        createCookie(cookie[0], cookie[1], 10);
      } else {
        xhr.setRequestHeader(key, options.headers[key]);
      }
    }
  }

  if (!("body" in options)) {
    options.body = null;
  }

  var abortReq = function () {
    if (requestCompleted) {
      return;
    }
    xhr.abort();
    onError(xhr, callback);
  };

  xhr.onreadystatechange = function () {
    if (xhr.readyState !== 4 || requestCompleted) {
      return;
    }
    clearTimeout(timer);
    if (xhr.status >= 200 && xhr.status < 300) {
      var data;
      if (options.binary) {
        data = createBlob([xhr.response || ''], {
          type: xhr.getResponseHeader('Content-Type')
        });
      } else {
        data = xhr.responseText;
      }
      onSuccess(data, xhr, callback);
    } else {
      onError(xhr, callback);
    }
  };

  if (options.timeout > 0) {
    timer = setTimeout(abortReq, options.timeout);
    xhr.onprogress = function () {
      clearTimeout(timer);
      timer = setTimeout(abortReq, options.timeout);
    };
    if (typeof hasUpload === 'undefined') {
      // IE throws an error if you try to access it directly
      hasUpload = Object.keys(xhr).indexOf('upload') !== -1;
    }
    if (hasUpload) { // does not exist in ie9
      xhr.upload.onprogress = xhr.onprogress;
    }
  }
  if (options.body && (options.body instanceof Blob)) {
    utils.readAsBinaryString(options.body, function (binary) {
      xhr.send(utils.fixBinary(binary));
    });
  } else {
    xhr.send(options.body);
  }
  return {abort: abortReq};
}

module.exports = ajax;
<|endoftext|>


<commit_before>/* globals describe, it */

var utils = require( '../utils' );
var assert = require('assert');
var fs = require('fs');
var path = require('path');

var fetchAndCacheMetadata = utils.fetchAndCacheMetadata;
var fetchAndCacheTarball = utils.fetchAndCacheTarball;

/* TODO: write test */
// var patchData = utils.patchData;

describe( 'Utility functions ', function(){

  it.skip( 'should fetchAndCacheMetadata', function( ){
    var cacheFile = '/home/hari/.npm/registry.npmjs.org/lodash/.cache.json';
    fetchAndCacheMetadata( 'lodash', cacheFile );
    assert( fs.existsSync( cacheFile ) );
  });

  it( 'should fetchAndCacheTarball', function(){
    var cacheFile = '/home/hari/.npm/lodash/4.2.1/package.tgz';
    var packageJsonFile =  path.dirname( cacheFile ) + '/package/package.json';

    fetchAndCacheTarball( 'lodash', '4.2.1', cacheFile );
    assert( fs.existsSync( cacheFile ) );
    assert( fs.existsSync( packageJsonFile ) );
  });
});
<commit_msg>More tests * Make functions as async * handle failures<commit_after>/* globals describe, it, before */

var utils = require( '../utils' );
var assert = require('assert');
var fs = require('fs');
var path = require('path');

var fetchAndCacheMetadata = utils.fetchAndCacheMetadata;
var fetchAndCacheTarball = utils.fetchAndCacheTarball;
var exec = utils.exec;

/* TODO: write test */
// var patchData = utils.patchData;

var homeDir = process.env.HOME;
var testCacheFile = homeDir + '/.npm/registry.npmjs.org/lodash/.cache.json';
var testPackageFile = homeDir + '/.npm/lodash/4.2.1/package.tgz';

describe( 'Utility function s', function(){

  before( function(done){
    var cmd = [
      'if [[ -f $testCacheFile ]]; then rm $testCacheFile; fi',
      'if [[ -f $testPackageFile ]]; then rm $testPackageFile; fi'
    ].join( ';' );

    return exec( cmd , {
      testCacheFile: testCacheFile,
      testPackageFile: testPackageFile
    })
    .then( done );
  });

  it( 'should fetchAndCacheMetadata', function( done ){

    fetchAndCacheMetadata( 'lodash', testCacheFile )
      .then( function(){
        assert( fs.existsSync( testCacheFile ) );
        done();
      })
      .catch( done );
  });

  it( 'should fetchAndCacheTarball', function( done ){
    var packageJsonFile =  path.dirname( testPackageFile ) + '/package/package.json';

    fetchAndCacheTarball( 'lodash', '4.2.1', testPackageFile )
      .then( function(){
        assert( fs.existsSync( testPackageFile ) );
        assert( fs.existsSync( packageJsonFile ) );
        done();
      })
      .catch( done );
  });

  it( 'should fail if downloading fails', function( done ){
    fetchAndCacheMetadata( '456613231')
      .then( function(){
        return done( new Error('This should not resolve' ) );
      })
      .catch( function(e){
        assert.ok( e );
        assert.ok ( !fs.existsSync( homeDir + '/.npm/registry.npmjs.org/456613231/.cache.json' ) );
        done();
      });
  });

});
<|endoftext|>


<commit_before>suite('taskcluster utilities', function() {
  var taskcluster       = require('../');
  var parseTime         = require('../lib/parsetime');
  var assert            = require('assert');

  test('parseTime 1 year', function() {
    assert.equal(parseTime('1y').years, 1);
    assert.equal(parseTime('1 yr').years, 1);
    assert.equal(parseTime('1 year').years, 1);
    assert.equal(parseTime('1 years').years, 1);
    assert.equal(parseTime('1year').years, 1);
    assert.equal(parseTime('1    yr').years, 1);
    assert.equal(parseTime('  1    year   ').years, 1);
    assert.equal(parseTime('  1 years   ').years, 1);
  });

  test('parseTime -1 year', function() {
    assert.equal(parseTime('- 1y').years, -1);
    assert.equal(parseTime('- 1 yr').years, -1);
    assert.equal(parseTime('- 1 year').years, -1);
    assert.equal(parseTime('- 1 years').years, -1);
    assert.equal(parseTime('- 1year').years, -1);
    assert.equal(parseTime('- 1    yr').years, -1);
    assert.equal(parseTime('  - 1    year   ').years, -1);
    assert.equal(parseTime('  -  1 years   ').years, -1);
  });

  test('parseTime +1 year', function() {
    assert.equal(parseTime('+ 1y').years, 1);
    assert.equal(parseTime('+ 1 yr').years, 1);
    assert.equal(parseTime('+ 1 year').years, 1);
    assert.equal(parseTime('+ 1 years').years, 1);
    assert.equal(parseTime('+ 1year').years, 1);
    assert.equal(parseTime('+ 1    yr').years, 1);
    assert.equal(parseTime('  + 1    year   ').years, 1);
    assert.equal(parseTime('  +  1 years   ').years, 1);
  });

  test('parseTime 1 month', function() {
    assert.equal(parseTime('1mo').months, 1);
    assert.equal(parseTime('1 mo').months, 1);
    assert.equal(parseTime('1 month').months, 1);
    assert.equal(parseTime('1 months').months, 1);
    assert.equal(parseTime('1month').months, 1);
    assert.equal(parseTime('1    mo').months, 1);
    assert.equal(parseTime('  1    month   ').months, 1);
    assert.equal(parseTime('  1 months   ').months, 1);
  });

  test('parseTime -1 month', function() {
    assert.equal(parseTime('- 1mo').months, -1);
    assert.equal(parseTime('- 1 mo').months, -1);
    assert.equal(parseTime('- 1 month').months, -1);
    assert.equal(parseTime('- 1 months').months, -1);
    assert.equal(parseTime('- 1month').months, -1);
    assert.equal(parseTime('- 1    mo').months, -1);
    assert.equal(parseTime('  - 1    month   ').months, -1);
    assert.equal(parseTime('  - 1 months   ').months, -1);
  });

  test('parseTime 1 week', function() {
    assert.equal(parseTime('1w').weeks, 1);
    assert.equal(parseTime('1 wk').weeks, 1);
    assert.equal(parseTime('1 week').weeks, 1);
    assert.equal(parseTime('1 weeks').weeks, 1);
    assert.equal(parseTime('1week').weeks, 1);
    assert.equal(parseTime('1    wk').weeks, 1);
    assert.equal(parseTime('  1    week   ').weeks, 1);
    assert.equal(parseTime('  1 weeks   ').weeks, 1);
  });

  test('parseTime 1 day', function() {
    assert.equal(parseTime('1d').days, 1);
    assert.equal(parseTime('1 d').days, 1);
    assert.equal(parseTime('1 day').days, 1);
    assert.equal(parseTime('1 days').days, 1);
    assert.equal(parseTime('1day').days, 1);
    assert.equal(parseTime('1    d').days, 1);
    assert.equal(parseTime('  1    day   ').days, 1);
    assert.equal(parseTime('  1 days   ').days, 1);
  });

  test('parseTime 3 days', function() {
    assert.equal(parseTime('3d').days, 3);
    assert.equal(parseTime('3 d').days, 3);
    assert.equal(parseTime('3 day').days, 3);
    assert.equal(parseTime('3 days').days, 3);
    assert.equal(parseTime('3day').days, 3);
    assert.equal(parseTime('3    d').days, 3);
    assert.equal(parseTime('  3    day   ').days, 3);
    assert.equal(parseTime('  3 days   ').days, 3);
  });

  test('parseTime 45 hours', function() {
    assert.equal(parseTime('45h').hours, 45);
    assert.equal(parseTime('45 h').hours, 45);
    assert.equal(parseTime('45 hour').hours, 45);
    assert.equal(parseTime('45 hours').hours, 45);
    assert.equal(parseTime('45hours').hours, 45);
    assert.equal(parseTime('45    h').hours, 45);
    assert.equal(parseTime('  45    hour   ').hours, 45);
    assert.equal(parseTime('  45 hours   ').hours, 45);
  });

  test('parseTime 45 min', function() {
    assert.equal(parseTime('45min').minutes, 45);
    assert.equal(parseTime('45 min').minutes, 45);
    assert.equal(parseTime('45 minute').minutes, 45);
    assert.equal(parseTime('45 minutes').minutes, 45);
    assert.equal(parseTime('45minutes').minutes, 45);
    assert.equal(parseTime('45    min').minutes, 45);
    assert.equal(parseTime('  45    min   ').minutes, 45);
    assert.equal(parseTime('  45 minutes   ').minutes, 45);
  });

  test('parseTime 45 seconds', function() {
    assert.equal(parseTime('45 s').seconds, 45);
    assert.equal(parseTime('45 s').seconds, 45);
    assert.equal(parseTime('45 sec').seconds, 45);
    assert.equal(parseTime('45 second').seconds, 45);
    assert.equal(parseTime('45 seconds').seconds, 45);
    assert.equal(parseTime('45seconds').seconds, 45);
    assert.equal(parseTime('45    s').seconds, 45);
    assert.equal(parseTime('  45    sec   ').seconds, 45);
    assert.equal(parseTime('  45 seconds   ').seconds, 45);
  });

  test('parseTime 1yr2mo3w4d5h6min7s', function() {
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').years, 1);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').months, 2);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').weeks, 3);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').days, 4);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').hours, 5);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').minutes, 6);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').seconds, 7);
    assert.equal(parseTime('2d3h').minutes, 0);
    assert.equal(parseTime('2d0h').hours, 0);
  });
  test('parseTime -1yr2mo3w4d5h6min7s', function() {
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').years, -1);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').months, -2);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').weeks, -3);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').days, -4);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').hours, -5);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').minutes, -6);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').seconds, -7);
    assert.equal(parseTime('-2d3h').minutes, 0);
    assert.equal(parseTime('-2d0h').hours, 0);
  });

  test('fromNow()', function() {
    var d1 = new Date();
    var d2 = taskcluster.fromNow();

    // Allow for 10 ms margin
    assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
  });

  test('fromNow(2 hours)', function() {
    var d1 = new Date();
    d1.setHours(d1.getHours() + 2)
    var d2 = taskcluster.fromNow('2 hours');

    // Allow for 10 ms margin
    assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
  });

  test('fromNow(2 years 15 months)', function() {
    var d1 = new Date();
    d1.setMonth(d1.getMonth() + 12 * 2 + 15)
    var d2 = taskcluster.fromNow('2 years 15mo');

    // Allow for 10ms margin
    assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
  });

  test('fromNow(2 years 55 months)', function() {
    var d1 = new Date();
    d1.setMonth(d1.getMonth() + 12 * 2 + 55)
    var d2 = taskcluster.fromNow('2 years 55mo');

    // Allow for 10ms margin
    assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
  });

  test('fromNow(240 months)', function() {
    var d1 = new Date();
    d1.setFullYear(d1.getFullYear() + 20)
    var d2 = taskcluster.fromNow('240 months');

    // Allow for 10ms margin
    assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
  });

  test('fromNow(-240 months)', function() {
    var d1 = new Date();
    d1.setFullYear(d1.getFullYear() - 20)
    var d2 = taskcluster.fromNow('-240 months');

    // Allow for 10ms margin
    assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
  });

  test('fromNow(20 years)', function() {
    var d1 = new Date();
    d1.setFullYear(d1.getFullYear() + 20)
    var d2 = taskcluster.fromNow('20 years');

    // Allow for 10ms margin
    assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
  });
});
<commit_msg>include some fromNow tests from json-e<commit_after>suite('taskcluster utilities', function() {
  var taskcluster       = require('../');
  var parseTime         = require('../lib/parsetime');
  var assert            = require('assert');

  test('parseTime 1 year', function() {
    assert.equal(parseTime('1y').years, 1);
    assert.equal(parseTime('1 yr').years, 1);
    assert.equal(parseTime('1 year').years, 1);
    assert.equal(parseTime('1 years').years, 1);
    assert.equal(parseTime('1year').years, 1);
    assert.equal(parseTime('1    yr').years, 1);
    assert.equal(parseTime('  1    year   ').years, 1);
    assert.equal(parseTime('  1 years   ').years, 1);
  });

  test('parseTime -1 year', function() {
    assert.equal(parseTime('- 1y').years, -1);
    assert.equal(parseTime('- 1 yr').years, -1);
    assert.equal(parseTime('- 1 year').years, -1);
    assert.equal(parseTime('- 1 years').years, -1);
    assert.equal(parseTime('- 1year').years, -1);
    assert.equal(parseTime('- 1    yr').years, -1);
    assert.equal(parseTime('  - 1    year   ').years, -1);
    assert.equal(parseTime('  -  1 years   ').years, -1);
  });

  test('parseTime +1 year', function() {
    assert.equal(parseTime('+ 1y').years, 1);
    assert.equal(parseTime('+ 1 yr').years, 1);
    assert.equal(parseTime('+ 1 year').years, 1);
    assert.equal(parseTime('+ 1 years').years, 1);
    assert.equal(parseTime('+ 1year').years, 1);
    assert.equal(parseTime('+ 1    yr').years, 1);
    assert.equal(parseTime('  + 1    year   ').years, 1);
    assert.equal(parseTime('  +  1 years   ').years, 1);
  });

  test('parseTime 1 month', function() {
    assert.equal(parseTime('1mo').months, 1);
    assert.equal(parseTime('1 mo').months, 1);
    assert.equal(parseTime('1 month').months, 1);
    assert.equal(parseTime('1 months').months, 1);
    assert.equal(parseTime('1month').months, 1);
    assert.equal(parseTime('1    mo').months, 1);
    assert.equal(parseTime('  1    month   ').months, 1);
    assert.equal(parseTime('  1 months   ').months, 1);
  });

  test('parseTime -1 month', function() {
    assert.equal(parseTime('- 1mo').months, -1);
    assert.equal(parseTime('- 1 mo').months, -1);
    assert.equal(parseTime('- 1 month').months, -1);
    assert.equal(parseTime('- 1 months').months, -1);
    assert.equal(parseTime('- 1month').months, -1);
    assert.equal(parseTime('- 1    mo').months, -1);
    assert.equal(parseTime('  - 1    month   ').months, -1);
    assert.equal(parseTime('  - 1 months   ').months, -1);
  });

  test('parseTime 1 week', function() {
    assert.equal(parseTime('1w').weeks, 1);
    assert.equal(parseTime('1 wk').weeks, 1);
    assert.equal(parseTime('1 week').weeks, 1);
    assert.equal(parseTime('1 weeks').weeks, 1);
    assert.equal(parseTime('1week').weeks, 1);
    assert.equal(parseTime('1    wk').weeks, 1);
    assert.equal(parseTime('  1    week   ').weeks, 1);
    assert.equal(parseTime('  1 weeks   ').weeks, 1);
  });

  test('parseTime 1 day', function() {
    assert.equal(parseTime('1d').days, 1);
    assert.equal(parseTime('1 d').days, 1);
    assert.equal(parseTime('1 day').days, 1);
    assert.equal(parseTime('1 days').days, 1);
    assert.equal(parseTime('1day').days, 1);
    assert.equal(parseTime('1    d').days, 1);
    assert.equal(parseTime('  1    day   ').days, 1);
    assert.equal(parseTime('  1 days   ').days, 1);
  });

  test('parseTime 3 days', function() {
    assert.equal(parseTime('3d').days, 3);
    assert.equal(parseTime('3 d').days, 3);
    assert.equal(parseTime('3 day').days, 3);
    assert.equal(parseTime('3 days').days, 3);
    assert.equal(parseTime('3day').days, 3);
    assert.equal(parseTime('3    d').days, 3);
    assert.equal(parseTime('  3    day   ').days, 3);
    assert.equal(parseTime('  3 days   ').days, 3);
  });

  test('parseTime 45 hours', function() {
    assert.equal(parseTime('45h').hours, 45);
    assert.equal(parseTime('45 h').hours, 45);
    assert.equal(parseTime('45 hour').hours, 45);
    assert.equal(parseTime('45 hours').hours, 45);
    assert.equal(parseTime('45hours').hours, 45);
    assert.equal(parseTime('45    h').hours, 45);
    assert.equal(parseTime('  45    hour   ').hours, 45);
    assert.equal(parseTime('  45 hours   ').hours, 45);
  });

  test('parseTime 45 min', function() {
    assert.equal(parseTime('45min').minutes, 45);
    assert.equal(parseTime('45 min').minutes, 45);
    assert.equal(parseTime('45 minute').minutes, 45);
    assert.equal(parseTime('45 minutes').minutes, 45);
    assert.equal(parseTime('45minutes').minutes, 45);
    assert.equal(parseTime('45    min').minutes, 45);
    assert.equal(parseTime('  45    min   ').minutes, 45);
    assert.equal(parseTime('  45 minutes   ').minutes, 45);
  });

  test('parseTime 45 seconds', function() {
    assert.equal(parseTime('45 s').seconds, 45);
    assert.equal(parseTime('45 s').seconds, 45);
    assert.equal(parseTime('45 sec').seconds, 45);
    assert.equal(parseTime('45 second').seconds, 45);
    assert.equal(parseTime('45 seconds').seconds, 45);
    assert.equal(parseTime('45seconds').seconds, 45);
    assert.equal(parseTime('45    s').seconds, 45);
    assert.equal(parseTime('  45    sec   ').seconds, 45);
    assert.equal(parseTime('  45 seconds   ').seconds, 45);
  });

  test('parseTime 1yr2mo3w4d5h6min7s', function() {
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').years, 1);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').months, 2);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').weeks, 3);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').days, 4);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').hours, 5);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').minutes, 6);
    assert.equal(parseTime('1yr2mo3w4d5h6min7s').seconds, 7);
    assert.equal(parseTime('2d3h').minutes, 0);
    assert.equal(parseTime('2d0h').hours, 0);
  });
  test('parseTime -1yr2mo3w4d5h6min7s', function() {
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').years, -1);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').months, -2);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').weeks, -3);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').days, -4);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').hours, -5);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').minutes, -6);
    assert.equal(parseTime('-1yr2mo3w4d5h6min7s').seconds, -7);
    assert.equal(parseTime('-2d3h').minutes, 0);
    assert.equal(parseTime('-2d0h').hours, 0);
  });

  suite('fromNow .. current time', function() {
    test('fromNow()', function() {
      var d1 = new Date();
      var d2 = taskcluster.fromNow();

      // Allow for 10 ms margin
      assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
    });

    test('fromNow(2 hours)', function() {
      var d1 = new Date();
      d1.setHours(d1.getHours() + 2)
        var d2 = taskcluster.fromNow('2 hours');

      // Allow for 10 ms margin
      assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
    });

    test('fromNow(2 years 15 months)', function() {
      var d1 = new Date();
      d1.setMonth(d1.getMonth() + 12 * 2 + 15)
        var d2 = taskcluster.fromNow('2 years 15mo');

      // Allow for 10ms margin
      assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
    });

    test('fromNow(2 years 55 months)', function() {
      var d1 = new Date();
      d1.setMonth(d1.getMonth() + 12 * 2 + 55)
        var d2 = taskcluster.fromNow('2 years 55mo');

      // Allow for 10ms margin
      assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
    });

    test('fromNow(240 months)', function() {
      var d1 = new Date();
      d1.setFullYear(d1.getFullYear() + 20)
        var d2 = taskcluster.fromNow('240 months');

      // Allow for 10ms margin
      assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
    });

    test('fromNow(-240 months)', function() {
      var d1 = new Date();
      d1.setFullYear(d1.getFullYear() - 20)
        var d2 = taskcluster.fromNow('-240 months');

      // Allow for 10ms margin
      assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
    });

    test('fromNow(20 years)', function() {
      var d1 = new Date();
      d1.setFullYear(d1.getFullYear() + 20)
        var d2 = taskcluster.fromNow('20 years');

      // Allow for 10ms margin
      assert(Math.abs(d2.getTime() - d1.getTime()) <= 10);
    });
  });

  suite('fromNow .. from', function() {
    [
    {expr: '1 hour', from: '2017-01-19T16:27:20.974Z', result: '2017-01-19T17:27:20.974Z'},
    {expr: '3h', from: '2017-01-19T16:27:20.974Z', result: '2017-01-19T19:27:20.974Z'},
    {expr: '1 hours', from: '2017-01-19T16:27:20.974Z', result: '2017-01-19T17:27:20.974Z'},
    {expr: '-1 hour', from: '2017-01-19T16:27:20.974Z', result: '2017-01-19T15:27:20.974Z'},
    {expr: '12 min', from: '2017-01-19T16:27:20.974Z', result: '2017-01-19T16:39:20.974Z'},
    {expr: '12min', from: '2017-01-19T16:27:20.974Z', result: '2017-01-19T16:39:20.974Z'},
    {expr: '1 day', from: '2017-01-19T16:27:20.974Z', result: '2017-01-20T16:27:20.974Z'},
    {expr: '2 days', from: '2017-01-19T16:27:20.974Z', result: '2017-01-21T16:27:20.974Z'},
    {expr: '1 second', from: '2017-01-19T16:27:20.974Z', result: '2017-01-19T16:27:21.974Z'},
    {expr: '1 week', from: '2017-01-19T16:27:20.974Z', result: '2017-01-26T16:27:20.974Z'},
    {expr: '1 year', from: '2017-01-19T16:27:20.974Z', result: '2018-01-19T16:27:20.974Z'},
    ].forEach(({expr, from, result}) => {
      test(expr, function() {
        assert.equal(taskcluster.fromNow(expr, new Date(from)).toJSON(), result);
      });
    });
  });
});
<|endoftext|>


<commit_before>import React from "react";

import SimpleChildComponent from "./internals/SimpleChildComponent";
import createRegisterEvents from "./internals/createRegisterEvents";

import InfoWindow from "./InfoWindow";

class Marker extends SimpleChildComponent {

  render () {
    const {props} = this;

    return (
      <noscript>
        {this._render_potential_info_windows_()}
      </noscript>
    );
  }

  _render_potential_info_windows_ () {
    const extraProps = {
      googleMapsApi: this.props.googleMapsApi,
      map: this.props.map,
      anchor: this.state.instance,
    };

    return React.Children.map(this.props.children, (child) => {
      if (React.isValidElement(child) && child.type === InfoWindow) {
        child = React.cloneElement(child, extraProps);
      }
      return child;
    }, this);
  }

}

Marker._GoogleMapsClassName = "Marker";

Marker._registerEvents = createRegisterEvents(
  "animation_changed click clickable_changed cursor_changed dblclick drag dragend draggable_changed dragstart flat_changed icon_changed mousedown mouseout mouseover mouseup position_changed rightclick shape_changed title_changed visible_changed zindex_changed"
);

export default Marker;
<commit_msg>fix(Marker): dont wrap children inside noscript tag<commit_after>import React from "react";

import SimpleChildComponent from "./internals/SimpleChildComponent";
import createRegisterEvents from "./internals/createRegisterEvents";

import InfoWindow from "./InfoWindow";

const {Children} = React;

class Marker extends SimpleChildComponent {

  render () {
    if (0 === Children.count(this.props.children)) {
      return <noscript />;
    }

    return (
      <div>
        {this._render_potential_info_windows_()}
      </div>
    );
  }

  _render_potential_info_windows_ () {
    const {props} = this;
    const extraProps = {
      googleMapsApi: props.googleMapsApi,
      map: props.map,
      anchor: this.state.instance,
    };

    return Children.map(props.children, (child) => {
      if (React.isValidElement(child) && child.type === InfoWindow) {
        child = React.cloneElement(child, extraProps);
      }
      return child;
    }, this);
  }

}

Marker._GoogleMapsClassName = "Marker";

Marker._registerEvents = createRegisterEvents(
  "animation_changed click clickable_changed cursor_changed dblclick drag dragend draggable_changed dragstart flat_changed icon_changed mousedown mouseout mouseover mouseup position_changed rightclick shape_changed title_changed visible_changed zindex_changed"
);

export default Marker;
<|endoftext|>


<commit_before>/**
 * ISARI Post LDAP File Definitions
 * =================================
 *
 * Files needing to wait for LDAP resolution to be processed.
 */
const fingerprint = require('talisman/keyers/fingerprint').default,
      helpers = require('../helpers'),
      hashPeople = helpers.hashPeople,
      chalk = require('chalk'),
      _ = require('lodash');

module.exports = {
  files: [

    /**
     * prix.csv
     * -------------------------------------------------------------------------
     */
    {
      name: 'prix',
      path: 'people/prix.csv',
      delimiter: ',',
      consumer(line) {
        const info = {
          organization: line['Nom Orga'],
          acronym: line.acronym,
          name: line.Nom,
          firstName: line.Prénom,
          title: line['Dénomination du prix'],
          date: line.Année,
          countries: line['Pays ISO'].split(',').map(c => c.trim())
        };

        return info;
      },
      process(indexes, id, line) {
        const key = hashPeople(line);

        // Matching the person
        const person = indexes.People.hashed[key];

        if (!person) {
          this.warning(`Could not match ${chalk.green(line.firstName + ' ' + line.name)}.`);
          return false;
        }

        // Checking whether the organization exists
        let org;

        if (line.organization) {
          org = indexes.Organization.name[line.organization];

          if (!org)
            org = indexes.Organization.acronym[line.acronym];

          const orgKey = fingerprint(line.organization);

          if (!org)
            org = indexes.Organization.fingerprint[orgKey];

          if (!org) {

            // We therefore create it
            org = {
              _id: id(),
              name: line.organization,
              countries: line.countries
            };

            if (line.acronym)
              org.acronym = line.acronym;

            indexes.Organization.name[org.name] = org;
            indexes.Organization.fingerprint[orgKey] = org;
            indexes.Organization.id[org._id] = org;
          }
        }

        // Building the distinction
        const distinction = {
          distinctionType: 'distinction',
          countries: line.countries,
          title: line.title
        };

        if (org)
          distinction.organizations = [org.name];

        if (line.date)
          distinction.date = line.date;

        person.distinctions = person.distinctions || [];
        person.distinctions.push(distinction);

        return true;
      }
    },

    /**
     * admin_roles.csv
     * -------------------------------------------------------------------------
     */
    {
      name: 'admin_roles',
      path: 'people/admin_roles.csv',
      process(indexes, id, line) {
        const {ldapUid, orgaAcronym, isariRole} = line;

        const person = indexes.People.ldap[ldapUid];

        if (!person) {
          log.error(`Could not match person with LDAP id ${chalk.green(ldapUid)}.`);
          return next(new ProcessError());
        }

        let org;

        if (orgaAcronym) {
          org = indexes.Organization.acronym[orgaAcronym.toUpperCase()];

          if (!org)
            org = indexes.Organization.name[orgaAcronym];

          if (!org) {
            log.error(`Could not match organization with acronym ${chalk.green(orgaAcronym)}`);
            return next(new ProcessError());
          }
        }
        else if (!/^central_/.test(isariRole)) {
          log.error(`Inconsistent role for id ${chalk.green(ldapUid)}. Cannot be ${chalk.grey(isariRole)} and be attached to an organization.`);
          return next(new ProcessError());
        }

        person.isariAuthorizedCenters = person.isariAuthorizedCenters || [];

        let authorization = org && person.isariAuthorizedCenters.find(a => a.organization === org._id);

        if (authorization) {
          authorization.isariRole = isariRole;
        }
        else {
          authorization = {isariRole};

          if (org)
            authorization.organization = org._id;

          person.isariAuthorizedCenters.push(authorization);
        }
      }
    }
  ]
};
<commit_msg>Linter pass<commit_after>/**
 * ISARI Post LDAP File Definitions
 * =================================
 *
 * Files needing to wait for LDAP resolution to be processed.
 */
const fingerprint = require('talisman/keyers/fingerprint').default,
      helpers = require('../helpers'),
      hashPeople = helpers.hashPeople,
      chalk = require('chalk');

module.exports = {
  files: [

    /**
     * prix.csv
     * -------------------------------------------------------------------------
     */
    {
      name: 'prix',
      path: 'people/prix.csv',
      delimiter: ',',
      consumer(line) {
        const info = {
          organization: line['Nom Orga'],
          acronym: line.acronym,
          name: line.Nom,
          firstName: line.Prénom,
          title: line['Dénomination du prix'],
          date: line.Année,
          countries: line['Pays ISO'].split(',').map(c => c.trim())
        };

        return info;
      },
      process(indexes, id, line) {
        const key = hashPeople(line);

        // Matching the person
        const person = indexes.People.hashed[key];

        if (!person) {
          this.warning(`Could not match ${chalk.green(line.firstName + ' ' + line.name)}.`);
          return false;
        }

        // Checking whether the organization exists
        let org;

        if (line.organization) {
          org = indexes.Organization.name[line.organization];

          if (!org)
            org = indexes.Organization.acronym[line.acronym];

          const orgKey = fingerprint(line.organization);

          if (!org)
            org = indexes.Organization.fingerprint[orgKey];

          if (!org) {

            // We therefore create it
            org = {
              _id: id(),
              name: line.organization,
              countries: line.countries
            };

            if (line.acronym)
              org.acronym = line.acronym;

            indexes.Organization.name[org.name] = org;
            indexes.Organization.fingerprint[orgKey] = org;
            indexes.Organization.id[org._id] = org;
          }
        }

        // Building the distinction
        const distinction = {
          distinctionType: 'distinction',
          countries: line.countries,
          title: line.title
        };

        if (org)
          distinction.organizations = [org.name];

        if (line.date)
          distinction.date = line.date;

        person.distinctions = person.distinctions || [];
        person.distinctions.push(distinction);

        return true;
      }
    },

    /**
     * admin_roles.csv
     * -------------------------------------------------------------------------
     */
    {
      name: 'admin_roles',
      path: 'people/admin_roles.csv',
      process(indexes, id, line) {
        const {ldapUid, orgaAcronym, isariRole} = line;

        const person = indexes.People.ldap[ldapUid];

        if (!person) {
          this.error(`Could not match person with LDAP id ${chalk.green(ldapUid)}.`);
          return false;
        }

        let org;

        if (orgaAcronym) {
          org = indexes.Organization.acronym[orgaAcronym.toUpperCase()];

          if (!org)
            org = indexes.Organization.name[orgaAcronym];

          if (!org) {
            this.error(`Could not match organization with acronym ${chalk.green(orgaAcronym)}`);
            return false;
          }
        }
        else if (!/^central_/.test(isariRole)) {
          this.error(`Inconsistent role for id ${chalk.green(ldapUid)}. Cannot be ${chalk.grey(isariRole)} and be attached to an organization.`);
          return false;
        }

        person.isariAuthorizedCenters = person.isariAuthorizedCenters || [];

        let authorization = org && person.isariAuthorizedCenters.find(a => a.organization === org._id);

        if (authorization) {
          authorization.isariRole = isariRole;
        }
        else {
          authorization = {isariRole};

          if (org)
            authorization.organization = org._id;

          person.isariAuthorizedCenters.push(authorization);
        }
      }
    }
  ]
};
<|endoftext|>


<commit_before>import EventEmitter from 'events'
import { readFile } from './fs.js'
import { resolve } from 'path'

import File from './File.js'
import Watcher from './Watcher.js'

import symbols from './symbols.js'
// prettier-ignore
let { _origData, _status, _watcher, _transform, _generators, _resolver, _active, _waitingFor, _whenFound, _deps, _queue, _isProcessing, _startWave, _endWave, _enqueue, _processPhysicalFile, _processFile, _processGenerator, _cur, _newProxy, _processDependents, _markFound } = symbols

export default class Defiler extends EventEmitter {
	constructor({
		dir,
		filter,
		read = true,
		enc = 'utf8',
		watch = true,
		debounce = 10,
		transform,
		generators = [],
		resolver,
	}) {
		if (typeof dir !== 'string') throw new TypeError('defiler: dir must be a string')
		if (typeof filter !== 'undefined' && typeof filter !== 'function') {
			throw new TypeError('defiler: filter must be a function')
		}
		if (typeof read !== 'boolean') throw new TypeError('defiler: read must be a boolean')
		if (!Buffer.isEncoding(enc)) throw new TypeError('defiler: enc must be a supported encoding')
		if (typeof watch !== 'boolean') throw new TypeError('defiler: watch must be a boolean')
		if (typeof debounce !== 'number') throw new TypeError('defiler: debounce must be a number')
		if (typeof transform !== 'function') {
			throw new TypeError('defiler: transform must be a function')
		}
		if (
			!Array.isArray(generators) ||
			generators.some(generator => typeof generator !== 'function')
		) {
			throw new TypeError('defiler: generators must be an array of functions')
		}
		if (typeof resolver !== 'undefined' && typeof resolver !== 'function') {
			throw new TypeError('defiler: resolver must be a function')
		}
		super()
		this.paths = new Set() // set of original paths for all physical files
		this[_origData] = new Map() // original paths -> original file data for all physical files ({ path, stats, bytes, enc })
		this.files = new Map() // original paths -> transformed files for all physical and virtual files
		this[_status] = null // null = exec not called; false = exec pending; true = exec finished
		this[_watcher] = new Watcher({ dir: resolve(dir), filter, read, enc, watch, debounce }) // Watcher instance
		this[_transform] = transform // the transform to run on all files
		this[_generators] = new Map(generators.map(generator => [Symbol(), generator])) // unique symbols -> registered generators
		this[_resolver] = resolver // (base, path) => path resolver function, used in defiler.get and defiler.add from transform
		this[_active] = new Set() // original paths of all files currently undergoing transformation and symbols of all generators currently running
		this[_waitingFor] = new Map() // original paths -> number of other files they're currently waiting on to exist
		this[_whenFound] = new Map() // original paths -> { promise, resolve } objects for when awaited files become available
		this[_cur] = { root: null, parent: null } // (set via proxy) root: the current root dependent, for use in _deps; parent: the current immediate dependent, for use in _waitingFor and the resolver
		this[_deps] = [] // array of [dependent, dependency] pairs, specifying changes to which files should trigger re-processing which other files
		this[_queue] = [] // queue of pending Watcher events to handle
		this[_isProcessing] = false // whether some Watcher event is currently already in the process of being handled
	}

	// execute everything, and return a promise that resolves when the first wave of processing is complete
	async exec() {
		if (this[_status] !== null) throw new Error('defiler.exec: cannot call more than once')
		this[_status] = false
		this[_isProcessing] = true
		let done = this[_startWave]()
		// init the Watcher instance
		this[_watcher].on('', event => this[_enqueue](event))
		let files = await this[_watcher].init()
		// note that all files are pending transformation
		for (let { path } of files) {
			this.paths.add(path)
			this[_active].add(path)
		}
		for (let symbol of this[_generators].keys()) this[_active].add(symbol)
		// process each physical file
		for (let { path, stats } of files) this[_processPhysicalFile](path, stats)
		// process each generator
		for (let symbol of this[_generators].keys()) this[_processGenerator](symbol)
		// wait and finish up
		await done
		this[_status] = true
		this[_isProcessing] = false
		this[_enqueue]()
	}

	// wait for a file to be available and retrieve it, marking dependencies as appropriate
	async get(path) {
		if (Array.isArray(path)) return Promise.all(path.map(path => this.get(path)))
		let { [_cur]: cur, [_waitingFor]: waitingFor } = this
		if (this[_resolver] && typeof cur.parent === 'string') path = this[_resolver](cur.parent, path)
		if (typeof path !== 'string') throw new TypeError('defiler.get: path must be a string')
		if (cur.root) this[_deps].push([cur.root, path])
		if (!this[_status] && !this.files.has(path)) {
			if (cur.parent) waitingFor.set(cur.parent, (waitingFor.get(cur.parent) || 0) + 1)
			if (!this[_whenFound].has(path)) {
				let resolve
				this[_whenFound].set(path, { promise: new Promise(res => (resolve = res)), resolve })
			}
			await this[_whenFound].get(path).promise
			if (cur.parent) waitingFor.set(cur.parent, waitingFor.get(cur.parent) - 1)
		}
		return this.files.get(path)
	}

	// add a new virtual file
	add(file) {
		if (this[_status] === null) throw new Error('defiler.add: cannot call before calling exec')
		if (typeof file !== 'object') throw new TypeError('defiler.add: file must be an object')
		if (this[_resolver] && typeof this[_cur].parent === 'string') {
			file.path = this[_resolver](this[_cur].parent, file.path)
		}
		this[_processFile](file)
	}

	// private methods

	// return a Promise that we will resolve at the end of this wave, and save its resolver
	[_startWave]() {
		return new Promise(res => (this[_endWave] = res))
	}

	// add a Watcher event to the queue, and handle queued events
	async [_enqueue](event) {
		if (event) this[_queue].push(event)
		if (this[_isProcessing]) return
		this[_isProcessing] = true
		while (this[_queue].length) {
			let { event, path, stats } = this[_queue].shift()
			let done = this[_startWave]()
			if (event === '+') {
				this[_processPhysicalFile](path, stats)
			} else if (event === '-') {
				let file = this.files.get(path)
				this.paths.delete(path)
				this[_origData].delete(path)
				this.files.delete(path)
				this.emit('deleted', { defiler: this, file })
				if (this[_status]) this[_processDependents](path)
			}
			await done
		}
		this[_isProcessing] = false
	}

	// create a file object for a physical file and process it
	async [_processPhysicalFile](path, stats) {
		let { dir, read, enc } = this[_watcher]
		let data = { path, stats, enc }
		if (read) data.bytes = await readFile(dir + '/' + path)
		this.paths.add(path)
		this[_origData].set(path, data)
		this.emit('read', { defiler: this, file: Object.assign(new File(), data) })
		await this[_processFile](data)
	}

	// transform a file, store it, and process dependents
	async [_processFile](data) {
		let file = Object.assign(new File(), data)
		let { path } = file
		this[_active].add(path)
		let defiler = this[_newProxy](path)
		try {
			await this[_transform]({ defiler, file })
		} catch (error) {
			this.emit('error', { defiler, file, error })
		}
		this.files.set(path, file)
		this.emit('file', { defiler: this, file })
		this[_markFound](path)
		if (this[_status]) this[_processDependents](path)
		this[_active].delete(path)
		if (!this[_active].size) {
			this[_endWave]()
		} else if (!this[_status] && [...this[_active]].every(path => this[_waitingFor].get(path))) {
			// all pending files are currently waiting for one or more other files to exist
			// break deadlock: assume all files that have not appeared yet will never do so
			for (let path of this[_whenFound].keys()) if (!this[_active].has(path)) this[_markFound](path)
		}
	}

	// re-process all files that depend on a particular path
	[_processDependents](path) {
		let dependents = new Set(this[_deps].map(([dependent, dep]) => dep === path && dependent))
		this[_deps] = this[_deps].filter(([dependent]) => !dependents.has(dependent))
		if (!dependents.size && !this[_active].size) this[_endWave]()
		for (let dependent of dependents) {
			if (this[_origData].has(dependent)) {
				this[_processFile](this[_origData].get(dependent))
			} else if (this[_generators].has(dependent)) {
				this[_processGenerator](dependent)
			}
		}
	}

	// run the generator given by the symbol
	async [_processGenerator](symbol) {
		this[_active].add(symbol)
		let generator = this[_generators].get(symbol)
		let defiler = this[_newProxy](symbol)
		try {
			await generator({ defiler })
		} catch (error) {
			this.emit('error', { defiler, generator, error })
		}
		this[_active].delete(symbol)
	}

	// create a defiler Proxy for the given path, always overriding _cur.parent and only overriding _cur.root if it is not yet set
	[_newProxy](path) {
		let cur = { root: this[_cur].root || path, parent: path }
		return new Proxy(this, { get: (_, key) => (key === _cur ? cur : this[key]) })
	}

	// mark a given awaited file as being found
	[_markFound](path) {
		if (!this[_status] && this[_whenFound].has(path)) {
			this[_whenFound].get(path).resolve()
			this[_whenFound].delete(path)
		}
	}
}
<commit_msg>allow 'read' and 'enc' to vary across the individual files<commit_after>import EventEmitter from 'events'
import { readFile } from './fs.js'
import { resolve } from 'path'

import File from './File.js'
import Watcher from './Watcher.js'

import symbols from './symbols.js'
// prettier-ignore
let { _origData, _status, _watcher, _transform, _generators, _resolver, _active, _waitingFor, _whenFound, _deps, _queue, _isProcessing, _startWave, _endWave, _enqueue, _processPhysicalFile, _processFile, _processGenerator, _cur, _newProxy, _processDependents, _markFound } = symbols

export default class Defiler extends EventEmitter {
	constructor({
		dir,
		filter,
		read = true,
		enc = 'utf8',
		watch = true,
		debounce = 10,
		transform,
		generators = [],
		resolver,
	}) {
		if (typeof dir !== 'string') throw new TypeError('defiler: dir must be a string')
		if (typeof filter !== 'undefined' && typeof filter !== 'function') {
			throw new TypeError('defiler: filter must be a function')
		}
		if (typeof read !== 'boolean' && typeof read !== 'function') {
			throw new TypeError('defiler: read must be a boolean or a function')
		}
		if (!Buffer.isEncoding(enc) && typeof enc !== 'function') {
			throw new TypeError('defiler: enc must be a supported encoding or a function')
		}
		if (typeof watch !== 'boolean') throw new TypeError('defiler: watch must be a boolean')
		if (typeof debounce !== 'number') throw new TypeError('defiler: debounce must be a number')
		if (typeof transform !== 'function') {
			throw new TypeError('defiler: transform must be a function')
		}
		if (
			!Array.isArray(generators) ||
			generators.some(generator => typeof generator !== 'function')
		) {
			throw new TypeError('defiler: generators must be an array of functions')
		}
		if (typeof resolver !== 'undefined' && typeof resolver !== 'function') {
			throw new TypeError('defiler: resolver must be a function')
		}
		super()
		this.paths = new Set() // set of original paths for all physical files
		this[_origData] = new Map() // original paths -> original file data for all physical files ({ path, stats, bytes, enc })
		this.files = new Map() // original paths -> transformed files for all physical and virtual files
		this[_status] = null // null = exec not called; false = exec pending; true = exec finished
		this[_watcher] = new Watcher({ dir: resolve(dir), filter, read, enc, watch, debounce }) // Watcher instance
		this[_transform] = transform // the transform to run on all files
		this[_generators] = new Map(generators.map(generator => [Symbol(), generator])) // unique symbols -> registered generators
		this[_resolver] = resolver // (base, path) => path resolver function, used in defiler.get and defiler.add from transform
		this[_active] = new Set() // original paths of all files currently undergoing transformation and symbols of all generators currently running
		this[_waitingFor] = new Map() // original paths -> number of other files they're currently waiting on to exist
		this[_whenFound] = new Map() // original paths -> { promise, resolve } objects for when awaited files become available
		this[_cur] = { root: null, parent: null } // (set via proxy) root: the current root dependent, for use in _deps; parent: the current immediate dependent, for use in _waitingFor and the resolver
		this[_deps] = [] // array of [dependent, dependency] pairs, specifying changes to which files should trigger re-processing which other files
		this[_queue] = [] // queue of pending Watcher events to handle
		this[_isProcessing] = false // whether some Watcher event is currently already in the process of being handled
	}

	// execute everything, and return a promise that resolves when the first wave of processing is complete
	async exec() {
		if (this[_status] !== null) throw new Error('defiler.exec: cannot call more than once')
		this[_status] = false
		this[_isProcessing] = true
		let done = this[_startWave]()
		// init the Watcher instance
		this[_watcher].on('', event => this[_enqueue](event))
		let files = await this[_watcher].init()
		// note that all files are pending transformation
		for (let { path } of files) {
			this.paths.add(path)
			this[_active].add(path)
		}
		for (let symbol of this[_generators].keys()) this[_active].add(symbol)
		// process each physical file
		for (let { path, stats } of files) this[_processPhysicalFile](path, stats)
		// process each generator
		for (let symbol of this[_generators].keys()) this[_processGenerator](symbol)
		// wait and finish up
		await done
		this[_status] = true
		this[_isProcessing] = false
		this[_enqueue]()
	}

	// wait for a file to be available and retrieve it, marking dependencies as appropriate
	async get(path) {
		if (Array.isArray(path)) return Promise.all(path.map(path => this.get(path)))
		let { [_cur]: cur, [_waitingFor]: waitingFor } = this
		if (this[_resolver] && typeof cur.parent === 'string') path = this[_resolver](cur.parent, path)
		if (typeof path !== 'string') throw new TypeError('defiler.get: path must be a string')
		if (cur.root) this[_deps].push([cur.root, path])
		if (!this[_status] && !this.files.has(path)) {
			if (cur.parent) waitingFor.set(cur.parent, (waitingFor.get(cur.parent) || 0) + 1)
			if (!this[_whenFound].has(path)) {
				let resolve
				this[_whenFound].set(path, { promise: new Promise(res => (resolve = res)), resolve })
			}
			await this[_whenFound].get(path).promise
			if (cur.parent) waitingFor.set(cur.parent, waitingFor.get(cur.parent) - 1)
		}
		return this.files.get(path)
	}

	// add a new virtual file
	add(file) {
		if (this[_status] === null) throw new Error('defiler.add: cannot call before calling exec')
		if (typeof file !== 'object') throw new TypeError('defiler.add: file must be an object')
		if (this[_resolver] && typeof this[_cur].parent === 'string') {
			file.path = this[_resolver](this[_cur].parent, file.path)
		}
		this[_processFile](file)
	}

	// private methods

	// return a Promise that we will resolve at the end of this wave, and save its resolver
	[_startWave]() {
		return new Promise(res => (this[_endWave] = res))
	}

	// add a Watcher event to the queue, and handle queued events
	async [_enqueue](event) {
		if (event) this[_queue].push(event)
		if (this[_isProcessing]) return
		this[_isProcessing] = true
		while (this[_queue].length) {
			let { event, path, stats } = this[_queue].shift()
			let done = this[_startWave]()
			if (event === '+') {
				this[_processPhysicalFile](path, stats)
			} else if (event === '-') {
				let file = this.files.get(path)
				this.paths.delete(path)
				this[_origData].delete(path)
				this.files.delete(path)
				this.emit('deleted', { defiler: this, file })
				if (this[_status]) this[_processDependents](path)
			}
			await done
		}
		this[_isProcessing] = false
	}

	// create a file object for a physical file and process it
	async [_processPhysicalFile](path, stats) {
		let { dir, read, enc } = this[_watcher]
		let data = { path, stats }
		if (read && (typeof read !== 'function' || (await read({ path, stats })))) {
			data.bytes = await readFile(dir + '/' + path)
		}
		data.enc = typeof enc === 'function' ? await enc({ path, stats, bytes: data.bytes }) : enc
		this.paths.add(path)
		this[_origData].set(path, data)
		this.emit('read', { defiler: this, file: Object.assign(new File(), data) })
		await this[_processFile](data)
	}

	// transform a file, store it, and process dependents
	async [_processFile](data) {
		let file = Object.assign(new File(), data)
		let { path } = file
		this[_active].add(path)
		let defiler = this[_newProxy](path)
		try {
			await this[_transform]({ defiler, file })
		} catch (error) {
			this.emit('error', { defiler, file, error })
		}
		this.files.set(path, file)
		this.emit('file', { defiler: this, file })
		this[_markFound](path)
		if (this[_status]) this[_processDependents](path)
		this[_active].delete(path)
		if (!this[_active].size) {
			this[_endWave]()
		} else if (!this[_status] && [...this[_active]].every(path => this[_waitingFor].get(path))) {
			// all pending files are currently waiting for one or more other files to exist
			// break deadlock: assume all files that have not appeared yet will never do so
			for (let path of this[_whenFound].keys()) if (!this[_active].has(path)) this[_markFound](path)
		}
	}

	// re-process all files that depend on a particular path
	[_processDependents](path) {
		let dependents = new Set(this[_deps].map(([dependent, dep]) => dep === path && dependent))
		this[_deps] = this[_deps].filter(([dependent]) => !dependents.has(dependent))
		if (!dependents.size && !this[_active].size) this[_endWave]()
		for (let dependent of dependents) {
			if (this[_origData].has(dependent)) {
				this[_processFile](this[_origData].get(dependent))
			} else if (this[_generators].has(dependent)) {
				this[_processGenerator](dependent)
			}
		}
	}

	// run the generator given by the symbol
	async [_processGenerator](symbol) {
		this[_active].add(symbol)
		let generator = this[_generators].get(symbol)
		let defiler = this[_newProxy](symbol)
		try {
			await generator({ defiler })
		} catch (error) {
			this.emit('error', { defiler, generator, error })
		}
		this[_active].delete(symbol)
	}

	// create a defiler Proxy for the given path, always overriding _cur.parent and only overriding _cur.root if it is not yet set
	[_newProxy](path) {
		let cur = { root: this[_cur].root || path, parent: path }
		return new Proxy(this, { get: (_, key) => (key === _cur ? cur : this[key]) })
	}

	// mark a given awaited file as being found
	[_markFound](path) {
		if (!this[_status] && this[_whenFound].has(path)) {
			this[_whenFound].get(path).resolve()
			this[_whenFound].delete(path)
		}
	}
}
<|endoftext|>


<commit_before>module.exports = Messages

var h = require('virtual-dom/h')
var inherits = require('util').inherits
var BaseElement = require('./base-element')

function Messages (target) {
  BaseElement.call(this, target)
  this.shouldAutoScroll = true
}
inherits(Messages, BaseElement)

Messages.prototype.render = function (channel, users) {
  var self = this
  var childViews

  if (channel && channel.messages.length === 0) {
    var starterMessage = 'This is new channel. Send a message to start things off!'
    childViews = h('.messages.starterMessage', starterMessage)
  } else {
    var messages = (channel ? channel.messages : []).map(function (msg) {
      var user = users[msg.username]
      if (user && user.blocked) return null

      var verified = !/Anonymous/i.test(msg.username) && msg.valid
      return h('li.message.clearfix', [
        h('img.avatar', { src: msg.avatar }),
        h('.username', msg.username),
        verified ? h('.verified') : null,
        h('.timestamp', msg.timeago),
        msg.vdom || h('.text', msg.text)
      ])
    })
    childViews = h('.messages', {
      onscroll: function () {
        if (this.scrollHeight <= this.clientHeight + this.scrollTop) self.shouldAutoScroll = true
        else self.shouldAutoScroll = false
      }
    }, messages)
  }

  var onleave = function () {
    if (!channel || channel.name === 'friends') return
    self.send('leaveChannel', channel.name)
  }

  var leavableChannel = channel.name !== 'friends'

  return h('.messages-container', [
    h('div', { className: 'top-bar' }, [
      h('.channelName', '#' + (channel ? channel.name : 'friends') + ' (' + channel.peers + ' peer' + (channel.peers === 1 ? '' : 's') + ')'),
      leavableChannel ? h('a.button.leaveButton', {onclick: onleave}, 'Leave') : null
    ]),
    childViews
  ])
}

Messages.prototype.scrollToBottom = function (force) {
  if (!force && !this.shouldAutoScroll) return
  var messagesDiv = document.querySelector('.messages')
  if (messagesDiv) messagesDiv.scrollTop = messagesDiv.scrollHeight
}
<commit_msg>Making a button as that is what this is<commit_after>module.exports = Messages

var h = require('virtual-dom/h')
var inherits = require('util').inherits
var BaseElement = require('./base-element')

function Messages (target) {
  BaseElement.call(this, target)
  this.shouldAutoScroll = true
}
inherits(Messages, BaseElement)

Messages.prototype.render = function (channel, users) {
  var self = this
  var childViews

  if (channel && channel.messages.length === 0) {
    var starterMessage = 'This is new channel. Send a message to start things off!'
    childViews = h('.messages.starterMessage', starterMessage)
  } else {
    var messages = (channel ? channel.messages : []).map(function (msg) {
      var user = users[msg.username]
      if (user && user.blocked) return null

      var verified = !/Anonymous/i.test(msg.username) && msg.valid
      return h('li.message.clearfix', [
        h('img.avatar', { src: msg.avatar }),
        h('.username', msg.username),
        verified ? h('.verified') : null,
        h('.timestamp', msg.timeago),
        msg.vdom || h('.text', msg.text)
      ])
    })
    childViews = h('.messages', {
      onscroll: function () {
        if (this.scrollHeight <= this.clientHeight + this.scrollTop) self.shouldAutoScroll = true
        else self.shouldAutoScroll = false
      }
    }, messages)
  }

  var onleave = function () {
    if (!channel || channel.name === 'friends') return
    self.send('leaveChannel', channel.name)
  }

  var leavableChannel = channel.name !== 'friends'

  return h('.messages-container', [
    h('div', { className: 'top-bar' }, [
      h('.channelName', '#' + (channel ? channel.name : 'friends') + ' (' + channel.peers + ' peer' + (channel.peers === 1 ? '' : 's') + ')'),
      leavableChannel ? h('button.button.leaveButton', {onclick: onleave}, 'Leave') : null
    ]),
    childViews
  ])
}

Messages.prototype.scrollToBottom = function (force) {
  if (!force && !this.shouldAutoScroll) return
  var messagesDiv = document.querySelector('.messages')
  if (messagesDiv) messagesDiv.scrollTop = messagesDiv.scrollHeight
}
<|endoftext|>


<commit_before><commit_msg>Piaget Rose<commit_after><|endoftext|>