<commit_before>'use strict';

var typeUtils = require('../compiler/typeUtils.js');
var primUtils = require('./primUtils');
var liftStep = primUtils.liftStep;

function delay1(runtime, startTime, argStreams, baseTopoOrder, result) {
  if (argStreams.length !== 1) {
    throw new Error('got wrong number of arguments');
  }

  var argStream = argStreams[0];

  // create or validate outputStream, set initial value
  // initial output is just initial input
  var argVal = argStream.value;
  if (result) {
    if (result.outputStream.tempo !== 'step') {
      throw new Error('Incorrect output stream tempo');
    }
    result.outputStream.changeValue(argVal, startTime);
  } else {
    result = {
      outputStream: runtime.createStepStream(argVal, startTime),
      deactivator: null,
    };
  }

  if (result.deactivator) { throw new Error('Deactivator should be null'); }
  result.deactivator = function() {
    argStream.removeTrigger(argChangedTrigger);
    if (pendingOutputChangeTask) {
      runtime.priorityQueue.remove(pendingOutputChangeTask);
    }
  };

  var scheduledChanges = []; // ordered list of {time: ..., value: ...}
  var pendingOutputChangeTask = null;

  // if needed, add task for updating output, and update our bookeeping
  var updateTasks = function() {
    if ((scheduledChanges.length > 0) && !pendingOutputChangeTask) {
      var nextChange = scheduledChanges[0];
      // TODO: this should probably call a method of runtime instead of accessing priorityQueue directly
      // TODO: this call could get back a 'task handle' that we use to remove a pending task on deactivate
      var changeTask = {
        time: nextChange.time,
        topoOrder: baseTopoOrder,
        closure: changeOutput,
      };
      runtime.priorityQueue.insert(changeTask);
      pendingOutputChangeTask = changeTask;
    }
  };

  // closure to be called when time has come to change output value
  var changeOutput = function(atTime) {
    if (scheduledChanges.length === 0) {
      throw new Error('no changes to make');
    }

    // pull next change off 'front' of queue
    var nextChange = scheduledChanges.shift();

    // sanity check
    if (atTime !== nextChange.time) {
      throw new Error('times do not match');
    }

    result.outputStream.changeValue(nextChange.value, atTime);

    pendingOutputChangeTask = null;
    updateTasks();
  };

  var argChangedTask = function(atTime) {
    var argVal = argStream.value;
    scheduledChanges.push({
      time: atTime + 1.0, // here is the delay amount
      value: argVal,
    });

    updateTasks();
  };

  // make closure to add task when argument value changes
  var argChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder,
      closure: argChangedTask,
    });
  };

  // add trigger on argument
  argStream.addTrigger(argChangedTrigger);

  // create deactivator
  result.deactivator = function() {
    argStream.removeTrigger(argChangedTrigger);
    if (pendingOutputChangeTask) {
      runtime.priorityQueue.remove(pendingOutputChangeTask);
    }
  };

  return result;
};

function timeOfLatest(runtime, startTime, argStreams, baseTopoOrder, result) {
  if (argStreams.length !== 1) {
    throw new Error('got wrong number of arguments');
  }

  var argStream = argStreams[0];
  if (argStream.tempo !== 'event') {
    throw new Error('Incorrect input stream tempo');
  }

  // create or validate result, set initial output value
  if (result) {
    if (result.outputStream.tempo !== 'step') {
      throw new Error('Incorrect output stream tempo');
    }
    result.outputStream.changeValue(0, startTime);
  } else {
    result = {
      outputStream: runtime.createStepStream(0, startTime),
      deactivator: null,
    };
  }

  if (result.deactivator) { throw new Error('Deactivator should be null'); }
  result.deactivator = function() {
    argStream.removeTrigger(argChangedTrigger);
  };

  // closure to update output value
  var argChangedTask = function(atTime) {
    result.outputStream.changeValue(atTime-startTime, atTime);
  };

  // make closure to add task when argument value changes
  var argChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder,
      closure: argChangedTask,
    });
  };

  // add trigger on argument
  argStream.addTrigger(argChangedTrigger);

  return result;
}

function integral(runtime, startTime, argStreams, baseTopoOrder, result) {
  if (argStreams.length !== 3) {
    throw new Error('got wrong number of arguments');
  }

  // split out parameters and validate their tempos
  var integrand = argStreams[0];
  if (integrand.tempo !== 'step') {
    throw new Error('Argument integrand must be step');
  }
  var initialValue = argStreams[1];
  if (initialValue.tempo !== 'const') {
    throw new Error('Argument initialValue must be const');
  }
  var update = argStreams[2];
  if (update.tempo !== 'event') {
    throw new Error('Argument update must be event');
  }

  // here is our internal state and accumulating machinery
  var sum = initialValue.value; // the integral up to this point
  var lastTime = startTime; // the last time we accumulated to sum
  var lastIntegrandVal = undefined; // the value of integrand at lastTime
  function accumulate(upToTime) {
    if (lastIntegrandVal !== undefined) {
      sum += (upToTime - lastTime)*lastIntegrandVal;
    }
    lastTime = upToTime;
    lastIntegrandVal = integrand.value;
  }

  // create or validate result, set initial output value to zero
  if (result) {
    if (result.outputStream.tempo !== 'step') {
      throw new Error('Incorrect output stream tempo');
    }
    result.outputStream.changeValue(sum, startTime);
  } else {
    result = {
      outputStream: runtime.createStepStream(sum, startTime),
      deactivator: null,
    };
  }

  // If integrand and update inputs change at same time, it seems like it
  //  doesn't matter which we handle first, but we'll have integrand go
  //  first to keep things consistent.

  // task for when integrand changes
  var integrandChangedTask = function(atTime) {
    accumulate(atTime);
    // don't change output
  };

  // trigger for when integrand changes
  var integrandChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder+'0',
      closure: integrandChangedTask,
    });
  };

  // add trigger on integrand
  integrand.addTrigger(integrandChangedTrigger);

  // task for when update changes
  var updateChangedTask = function(atTime) {
    accumulate(atTime);
    result.outputStream.changeValue(sum, atTime);
  };

  // trigger for when update changes
  var updateChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder+'1',
      closure: updateChangedTask,
    });
  };

  // add trigger on update
  update.addTrigger(updateChangedTrigger);

  if (result.deactivator) { throw new Error('Deactivator should be null'); }
  result.deactivator = function() {
    update.removeTrigger(updateChangedTrigger);
    integrand.removeTrigger(integrandChangedTrigger);
  };

  return result;
}

module.exports = {
  id: {
    value: liftStep(function(a) { return a; }, 1),
    type: (function() {
      var a = typeUtils.createVariableType();
      return typeUtils.createFunctionType([{type: a}], a);
    })(),
  },
  Vec2: {
    value: liftStep(function(x, y) { return {x: x, y: y}; }, 2),
    // TODO: make yield type more specific when type system supports it
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER}, {type: typeUtils.NUMBER}], typeUtils.createVariableType()),
  },
  sin: {
    value: liftStep(function(x) { return Math.sin(x); }, 1),
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER}], typeUtils.NUMBER),
  },
  cos: {
    value: liftStep(function(x) { return Math.cos(x); }, 1),
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER}], typeUtils.NUMBER),
  },

  delay1: {
    value: delay1,
    type: (function() {
      var a = typeUtils.createVariableType();
      return typeUtils.createFunctionType([{type: a}], a);
    })(),
  },
  timeOfLatest: {
    value: timeOfLatest,
    // TODO: make parameter type more specific when type system supports it
    type: typeUtils.createFunctionType([{type: typeUtils.createVariableType()}], typeUtils.NUMBER),
  },
  integral: {
    value: integral,
    // TODO: make third parameter type more specific when type system supports it
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER, delayed: true}, {type: typeUtils.NUMBER}, {type: typeUtils.createVariableType()}], typeUtils.NUMBER),
  },
};
<commit_msg>Relax integral runtime checks for now<commit_after>'use strict';

var typeUtils = require('../compiler/typeUtils.js');
var primUtils = require('./primUtils');
var liftStep = primUtils.liftStep;

function delay1(runtime, startTime, argStreams, baseTopoOrder, result) {
  if (argStreams.length !== 1) {
    throw new Error('got wrong number of arguments');
  }

  var argStream = argStreams[0];

  // create or validate outputStream, set initial value
  // initial output is just initial input
  var argVal = argStream.value;
  if (result) {
    if (result.outputStream.tempo !== 'step') {
      throw new Error('Incorrect output stream tempo');
    }
    result.outputStream.changeValue(argVal, startTime);
  } else {
    result = {
      outputStream: runtime.createStepStream(argVal, startTime),
      deactivator: null,
    };
  }

  if (result.deactivator) { throw new Error('Deactivator should be null'); }
  result.deactivator = function() {
    argStream.removeTrigger(argChangedTrigger);
    if (pendingOutputChangeTask) {
      runtime.priorityQueue.remove(pendingOutputChangeTask);
    }
  };

  var scheduledChanges = []; // ordered list of {time: ..., value: ...}
  var pendingOutputChangeTask = null;

  // if needed, add task for updating output, and update our bookeeping
  var updateTasks = function() {
    if ((scheduledChanges.length > 0) && !pendingOutputChangeTask) {
      var nextChange = scheduledChanges[0];
      // TODO: this should probably call a method of runtime instead of accessing priorityQueue directly
      // TODO: this call could get back a 'task handle' that we use to remove a pending task on deactivate
      var changeTask = {
        time: nextChange.time,
        topoOrder: baseTopoOrder,
        closure: changeOutput,
      };
      runtime.priorityQueue.insert(changeTask);
      pendingOutputChangeTask = changeTask;
    }
  };

  // closure to be called when time has come to change output value
  var changeOutput = function(atTime) {
    if (scheduledChanges.length === 0) {
      throw new Error('no changes to make');
    }

    // pull next change off 'front' of queue
    var nextChange = scheduledChanges.shift();

    // sanity check
    if (atTime !== nextChange.time) {
      throw new Error('times do not match');
    }

    result.outputStream.changeValue(nextChange.value, atTime);

    pendingOutputChangeTask = null;
    updateTasks();
  };

  var argChangedTask = function(atTime) {
    var argVal = argStream.value;
    scheduledChanges.push({
      time: atTime + 1.0, // here is the delay amount
      value: argVal,
    });

    updateTasks();
  };

  // make closure to add task when argument value changes
  var argChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder,
      closure: argChangedTask,
    });
  };

  // add trigger on argument
  argStream.addTrigger(argChangedTrigger);

  // create deactivator
  result.deactivator = function() {
    argStream.removeTrigger(argChangedTrigger);
    if (pendingOutputChangeTask) {
      runtime.priorityQueue.remove(pendingOutputChangeTask);
    }
  };

  return result;
};

function timeOfLatest(runtime, startTime, argStreams, baseTopoOrder, result) {
  if (argStreams.length !== 1) {
    throw new Error('got wrong number of arguments');
  }

  var argStream = argStreams[0];
  if (argStream.tempo !== 'event') {
    throw new Error('Incorrect input stream tempo');
  }

  // create or validate result, set initial output value
  if (result) {
    if (result.outputStream.tempo !== 'step') {
      throw new Error('Incorrect output stream tempo');
    }
    result.outputStream.changeValue(0, startTime);
  } else {
    result = {
      outputStream: runtime.createStepStream(0, startTime),
      deactivator: null,
    };
  }

  if (result.deactivator) { throw new Error('Deactivator should be null'); }
  result.deactivator = function() {
    argStream.removeTrigger(argChangedTrigger);
  };

  // closure to update output value
  var argChangedTask = function(atTime) {
    result.outputStream.changeValue(atTime-startTime, atTime);
  };

  // make closure to add task when argument value changes
  var argChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder,
      closure: argChangedTask,
    });
  };

  // add trigger on argument
  argStream.addTrigger(argChangedTrigger);

  return result;
}

function integral(runtime, startTime, argStreams, baseTopoOrder, result) {
  if (argStreams.length !== 3) {
    throw new Error('got wrong number of arguments');
  }

  // split out parameters and validate their tempos
  var integrand = argStreams[0];
  if (integrand.tempo !== 'step') {
    throw new Error('Argument integrand must be step');
  }
  var initialValue = argStreams[1];
  // TODO: put this check back in
  /*
  if (initialValue.tempo !== 'const') {
    throw new Error('Argument initialValue must be const');
  }
  */
  var update = argStreams[2];
  if (update.tempo !== 'event') {
    throw new Error('Argument update must be event');
  }

  // here is our internal state and accumulating machinery
  var sum = initialValue.value; // the integral up to this point
  var lastTime = startTime; // the last time we accumulated to sum
  var lastIntegrandVal = undefined; // the value of integrand at lastTime
  function accumulate(upToTime) {
    if (lastIntegrandVal !== undefined) {
      sum += (upToTime - lastTime)*lastIntegrandVal;
    }
    lastTime = upToTime;
    lastIntegrandVal = integrand.value;
  }

  // create or validate result, set initial output value to zero
  if (result) {
    if (result.outputStream.tempo !== 'step') {
      throw new Error('Incorrect output stream tempo');
    }
    result.outputStream.changeValue(sum, startTime);
  } else {
    result = {
      outputStream: runtime.createStepStream(sum, startTime),
      deactivator: null,
    };
  }

  // If integrand and update inputs change at same time, it seems like it
  //  doesn't matter which we handle first, but we'll have integrand go
  //  first to keep things consistent.

  // task for when integrand changes
  var integrandChangedTask = function(atTime) {
    accumulate(atTime);
    // don't change output
  };

  // trigger for when integrand changes
  var integrandChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder+'0',
      closure: integrandChangedTask,
    });
  };

  // add trigger on integrand
  integrand.addTrigger(integrandChangedTrigger);

  // task for when update changes
  var updateChangedTask = function(atTime) {
    accumulate(atTime);
    result.outputStream.changeValue(sum, atTime);
  };

  // trigger for when update changes
  var updateChangedTrigger = function(atTime) {
    runtime.priorityQueue.insert({
      time: atTime,
      topoOrder: baseTopoOrder+'1',
      closure: updateChangedTask,
    });
  };

  // add trigger on update
  update.addTrigger(updateChangedTrigger);

  if (result.deactivator) { throw new Error('Deactivator should be null'); }
  result.deactivator = function() {
    update.removeTrigger(updateChangedTrigger);
    integrand.removeTrigger(integrandChangedTrigger);
  };

  return result;
}

module.exports = {
  id: {
    value: liftStep(function(a) { return a; }, 1),
    type: (function() {
      var a = typeUtils.createVariableType();
      return typeUtils.createFunctionType([{type: a}], a);
    })(),
  },
  Vec2: {
    value: liftStep(function(x, y) { return {x: x, y: y}; }, 2),
    // TODO: make yield type more specific when type system supports it
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER}, {type: typeUtils.NUMBER}], typeUtils.createVariableType()),
  },
  sin: {
    value: liftStep(function(x) { return Math.sin(x); }, 1),
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER}], typeUtils.NUMBER),
  },
  cos: {
    value: liftStep(function(x) { return Math.cos(x); }, 1),
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER}], typeUtils.NUMBER),
  },

  delay1: {
    value: delay1,
    type: (function() {
      var a = typeUtils.createVariableType();
      return typeUtils.createFunctionType([{type: a}], a);
    })(),
  },
  timeOfLatest: {
    value: timeOfLatest,
    // TODO: make parameter type more specific when type system supports it
    type: typeUtils.createFunctionType([{type: typeUtils.createVariableType()}], typeUtils.NUMBER),
  },
  integral: {
    value: integral,
    // TODO: make third parameter type more specific when type system supports it
    type: typeUtils.createFunctionType([{type: typeUtils.NUMBER, delayed: true}, {type: typeUtils.NUMBER}, {type: typeUtils.createVariableType()}], typeUtils.NUMBER),
  },
};
<|endoftext|>


<commit_before>describe('Modifications', () => {
  before(() => {
    cy.setupProject('scratch')
  })

  beforeEach(() => {
    cy.fixture('regions/scratch.json').as('region')
    cy.findByTitle(/Edit Modifications/).click({force: true})
    cy.location('pathname').should('match', /.*\/projects\/.{24}$/)
  })

  it('can be created, saved, and deleted', () => {
    // create an arbitrary modification type
    // these actions should be the same across all types
    // TODO the types that are commented out are producing errors locally
    let mods = [
      'Add Trip Pattern',
      //'Adjust Dwell Time',
      'Adjust Speed',
      //'Convert To Frequency',
      //'Remove Stops',
      'Remove Trips',
      'Reroute',
      'Custom'
    ]
    let modType = mods[Math.floor(Math.random() * mods.length)]
    let modName = 'tempMod ' + Date.now()
    cy.findByRole('link', {name: 'Create a modification'}).click()
    cy.findByLabelText(/Modification type/i).select(modType)
    cy.findByLabelText(/Modification name/i).type(modName)
    cy.findByRole('link', {name: 'Create'}).click()
    cy.location('pathname').should('match', /.*\/modifications\/.{24}$/)
    cy.contains(modName)
    cy.findByRole('link', {name: /Add description/}).click()
    cy.findByLabelText('Description').type('descriptive text')
    // go back and see if it saved
    cy.findByTitle(/Edit Modifications/).click({force: true})
    cy.location('pathname').should('match', /\/projects\/.{24}$/)
    // TODO needs to be conditional in case the list is collapsed
    cy.contains(modType).parent().contains(modName).click()
    cy.location('pathname').should('match', /.*\/modifications\/.{24}$/)
    cy.contains(modName)
    cy.findByLabelText('Description').contains('descriptive text')
    // delete it
    cy.get('a[name="Delete modification"]').click()
    cy.location('pathname').should('match', /.*\/projects\/.{24}$/)
    cy.contains('Create a modification')
    cy.findByText(modName).should('not.exist')
  })

  context('new trip patterns', () => {
    it('can be imported from shapefile, in theory', () => {
      cy.get('svg[data-icon="upload"]').click()
      cy.contains(/Route alignments from shapefile/)
      // TODO need better selectors
    })

    it('can be drawn on map', function () {
      let modName = Date.now() + ''
      cy.setupModification('scratch', 'Add Trip Pattern', modName)
      cy.findByText(/Edit route geometry/i)
        .click()
        .contains(/Stop editing/i)
      cy.get('div.leaflet-container').as('map')
      cy.window()
        .its('LeafletMap')
        .then((map) => {
          // zoom to route to be drawn
          map.fitBounds(this.region.newRoute)
          cy.wait(500) // TODO need to properly wait for map to stop moving
          // click at the coordinates
          this.region.newRoute.forEach((point) => {
            // TODO this does not project to pixels properly
            // but only when running within cypress
            let pix = map.latLngToContainerPoint(point)
            cy.get('@map').click(pix.x, pix.y)
          })
        })
      cy.findByText(/Stop editing/i)
        .click()
        .contains(/Edit route geometry/i)
      cy.get('a[name="Delete modification"]').click()
    })

    it('can create and reuse timetables', function () {
      let modName = 'timetable templates'
      cy.setupModification('scratch', 'Add Trip Pattern', modName)
      cy.findByText(/Add new timetable/).click()
      cy.findByText(/Timetable 1/).click()
      cy.get('input[name="Name"]').clear().type('Weekday')
      cy.findByLabelText(/Mon/).check()
      cy.findByLabelText(/Tue/).check()
      cy.findByLabelText(/Wed/).check()
      cy.findByLabelText(/Thu/).check()
      cy.findByLabelText(/Fri/).check()
      cy.findByLabelText(/Sat/).uncheck()
      cy.findByLabelText(/Sun/).uncheck()
      // TODO these selectors not working
      //cy.findByLabelText(/Frequency/).clear().type('00:20:00')
      //cy.findByLabelText(/Start time/).clear().type('06:00')
      //cy.findByLabelText(/End time/).clear().type('23:00')
      //cy.findByLabelText(/dwell time/).clear().type('00:30:00')
      // exit and create new mod to copy into
      cy.setupModification('scratch', 'Add Trip Pattern', 'temp')
      cy.findByText(/Copy existing timetable/).click()
      cy.findByRole('dialog').as('dialog')
      cy.get('@dialog')
        .findByLabelText(/Region/)
        .select('scratch')
      cy.get('@dialog')
        .findByLabelText(/Project/)
        .select('scratch project')
      cy.get('@dialog')
        .findByLabelText(/Modification/)
        .select(modName)
      cy.get('@dialog')
        .findByLabelText(/Timetable/)
        .select('Weekday')
      cy.findByText(/Copy into new timetable/i).click()
      cy.contains(/copy of Weekday/i).click()
      // verify the settings from above
      cy.findByLabelText(/Mon/).should('be.checked')
      cy.findByLabelText(/Tue/).should('be.checked')
      cy.findByLabelText(/Wed/).should('be.checked')
      cy.findByLabelText(/Thu/).should('be.checked')
      cy.findByLabelText(/Fri/).should('be.checked')
      cy.findByLabelText(/Sat/).should('not.be.checked')
      cy.findByLabelText(/Sun/).should('not.be.checked')
      // delete the temp modification
      cy.get('a[name="Delete modification"]').click()
      // delete the template modification
      cy.findByText(modName).click()
      cy.get('a[name="Delete modification"]').click()
    })
  })

  it('Can select a feed, route and pattern', () => {
    const modType = 'Adjust Speed'
    const modName = 'Mod Name'
    cy.findByRole('link', {name: 'Create a modification'}).click()
    cy.findByLabelText(/Modification type/i).select(modType)
    cy.findByLabelText(/Modification name/i).type(modName)
    cy.findByRole('link', {name: 'Create'}).click()

    cy.findByLabelText(/Select feed/)
      .click({force: true})
      .type('Northern Kentucky')
      .type('{enter}')

    cy.findByLabelText(/Select route/)
      .click({force: true})
      .type('Taylor Mill')
      .type('{enter}')
    cy.get('a[name="Delete modification"]').click()
  })
})
<commit_msg>start adjust speed mod<commit_after>describe('Modifications', () => {
  before(() => {
    cy.setupProject('scratch')
  })

  beforeEach(() => {
    cy.fixture('regions/scratch.json').as('region')
    cy.findByTitle(/Edit Modifications/).click({force: true})
    cy.location('pathname').should('match', /.*\/projects\/.{24}$/)
  })

  it('can be created, saved, and deleted', () => {
    // create an arbitrary modification type
    // these actions should be the same across all types
    // TODO the types that are commented out are producing errors locally
    let mods = [
      'Add Trip Pattern',
      //'Adjust Dwell Time',
      'Adjust Speed',
      //'Convert To Frequency',
      //'Remove Stops',
      'Remove Trips',
      'Reroute',
      'Custom'
    ]
    let modType = mods[Math.floor(Math.random() * mods.length)]
    let modName = 'tempMod ' + Date.now()
    cy.findByRole('link', {name: 'Create a modification'}).click()
    cy.findByLabelText(/Modification type/i).select(modType)
    cy.findByLabelText(/Modification name/i).type(modName)
    cy.findByRole('link', {name: 'Create'}).click()
    cy.location('pathname').should('match', /.*\/modifications\/.{24}$/)
    cy.contains(modName)
    cy.findByRole('link', {name: /Add description/}).click()
    cy.findByLabelText('Description').type('descriptive text')
    // go back and see if it saved
    cy.findByTitle(/Edit Modifications/).click({force: true})
    cy.location('pathname').should('match', /\/projects\/.{24}$/)
    // TODO needs to be conditional in case the list is collapsed
    cy.contains(modType).parent().contains(modName).click()
    cy.location('pathname').should('match', /.*\/modifications\/.{24}$/)
    cy.contains(modName)
    cy.findByLabelText('Description').contains('descriptive text')
    // delete it
    cy.get('a[name="Delete modification"]').click()
    cy.location('pathname').should('match', /.*\/projects\/.{24}$/)
    cy.contains('Create a modification')
    cy.findByText(modName).should('not.exist')
  })

  context('new trip patterns', () => {
    it('can be imported from shapefile, in theory', () => {
      cy.get('svg[data-icon="upload"]').click()
      cy.contains(/Route alignments from shapefile/)
      // TODO need better selectors
    })

    it('can be drawn on map', function () {
      let modName = Date.now() + ''
      cy.setupModification('scratch', 'Add Trip Pattern', modName)
      cy.findByText(/Edit route geometry/i)
        .click()
        .contains(/Stop editing/i)
      cy.get('div.leaflet-container').as('map')
      cy.window()
        .its('LeafletMap')
        .then((map) => {
          // zoom to route to be drawn
          map.fitBounds(this.region.newRoute)
          cy.wait(500) // TODO need to properly wait for map to stop moving
          // click at the coordinates
          this.region.newRoute.forEach((point) => {
            // TODO this does not project to pixels properly
            // but only when running within cypress
            let pix = map.latLngToContainerPoint(point)
            cy.get('@map').click(pix.x, pix.y)
          })
        })
      cy.findByText(/Stop editing/i)
        .click()
        .contains(/Edit route geometry/i)
      cy.get('a[name="Delete modification"]').click()
    })

    it('can create and reuse timetables', function () {
      let modName = 'timetable templates'
      cy.setupModification('scratch', 'Add Trip Pattern', modName)
      cy.findByText(/Add new timetable/).click()
      cy.findByText(/Timetable 1/).click()
      cy.get('input[name="Name"]').clear().type('Weekday')
      cy.findByLabelText(/Mon/).check()
      cy.findByLabelText(/Tue/).check()
      cy.findByLabelText(/Wed/).check()
      cy.findByLabelText(/Thu/).check()
      cy.findByLabelText(/Fri/).check()
      cy.findByLabelText(/Sat/).uncheck()
      cy.findByLabelText(/Sun/).uncheck()
      // TODO these selectors not working
      //cy.findByLabelText(/Frequency/).clear().type('00:20:00')
      //cy.findByLabelText(/Start time/).clear().type('06:00')
      //cy.findByLabelText(/End time/).clear().type('23:00')
      //cy.findByLabelText(/dwell time/).clear().type('00:30:00')
      // exit and create new mod to copy into
      cy.setupModification('scratch', 'Add Trip Pattern', 'temp')
      cy.findByText(/Copy existing timetable/).click()
      cy.findByRole('dialog').as('dialog')
      cy.get('@dialog')
        .findByLabelText(/Region/)
        .select('scratch')
      cy.get('@dialog')
        .findByLabelText(/Project/)
        .select('scratch project')
      cy.get('@dialog')
        .findByLabelText(/Modification/)
        .select(modName)
      cy.get('@dialog')
        .findByLabelText(/Timetable/)
        .select('Weekday')
      cy.findByText(/Copy into new timetable/i).click()
      cy.contains(/copy of Weekday/i).click()
      // verify the settings from above
      cy.findByLabelText(/Mon/).should('be.checked')
      cy.findByLabelText(/Tue/).should('be.checked')
      cy.findByLabelText(/Wed/).should('be.checked')
      cy.findByLabelText(/Thu/).should('be.checked')
      cy.findByLabelText(/Fri/).should('be.checked')
      cy.findByLabelText(/Sat/).should('not.be.checked')
      cy.findByLabelText(/Sun/).should('not.be.checked')
      // delete the temp modification
      cy.get('a[name="Delete modification"]').click()
      // delete the template modification
      cy.findByText(modName).click()
      cy.get('a[name="Delete modification"]').click()
    })
  })

  context('Adjust speed', () => {
    it.only('can select a feed & route', () => {
      let modName = Date.now() + ''
      cy.setupModification('scratch', 'Adjust Speed', modName)
      cy.findByLabelText(/Select feed/)
        .click({force: true})
        .type('Northern Kentucky{enter}')
      cy.findByLabelText(/Select route/)
        .click({force: true})
        .type('Taylor Mill{enter}')
      cy.findByLabelText(/Select patterns/i)
      // TODO select a pattern

      cy.get('a[name="Delete modification"]').click()
    })
  })
})
<|endoftext|>


<commit_before>const frisby = require('frisby')

const URL = 'http://localhost:3000'

describe('/ftp', () => {
  it('GET serves a directory listing', () => {
    return frisby.get(URL + '/ftp')
      .expect('status', 200)
      .expect('header', 'content-type', /text\/html/)
      .expect('bodyContains', '<title>listing directory /ftp</title>')
  })

  it('GET a non-existing Markdown file in /ftp will return a 404 error', () => {
    return frisby.get(URL + '/ftp/doesnotexist.md')
      .expect('status', 404)
  })

  it('GET a non-existing PDF file in /ftp will return a 404 error', () => {
    return frisby.get(URL + '/ftp/doesnotexist.pdf')
      .expect('status', 404)
  })

  it('GET a non-existing file in /ftp will return a 403 error for invalid file type', () => {
    return frisby.get(URL + '/ftp/doesnotexist.exe')
      .expect('status', 403)
  })

  it('GET an existing file in /ftp will return a 403 error for invalid file type .gg', () => {
    return frisby.get(URL + '/ftp/eastere.gg')
      .expect('status', 403)
  })

  it('GET existing file /ftp/coupons_2013.md.bak will return a 403 error for invalid file type .bak', () => {
    return frisby.get(URL + '/ftp/coupons_2013.md.bak')
      .expect('status', 403)
  })

  it('GET existing file /ftp/package.json.bak will return a 403 error for invalid file type .bak', () => {
    return frisby.get(URL + '/ftp/package.json.bak')
      .expect('status', 403)
  })

  it('GET existing file /ftp/suspicious_errors.yml will return a 403 error for invalid file type .yml', () => {
    return frisby.get(URL + '/ftp/suspicious_errors.yml')
      .expect('status', 403)
  })

  it('GET the confidential file in /ftp', () => {
    return frisby.get(URL + '/ftp/acquisitions.md')
      .expect('status', 200)
      .expect('bodyContains', '# Planned Acquisitions')
  })

  it('GET the KeePass database in /ftp', () => {
    return frisby.get(URL + '/ftp/incident-support.kdbx')
      .expect('status', 200)
  })

  it('GET the easter egg file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/eastere.gg%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', 'Congratulations, you found the easter egg!')
  })

  it('GET the easter egg file by using Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/eastere.gg%00.md')
      .expect('status', 200)
      .expect('bodyContains', 'Congratulations, you found the easter egg!')
  })
  it('GET the SIEM signature file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/suspicious_errors.yml%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', 'Suspicious error messages specific to the application')
  })

  it('GET the SIEM signature file by using Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/suspicious_errors.yml%00.md')
      .expect('status', 200)
      .expect('bodyContains', 'Suspicious error messages specific to the application')
  })

  it('GET the 2013 coupon code file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/coupons_2013.md.bak%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', 'n<MibgC7sn')
  })

  it('GET the 2013 coupon code file by using an Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/coupons_2013.md.bak%00.md')
      .expect('status', 200)
      .expect('bodyContains', 'n<MibgC7sn')
  })

  it('GET the package.json file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/package.json.bak%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', '"name": "juice-shop",')
  })

  it('GET the package.json file by using Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/package.json.bak%00.md')
      .expect('status', 200)
      .expect('bodyContains', '"name": "juice-shop",')
  })

  it('GET a restricted file directly from file system path on server by tricking route definitions fails with 403 error', () => {
    return frisby.get(URL + '/ftp///eastere.gg')
      .expect('status', 403)
  })

  it('GET a restricted file directly from file system path on server by appending URL parameter fails with 403 error', () => {
    return frisby.get(URL + '/ftp/eastere.gg?.md')
      .expect('status', 403)
  })

  it('GET a file whose name contains a "/" fails with a 403 error', () => {
    frisby.fetch(URL + '/ftp/%2fetc%2fos-release%2500.md', {}, { urlEncode: false })
      .expect('status', 403)
      .expect('bodyContains', 'Error: File names cannot contain forward slashes!')
  })

  it('GET an accessible file directly from file system path on server', () => {
    return frisby.get(URL + '/ftp/legal.md')
      .expect('status', 200)
      .expect('bodyContains', '# Legal Information')
  })

  it('GET a non-existing file via direct server file path /ftp will return a 404 error', () => {
    return frisby.get(URL + '/ftp/doesnotexist.md')
      .expect('status', 404)
  })
})
<commit_msg>Verify dependency for "Typosquatting Tier 1" is leaked<commit_after>const frisby = require('frisby')

const URL = 'http://localhost:3000'

describe('/ftp', () => {
  it('GET serves a directory listing', () => {
    return frisby.get(URL + '/ftp')
      .expect('status', 200)
      .expect('header', 'content-type', /text\/html/)
      .expect('bodyContains', '<title>listing directory /ftp</title>')
  })

  it('GET a non-existing Markdown file in /ftp will return a 404 error', () => {
    return frisby.get(URL + '/ftp/doesnotexist.md')
      .expect('status', 404)
  })

  it('GET a non-existing PDF file in /ftp will return a 404 error', () => {
    return frisby.get(URL + '/ftp/doesnotexist.pdf')
      .expect('status', 404)
  })

  it('GET a non-existing file in /ftp will return a 403 error for invalid file type', () => {
    return frisby.get(URL + '/ftp/doesnotexist.exe')
      .expect('status', 403)
  })

  it('GET an existing file in /ftp will return a 403 error for invalid file type .gg', () => {
    return frisby.get(URL + '/ftp/eastere.gg')
      .expect('status', 403)
  })

  it('GET existing file /ftp/coupons_2013.md.bak will return a 403 error for invalid file type .bak', () => {
    return frisby.get(URL + '/ftp/coupons_2013.md.bak')
      .expect('status', 403)
  })

  it('GET existing file /ftp/package.json.bak will return a 403 error for invalid file type .bak', () => {
    return frisby.get(URL + '/ftp/package.json.bak')
      .expect('status', 403)
  })

  it('GET existing file /ftp/suspicious_errors.yml will return a 403 error for invalid file type .yml', () => {
    return frisby.get(URL + '/ftp/suspicious_errors.yml')
      .expect('status', 403)
  })

  it('GET the confidential file in /ftp', () => {
    return frisby.get(URL + '/ftp/acquisitions.md')
      .expect('status', 200)
      .expect('bodyContains', '# Planned Acquisitions')
  })

  it('GET the KeePass database in /ftp', () => {
    return frisby.get(URL + '/ftp/incident-support.kdbx')
      .expect('status', 200)
  })

  it('GET the easter egg file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/eastere.gg%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', 'Congratulations, you found the easter egg!')
  })

  it('GET the easter egg file by using Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/eastere.gg%00.md')
      .expect('status', 200)
      .expect('bodyContains', 'Congratulations, you found the easter egg!')
  })
  it('GET the SIEM signature file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/suspicious_errors.yml%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', 'Suspicious error messages specific to the application')
  })

  it('GET the SIEM signature file by using Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/suspicious_errors.yml%00.md')
      .expect('status', 200)
      .expect('bodyContains', 'Suspicious error messages specific to the application')
  })

  it('GET the 2013 coupon code file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/coupons_2013.md.bak%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', 'n<MibgC7sn')
  })

  it('GET the 2013 coupon code file by using an Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/coupons_2013.md.bak%00.md')
      .expect('status', 200)
      .expect('bodyContains', 'n<MibgC7sn')
  })

  it('GET the package.json.bak file by using Poison Null Byte attack with .pdf suffix', () => {
    return frisby.get(URL + '/ftp/package.json.bak%00.pdf')
      .expect('status', 200)
      .expect('bodyContains', '"name": "juice-shop",')
  })

  it('GET the package.json.bak file by using Poison Null Byte attack with .md suffix', () => {
    return frisby.get(URL + '/ftp/package.json.bak%00.md')
      .expect('status', 200)
      .expect('bodyContains', '"name": "juice-shop",')
  })

  it('GET a restricted file directly from file system path on server by tricking route definitions fails with 403 error', () => {
    return frisby.get(URL + '/ftp///eastere.gg')
      .expect('status', 403)
  })

  it('GET a restricted file directly from file system path on server by appending URL parameter fails with 403 error', () => {
    return frisby.get(URL + '/ftp/eastere.gg?.md')
      .expect('status', 403)
  })

  it('GET a file whose name contains a "/" fails with a 403 error', () => {
    frisby.fetch(URL + '/ftp/%2fetc%2fos-release%2500.md', {}, { urlEncode: false })
      .expect('status', 403)
      .expect('bodyContains', 'Error: File names cannot contain forward slashes!')
  })

  it('GET an accessible file directly from file system path on server', () => {
    return frisby.get(URL + '/ftp/legal.md')
      .expect('status', 200)
      .expect('bodyContains', '# Legal Information')
  })

  it('GET a non-existing file via direct server file path /ftp will return a 404 error', () => {
    return frisby.get(URL + '/ftp/doesnotexist.md')
      .expect('status', 404)
  })

  it('GET the package.json.bak file contains a dependency on epilogue-js for "Typosquatting Tier 1" challenge', () => {
    return frisby.get(URL + '/ftp/package.json.bak%00.md')
      .expect('status', 200)
      .expect('bodyContains', '"epilogue-js": "~0.7",')
  })
})
<|endoftext|>


<commit_before>/*
 * ------------------------------------------
 * 列表项控件基类实现文件
 * @version  1.0
 * @author   genify(caijf@corp.netease.com)
 * ------------------------------------------
 */
var f = function(){
    var _  = NEJ.P,
        _o = NEJ.O,
        _f = NEJ.F,
        _p = _('nej.ui'),
        _pro;
    if (!!_p._$$Item) return;
    /**
     * 列表项控件基类

     * 页面结构举例
     * [code type="html"]
     *

     * [/code]
     * 脚本举例
     * [code]
     *   var _  = NEJ.P,
     *   _p = _('nej.ut'),
     *   _e = _('nej.e');
     *   // 第一步：新建一个类，继承自此基类
     *   var _html_key = _e._$addNodeTemplate('
123
');
     *   _p._$$MyItem = NEJ.C();
     *   _proMyItem = _p._$$MyItem._$extend(_u._$$Item);

     *   _proMyItem.__reset = function(_options){
     *       this.__data = _options.data;
     *       this.__supReset(_options);
     *   }
     *
     *   _proMyItem.__doRefresh = function(){
     *       // 刷新一项，设置数据{name:'sean'}
     *       this.__body.innerText = this.__data.name;
     *   };
     *
     *   _proMyItem.__initXGui = function(){
     *       this.__seed_html = _e._$getNodeTemplate(_html_key);
     *   };
     *
     *   // 第二步：生成item列表
     *   // 可以自己循环list，生成item
     *   var _item = _p._$$MyItem._$allocate({
     *       parent:'item-box',
     *       data:list[i]
     *   });
     *   // 可以利用_e._$getItemTemplate接口，返回item列表
     *   _e._$getItemTemplate(
     *       [{name:'jack'},{name:'sean'}],
     *       _p._$$MyItem,
     *       {parent:'item-box'}
     *   );
     * [/code]
     * @class   {nej.ui._$$Item} 列表项控件基类
     * @extends {nej.ui._$$Abstract}
     * @param   {Object} 可选配置参数，已处理参数列表如下
     * @config  {Object} data 当前项绑定的数据
     * @config  {Number} index 当前项的索引
     * @config  {Number} total 总列表长度
     * @config  {Array}  range 当前项所在的列表片段方位(begin,end)
     */
    _p._$$Item = NEJ.C();
    _pro = _p._$$Item._$extend(_p._$$Abstract);
    /**
     * 控件初始化
     * @protected
     * @method {__init}
     * @return {Void}
     */
    _pro.__init = function(){
        this.__id = this.__genId();
        this.__supInit();
    };
    /**
     * 控件重置
     * @protected
     * @method {__reset}
     * @param  {Object} 可选配置参数
     * @return {Void}
     */
    _pro.__reset = function(_options){
        this.__supReset(_options);
        this.__index = _options.index;
        this.__total = _options.total;
        this.__range = _options.range;
        this._$refresh(_options.data);
    };
    /**
     * 控件销毁
     * @protected
     * @method {__destroy}
     * @return {Void}
     */
    _pro.__destroy = function(){
        this.__supDestroy();
        delete this.__data;
        delete this.__index;
        delete this.__total;
        delete this.__range;
    };
    /**
     * 刷新项,子类实现具体逻辑
     * @protected
     * @method {__doRefresh}
     * @return {Void}
     */
    _pro.__doRefresh = _f;
    /**
     * 生成ID
     * @return {String} ID
     */
    _pro.__genId = (function(){
        var _seed = +new Date;
        return function(){
            return 'itm-'+(++_seed);
        };
    })();
    /**
     * 取项标识

     * 脚本举例
     * [code]
     *  // 获取当前item的id标识
     *   _item._$getId();
     * [/code]
     * @method {_$getId}
     * @return {String} 项标识
     */
    _pro._$getId = function(){
        return this.__id;
    };
    /**
     * 取项绑定数据

     *
     * 脚本举例：
     * [code]
     *   // 获取当前item的数据信息
     *   _item._$getData();
     * [/code]
     * @method {_$getData}
     * @return {Object} 数据信息
     */
    _pro._$getData = function(){
        return this.__data;
    };
    /**
     * 刷新项绑定的数据

     *
     * 脚本举例：
     * [code]
     *   // 获取当前item的数据信息
     *   _item._$refresh({
     *       a:'aaaaa',
     *       b:'bbbbb'
     *   });
     * [/code]
     *
     * @method {_$refresh}
     * @param  {Object} 项绑定的数据
     * @return {Void}
     */
    _pro._$refresh = function(_data){
        this.__data  = _data||{};
        this.__doRefresh(this.__data);
    };
};
NEJ.define(
    '{lib}ui/item/item.js',[
    '{lib}ui/base.js'
],f);<commit_msg>comment<commit_after>/*
 * ------------------------------------------
 * 列表项控件基类实现文件
 * @version  1.0
 * @author   genify(caijf@corp.netease.com)
 * ------------------------------------------
 */
var f = function(){
    var _  = NEJ.P,
        _o = NEJ.O,
        _f = NEJ.F,
        _p = _('nej.ui'),
        _pro;
    if (!!_p._$$Item) return;
    /**
     * 列表项控件基类

     * 页面结构举例
     * [code type="html"]
     *

     * [/code]
     * 脚本举例
     * [code]
     *   var _  = NEJ.P,
     *   _p = _('nej.ut'),
     *   _e = _('nej.e');
     *   // 第一步：新建一个类，继承自此基类
     *   var _html_key = _e._$addNodeTemplate('
123
');
     *   _p._$$MyItem = NEJ.C();
     *   _proMyItem = _p._$$MyItem._$extend(_u._$$Item);

     *   _proMyItem.__reset = function(_options){
     *       this.__data = _options.data;
     *       this.__supReset(_options);
     *   }
     *
     *   _proMyItem.__doRefresh = function(){
     *       // 刷新一项，设置数据{name:'sean'}
     *       this.__body.innerText = this.__data.name;
     *   };
     *
     *   _proMyItem.__initXGui = function(){
     *       this.__seed_html = _html_key;
     *   };
     *
     *   // 第二步：生成item列表
     *   // 可以自己循环list，生成item
     *   var _item = _p._$$MyItem._$allocate({
     *       parent:'item-box',
     *       data:list[i]
     *   });
     *   // 可以利用_e._$getItemTemplate接口，返回item列表
     *   _e._$getItemTemplate(
     *       [{name:'jack'},{name:'sean'}],
     *       _p._$$MyItem,
     *       {parent:'item-box'}
     *   );
     * [/code]
     * @class   {nej.ui._$$Item} 列表项控件基类
     * @extends {nej.ui._$$Abstract}
     * @param   {Object} 可选配置参数，已处理参数列表如下
     * @config  {Object} data 当前项绑定的数据
     * @config  {Number} index 当前项的索引
     * @config  {Number} total 总列表长度
     * @config  {Array}  range 当前项所在的列表片段方位(begin,end)
     */
    _p._$$Item = NEJ.C();
    _pro = _p._$$Item._$extend(_p._$$Abstract);
    /**
     * 控件初始化
     * @protected
     * @method {__init}
     * @return {Void}
     */
    _pro.__init = function(){
        this.__id = this.__genId();
        this.__supInit();
    };
    /**
     * 控件重置
     * @protected
     * @method {__reset}
     * @param  {Object} 可选配置参数
     * @return {Void}
     */
    _pro.__reset = function(_options){
        this.__supReset(_options);
        this.__index = _options.index;
        this.__total = _options.total;
        this.__range = _options.range;
        this._$refresh(_options.data);
    };
    /**
     * 控件销毁
     * @protected
     * @method {__destroy}
     * @return {Void}
     */
    _pro.__destroy = function(){
        this.__supDestroy();
        delete this.__data;
        delete this.__index;
        delete this.__total;
        delete this.__range;
    };
    /**
     * 刷新项,子类实现具体逻辑
     * @protected
     * @method {__doRefresh}
     * @return {Void}
     */
    _pro.__doRefresh = _f;
    /**
     * 生成ID
     * @return {String} ID
     */
    _pro.__genId = (function(){
        var _seed = +new Date;
        return function(){
            return 'itm-'+(++_seed);
        };
    })();
    /**
     * 取项标识

     * 脚本举例
     * [code]
     *  // 获取当前item的id标识
     *   _item._$getId();
     * [/code]
     * @method {_$getId}
     * @return {String} 项标识
     */
    _pro._$getId = function(){
        return this.__id;
    };
    /**
     * 取项绑定数据

     *
     * 脚本举例：
     * [code]
     *   // 获取当前item的数据信息
     *   _item._$getData();
     * [/code]
     * @method {_$getData}
     * @return {Object} 数据信息
     */
    _pro._$getData = function(){
        return this.__data;
    };
    /**
     * 刷新项绑定的数据

     *
     * 脚本举例：
     * [code]
     *   // 获取当前item的数据信息
     *   _item._$refresh({
     *       a:'aaaaa',
     *       b:'bbbbb'
     *   });
     * [/code]
     *
     * @method {_$refresh}
     * @param  {Object} 项绑定的数据
     * @return {Void}
     */
    _pro._$refresh = function(_data){
        this.__data  = _data||{};
        this.__doRefresh(this.__data);
    };
};
NEJ.define(
    '{lib}ui/item/item.js',[
    '{lib}ui/base.js'
],f);<|endoftext|>


<commit_before>makeInstaller = function (options) {
  "use strict";

  options = options || {};

  // These file extensions will be appended to required module identifiers
  // if they do not exactly match an installed module.
  var defaultExtensions = options.extensions || [".js", ".json"];

  // If defined, the options.onInstall function will be called any time
  // new modules are installed.
  var onInstall = options.onInstall;

  // If defined, each module-specific require function will be passed to
  // this function, along with the module.id of the parent module, and
  // the result will be used in place of the original require function.
  var wrapRequire = options.wrapRequire;

  // If defined, the options.override function will be called before
  // looking up any top-level package identifiers in node_modules
  // directories. It can either return a string to provide an alternate
  // package identifier, or a non-string value to prevent the lookup from
  // proceeding.
  var override = options.override;

  // If defined, the options.fallback function will be called when no
  // installed module is found for a required module identifier. Often
  // options.fallback will be implemented in terms of the native Node
  // require function, which has the ability to load binary modules.
  var fallback = options.fallback;

  // List of fields to look for in package.json files to determine the
  // main entry module of the package. The first field listed here whose
  // value is a string will be used to resolve the entry module.
  var mainFields = options.mainFields ||
    // If options.mainFields is absent and options.browser is truthy,
    // package resolution will prefer the "browser" field of package.json
    // files to the "main" field. Note that this only supports
    // string-valued "browser" fields for now, though in the future it
    // might make sense to support the object version, a la browserify.
    (options.browser ? ["browser", "main"] : ["main"]);

  // Called below as hasOwn.call(obj, key).
  var hasOwn = {}.hasOwnProperty;

  // The file object representing the root directory of the installed
  // module tree.
  var root = new File("/", new File("/.."));
  var rootRequire = makeRequire(root);

  // Merges the given tree of directories and module factory functions
  // into the tree of installed modules and returns a require function
  // that behaves as if called from a module in the root directory.
  function install(tree, options) {
    if (isObject(tree)) {
      fileMergeContents(root, tree, options);
      if (isFunction(onInstall)) {
        onInstall(rootRequire);
      }
    }
    return rootRequire;
  }

  // This constructor will be used to instantiate the module objects
  // passed to module factory functions (i.e. the third argument after
  // require and exports), and is exposed as install.Module in case the
  // caller of makeInstaller wishes to modify Module.prototype.
  function Module(id) {
    this.id = id;

    // The Node implementation of module.children unfortunately includes
    // only those child modules that were imported for the first time by
    // this parent module (i.e., child.parent === this).
    this.children = [];

    // This object is an install.js extension that includes all child
    // modules imported by this module, even if this module is not the
    // first to import them.
    this.childrenById = {};
  }

  Module.prototype.resolve = function (id) {
    return this.require.resolve(id);
  };

  install.Module = Module;

  function getOwn(obj, key) {
    return hasOwn.call(obj, key) && obj[key];
  }

  function isObject(value) {
    return typeof value === "object" && value !== null;
  }

  function isFunction(value) {
    return typeof value === "function";
  }

  function isString(value) {
    return typeof value === "string";
  }

  function makeRequire(file) {
    function require(id) {
      var result = fileResolve(file, id);
      if (result) {
        return fileEvaluate(result, file.module);
      }

      var error = new Error("Cannot find module '" + id + "'");

      if (isFunction(fallback)) {
        return fallback(
          id, // The missing module identifier.
          file.module.id, // The path of the requiring file.
          error // The error we would have thrown.
        );
      }

      throw error;
    }

    if (isFunction(wrapRequire)) {
      require = wrapRequire(require, file.module.id);
    }

    require.extensions = fileGetExtensions(file).slice(0);

    require.resolve = function (id) {
      var f = fileResolve(file, id);
      if (f) return f.module.id;
      var error = new Error("Cannot find module '" + id + "'");
      if (fallback && isFunction(fallback.resolve)) {
        return fallback.resolve(id, file.module.id, error);
      }
      throw error;
    };

    return require;
  }

  // File objects represent either directories or modules that have been
  // installed. When a `File` respresents a directory, its `.contents`
  // property is an object containing the names of the files (or
  // directories) that it contains. When a `File` represents a module, its
  // `.contents` property is a function that can be invoked with the
  // appropriate `(require, exports, module)` arguments to evaluate the
  // module. If the `.contents` property is a string, that string will be
  // resolved as a module identifier, and the exports of the resulting
  // module will provide the exports of the original file. The `.parent`
  // property of a File is either a directory `File` or `null`. Note that
  // a child may claim another `File` as its parent even if the parent
  // does not have an entry for that child in its `.contents` object.
  // This is important for implementing anonymous files, and preventing
  // child modules from using `../relative/identifier` syntax to examine
  // unrelated modules.
  function File(name, parent) {
    var file = this;

    // Link to the parent file.
    file.parent = parent = parent || null;

    // The module object for this File, which will eventually boast an
    // .exports property when/if the file is evaluated.
    file.module = new Module(name);

    // The .contents of the file can be either (1) an object, if the file
    // represents a directory containing other files; (2) a factory
    // function, if the file represents a module that can be imported; or
    // (3) a string, if the file is an alias for another file.
    file.contents = null;

    // Set of module identifiers imported by this module. Note that this
    // set is not necessarily complete, so don't rely on it unless you
    // know what you're doing.
    file.deps = {};
  }

  function fileEvaluate(file, parentModule) {
    var contents = file && file.contents;

    if (! contents && file.stub) {
      // If this file was installed with array notation, and the array
      // contained one or more objects but no functions, then the combined
      // properties of the objects are treated as a temporary stub for
      // file.module.exports. This is particularly important for partial
      // package.json modules, so that the resolution logic can know the
      // value of the "main" and/or "browser" fields, at least, even if
      // the rest of the package.json file is not (yet) available.
      return file.stub;
    }

    var module = file.module;

    if (! hasOwn.call(module, "exports")) {
      if (parentModule) {
        module.parent = parentModule;
        var children = parentModule.children;
        if (Array.isArray(children)) {
          children.push(module);
        }
      }

      // If a Module.prototype.useNode method is defined, give it a chance
      // to define module.exports based on module.id using Node.
      if (! isFunction(module.useNode) ||
          ! module.useNode()) {
        contents(
          module.require = module.require || makeRequire(file),
          // If the file had a .stub, reuse the same object for exports.
          module.exports = file.stub || {},
          module,
          file.module.id,
          file.parent.module.id
        );
      }

      module.loaded = true;
    }

    if (isFunction(module.runModuleSetters)) {
      module.runModuleSetters();
    }

    return module.exports;
  }

  function fileIsDirectory(file) {
    return file && isObject(file.contents);
  }

  function fileMergeContents(file, contents, options) {
    if (Array.isArray(contents)) {
      contents.forEach(function (item) {
        if (isString(item)) {
          file.deps[item] = file.module.id;
        } else if (isFunction(item)) {
          contents = item;
        } else if (isObject(item)) {
          file.stub = file.stub || {};
          each(item, function (value, key) {
            file.stub[key] = value;
          });
        }
      });

      if (! isFunction(contents)) {
        // If the array did not contain a function, merge nothing.
        contents = null;
      }

    } else if (! isFunction(contents) &&
               ! isString(contents) &&
               ! isObject(contents)) {
      // If contents is neither an array nor a function nor a string nor
      // an object, just give up and merge nothing.
      contents = null;
    }

    if (contents) {
      file.contents = file.contents || (isObject(contents) ? {} : contents);
      if (isObject(contents) && fileIsDirectory(file)) {
        each(contents, function (value, key) {
          if (key === "..") {
            child = file.parent;

          } else {
            var child = getOwn(file.contents, key);
            if (! child) {
              child = file.contents[key] = new File(
                file.module.id.replace(/\/*$/, "/") + key,
                file
              );

              child.options = options;
            }
          }

          fileMergeContents(child, value, options);
        });
      }
    }
  }

  function each(obj, callback, context) {
    Object.keys(obj).forEach(function (key) {
      callback.call(this, obj[key], key);
    }, context);
  }

  function fileGetExtensions(file) {
    return file.options
      && file.options.extensions
      || defaultExtensions;
  }

  function fileAppendIdPart(file, part, extensions) {
    // Always append relative to a directory.
    while (file && ! fileIsDirectory(file)) {
      file = file.parent;
    }

    if (! file || ! part || part === ".") {
      return file;
    }

    if (part === "..") {
      return file.parent;
    }

    var exactChild = getOwn(file.contents, part);

    // Only consider multiple file extensions if this part is the last
    // part of a module identifier and not equal to `.` or `..`, and there
    // was no exact match or the exact match was a directory.
    if (extensions && (! exactChild || fileIsDirectory(exactChild))) {
      for (var e = 0; e < extensions.length; ++e) {
        var child = getOwn(file.contents, part + extensions[e]);
        if (child && ! fileIsDirectory(child)) {
          return child;
        }
      }
    }

    return exactChild;
  }

  function fileAppendId(file, id, extensions) {
    var parts = id.split("/");

    // Use `Array.prototype.every` to terminate iteration early if
    // `fileAppendIdPart` returns a falsy value.
    parts.every(function (part, i) {
      return file = i < parts.length - 1
        ? fileAppendIdPart(file, part)
        : fileAppendIdPart(file, part, extensions);
    });

    return file;
  }

  function recordChild(parentModule, childFile) {
    var childModule = childFile && childFile.module;
    if (parentModule && childModule) {
      parentModule.childrenById[childModule.id] = childModule;
    }
  }

  function fileResolve(file, id, parentModule, seenDirFiles) {
    var parentModule = parentModule || file.module;
    var extensions = fileGetExtensions(file);

    file =
      // Absolute module identifiers (i.e. those that begin with a `/`
      // character) are interpreted relative to the root directory, which
      // is a slight deviation from Node, which has access to the entire
      // file system.
      id.charAt(0) === "/" ? fileAppendId(root, id, extensions) :
      // Relative module identifiers are interpreted relative to the
      // current file, naturally.
      id.charAt(0) === "." ? fileAppendId(file, id, extensions) :
      // Top-level module identifiers are interpreted as referring to
      // packages in `node_modules` directories.
      nodeModulesLookup(file, id, extensions);

    // If the identifier resolves to a directory, we use the same logic as
    // Node to find an `index.js` or `package.json` file to evaluate.
    while (fileIsDirectory(file)) {
      seenDirFiles = seenDirFiles || [];

      // If the "main" field of a `package.json` file resolves to a
      // directory we've already considered, then we should not attempt to
      // read the same `package.json` file again. Using an array as a set
      // is acceptable here because the number of directories to consider
      // is rarely greater than 1 or 2. Also, using indexOf allows us to
      // store File objects instead of strings.
      if (seenDirFiles.indexOf(file) < 0) {
        seenDirFiles.push(file);

        var pkgJsonFile = fileAppendIdPart(file, "package.json"), main;
        var pkg = pkgJsonFile && fileEvaluate(pkgJsonFile, parentModule);
        if (pkg &&
            mainFields.some(function (name) {
              return isString(main = pkg[name]);
            })) {
          recordChild(parentModule, pkgJsonFile);

          // The "main" field of package.json does not have to begin with
          // ./ to be considered relative, so first we try simply
          // appending it to the directory path before falling back to a
          // full fileResolve, which might return a package from a
          // node_modules directory.
          file = fileAppendId(file, main, extensions) ||
            fileResolve(file, main, parentModule, seenDirFiles);

          if (file) {
            // The fileAppendId call above may have returned a directory,
            // so continue the loop to make sure we resolve it to a
            // non-directory file.
            continue;
          }
        }
      }

      // If we didn't find a `package.json` file, or it didn't have a
      // resolvable `.main` property, the only possibility left to
      // consider is that this directory contains an `index.js` module.
      // This assignment almost always terminates the while loop, because
      // there's very little chance `fileIsDirectory(file)` will be true
      // for the result of `fileAppendIdPart(file, "index.js")`. However,
      // in principle it is remotely possible that a file called
      // `index.js` could be a directory instead of a file.
      file = fileAppendIdPart(file, "index.js");
    }

    if (file && isString(file.contents)) {
      file = fileResolve(file, file.contents, parentModule, seenDirFiles);
    }

    recordChild(parentModule, file);

    return file;
  };

  function nodeModulesLookup(file, id, extensions) {
    if (isFunction(override)) {
      id = override(id, file.module.id);
    }

    if (isString(id)) {
      for (var resolved; file && ! resolved; file = file.parent) {
        resolved = fileIsDirectory(file) &&
          fileAppendId(file, "node_modules/" + id, extensions);
      }

      return resolved;
    }
  }

  return install;
};

if (typeof exports === "object") {
  exports.makeInstaller = makeInstaller;
}
<commit_msg>Decompose a makeMissingError helper function.<commit_after>makeInstaller = function (options) {
  "use strict";

  options = options || {};

  // These file extensions will be appended to required module identifiers
  // if they do not exactly match an installed module.
  var defaultExtensions = options.extensions || [".js", ".json"];

  // If defined, the options.onInstall function will be called any time
  // new modules are installed.
  var onInstall = options.onInstall;

  // If defined, each module-specific require function will be passed to
  // this function, along with the module.id of the parent module, and
  // the result will be used in place of the original require function.
  var wrapRequire = options.wrapRequire;

  // If defined, the options.override function will be called before
  // looking up any top-level package identifiers in node_modules
  // directories. It can either return a string to provide an alternate
  // package identifier, or a non-string value to prevent the lookup from
  // proceeding.
  var override = options.override;

  // If defined, the options.fallback function will be called when no
  // installed module is found for a required module identifier. Often
  // options.fallback will be implemented in terms of the native Node
  // require function, which has the ability to load binary modules.
  var fallback = options.fallback;

  // List of fields to look for in package.json files to determine the
  // main entry module of the package. The first field listed here whose
  // value is a string will be used to resolve the entry module.
  var mainFields = options.mainFields ||
    // If options.mainFields is absent and options.browser is truthy,
    // package resolution will prefer the "browser" field of package.json
    // files to the "main" field. Note that this only supports
    // string-valued "browser" fields for now, though in the future it
    // might make sense to support the object version, a la browserify.
    (options.browser ? ["browser", "main"] : ["main"]);

  // Called below as hasOwn.call(obj, key).
  var hasOwn = {}.hasOwnProperty;

  // The file object representing the root directory of the installed
  // module tree.
  var root = new File("/", new File("/.."));
  var rootRequire = makeRequire(root);

  // Merges the given tree of directories and module factory functions
  // into the tree of installed modules and returns a require function
  // that behaves as if called from a module in the root directory.
  function install(tree, options) {
    if (isObject(tree)) {
      fileMergeContents(root, tree, options);
      if (isFunction(onInstall)) {
        onInstall(rootRequire);
      }
    }
    return rootRequire;
  }

  // This constructor will be used to instantiate the module objects
  // passed to module factory functions (i.e. the third argument after
  // require and exports), and is exposed as install.Module in case the
  // caller of makeInstaller wishes to modify Module.prototype.
  function Module(id) {
    this.id = id;

    // The Node implementation of module.children unfortunately includes
    // only those child modules that were imported for the first time by
    // this parent module (i.e., child.parent === this).
    this.children = [];

    // This object is an install.js extension that includes all child
    // modules imported by this module, even if this module is not the
    // first to import them.
    this.childrenById = {};
  }

  Module.prototype.resolve = function (id) {
    return this.require.resolve(id);
  };

  install.Module = Module;

  function getOwn(obj, key) {
    return hasOwn.call(obj, key) && obj[key];
  }

  function isObject(value) {
    return typeof value === "object" && value !== null;
  }

  function isFunction(value) {
    return typeof value === "function";
  }

  function isString(value) {
    return typeof value === "string";
  }

  function makeMissingError(id) {
    return new Error("Cannot find module '" + id + "'");
  }

  function makeRequire(file) {
    function require(id) {
      var result = fileResolve(file, id);
      if (result) {
        return fileEvaluate(result, file.module);
      }

      var error = makeMissingError(id);

      if (isFunction(fallback)) {
        return fallback(
          id, // The missing module identifier.
          file.module.id, // The path of the requiring file.
          error // The error we would have thrown.
        );
      }

      throw error;
    }

    if (isFunction(wrapRequire)) {
      require = wrapRequire(require, file.module.id);
    }

    require.extensions = fileGetExtensions(file).slice(0);

    require.resolve = function (id) {
      var f = fileResolve(file, id);
      if (f) return f.module.id;
      var error = makeMissingError(id);
      if (fallback && isFunction(fallback.resolve)) {
        return fallback.resolve(id, file.module.id, error);
      }
      throw error;
    };

    return require;
  }

  // File objects represent either directories or modules that have been
  // installed. When a `File` respresents a directory, its `.contents`
  // property is an object containing the names of the files (or
  // directories) that it contains. When a `File` represents a module, its
  // `.contents` property is a function that can be invoked with the
  // appropriate `(require, exports, module)` arguments to evaluate the
  // module. If the `.contents` property is a string, that string will be
  // resolved as a module identifier, and the exports of the resulting
  // module will provide the exports of the original file. The `.parent`
  // property of a File is either a directory `File` or `null`. Note that
  // a child may claim another `File` as its parent even if the parent
  // does not have an entry for that child in its `.contents` object.
  // This is important for implementing anonymous files, and preventing
  // child modules from using `../relative/identifier` syntax to examine
  // unrelated modules.
  function File(name, parent) {
    var file = this;

    // Link to the parent file.
    file.parent = parent = parent || null;

    // The module object for this File, which will eventually boast an
    // .exports property when/if the file is evaluated.
    file.module = new Module(name);

    // The .contents of the file can be either (1) an object, if the file
    // represents a directory containing other files; (2) a factory
    // function, if the file represents a module that can be imported; or
    // (3) a string, if the file is an alias for another file.
    file.contents = null;

    // Set of module identifiers imported by this module. Note that this
    // set is not necessarily complete, so don't rely on it unless you
    // know what you're doing.
    file.deps = {};
  }

  function fileEvaluate(file, parentModule) {
    var contents = file && file.contents;

    if (! contents && file.stub) {
      // If this file was installed with array notation, and the array
      // contained one or more objects but no functions, then the combined
      // properties of the objects are treated as a temporary stub for
      // file.module.exports. This is particularly important for partial
      // package.json modules, so that the resolution logic can know the
      // value of the "main" and/or "browser" fields, at least, even if
      // the rest of the package.json file is not (yet) available.
      return file.stub;
    }

    var module = file.module;

    if (! hasOwn.call(module, "exports")) {
      if (parentModule) {
        module.parent = parentModule;
        var children = parentModule.children;
        if (Array.isArray(children)) {
          children.push(module);
        }
      }

      // If a Module.prototype.useNode method is defined, give it a chance
      // to define module.exports based on module.id using Node.
      if (! isFunction(module.useNode) ||
          ! module.useNode()) {
        contents(
          module.require = module.require || makeRequire(file),
          // If the file had a .stub, reuse the same object for exports.
          module.exports = file.stub || {},
          module,
          file.module.id,
          file.parent.module.id
        );
      }

      module.loaded = true;
    }

    if (isFunction(module.runModuleSetters)) {
      module.runModuleSetters();
    }

    return module.exports;
  }

  function fileIsDirectory(file) {
    return file && isObject(file.contents);
  }

  function fileMergeContents(file, contents, options) {
    if (Array.isArray(contents)) {
      contents.forEach(function (item) {
        if (isString(item)) {
          file.deps[item] = file.module.id;
        } else if (isFunction(item)) {
          contents = item;
        } else if (isObject(item)) {
          file.stub = file.stub || {};
          each(item, function (value, key) {
            file.stub[key] = value;
          });
        }
      });

      if (! isFunction(contents)) {
        // If the array did not contain a function, merge nothing.
        contents = null;
      }

    } else if (! isFunction(contents) &&
               ! isString(contents) &&
               ! isObject(contents)) {
      // If contents is neither an array nor a function nor a string nor
      // an object, just give up and merge nothing.
      contents = null;
    }

    if (contents) {
      file.contents = file.contents || (isObject(contents) ? {} : contents);
      if (isObject(contents) && fileIsDirectory(file)) {
        each(contents, function (value, key) {
          if (key === "..") {
            child = file.parent;

          } else {
            var child = getOwn(file.contents, key);
            if (! child) {
              child = file.contents[key] = new File(
                file.module.id.replace(/\/*$/, "/") + key,
                file
              );

              child.options = options;
            }
          }

          fileMergeContents(child, value, options);
        });
      }
    }
  }

  function each(obj, callback, context) {
    Object.keys(obj).forEach(function (key) {
      callback.call(this, obj[key], key);
    }, context);
  }

  function fileGetExtensions(file) {
    return file.options
      && file.options.extensions
      || defaultExtensions;
  }

  function fileAppendIdPart(file, part, extensions) {
    // Always append relative to a directory.
    while (file && ! fileIsDirectory(file)) {
      file = file.parent;
    }

    if (! file || ! part || part === ".") {
      return file;
    }

    if (part === "..") {
      return file.parent;
    }

    var exactChild = getOwn(file.contents, part);

    // Only consider multiple file extensions if this part is the last
    // part of a module identifier and not equal to `.` or `..`, and there
    // was no exact match or the exact match was a directory.
    if (extensions && (! exactChild || fileIsDirectory(exactChild))) {
      for (var e = 0; e < extensions.length; ++e) {
        var child = getOwn(file.contents, part + extensions[e]);
        if (child && ! fileIsDirectory(child)) {
          return child;
        }
      }
    }

    return exactChild;
  }

  function fileAppendId(file, id, extensions) {
    var parts = id.split("/");

    // Use `Array.prototype.every` to terminate iteration early if
    // `fileAppendIdPart` returns a falsy value.
    parts.every(function (part, i) {
      return file = i < parts.length - 1
        ? fileAppendIdPart(file, part)
        : fileAppendIdPart(file, part, extensions);
    });

    return file;
  }

  function recordChild(parentModule, childFile) {
    var childModule = childFile && childFile.module;
    if (parentModule && childModule) {
      parentModule.childrenById[childModule.id] = childModule;
    }
  }

  function fileResolve(file, id, parentModule, seenDirFiles) {
    var parentModule = parentModule || file.module;
    var extensions = fileGetExtensions(file);

    file =
      // Absolute module identifiers (i.e. those that begin with a `/`
      // character) are interpreted relative to the root directory, which
      // is a slight deviation from Node, which has access to the entire
      // file system.
      id.charAt(0) === "/" ? fileAppendId(root, id, extensions) :
      // Relative module identifiers are interpreted relative to the
      // current file, naturally.
      id.charAt(0) === "." ? fileAppendId(file, id, extensions) :
      // Top-level module identifiers are interpreted as referring to
      // packages in `node_modules` directories.
      nodeModulesLookup(file, id, extensions);

    // If the identifier resolves to a directory, we use the same logic as
    // Node to find an `index.js` or `package.json` file to evaluate.
    while (fileIsDirectory(file)) {
      seenDirFiles = seenDirFiles || [];

      // If the "main" field of a `package.json` file resolves to a
      // directory we've already considered, then we should not attempt to
      // read the same `package.json` file again. Using an array as a set
      // is acceptable here because the number of directories to consider
      // is rarely greater than 1 or 2. Also, using indexOf allows us to
      // store File objects instead of strings.
      if (seenDirFiles.indexOf(file) < 0) {
        seenDirFiles.push(file);

        var pkgJsonFile = fileAppendIdPart(file, "package.json"), main;
        var pkg = pkgJsonFile && fileEvaluate(pkgJsonFile, parentModule);
        if (pkg &&
            mainFields.some(function (name) {
              return isString(main = pkg[name]);
            })) {
          recordChild(parentModule, pkgJsonFile);

          // The "main" field of package.json does not have to begin with
          // ./ to be considered relative, so first we try simply
          // appending it to the directory path before falling back to a
          // full fileResolve, which might return a package from a
          // node_modules directory.
          file = fileAppendId(file, main, extensions) ||
            fileResolve(file, main, parentModule, seenDirFiles);

          if (file) {
            // The fileAppendId call above may have returned a directory,
            // so continue the loop to make sure we resolve it to a
            // non-directory file.
            continue;
          }
        }
      }

      // If we didn't find a `package.json` file, or it didn't have a
      // resolvable `.main` property, the only possibility left to
      // consider is that this directory contains an `index.js` module.
      // This assignment almost always terminates the while loop, because
      // there's very little chance `fileIsDirectory(file)` will be true
      // for the result of `fileAppendIdPart(file, "index.js")`. However,
      // in principle it is remotely possible that a file called
      // `index.js` could be a directory instead of a file.
      file = fileAppendIdPart(file, "index.js");
    }

    if (file && isString(file.contents)) {
      file = fileResolve(file, file.contents, parentModule, seenDirFiles);
    }

    recordChild(parentModule, file);

    return file;
  };

  function nodeModulesLookup(file, id, extensions) {
    if (isFunction(override)) {
      id = override(id, file.module.id);
    }

    if (isString(id)) {
      for (var resolved; file && ! resolved; file = file.parent) {
        resolved = fileIsDirectory(file) &&
          fileAppendId(file, "node_modules/" + id, extensions);
      }

      return resolved;
    }
  }

  return install;
};

if (typeof exports === "object") {
  exports.makeInstaller = makeInstaller;
}
<|endoftext|>


<commit_before>var muoncore = require('../../muon/api/muoncore.js');
var assert = require('assert');

var muon;
var muon2;

describe("Muon core test", function () {

    this.timeout(7000);

    var transportUrl = "amqp://muon:microservices@localhost";
    var discoveryUrl = transportUrl;
    var config = {};

    before(function () {
        muon = muoncore.create("ExampleService1", config, discoveryUrl, transportUrl);
        muon.handle('muon://ExampleService1/shop', function (event, respond) {
            logger.info('*****   muoncore-test.js ************************************************************************');
            logger.debug('muon://ExampleService1/shop server responding to event.id' + event.headers.id);
            event.payload.message = "pong";
            respond(event);
        });
    });

    after(function() {
       muon.shutdown();
       muon2.shutdown();
    });

    it("create request protocol stack", function (done) {

        var event = {
            headers: {
                eventType: "RequestMade",
                id: "ABCDEFGH",
                targetService: "ExampleService1",
                sourceService: "ExampleService2",
                protocol: "request",
                url: "muon://ExampleService1/shop",
                "Content-Type": "application/json",
                sourceAvailableContentTypes: ["application/json"],
                channelOperation: "NORMAL"
            },
            payload: {
                message: "ping"
            }
        };
        muon2 = muoncore.create("ExampleService2", config, discoveryUrl, transportUrl);

        setTimeout(function () {

            var promise = muon2.request('muon://ExampleService2/shop', event);

            promise.then(function (event) {
                logger.info("muon://ExampleService2/customer server response received! event.id=" + event.id);
                logger.info("muon promise.then() asserting response...");
                assert(event, "request event is undefined");
                assert.equal(event.payload.message, "pong", "expected 'pong' response message from muon://ExampleService2/shop")
                done();
            }, function (err) {
                logger.error("muon promise.then() error!!!!!");
                throw new Error('error in promise');
            });

        }, 1000);

    });
});

<commit_msg>updated end to end test endpoints<commit_after>var muoncore = require('../../muon/api/muoncore.js');
var assert = require('assert');

var muon;
var muon2;

describe("Muon core test", function () {

    this.timeout(7000);

    var transportUrl = "amqp://muon:microservices@localhost";
    var discoveryUrl = transportUrl;
    var config = {};

    before(function () {
        muon = muoncore.create("example-service", config, discoveryUrl, transportUrl);
        muon.handle('muon://example-service/tennis', function (event, respond) {
            logger.info('*****   muoncore-test.js *************************************************');
            logger.debug('muon://service/tennis server responding to event.id' + event.headers.id);
            event.payload.message = "pong";
            respond(event);
        });
    });

    after(function() {
       muon.shutdown();
       muon2.shutdown();
    });

    it("create request protocol stack", function (done) {

        var event = {
            headers: {
                eventType: "RequestMade",
                id: "ABCDEFGH",
                targetService: "example-service",
                sourceService: "example-client",
                protocol: "request",
                url: "muon://example-service/tennis",
                "Content-Type": "application/json",
                sourceAvailableContentTypes: ["application/json"],
                channelOperation: "NORMAL"
            },
            payload: {
                message: "ping"
            }
        };
        muon2 = muoncore.create("example-service", config, discoveryUrl, transportUrl);

        setTimeout(function () {

            var promise = muon2.request('muon://example-service/tennis', event);

            promise.then(function (event) {
                logger.info("muon://example-client server response received! event.id=" + event.id);
                logger.info("muon promise.then() asserting response...");
                assert(event, "request event is undefined");
                assert.equal(event.payload.message, "pong", "expected 'pong' response message from muon://example-service/tennis")
                done();
            }, function (err) {
                logger.error("muon promise.then() error!!!!!");
                throw new Error('error in promise');
            });

        }, 1000);

    });
});

<|endoftext|>


<commit_before>var fs=require('fs'), exec=require('child_process').exec;

fs.readFile(__dirname+'/templates/ood-init.sh', prepareTemplate);

function prepareTemplate(err, tmpl) {
  if (err) {
    console.error('Could not load service template');
    return;
  }
  tmpl=tmpl.toString()
    .replace(/%NODE%/g, process.execPath)
    .replace(/%OOD%/g, __dirname+'/service');
  fs.writeFile('/etc/init.d/ood', tmpl, {mode:0755}, function(err) {
    if (err) {
      console.error('Could not write /etc/init.d/ood');
      return;
    }
    installService();
  });

}

function installService() {
  exec('update-rc.d ood defaults', function(err) {
    if (err) {
      console.error('Could not install service');
      return;
    }
    startService();
  });
}

function startService() {
  exec('/etc/init.d/ood start', function(err, stdout, stderr) {
    if (err || stderr) {
      console.error('Could not start service\n'+stderr);
      return;
    }
    console.log('Installation complete, service running.');
  });
}
<commit_msg>improved install script<commit_after>var fs=require('fs'), mkdirp=require('mkdirp'), exec=require('child_process').exec,
  destination='/etc/init.d/ood', template='ood-init.sh';

fs.readFile(__dirname+'/templates/'+template, prepareTemplate);

function prepareTemplate(err, tmpl) {
  if (err) {
    console.error('Could not load service template');
    return;
  }
  tmpl=tmpl.toString()
    .replace(/%NODE%/g, process.execPath)
    .replace(/%OOD%/g, __dirname+'/service');
  fs.writeFile(destination, tmpl, {mode:0755}, function(err) {
    if (err) {
      console.error('Could not write '+destination);
      return;
    }
    installService();
  });

}

function installService() {
  exec('update-rc.d ood defaults', function(err) {
    if (err) {
      console.error('Could not install service');
      return;
    }
    createEtcOod();
  });
}

function createEtcOod() {
  mkdirp('/etc/ood', {mode:0750}, function(err) {
    if (err) {
      console.error('Could not create /etc/ood');
      return;
    }
    startService();
  });
}

function startService() {
  exec('/etc/init.d/ood start', function(err, stdout, stderr) {
    if (err || stderr) {
      console.error('Could not start service\n'+stderr);
      return;
    }
    console.log('Installation complete, service running.');
  });
}
<|endoftext|>