<commit_before>import {averageColors} from "./colorHelpers";

const getLatLongs = (nodes, tipVisibility, metadata, map, colorBy, geoResolution, colorScale) => {

  const aggregatedLocations = {}; /* demes */
  const aggregatedTransmissions = {}; /* edges, animation paths */
  const demesToColors = {};
  const transmissionsToColors = {};

  const nestedTransmissions = [];
  const demesAndTransmissions = {
    demes: [],
    transmissions: []
  };
  const geo = metadata.geo;

  /*
    walk through nodes and collect a bunch of arrays...
    can count how many times observe a tip and make an array of an attribute,
    which in this case will be color,
    could be an array of hexes which would be enough,
    similar operation for each transmissino -
    for each deme pair observe how many and record a hex value from the from deme and
    count them for width and average to get color
  */

  /*
    aggregate locations for demes
  */
  nodes.forEach((n, i) => {
    if (!n.children && tipVisibility[i] === "visible") {
      // look up geo1 geo2 geo3 do lat longs differ
      if (aggregatedLocations[n.attr[geoResolution]]) {
        aggregatedLocations[n.attr[geoResolution]].push(colorScale(n.attr[colorBy]));
      } else {
        // if we haven't added this pair, add it
        aggregatedLocations[n.attr[geoResolution]] = [colorScale(n.attr[colorBy])];
      }
    }
    if (n.children) {
      // if (parent.attr.country !== "china") { return; } // remove me, example filter
      n.children.forEach((child) => {
        if (n.attr[geoResolution] === child.attr[geoResolution]) { return; }

        // look up in transmissions dictionary
        if (aggregatedTransmissions[n.attr[geoResolution] + "/" + child.attr[geoResolution]]) {
          aggregatedTransmissions[n.attr[geoResolution] + "/" + child.attr[geoResolution]].push(colorScale(n.attr[colorBy]));
        } else {
          // we don't have it, add it
          aggregatedTransmissions[n.attr[geoResolution] + "/" + child.attr[geoResolution]] = [colorScale(n.attr[colorBy])];
        }
      });
    }
  });

  /*
    create a latlong pair for each country's location and push them all to a common array
  */
  _.forOwn(aggregatedLocations, (value, key) => {
    demesAndTransmissions.demes.push({
      location: key, // Thailand:
      total: value.length, // 20
      color: averageColors(value),
      coords: map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) we MAY have to do this every time rather than just once */
        new L.LatLng(
          metadata.geo[geoResolution][key].latitude,
          metadata.geo[geoResolution][key].longitude
        )
      )
    });
  });

  /*
    count transmissions for line thickness
  */

  // for each item in the object produced above...
  _.forOwn(aggregatedTransmissions, (value, key) => {

    // go from "brazil/cuba" to ["brazil", "cuba"]
    const countries = key.split("/");
    // go from "brazil" to lat0 = -14.2350
    let long0 = geo[geoResolution][countries[0]].longitude;
    let long1 = geo[geoResolution][countries[1]].longitude;
    let lat0 = geo[geoResolution][countries[0]].latitude;
    let lat1 = geo[geoResolution][countries[1]].latitude;

    // create new leaflet LatLong objects
    const start = new L.LatLng(lat0, long0)
    const end = new L.LatLng(lat1, long1)
    const dlambda = Math.abs((long1-long0)%360)*Math.PI/180.0;
    const angle = Math.acos(Math.sin(lat1*Math.PI/180.0)*Math.sin(lat0*Math.PI/180.0)
                            + Math.cos(lat1*Math.PI/180.0)*Math.cos(lat0*Math.PI/180.0)*Math.cos(dlambda));
    // this sets the number of segments of the path, min 4, max 36 for half way around the globe
    const nSteps = Math.ceil(Math.max(4,angle*36/Math.PI));

    /*
      add a polyline to the map for current country pair iteratee
      store the computation. access _latlngs to show where each segment is on the map
    */
    const rawGeodesic = L.geodesic([[start,end]], {
      // stroke:	value,
      // radius: value,
      // color: colorScale(countries[0]), /* this will go up above in d3 rather than in leaflet now */
      // opacity: .5,
      steps: nSteps,
      // weight:	value	/* Stroke width in pixels.*/
      // opacity:	0.5	Stroke opacity.
      // fill:
      // fillColor: randomColor
      // fillOpacity:
    })

    const geodesics = [];

    rawGeodesic._latlngs.forEach((arr) => {
      geodesics.push(arr.map((pair) => {
        return map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) We may have to do this every time */
          new L.LatLng(
            pair.lat,
            pair.lng
          )
        );
      }));
    })

    nestedTransmissions.push({
      start,
      end,
      total: value.length,
      color: averageColors(value),
      rawGeodesic,
      geodesics, /* incomplete for dev, will need to grab BOTH lines when there is wraparound */
      from: countries[0],
      to: countries[1]
    })
  });

  /* flatter data structure */
  nestedTransmissions.forEach((transmission, i) => { /* for each transmission */
    transmission.geodesics.forEach((geodesic, j) => { /* and for each part of a lines split across dateline in each */
      demesAndTransmissions.transmissions.push({ /* and add it to an array, which we'll map over to create our paths. */ /* not optimized for missiles here. we could check index of for each and if it's greater than one add a flag for partials, and their order? so that we can animate around the map */
        data: transmission,
        coords: geodesic,
        wraparoundKey: j,
      });
    });
  });
  return demesAndTransmissions;
}

export default getLatLongs;
<commit_msg>transmissions listen for 'hidden' state in children<commit_after>import {averageColors} from "./colorHelpers";

const getLatLongs = (nodes, tipVisibility, metadata, map, colorBy, geoResolution, colorScale) => {

  const aggregatedLocations = {}; /* demes */
  const aggregatedTransmissions = {}; /* edges, animation paths */
  const demesToColors = {};
  const transmissionsToColors = {};

  const nestedTransmissions = [];
  const demesAndTransmissions = {
    demes: [],
    transmissions: []
  };
  const geo = metadata.geo;

  /*
    walk through nodes and collect a bunch of arrays...
    can count how many times observe a tip and make an array of an attribute,
    which in this case will be color,
    could be an array of hexes which would be enough,
    similar operation for each transmissino -
    for each deme pair observe how many and record a hex value from the from deme and
    count them for width and average to get color
  */

  /*
    aggregate locations for demes
  */
  nodes.forEach((n, i) => {
    if (!n.children && tipVisibility[i] === "visible") {
      // look up geo1 geo2 geo3 do lat longs differ
      if (aggregatedLocations[n.attr[geoResolution]]) {
        aggregatedLocations[n.attr[geoResolution]].push(colorScale(n.attr[colorBy]));
      } else {
        // if we haven't added this pair, add it
        aggregatedLocations[n.attr[geoResolution]] = [colorScale(n.attr[colorBy])];
      }
    }
    if (n.children) {
      n.children.forEach((child) => {

        if (n.attr[geoResolution] === child.attr[geoResolution] || child["tip-visible"] === false) { return; }
        // look up in transmissions dictionary
        if (aggregatedTransmissions[n.attr[geoResolution] + "/" + child.attr[geoResolution]]) {
          aggregatedTransmissions[n.attr[geoResolution] + "/" + child.attr[geoResolution]].push(colorScale(n.attr[colorBy]));
        } else {
          // we don't have it, add it
          aggregatedTransmissions[n.attr[geoResolution] + "/" + child.attr[geoResolution]] = [colorScale(n.attr[colorBy])];
        }
      });
    }
  });

  /*
    create a latlong pair for each country's location and push them all to a common array
  */
  _.forOwn(aggregatedLocations, (value, key) => {
    demesAndTransmissions.demes.push({
      location: key, // Thailand:
      total: value.length, // 20
      color: averageColors(value),
      coords: map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) we MAY have to do this every time rather than just once */
        new L.LatLng(
          metadata.geo[geoResolution][key].latitude,
          metadata.geo[geoResolution][key].longitude
        )
      )
    });
  });

  /*
    count transmissions for line thickness
  */

  // for each item in the object produced above...
  _.forOwn(aggregatedTransmissions, (value, key) => {

    // go from "brazil/cuba" to ["brazil", "cuba"]
    const countries = key.split("/");
    // go from "brazil" to lat0 = -14.2350
    let long0 = geo[geoResolution][countries[0]].longitude;
    let long1 = geo[geoResolution][countries[1]].longitude;
    let lat0 = geo[geoResolution][countries[0]].latitude;
    let lat1 = geo[geoResolution][countries[1]].latitude;

    // create new leaflet LatLong objects
    const start = new L.LatLng(lat0, long0)
    const end = new L.LatLng(lat1, long1)
    const dlambda = Math.abs((long1-long0)%360)*Math.PI/180.0;
    const angle = Math.acos(Math.sin(lat1*Math.PI/180.0)*Math.sin(lat0*Math.PI/180.0)
                            + Math.cos(lat1*Math.PI/180.0)*Math.cos(lat0*Math.PI/180.0)*Math.cos(dlambda));
    // this sets the number of segments of the path, min 4, max 36 for half way around the globe
    const nSteps = Math.ceil(Math.max(4,angle*36/Math.PI));

    /*
      add a polyline to the map for current country pair iteratee
      store the computation. access _latlngs to show where each segment is on the map
    */
    const rawGeodesic = L.geodesic([[start,end]], {
      // stroke:	value,
      // radius: value,
      // color: colorScale(countries[0]), /* this will go up above in d3 rather than in leaflet now */
      // opacity: .5,
      steps: nSteps,
      // weight:	value	/* Stroke width in pixels.*/
      // opacity:	0.5	Stroke opacity.
      // fill:
      // fillColor: randomColor
      // fillOpacity:
    })

    const geodesics = [];

    rawGeodesic._latlngs.forEach((arr) => {
      geodesics.push(arr.map((pair) => {
        return map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) We may have to do this every time */
          new L.LatLng(
            pair.lat,
            pair.lng
          )
        );
      }));
    })

    nestedTransmissions.push({
      start,
      end,
      total: value.length,
      color: averageColors(value),
      rawGeodesic,
      geodesics, /* incomplete for dev, will need to grab BOTH lines when there is wraparound */
      from: countries[0],
      to: countries[1]
    })
  });

  /* flatter data structure */
  nestedTransmissions.forEach((transmission, i) => { /* for each transmission */
    transmission.geodesics.forEach((geodesic, j) => { /* and for each part of a lines split across dateline in each */
      demesAndTransmissions.transmissions.push({ /* and add it to an array, which we'll map over to create our paths. */ /* not optimized for missiles here. we could check index of for each and if it's greater than one add a flag for partials, and their order? so that we can animate around the map */
        data: transmission,
        coords: geodesic,
        wraparoundKey: j,
      });
    });
  });
  return demesAndTransmissions;
}

export default getLatLongs;
<|endoftext|>


<commit_before>import {averageColors} from "./colorHelpers";
import {getTipColorAttribute} from "./treeHelpers";

const aggregated = (nodes, visibility, geoResolution, colorScale, sequences) => {
  const aggregatedLocations = {}; /* demes */
  const aggregatedTransmissions = {}; /* edges, animation paths */
  /*
    walk through nodes and collect a bunch of arrays...
    can count how many times observe a tip and make an array of an attribute,
    which in this case will be color,
    could be an array of hexes which would be enough,
    similar operation for each transmissino -
    for each deme pair observe how many and record a hex value from the from deme and
    count them for width and average to get color
  */

  /*
    aggregate locations for demes
  */
  nodes.forEach((n, i) => {
    /* demes only count terminal nodes */
    const tipColorAttribute = getTipColorAttribute(n, colorScale, sequences);
    if (!n.children && visibility[i] === "visible") {
      // look up geo1 geo2 geo3 do lat longs differ
      if (aggregatedLocations[n.attr[geoResolution]]) {
        aggregatedLocations[n.attr[geoResolution]].push(colorScale.scale(tipColorAttribute));
      } else {
        // if we haven't added this pair, add it
        aggregatedLocations[n.attr[geoResolution]] = [colorScale.scale(tipColorAttribute)];
      }
    }
    /* transmissions count internal node transitions as well
    they are from the parent of the node to the node itself
    */
    if (n.children) {
      n.children.forEach((child) => {
        /* only draw transmissions if
        (1) the node & child aren't the same location and
        (2) if child is visibile
        */
        if (n.attr[geoResolution] !== child.attr[geoResolution] &&
          visibility[child.arrayIdx] === "visible") {
          const transmission = n.attr[geoResolution] + "/" + child.attr[geoResolution];
          if (aggregatedTransmissions[transmission]) {
            aggregatedTransmissions[transmission].push(colorScale.scale(tipColorAttribute));
          } else {
            aggregatedTransmissions[transmission] = [colorScale.scale(tipColorAttribute)];
          }
        }
      });
    }
  });
  return {
    aggregatedLocations,
    aggregatedTransmissions
  }
}

export const getLatLongs = (nodes, visibility, metadata, map, colorBy, geoResolution, colorScale, sequences, include) => {

  const {aggregatedLocations, aggregatedTransmissions} = aggregated(nodes, visibility, geoResolution, colorScale, sequences);

  const demesAndTransmissions = {
    demes: [],
    transmissions: []
  };
  const geo = metadata.geo;

  /*
    create a latlong pair for each country's location and push them all to a common array
  */
  _.forOwn(aggregatedLocations, (value, key) => {
    demesAndTransmissions.demes.push({
      location: key, // Thailand:
      total: value.length, // 20
      color: averageColors(value),
      coords: map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) we MAY have to do this every time rather than just once */
        new L.LatLng(
          metadata.geo[geoResolution][key].latitude,
          metadata.geo[geoResolution][key].longitude
        )
      )
    });
  });

  /*
    count transmissions for line thickness
  */

  // for each item in the object produced above...
  _.forOwn(aggregatedTransmissions, (value, key) => {

    const countries = key.split("/");
    const originToDestinationXYs = [
      map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) We may have to do this every time */
        new L.LatLng(
          geo[geoResolution][countries[0]].latitude,
          geo[geoResolution][countries[0]].longitude
        )
      ),
      map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) We may have to do this every time */
        new L.LatLng(
          geo[geoResolution][countries[1]].latitude,
          geo[geoResolution][countries[1]].longitude
        )
      )
    ];

    const transmission = {
      originToDestinationXYs,
      total: value.length, /* changes over time */
      color: averageColors(value), /* changes over time */
    }

    demesAndTransmissions.transmissions.push({data: transmission})
  });

  return demesAndTransmissions;
}

/* we used to return this in transmission */
// create new leaflet LatLong objects
// const start = new L.LatLng(lat0, long0)
// const end = new L.LatLng(lat1, long1)
// start, /* changes with zoom level */
// end, /* changes with zoom level */
// from: countries[0],
// to: countries[1]

/* we used to compute this... likely with geodesic from leaflet */
// const dlambda = Math.abs((long1-long0)%360)*Math.PI/180.0;
// const angle = Math.acos(Math.sin(lat1*Math.PI/180.0)*Math.sin(lat0*Math.PI/180.0)
//                         + Math.cos(lat1*Math.PI/180.0)*Math.cos(lat0*Math.PI/180.0)*Math.cos(dlambda));
// // this sets the number of segments of the path, min 4, max 36 for half way around the globe
// const nSteps = Math.ceil(Math.max(4,angle*36/Math.PI));
<commit_msg>comments<commit_after>import {averageColors} from "./colorHelpers";
import {getTipColorAttribute} from "./treeHelpers";

const aggregated = (nodes, visibility, geoResolution, colorScale, sequences) => {
  const aggregatedLocations = {}; /* demes */
  const aggregatedTransmissions = {}; /* edges, animation paths */
  /*
    walk through nodes and collect a bunch of arrays...
    can count how many times observe a tip and make an array of an attribute,
    which in this case will be color,
    could be an array of hexes which would be enough,
    similar operation for each transmissino -
    for each deme pair observe how many and record a hex value from the from deme and
    count them for width and average to get color
  */

  /*
    aggregate locations for demes
  */
  nodes.forEach((n, i) => {
    /* demes only count terminal nodes */
    const tipColorAttribute = getTipColorAttribute(n, colorScale, sequences);
    if (!n.children && visibility[i] === "visible") {
      // look up geo1 geo2 geo3 do lat longs differ
      if (aggregatedLocations[n.attr[geoResolution]]) {
        aggregatedLocations[n.attr[geoResolution]].push(colorScale.scale(tipColorAttribute));
      } else {
        // if we haven't added this pair, add it
        aggregatedLocations[n.attr[geoResolution]] = [colorScale.scale(tipColorAttribute)];
      }
    }
    /* transmissions count internal node transitions as well
    they are from the parent of the node to the node itself
    */
    if (n.children) {
      n.children.forEach((child) => {
        /* only draw transmissions if
        (1) the node & child aren't the same location and
        (2) if child is visibile
        */
        if (n.attr[geoResolution] !== child.attr[geoResolution] &&
          visibility[child.arrayIdx] === "visible") {
          const transmission = n.attr[geoResolution] + "/" + child.attr[geoResolution];
          if (aggregatedTransmissions[transmission]) {
            aggregatedTransmissions[transmission].push(colorScale.scale(tipColorAttribute));
          } else {
            aggregatedTransmissions[transmission] = [colorScale.scale(tipColorAttribute)];
          }
        }
      });
    }
  });
  return {
    aggregatedLocations,
    aggregatedTransmissions
  }
}

export const getLatLongs = (nodes, visibility, metadata, map, colorBy, geoResolution, colorScale, sequences, include) => {

  const {aggregatedLocations, aggregatedTransmissions} = aggregated(nodes, visibility, geoResolution, colorScale, sequences);
  const geo = metadata.geo;
  const demesAndTransmissions = {
    demes: [],
    transmissions: []
  };

  /* count DEMES */
  _.forOwn(aggregatedLocations, (value, key) => {
    demesAndTransmissions.demes.push({
      location: key, // Thailand:
      total: value.length, // 20, this is an array of all demes of a certain type
      color: averageColors(value),
      coords: map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) we MAY have to do this every time rather than just once */
        new L.LatLng(
          metadata.geo[geoResolution][key].latitude,
          metadata.geo[geoResolution][key].longitude
        )
      )
    });
  });

  /* count TRANSMISSIONS for line thickness */
  _.forOwn(aggregatedTransmissions, (value, key) => {

    const countries = key.split("/");
    const originToDestinationXYs = [
      map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) We may have to do this every time */
        new L.LatLng(
          geo[geoResolution][countries[0]].latitude,
          geo[geoResolution][countries[0]].longitude
        )
      ),
      map.latLngToLayerPoint( /* interchange. this is a leaflet method that will tell d3 where to draw. -Note (A) We may have to do this every time */
        new L.LatLng(
          geo[geoResolution][countries[1]].latitude,
          geo[geoResolution][countries[1]].longitude
        )
      )
    ];

    const transmission = {
      originToDestinationXYs,
      total: value.length, /* changes over time */
      color: averageColors(value), /* changes over time */
    }

    demesAndTransmissions.transmissions.push({data: transmission})
  });

  return demesAndTransmissions;
}

/* we used to return this in transmission */
// create new leaflet LatLong objects
// const start = new L.LatLng(lat0, long0)
// const end = new L.LatLng(lat1, long1)
// start, /* changes with zoom level */
// end, /* changes with zoom level */
// from: countries[0],
// to: countries[1]

/* we used to compute this... likely with geodesic from leaflet */
// const dlambda = Math.abs((long1-long0)%360)*Math.PI/180.0;
// const angle = Math.acos(Math.sin(lat1*Math.PI/180.0)*Math.sin(lat0*Math.PI/180.0)
//                         + Math.cos(lat1*Math.PI/180.0)*Math.cos(lat0*Math.PI/180.0)*Math.cos(dlambda));
// // this sets the number of segments of the path, min 4, max 36 for half way around the globe
// const nSteps = Math.ceil(Math.max(4,angle*36/Math.PI));
<|endoftext|>


<commit_before>/**
 * Extracts a styles object with only props that contain function values.
 */
export default (styles: Object): Object | null => {
  // eslint-disable-next-line no-shadow
  function extract(styles: Object): Object {
    let to = null

    for (const key in styles) {
      const value = styles[key]
      const type = typeof value

      if (type === 'function') {
        if (!to) to = {}
        to[key] = value
      } else if (type === 'object' && value !== null && !Array.isArray(value)) {
        const extracted = extract(value)
        if (extracted) {
          if (!to) to = {}
          to[key] = extracted
        }
      }
    }

    return to
  }

  return extract(styles)
}
<commit_msg>simplify getDynamicStyles<commit_after>/**
 * Extracts a styles object with only props that contain function values.
 */
export default function getDynamicStyles(styles: Object): Object | null {
  let to = null

  for (const key in styles) {
    const value = styles[key]
    const type = typeof value

    if (type === 'function') {
      if (!to) to = {}
      to[key] = value
    } else if (type === 'object' && value !== null && !Array.isArray(value)) {
      const extracted = getDynamicStyles(value)
      if (extracted) {
        if (!to) to = {}
        to[key] = extracted
      }
    }
  }

  return to
}
<|endoftext|>


<commit_before>/**
 * SchedulingQueue base class
 * http://wavesjs.github.io/audio/#audio-scheduling-queue
 *
 * Norbert.Schnell@ircam.fr
 * Copyright 2014, 2015 IRCAM – Centre Pompidou
 */

import PriorityQueue from '../utils/priority-queue';
import TimeEngine from '../core/time-engine';
import defaultAudioContext from '../core/audio-context';

/**
 * @class SchedulingQueue
 */
export default class SchedulingQueue extends TimeEngine {
  constructor() {
    super();

    this.__queue = new PriorityQueue();
    this.__engines = new Set();
  }

  // TimeEngine 'scheduled' interface
  advanceTime(time) {
    var nextTime = this.__queue.time;

    while (nextTime <= time) {
      var engine = this.__queue.head;
      var nextEngineTime = engine.advanceTime(time);

      if (!nextEngineTime) {
        engine.master = null;
        this.__engines.delete(engine);
        nextTime = this.__queue.remove(engine);
      } else if (nextEngineTime > time && nextEngineTime <= Infinity) {
        nextTime = this.__queue.move(engine, nextEngineTime);
      } else {
        throw new Error('engine did not advance time');
      }
    }

    return nextTime;
  }

  // TimeEngine master method to be implemented by derived class
  get currentTime() {
    return 0;
  }

  // call a function at a given time
  defer(fun, time = this.currentTime) {
    if (!(fun instanceof Function))
      throw new Error("object cannot be defered by scheduler");

    this.add({
      advanceTime: function(time) { fun(time); }, // make sur that the advanceTime method does not returm anything
    }, time);
  }

  // add a time engine to the scheduler
  add(engine, time = this.currentTime) {
    if (!TimeEngine.implementsScheduled(engine))
      throw new Error("object cannot be added to scheduler");

    if (engine.master)
      throw new Error("object has already been added to a master");

    engine.master = this;

    // add to engines and queue
    this.__engines.add(engine);
    var nextTime = this.__queue.insert(engine, time);

    // reschedule queue
    this.resetTime(nextTime);
  }

  // remove a time engine from the queue
  remove(engine) {
    if (engine.master !== this)
      throw new Error("object has not been added to this scheduler");

    engine.master = null;

    // remove from array and queue
    this.__engines.delete(engine);
    var nextTime = this.__queue.remove(engine);

    // reschedule queue
    this.resetTime(nextTime);
  }

  // reset next engine time
  resetEngineTime(engine, time = this.currentTime) {
    if (engine.master !== this)
      throw new Error("object has not been added to this scheduler");

    var nextTime = this.__queue.move(engine, time);
    this.resetTime(nextTime);
  }

  // check whether a given engine is scheduled
  has(engine) {
    return this.__engines.has(engine);
  }

  // clear queue
  clear() {
    this.__queue.clear();
    this.__engines.clear;
    this.resetTime(Infinity);
  }
}
<commit_msg>removed 0 period scheduling security<commit_after>/**
 * SchedulingQueue base class
 * http://wavesjs.github.io/audio/#audio-scheduling-queue
 *
 * Norbert.Schnell@ircam.fr
 * Copyright 2014, 2015 IRCAM – Centre Pompidou
 */

import PriorityQueue from '../utils/priority-queue';
import TimeEngine from '../core/time-engine';
import defaultAudioContext from '../core/audio-context';

/**
 * @class SchedulingQueue
 */
export default class SchedulingQueue extends TimeEngine {
  constructor() {
    super();

    this.__queue = new PriorityQueue();
    this.__engines = new Set();
  }

  // TimeEngine 'scheduled' interface
  advanceTime(time) {
    var nextTime = this.__queue.time;

    while (nextTime <= time) {
      var engine = this.__queue.head;
      var nextEngineTime = engine.advanceTime(time);

      if (!nextEngineTime) {
        engine.master = null;
        this.__engines.delete(engine);
        nextTime = this.__queue.remove(engine);
      } else {
        nextTime = this.__queue.move(engine, nextEngineTime);
      }
    }

    return nextTime;
  }

  // TimeEngine master method to be implemented by derived class
  get currentTime() {
    return 0;
  }

  // call a function at a given time
  defer(fun, time = this.currentTime) {
    if (!(fun instanceof Function))
      throw new Error("object cannot be defered by scheduler");

    this.add({
      advanceTime: function(time) { fun(time); }, // make sur that the advanceTime method does not returm anything
    }, time);
  }

  // add a time engine to the scheduler
  add(engine, time = this.currentTime) {
    if (!TimeEngine.implementsScheduled(engine))
      throw new Error("object cannot be added to scheduler");

    if (engine.master)
      throw new Error("object has already been added to a master");

    engine.master = this;

    // add to engines and queue
    this.__engines.add(engine);
    var nextTime = this.__queue.insert(engine, time);

    // reschedule queue
    this.resetTime(nextTime);
  }

  // remove a time engine from the queue
  remove(engine) {
    if (engine.master !== this)
      throw new Error("object has not been added to this scheduler");

    engine.master = null;

    // remove from array and queue
    this.__engines.delete(engine);
    var nextTime = this.__queue.remove(engine);

    // reschedule queue
    this.resetTime(nextTime);
  }

  // reset next engine time
  resetEngineTime(engine, time = this.currentTime) {
    if (engine.master !== this)
      throw new Error("object has not been added to this scheduler");

    var nextTime = this.__queue.move(engine, time);
    this.resetTime(nextTime);
  }

  // check whether a given engine is scheduled
  has(engine) {
    return this.__engines.has(engine);
  }

  // clear queue
  clear() {
    this.__queue.clear();
    this.__engines.clear;
    this.resetTime(Infinity);
  }
}
<|endoftext|>


<commit_before>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/Edit.js"/>
/// <reference path="../../Format.js"/>

Ext.namespace("Mobile.SalesLogix.History");

(function() {
    Mobile.SalesLogix.History.NoteEdit = Ext.extend(Sage.Platform.Mobile.Edit, {
        //Localization
        accountText: 'account',
        noteDescriptionTitleText: 'Note Description',
        contactText: 'contact',
        longNotesText: 'notes',
        longNotesTitleText: 'Notes',
        opportunityText: 'opportunity',
        ticketNumberText: 'ticket',
        regardingText: 'regarding',
        isLeadText: 'for lead',
        startingText: 'start time',
        titleText: 'Note',
        companyText: 'company',
        leadText: 'lead',
        relatedItemsText: 'Related Items',

        //View Properties
        id: 'history_note_edit',
        fieldsForLeads: ['AccountName', 'Lead'],
        fieldsForStandard: ['Account', 'Contact', 'Opportunity', 'Ticket'],
        entityName: 'History',
        resourceKind: 'history',
        querySelect: [
            'AccountId',
            'AccountName',
            'ContactId',
            'ContactName',
            'Description',
            'LongNotes',
            'Notes',
            'OpportunityId',
            'OpportunityName',
            'TicketId',
            'TicketNumber',
            'Type',
            'LeadId',
            'LeadName',
            'StartDate'
        ],

        init: function() {
            Mobile.SalesLogix.History.NoteEdit.superclass.init.apply(this, arguments);

            this.fields['Lead'].on('change', this.onLeadChange, this);
            this.fields['IsLead'].on('change', this.onIsLeadChange, this);
        },
        isHistoryForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        isInLeadContext: function() {
            var insert = this.options && this.options.insert,
                entry = this.options && this.options.entry,
                lead = (insert && App.isNavigationFromResourceKind('leads', function(o, c) { return c.key; })) || this.isHistoryForLead(entry);

            return !!lead;
        },
        beforeTransitionTo: function() {
            Mobile.SalesLogix.History.NoteEdit.superclass.beforeTransitionTo.apply(this, arguments);

            // we hide the lead or standard fields here, as the view is currently hidden, in order to prevent flashing.
            // the value for the 'IsLead' field will be set later, based on the value derived here.

            // todo: there is an issue when refreshing the edit view as options.isLead is persisted in the navigation state.
            if (this.options.isForLead != undefined) return;

            this.options.isForLead = this.isInLeadContext();

            if (this.options.isForLead)
                this.showFieldsForLead();
            else
                this.showFieldsForStandard();
        },
        onIsLeadChange: function(value, field) {
            this.options.isForLead = value;

            if (this.options.isForLead)
                this.showFieldsForLead();
            else
                this.showFieldsForStandard();
        },
        onLeadChange: function(value, field) {
            var selection = field.getSelection(),
                getV = Sage.Platform.Mobile.Utility.getValue;

            if (selection && this.insert)
            {
                this.fields['AccountName'].setValue(getV(selection, 'Company'));
            }
        },
        showFieldsForLead: function() {
            Ext.each(this.fieldsForStandard.concat(this.fieldsForLeads), function(item) {
                if (this.fields[item])
                    this.fields[item].hide();
            }, this);

            Ext.each(this.fieldsForLeads, function(item) {
                if (this.fields[item])
                    this.fields[item].show();
            }, this);
        },
        showFieldsForStandard: function() {
            Ext.each(this.fieldsForStandard.concat(this.fieldsForLeads), function(item) {
                if (this.fields[item])
                    this.fields[item].hide();
            }, this);

            Ext.each(this.fieldsForStandard, function(item) {
                    if (this.fields[item])
                        this.fields[item].show();
                }, this);
        },
        applyContext: function() {
            var found = App.queryNavigationContext(function(o) {
                return /^(accounts|contacts|opportunities|leads|tickets)$/.test(o.resourceKind) && o.key;
            });

            var lookup = {
                'accounts': this.applyAccountContext,
                'contacts': this.applyContactContext,
                'opportunities': this.applyOpportunityContext,
                'leads': this.applyLeadContext,
                'tickets': this.applyTicketContext
            };

            if (found && lookup[found.resourceKind]) lookup[found.resourceKind].call(this, found);

            var user = App.context && App.context.user;

            this.fields['Type'].setValue('atNote');
            this.fields['UserId'].setValue(user && user['$key']);
            this.fields['UserName'].setValue(user && user['$descriptor']);
        },
        applyAccountContext: function(context) {
            this.fields['Account'].setValue({
                'AccountId': context.key,
                'AccountName': context.descriptor
            });
        },
        applyLeadContext: function(context) {
            this.fields['Lead'].setValue({
                'LeadId': context.key,
                'LeadName': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Company']) this.fields['AccountName'].setValue(entry['Company']);
        },
        applyOpportunityContext: function(context) {
            this.fields['Opportunity'].setValue({
                'OpportunityId': context.key,
                'OpportunityName': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Account'])
            {
                this.fields['Account'].setValue({
                    'AccountId': entry['Account']['$key'],
                    'AccountName': entry['Account']['AccountName']
                });
            }

            // todo: find a good way to get the primary contact and apply
        },
        applyContactContext: function(context) {
            this.fields['Contact'].setValue({
                'ContactId': context.key,
                'ContactName': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Account'])
            {
                this.fields['Account'].setValue({
                    'AccountId': entry['Account']['$key'],
                    'AccountName': entry['Account']['AccountName']
                });
            }
        },
        applyTicketContext: function(context) {
            this.fields['Ticket'].setValue({
                'TicketId': context.key,
                'TicketNumber': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Account'])
            {
                this.fields['Account'].setValue({
                    'AccountId': entry['Account']['$key'],
                    'AccountName': entry['Account']['AccountName']
                });
            }

            if (entry && entry['Contact'])
            {
                 this.fields['Contact'].setValue({
                    'ContactId': entry['Contact']['$key'],
                    'ContactName': entry['Contact']['NameLF']
                });
            }
        },
        setValues: function(values) {
            Mobile.SalesLogix.History.NoteEdit.superclass.setValues.apply(this, arguments);

            this.fields['IsLead'].setValue(this.options.isForLead);
        },
        formatDependentQuery: function(dependentValue, format, property) {
            var getV = Sage.Platform.Mobile.Utility.getValue;

            property = property || '$key';

            return String.format(format, getV(dependentValue, property));
        },
        getValues: function() {
            var values = Mobile.SalesLogix.Note.Edit.superclass.getValues.apply(this, arguments);

            if (this.fields['Text'].isDirty())
            {
                var text = this.fields['Text'].getValue();

                values = values || {};
                values['LongNotes'] = text;
                values['Notes'] = text && text.length > 250
                    ? text.substr(0, 250)
                    : text;
            }

            return values;
        },
        createLayout: function() {
            return this.layout || (this.layout = [{
                options: {
                    title: this.detailsText
                },
                as: [{
                    name: 'Type',
                    type: 'hidden'
                },{
                    name: 'UserId',
                    type: 'hidden'
                },{
                    name: 'UserName',
                    type: 'hidden'
                },{
                    label: this.startingText,
                    name: 'StartDate',
                    type: 'date',
                    showTimePicker: true,
                    formatString: 'M/d/yyyy h:mm tt',
                    minValue: (new Date(1900, 0, 1)),
                    validator: [
                        Mobile.SalesLogix.Validator.exists,
                        Mobile.SalesLogix.Validator.isDateInRange
                    ]
                },{
                    dependsOn: 'Type',
                    label: this.regardingText,
                    name: 'Description',
                    picklist: 'Note Regarding',
                    orderBy: 'text asc',
                    title: this.noteDescriptionTitleText,
                    type: 'picklist'
                }]
            },{
                options: {
                    title: this.longNotesTitleText
                },
                as: [{
                    name: 'Text',
                    label: this.longNotesText,
                    cls: 'row-edit-text',
                    type: 'text',
                    multiline: true
                }]
            },{
                options: {
                    title: this.relatedItemsText
                },
                as: [{
                    label: this.isLeadText,
                    name: 'IsLead',
                    include: false,
                    type: 'boolean'
                },{
                    label: this.accountText,
                    name: 'Account',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'AccountId',
                    valueTextProperty: 'AccountName',
                    view: 'account_related',
                    validator: Mobile.SalesLogix.Validator.exists
                },{
                    dependsOn: 'Account',
                    label: this.contactText,
                    name: 'Contact',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'ContactId',
                    valueTextProperty: 'ContactName',
                    view: 'contact_related',
                    where: this.formatDependentQuery.createDelegate(
                        this, ['Account.Id eq "{0}"', 'AccountId'], true
                    )
                },{
                    dependsOn: 'Account',
                    label: this.opportunityText,
                    name: 'Opportunity',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'OpportunityId',
                    valueTextProperty: 'OpportunityName',
                    view: 'opportunity_related',
                    where: this.formatDependentQuery.createDelegate(
                        this, ['Account.Id eq "{0}"', 'AccountId'], true
                    )
                },{
                    dependsOn: 'Account',
                    label: this.ticketNumberText,
                    name: 'Ticket',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'TicketId',
                    valueTextProperty: 'TicketNumber',
                    view: 'ticket_related',
                    where: this.formatDependentQuery.createDelegate(
                        this, ['Account.Id eq "{0}"', 'AccountId'], true
                    )
                },{
                    label: this.leadText,
                    name: 'Lead',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'LeadId',
                    valueTextProperty: 'LeadName',
                    view: 'lead_related',
                    validator: Mobile.SalesLogix.Validator.exists
                },{
                    label: this.companyText,
                    name: 'AccountName',
                    type: 'text'
                }]
            }]);
        }
    });
})();
<commit_msg>label and default time adjustments for new note edit view.<commit_after>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/Edit.js"/>
/// <reference path="../../Format.js"/>

Ext.namespace("Mobile.SalesLogix.History");

(function() {
    Mobile.SalesLogix.History.NoteEdit = Ext.extend(Sage.Platform.Mobile.Edit, {
        //Localization
        accountText: 'account',
        noteDescriptionTitleText: 'Note Description',
        contactText: 'contact',
        longNotesText: 'notes',
        longNotesTitleText: 'Notes',
        opportunityText: 'opportunity',
        ticketNumberText: 'ticket',
        regardingText: 'regarding',
        isLeadText: 'for lead',
        startingText: 'time',
        titleText: 'Note',
        companyText: 'company',
        leadText: 'lead',
        relatedItemsText: 'Related Items',

        //View Properties
        id: 'history_note_edit',
        fieldsForLeads: ['AccountName', 'Lead'],
        fieldsForStandard: ['Account', 'Contact', 'Opportunity', 'Ticket'],
        entityName: 'History',
        resourceKind: 'history',
        querySelect: [
            'AccountId',
            'AccountName',
            'ContactId',
            'ContactName',
            'Description',
            'LongNotes',
            'Notes',
            'OpportunityId',
            'OpportunityName',
            'TicketId',
            'TicketNumber',
            'Type',
            'LeadId',
            'LeadName',
            'StartDate'
        ],

        init: function() {
            Mobile.SalesLogix.History.NoteEdit.superclass.init.apply(this, arguments);

            this.fields['Lead'].on('change', this.onLeadChange, this);
            this.fields['IsLead'].on('change', this.onIsLeadChange, this);
        },
        isHistoryForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        isInLeadContext: function() {
            var insert = this.options && this.options.insert,
                entry = this.options && this.options.entry,
                lead = (insert && App.isNavigationFromResourceKind('leads', function(o, c) { return c.key; })) || this.isHistoryForLead(entry);

            return !!lead;
        },
        beforeTransitionTo: function() {
            Mobile.SalesLogix.History.NoteEdit.superclass.beforeTransitionTo.apply(this, arguments);

            // we hide the lead or standard fields here, as the view is currently hidden, in order to prevent flashing.
            // the value for the 'IsLead' field will be set later, based on the value derived here.

            // todo: there is an issue when refreshing the edit view as options.isLead is persisted in the navigation state.
            if (this.options.isForLead != undefined) return;

            this.options.isForLead = this.isInLeadContext();

            if (this.options.isForLead)
                this.showFieldsForLead();
            else
                this.showFieldsForStandard();
        },
        onIsLeadChange: function(value, field) {
            this.options.isForLead = value;

            if (this.options.isForLead)
                this.showFieldsForLead();
            else
                this.showFieldsForStandard();
        },
        onLeadChange: function(value, field) {
            var selection = field.getSelection(),
                getV = Sage.Platform.Mobile.Utility.getValue;

            if (selection && this.insert)
            {
                this.fields['AccountName'].setValue(getV(selection, 'Company'));
            }
        },
        showFieldsForLead: function() {
            Ext.each(this.fieldsForStandard.concat(this.fieldsForLeads), function(item) {
                if (this.fields[item])
                    this.fields[item].hide();
            }, this);

            Ext.each(this.fieldsForLeads, function(item) {
                if (this.fields[item])
                    this.fields[item].show();
            }, this);
        },
        showFieldsForStandard: function() {
            Ext.each(this.fieldsForStandard.concat(this.fieldsForLeads), function(item) {
                if (this.fields[item])
                    this.fields[item].hide();
            }, this);

            Ext.each(this.fieldsForStandard, function(item) {
                    if (this.fields[item])
                        this.fields[item].show();
                }, this);
        },
        applyContext: function() {
            var found = App.queryNavigationContext(function(o) {
                return /^(accounts|contacts|opportunities|leads|tickets)$/.test(o.resourceKind) && o.key;
            });

            var lookup = {
                'accounts': this.applyAccountContext,
                'contacts': this.applyContactContext,
                'opportunities': this.applyOpportunityContext,
                'leads': this.applyLeadContext,
                'tickets': this.applyTicketContext
            };

            if (found && lookup[found.resourceKind]) lookup[found.resourceKind].call(this, found);

            var user = App.context && App.context.user;

            this.fields['Type'].setValue('atNote');
            this.fields['UserId'].setValue(user && user['$key']);
            this.fields['UserName'].setValue(user && user['$descriptor']);
            this.fields['StartDate'].setValue(new Date());
        },
        applyAccountContext: function(context) {
            this.fields['Account'].setValue({
                'AccountId': context.key,
                'AccountName': context.descriptor
            });
        },
        applyLeadContext: function(context) {
            this.fields['Lead'].setValue({
                'LeadId': context.key,
                'LeadName': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Company']) this.fields['AccountName'].setValue(entry['Company']);
        },
        applyOpportunityContext: function(context) {
            this.fields['Opportunity'].setValue({
                'OpportunityId': context.key,
                'OpportunityName': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Account'])
            {
                this.fields['Account'].setValue({
                    'AccountId': entry['Account']['$key'],
                    'AccountName': entry['Account']['AccountName']
                });
            }

            // todo: find a good way to get the primary contact and apply
        },
        applyContactContext: function(context) {
            this.fields['Contact'].setValue({
                'ContactId': context.key,
                'ContactName': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Account'])
            {
                this.fields['Account'].setValue({
                    'AccountId': entry['Account']['$key'],
                    'AccountName': entry['Account']['AccountName']
                });
            }
        },
        applyTicketContext: function(context) {
            this.fields['Ticket'].setValue({
                'TicketId': context.key,
                'TicketNumber': context.descriptor
            });

            var view = App.getView(context.id),
                entry = view && view.entry;

            if (entry && entry['Account'])
            {
                this.fields['Account'].setValue({
                    'AccountId': entry['Account']['$key'],
                    'AccountName': entry['Account']['AccountName']
                });
            }

            if (entry && entry['Contact'])
            {
                 this.fields['Contact'].setValue({
                    'ContactId': entry['Contact']['$key'],
                    'ContactName': entry['Contact']['NameLF']
                });
            }
        },
        setValues: function(values) {
            Mobile.SalesLogix.History.NoteEdit.superclass.setValues.apply(this, arguments);

            this.fields['IsLead'].setValue(this.options.isForLead);
        },
        formatDependentQuery: function(dependentValue, format, property) {
            var getV = Sage.Platform.Mobile.Utility.getValue;

            property = property || '$key';

            return String.format(format, getV(dependentValue, property));
        },
        getValues: function() {
            var values = Mobile.SalesLogix.Note.Edit.superclass.getValues.apply(this, arguments);

            if (this.fields['Text'].isDirty())
            {
                var text = this.fields['Text'].getValue();

                values = values || {};
                values['LongNotes'] = text;
                values['Notes'] = text && text.length > 250
                    ? text.substr(0, 250)
                    : text;
            }

            return values;
        },
        createLayout: function() {
            return this.layout || (this.layout = [{
                options: {
                    title: this.detailsText
                },
                as: [{
                    name: 'Type',
                    type: 'hidden'
                },{
                    name: 'UserId',
                    type: 'hidden'
                },{
                    name: 'UserName',
                    type: 'hidden'
                },{
                    label: this.startingText,
                    name: 'StartDate',
                    type: 'date',
                    showTimePicker: true,
                    formatString: 'M/d/yyyy h:mm tt',
                    minValue: (new Date(1900, 0, 1)),
                    validator: [
                        Mobile.SalesLogix.Validator.exists,
                        Mobile.SalesLogix.Validator.isDateInRange
                    ]
                },{
                    dependsOn: 'Type',
                    label: this.regardingText,
                    name: 'Description',
                    picklist: 'Note Regarding',
                    orderBy: 'text asc',
                    title: this.noteDescriptionTitleText,
                    type: 'picklist'
                }]
            },{
                options: {
                    title: this.longNotesTitleText
                },
                as: [{
                    name: 'Text',
                    label: this.longNotesText,
                    cls: 'row-edit-text',
                    type: 'text',
                    multiline: true
                }]
            },{
                options: {
                    title: this.relatedItemsText
                },
                as: [{
                    label: this.isLeadText,
                    name: 'IsLead',
                    include: false,
                    type: 'boolean'
                },{
                    label: this.accountText,
                    name: 'Account',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'AccountId',
                    valueTextProperty: 'AccountName',
                    view: 'account_related',
                    validator: Mobile.SalesLogix.Validator.exists
                },{
                    dependsOn: 'Account',
                    label: this.contactText,
                    name: 'Contact',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'ContactId',
                    valueTextProperty: 'ContactName',
                    view: 'contact_related',
                    where: this.formatDependentQuery.createDelegate(
                        this, ['Account.Id eq "{0}"', 'AccountId'], true
                    )
                },{
                    dependsOn: 'Account',
                    label: this.opportunityText,
                    name: 'Opportunity',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'OpportunityId',
                    valueTextProperty: 'OpportunityName',
                    view: 'opportunity_related',
                    where: this.formatDependentQuery.createDelegate(
                        this, ['Account.Id eq "{0}"', 'AccountId'], true
                    )
                },{
                    dependsOn: 'Account',
                    label: this.ticketNumberText,
                    name: 'Ticket',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'TicketId',
                    valueTextProperty: 'TicketNumber',
                    view: 'ticket_related',
                    where: this.formatDependentQuery.createDelegate(
                        this, ['Account.Id eq "{0}"', 'AccountId'], true
                    )
                },{
                    label: this.leadText,
                    name: 'Lead',
                    type: 'lookup',
                    emptyText: '',
                    applyTo: '.',
                    valueKeyProperty: 'LeadId',
                    valueTextProperty: 'LeadName',
                    view: 'lead_related',
                    validator: Mobile.SalesLogix.Validator.exists
                },{
                    label: this.companyText,
                    name: 'AccountName',
                    type: 'text'
                }]
            }]);
        }
    });
})();
<|endoftext|>


<commit_before>function BeamModelDemo(id, map, sensorRadius, sensorNoise)
{
	//Visualization stuff
	const nLasers = 19;

	//the canvas element
	this.view = new View(document.getElementById(id), 20);
	this.view.setPreviewScale(map);

	this.robotSize = 0.2;
	this.map = map;
	this.z = new Array(nLasers);
	this.tracker = new ParticleTracker();
	this.resolution = 10;
	this.shouldColor = false;
	this.mouseout = true;

	//Initial robot pose
	this.x = random() * this.view.width;
	this.y = random() * this.view.height;
	this.dir = random() * TWO_PI;

	//Math model used for likelihood calculation
	this.sensorModel = new BeamModel(sensorNoise, sensorRadius, map);
	this.sensorRadius = sensorRadius;

	//Event listeners
	const self = this;
	this.view.canvas.onmousedown = function (event){
		return self.mouseDown(event)
	};
	this.view.canvas.onmousemove = function (event) {
		return self.trackPosition(event)
	};
	this.view.canvas.onmouseout = function (event) {
		return self.mouseOut(event)
	};
	this.view.ctx.drawMap(map);
	this.update();
}

BeamModelDemo.prototype.mouseDown = function (event)
{
	//Shorthand for this.view and this.ctx
	const view = this.view;
	var coor = getClickLoc(event);

	const x = view.toWorldX(coor.x);
	const y = view.toWorldY(coor.y);
	if (event.altKey)
	{
		if (this.shouldColor)
			return;
		const resolution = this.resolution / this.view.scale;
		const w = this.sensorModel.probability(this.z,
			new RobotState(x - resolution / 2, y - resolution / 2, this.dir));
		this.tracker.addParticle(new Particle(x, y, this.dir, w));
		this.draw();
		this.drawLaserLines();
		this.view.ctx.strokeTextWithColorFont('probability: ' + w, 'black', '12 Menlo Regular', 10, 20);
		return;
	}

	cancelAnimationFrame(this.frameId);

	//update robot's location
	this.x = x;
	this.y = y;

	const self = this;
	this.view.canvas.onmousemove = function (event)
	{
		return self.trackDirection(event);
	};
	this.view.canvas.onmouseup = function (event)
	{
		return self.mouseUp(event);
	};

	this.draw();
};

BeamModelDemo.prototype.trackPosition = function (event) {
	this.mouseout = false;
	const view = this.view;
	const coor = getClickLoc(event);
	const x = coor.x;
	const y = coor.y;
	view.setScale(50);
	var mapsize = getMapSize(this.map);

	var ratioX = x / view.canvas.width;
	var ratioY = y / view.canvas.height;

	var worldX = mapsize.x * ratioX;
	var worldY = mapsize.y * (1 - ratioY);

	this.view.adjustToPoint(view.toScreenX(worldX), view.toScreenY(worldY));
	// view.canvas.getContext('2d').fillRect(0,0,view.canvas.width,view.canvas.height);
	this.draw();
	this.drawLaserLines();
}

BeamModelDemo.prototype.trackDirection = function (event)
{
	const view = this.view;
	const coor = getClickLoc(event);
	const x = view.toWorldX(coor.x);
	const y = view.toWorldY(coor.y);

	this.dir = atan2(y - this.y, x - this.x);
	this.draw();
};

BeamModelDemo.prototype.mouseUp = function (event)
{
	const self = this;
	this.view.canvas.onmousemove = function (event) {
		return self.trackPosition(event)
	}
	this.view.canvas.onmouseup = undefined;
	this.tracker.clear();
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.mouseOut = function (event) {
	this.mouseout = true;
	const self = this;
	clearCanvas(self.view.canvas);
	self.view.setPreviewScale(self.map);
	self.view.setOffset(0, self.view.canvas.clientHeight);
	self.draw();
	self.drawLaserLines();
	// self.view.ctx.drawMap(self.map);
};

BeamModelDemo.prototype.draw = function ()
{
	clearCanvas(this.view.canvas);
	const ctx = this.view.ctx;
	ctx.drawMap(this.map);
	ctx.drawRobot(this.x, this.y, this.dir, this.robotSize);
	if (!this.shouldColor)
	{
		const resolution = this.resolution / this.view.scale;
		this.tracker.forEach(function (x, y, dir, w)
		{
			ctx.fillStyle = 'rgba(' + round(w * 255) + ', 0, ' + (255 - round(w * 255)) + ', 0.5)';
			ctx.fillRect(x - resolution / 2, y - resolution / 2, resolution, resolution);
		});
	} else if (this.view.canvas.onmouseout)
	{
		//If user is moving its mouse, don't color the map, too expensive
		if (!this.mouseout)
			return;
		this.view.colorMap(this.resolution, this.sensorModel, this.z, this.dir);
	}
};

BeamModelDemo.prototype.update = function ()
{
	//Only scan if location changed
	scan(this.x, this.y, this.dir, this.sensorRadius, this.map, this.z);
	for (var i = 0; i < this.z.length; i++)
	{
		this.z[i] += gaussian() * this.sensorModel.a1;
	}
};

BeamModelDemo.prototype.setNLasers = function (n)
{
	this.z = new Array(n + 1);
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.setSensorRadius = function (r)
{
	this.sensorRadius = r;
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.setSensorNoise = function (p)
{
	this.sensorModel.a1 = p;
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.drawLaserLines = function ()
{
	this.view.ctx.drawLaserLines(this.z, this.x, this.y, this.dir, this.sensorRadius);
};

BeamModelDemo.prototype.setColoring = function (shouldColor)
{
	this.shouldColor = shouldColor;
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.setColoringResolution = function (resolution)
{
	this.resolution = resolution;
	this.draw();
	this.drawLaserLines();
};

function ParticleTracker()
{
	this.clear();
}

ParticleTracker.prototype.clear = function ()
{
	this.maxW = Number.NEGATIVE_INFINITY;
	this.minW = Number.POSITIVE_INFINITY;
	this.particles = [];
};

ParticleTracker.prototype.addParticle = function (particle)
{
	this.particles.push(particle);
	this.maxW = max(particle.w, this.maxW);
	this.minW = min(particle.w, this.minW);
};

ParticleTracker.prototype.forEach = function (callback)
{
	const minW = this.minW;
	const maxW = this.maxW;
	if (this.particles.length === 1)
	{
		const p = this.particles[0];
		callback(p.x, p.y, p.dir, p.w);
	} else if (this.particles.length)
	{
		this.particles.forEach(function (p)
		{
			callback(p.x, p.y, p.dir, (p.w - minW) / (maxW - minW));
		});
	}
};
<commit_msg>add missing semicolon<commit_after>function BeamModelDemo(id, map, sensorRadius, sensorNoise)
{
	//Visualization stuff
	const nLasers = 19;

	//the canvas element
	this.view = new View(document.getElementById(id), 20);
	this.view.setPreviewScale(map);

	this.robotSize = 0.2;
	this.map = map;
	this.z = new Array(nLasers);
	this.tracker = new ParticleTracker();
	this.resolution = 10;
	this.shouldColor = false;
	this.mouseout = true;

	//Initial robot pose
	this.x = random() * this.view.width;
	this.y = random() * this.view.height;
	this.dir = random() * TWO_PI;

	//Math model used for likelihood calculation
	this.sensorModel = new BeamModel(sensorNoise, sensorRadius, map);
	this.sensorRadius = sensorRadius;

	//Event listeners
	const self = this;
	this.view.canvas.onmousedown = function (event)
	{
		return self.mouseDown(event)
	};
	this.view.canvas.onmousemove = function (event)
	{
		return self.trackPosition(event)
	};
	this.view.canvas.onmouseout = function (event)
	{
		return self.mouseOut(event)
	};
	this.view.ctx.drawMap(map);
	this.update();
}

BeamModelDemo.prototype.mouseDown = function (event)
{
	//Shorthand for this.view and this.ctx
	const view = this.view;
	var coor = getClickLoc(event);

	const x = view.toWorldX(coor.x);
	const y = view.toWorldY(coor.y);
	if (event.altKey)
	{
		if (this.shouldColor)
			return;
		const resolution = this.resolution / this.view.scale;
		const w = this.sensorModel.probability(this.z,
			new RobotState(x - resolution / 2, y - resolution / 2, this.dir));
		this.tracker.addParticle(new Particle(x, y, this.dir, w));
		this.draw();
		this.drawLaserLines();
		this.view.ctx.strokeTextWithColorFont('probability: ' + w, 'black', '12 Menlo Regular', 10, 20);
		return;
	}

	cancelAnimationFrame(this.frameId);

	//update robot's location
	this.x = x;
	this.y = y;

	const self = this;
	this.view.canvas.onmousemove = function (event)
	{
		return self.trackDirection(event);
	};
	this.view.canvas.onmouseup = function (event)
	{
		return self.mouseUp(event);
	};

	this.draw();
};

BeamModelDemo.prototype.trackPosition = function (event)
{
	this.mouseout = false;
	const view = this.view;
	const coor = getClickLoc(event);
	const x = coor.x;
	const y = coor.y;
	view.setScale(50);
	var mapsize = getMapSize(this.map);

	var ratioX = x / view.canvas.width;
	var ratioY = y / view.canvas.height;

	var worldX = mapsize.x * ratioX;
	var worldY = mapsize.y * (1 - ratioY);

	this.view.adjustToPoint(view.toScreenX(worldX), view.toScreenY(worldY));
	// view.canvas.getContext('2d').fillRect(0,0,view.canvas.width,view.canvas.height);
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.trackDirection = function (event)
{
	const view = this.view;
	const coor = getClickLoc(event);
	const x = view.toWorldX(coor.x);
	const y = view.toWorldY(coor.y);

	this.dir = atan2(y - this.y, x - this.x);
	this.draw();
};

BeamModelDemo.prototype.mouseUp = function (event)
{
	const self = this;
	this.view.canvas.onmousemove = function (event)
	{
		return self.trackPosition(event)
	}
	this.view.canvas.onmouseup = undefined;
	this.tracker.clear();
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.mouseOut = function (event)
{
	this.mouseout = true;
	const self = this;
	clearCanvas(self.view.canvas);
	self.view.setPreviewScale(self.map);
	self.view.setOffset(0, self.view.canvas.clientHeight);
	self.draw();
	self.drawLaserLines();
	// self.view.ctx.drawMap(self.map);
};

BeamModelDemo.prototype.draw = function ()
{
	clearCanvas(this.view.canvas);
	const ctx = this.view.ctx;
	ctx.drawMap(this.map);
	ctx.drawRobot(this.x, this.y, this.dir, this.robotSize);
	if (!this.shouldColor)
	{
		const resolution = this.resolution / this.view.scale;
		this.tracker.forEach(function (x, y, dir, w)
		{
			ctx.fillStyle = 'rgba(' + round(w * 255) + ', 0, ' + (255 - round(w * 255)) + ', 0.5)';
			ctx.fillRect(x - resolution / 2, y - resolution / 2, resolution, resolution);
		});
	} else if (this.view.canvas.onmouseout)
	{
		//If user is moving its mouse, don't color the map, too expensive
		if (!this.mouseout)
			return;
		this.view.colorMap(this.resolution, this.sensorModel, this.z, this.dir);
	}
};

BeamModelDemo.prototype.update = function ()
{
	//Only scan if location changed
	scan(this.x, this.y, this.dir, this.sensorRadius, this.map, this.z);
	for (var i = 0; i < this.z.length; i++)
	{
		this.z[i] += gaussian() * this.sensorModel.a1;
	}
};

BeamModelDemo.prototype.setNLasers = function (n)
{
	this.z = new Array(n + 1);
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.setSensorRadius = function (r)
{
	this.sensorRadius = r;
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.setSensorNoise = function (p)
{
	this.sensorModel.a1 = p;
	this.update();
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.drawLaserLines = function ()
{
	this.view.ctx.drawLaserLines(this.z, this.x, this.y, this.dir, this.sensorRadius);
};

BeamModelDemo.prototype.setColoring = function (shouldColor)
{
	this.shouldColor = shouldColor;
	this.draw();
	this.drawLaserLines();
};

BeamModelDemo.prototype.setColoringResolution = function (resolution)
{
	this.resolution = resolution;
	this.draw();
	this.drawLaserLines();
};

function ParticleTracker()
{
	this.clear();
}

ParticleTracker.prototype.clear = function ()
{
	this.maxW = Number.NEGATIVE_INFINITY;
	this.minW = Number.POSITIVE_INFINITY;
	this.particles = [];
};

ParticleTracker.prototype.addParticle = function (particle)
{
	this.particles.push(particle);
	this.maxW = max(particle.w, this.maxW);
	this.minW = min(particle.w, this.minW);
};

ParticleTracker.prototype.forEach = function (callback)
{
	const minW = this.minW;
	const maxW = this.maxW;
	if (this.particles.length === 1)
	{
		const p = this.particles[0];
		callback(p.x, p.y, p.dir, p.w);
	} else if (this.particles.length)
	{
		this.particles.forEach(function (p)
		{
			callback(p.x, p.y, p.dir, (p.w - minW) / (maxW - minW));
		});
	}
};
<|endoftext|>


<commit_before>import ide from '../../ide';
import controller from './controller';
import auth from '../../auth';

var openNew = function(position) {
  var code = 'this.onInteract = function() {\n  console.log(\'hello w0rld from '+ position + '\');\n};\n'; // TODO bring from server or something

  return ide.open({position, code}).then(data => {
    return controller.createNewPrototype(position, data.value, data.name).then(codeObj => {
      alert('New code was created correctly with ID: ' + codeObj.id);
    }, err => {
      alert('Error storing code: ' + err);
    });
  });
};

var openExisting = function(position, blockType) {
  return ide.open({position, blockType}).then(data => {
    if(data.name) {
      return controller.forkPrototype(position, data.value, data.name).then((codeObj) => {
        alert('Existing code was forked with ID: ' + codeObj.id);
      }, err => {
        alert('Error storing code: ' + err);
      });
    } else {
      return controller.modifyPrototype(position, data.value).then(() => {
        alert('Existing code was updated correctly');
      }, err => {
        alert('Error storing code: ' + err);
      });
    }
  });
};

export default function(position) {
  if(!auth.isLogged()) {
    return Promise.reject('Please login to be able to edit code');
  }

  if(controller.hasCode(position)) {
    return openExisting(position, controller.getCode(position));
  } else {
    return openNew(position);
  }
}
<commit_msg>updating default text in ide<commit_after>import ide from '../../ide';
import controller from './controller';
import auth from '../../auth';

var openNew = function(position) {
  var code = "function SuchBlockBehavior(world, block) {\n  console.log('much instantiate. amaze');\n\n  this.onInteract = function() {\n    alert('such interact. wow.');\n  };\n\n  this.onHover = function() {\n    console.log('very hover');\n  };\n\n  this.onDestroy = function() {\n    console.log(':(');\n  };\n}"; // TODO bring from server or something

  return ide.open({position, code}).then(data => {
    return controller.createNewPrototype(position, data.value, data.name).then(codeObj => {
      alert('New code was created correctly with ID: ' + codeObj.id);
    }, err => {
      alert('Error storing code: ' + err);
    });
  });
};

var openExisting = function(position, blockType) {
  return ide.open({position, blockType}).then(data => {
    if(data.name) {
      return controller.forkPrototype(position, data.value, data.name).then((codeObj) => {
        alert('Existing code was forked with ID: ' + codeObj.id);
      }, err => {
        alert('Error storing code: ' + err);
      });
    } else {
      return controller.modifyPrototype(position, data.value).then(() => {
        alert('Existing code was updated correctly');
      }, err => {
        alert('Error storing code: ' + err);
      });
    }
  });
};

export default function(position) {
  if(!auth.isLogged()) {
    return Promise.reject('Please login to be able to edit code');
  }

  if(controller.hasCode(position)) {
    return openExisting(position, controller.getCode(position));
  } else {
    return openNew(position);
  }
}
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

function createModuleDescription(name, exclude) {
	var result = {};
	var excludes = ['vs/css', 'vs/nls'];
	result.name = name;
	if (Array.isArray(exclude) && exclude.length > 0) {
		excludes = excludes.concat(exclude);
	}
	result.exclude = excludes;
	return result;
}

exports.collectModules = function () {
	var modules = [
		createModuleDescription('vs/workbench/parts/output/common/outputLinkComputer', ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']),

		createModuleDescription('vs/workbench/parts/debug/node/telemetryApp', []),

		createModuleDescription('vs/workbench/services/search/node/searchApp', []),
		createModuleDescription('vs/workbench/services/search/node/legacy/worker/searchWorkerApp', []),
		createModuleDescription('vs/workbench/services/files/node/watcher/unix/watcherApp', []),
		createModuleDescription('vs/workbench/services/files/node/watcher/nsfw/watcherApp', []),

		createModuleDescription('vs/workbench/node/extensionHostProcess', []),
	];

	return modules;
};<commit_msg>remove more search legacy<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

function createModuleDescription(name, exclude) {
	var result = {};
	var excludes = ['vs/css', 'vs/nls'];
	result.name = name;
	if (Array.isArray(exclude) && exclude.length > 0) {
		excludes = excludes.concat(exclude);
	}
	result.exclude = excludes;
	return result;
}

exports.collectModules = function () {
	var modules = [
		createModuleDescription('vs/workbench/parts/output/common/outputLinkComputer', ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']),

		createModuleDescription('vs/workbench/parts/debug/node/telemetryApp', []),

		createModuleDescription('vs/workbench/services/search/node/searchApp', []),
		createModuleDescription('vs/workbench/services/files/node/watcher/unix/watcherApp', []),
		createModuleDescription('vs/workbench/services/files/node/watcher/nsfw/watcherApp', []),

		createModuleDescription('vs/workbench/node/extensionHostProcess', []),
	];

	return modules;
};<|endoftext|>


<commit_before>// Copyright 2015 Volker Sorge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview A semantic walker.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */

goog.provide('sre.SemanticWalker');

goog.require('sre.AbstractWalker');
goog.require('sre.Levels');
goog.require('sre.WalkerUtil');

/**
 * @constructor
 * @extends {sre.AbstractWalker}
 * @override
 */
sre.SemanticWalker = function(node, generator) {
  goog.base(this, node, generator);

  /**
   * Caching of levels.
   * @type {!sre.Levels<sre.Focus>}
   */
  this.levels = new sre.Levels();

  this.levels.push([this.getFocus()]);
};
goog.inherits(sre.SemanticWalker, sre.AbstractWalker);

//TODO: Remove or refactor.
/**
 * Creates a simple focus for a solitary node.
 * @param {!string} id The node id to focus.
 * @return {!sre.Focus} A focus containing only this node and the other
 *     properties of the old focus.
 * @private
 */
sre.SemanticWalker.prototype.singletonFocus_ = function(id) {
  var node = this.getBySemanticId(id);
  return new sre.Focus({nodes: [node], primary: node});
};

/**
 * Makes a focus for a primary node and a node list, all given by their ids.
 * @param {string} id The semantic id of the primary node.
 * @param {!Array.<string>} ids The semantic id of the node list.
 * @return {?sre.Focus} The new focus.
 * @private
 */
sre.SemanticWalker.prototype.focusFromId_ = function(id, ids) {
  var node = this.getBySemanticId(id);
  var nodes = ids.map(goog.bind(this.getBySemanticId, this));
  return new sre.Focus({nodes: nodes, primary: node});
};

/**
 * @override
 */
sre.SemanticWalker.prototype.up = function() {
  var parent = this.primaryAttribute(sre.EnrichMathml.Attribute.PARENT);
  if (!parent) return null;
  this.levels.pop();
  var found = this.levels.find(
      function(x) {
        for (var i = 0, node, nodes = x.getNodes(); node = nodes[i]; i++) {
          if (sre.WalkerUtil.getAttribute(
              node, sre.EnrichMathml.Attribute.ID) === parent) {
            return true;
          }
        }
        return false;
      });
  return found;
};

/**
 * @override
 */
sre.SemanticWalker.prototype.down = function() {
  var children = this.nextLevel_();
  if (children.length === 0) {
    return null;
  }
  this.levels.push(children);
  return children[0];
};

/**
 * Computes the next lower level from children and content.
 * @return {!Array.<sre.Focus>} The next lower level.
 * @private
 */
sre.SemanticWalker.prototype.nextLevel_ = function() {
  var children = sre.WalkerUtil.splitAttribute(
      this.primaryAttribute(sre.EnrichMathml.Attribute.CHILDREN));
  var content = sre.WalkerUtil.splitAttribute(
      this.primaryAttribute(sre.EnrichMathml.Attribute.CONTENT));
  if (children.length === 0) return [];
  var primary = /** @type {!Node} */ (this.getFocus().getPrimary());
  var type = sre.WalkerUtil.getAttribute(
      primary, sre.EnrichMathml.Attribute.TYPE);
  var role = sre.WalkerUtil.getAttribute(
      primary, sre.EnrichMathml.Attribute.ROLE);
  return this.combineContentChildren(
      /** @type {!sre.SemanticAttr.Type} */ (type),
      /** @type {!sre.SemanticAttr.Role} */ (role),
      content, children);
};

/**
 * Combines content and children lists depending on semantic type and role.
 * @param {!sre.SemanticAttr.Type} type The semantic type.
 * @param {!sre.SemanticAttr.Role} role The semantic role.
 * @param {!Array.<string>} content The list of content nodes.
 * @param {!Array.<string>} children The list of child nodes.
 * @return {!Array.<sre.Focus>} The list of focus elements.
 */
sre.SemanticWalker.prototype.combineContentChildren = function(
    type, role, content, children) {
  switch (type) {
    case sre.SemanticAttr.Type.RELSEQ:
    case sre.SemanticAttr.Type.INFIXOP:
    case sre.SemanticAttr.Type.MULTIREL:
      return this.makePairList(children, content);
    case sre.SemanticAttr.Type.PREFIXOP:
      return [this.focusFromId_(children[0], content.concat(children))];
    case sre.SemanticAttr.Type.POSTFIXOP:
      return [this.focusFromId_(children[0], children.concat(content))];
    case sre.SemanticAttr.Type.MATRIX:
    case sre.SemanticAttr.Type.VECTOR:
    case sre.SemanticAttr.Type.FENCED:
      return [this.focusFromId_(children[0],
          [content[0], children[0], content[1]])];
    case sre.SemanticAttr.Type.CASES:
      return [this.focusFromId_(children[0],
          [content[0], children[0]])];
    case sre.SemanticAttr.Type.PUNCTUATED:
      if (role === sre.SemanticAttr.Role.TEXT) {
        return children.map(goog.bind(this.singletonFocus_, this));
      }
      //TODO: That needs to be fixed!
      if (children.length === content.length) {
        return content.map(goog.bind(this.singletonFocus_, this));
      }
      var focusList = this.combinePunctuations(children, content, [], []);
      return focusList;
    case sre.SemanticAttr.Type.APPL:
      return [this.focusFromId_(children[0], [children[0], content[0]]),
        this.singletonFocus_(children[1])];
    case sre.SemanticAttr.Type.ROOT:
      return [this.singletonFocus_(children[1]),
              this.singletonFocus_(children[0])];
    default:
      return children.map(goog.bind(this.singletonFocus_, this));
  }
};

// This does not work yet!
/**
 * Makes a focus list from children of a punctuated element.
 * @param {!Array.<string>} children Child node ids.
 * @param {!Array.<string>} content Content node ids.
 * @param {!Array.<string>} prepunct List of prefix punctuations.
 * @param {!Array.<sre.Focus>} acc Result accumulator.
 * @return {!Array.<sre.Focus>} The list of focuses with paired nodes.
 */
sre.SemanticWalker.prototype.combinePunctuations = function(
    children, content, prepunct, acc) {
  var child = children.shift();
  var cont = content.shift();
  if (child === cont) {
    prepunct.push(cont);
    return this.combinePunctuations(children, content, prepunct, acc);
  } else {
    content.unshift(cont);
    prepunct.push(child);
    if (children.length === content.length) {
      acc.push(this.focusFromId_(child, prepunct.concat(content)));
      return acc;
    } else {
      acc.push(this.focusFromId_(child, prepunct));
      return this.combinePunctuations(children, content, [], acc);
    }
  }
};

/**
 * Makes pairwise focus structures from two lists.
 * @param {!Array.<string>} children Child nodes of length n.
 * @param {!Array.<string>} content Content nodes of length n - 1.
 * @return {!Array.<sre.Focus>} The list of focuses with paired nodes.
 */
sre.SemanticWalker.prototype.makePairList = function(children, content) {
  if (children.length === 0) return [];
  if (children.length === 1) {
    return [this.singletonFocus_(children[0])];
  }
  var result = [this.singletonFocus_(children.shift())];
  for (var i = 0, l = children.length; i < l; i++) {
    result.push(this.focusFromId_(children[i], [content[i], children[i]]));
  }
  return result;
};

/**
 * @override
 */
sre.SemanticWalker.prototype.left = function() {
  var index = this.levels.indexOf(this.getFocus()) - 1;
  var ids = this.levels.get(index);
  return ids ? ids : null;
};

/**
 * @override
 */
sre.SemanticWalker.prototype.right = function() {
  var index = this.levels.indexOf(this.getFocus()) + 1;
  var ids = this.levels.get(index);
  return ids ? ids : null;
};
<commit_msg>Fixes missing base case for punctuations.<commit_after>// Copyright 2015 Volker Sorge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview A semantic walker.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */

goog.provide('sre.SemanticWalker');

goog.require('sre.AbstractWalker');
goog.require('sre.Levels');
goog.require('sre.WalkerUtil');

/**
 * @constructor
 * @extends {sre.AbstractWalker}
 * @override
 */
sre.SemanticWalker = function(node, generator) {
  goog.base(this, node, generator);

  /**
   * Caching of levels.
   * @type {!sre.Levels<sre.Focus>}
   */
  this.levels = new sre.Levels();

  this.levels.push([this.getFocus()]);
};
goog.inherits(sre.SemanticWalker, sre.AbstractWalker);

//TODO: Remove or refactor.
/**
 * Creates a simple focus for a solitary node.
 * @param {!string} id The node id to focus.
 * @return {!sre.Focus} A focus containing only this node and the other
 *     properties of the old focus.
 * @private
 */
sre.SemanticWalker.prototype.singletonFocus_ = function(id) {
  var node = this.getBySemanticId(id);
  return new sre.Focus({nodes: [node], primary: node});
};

/**
 * Makes a focus for a primary node and a node list, all given by their ids.
 * @param {string} id The semantic id of the primary node.
 * @param {!Array.<string>} ids The semantic id of the node list.
 * @return {?sre.Focus} The new focus.
 * @private
 */
sre.SemanticWalker.prototype.focusFromId_ = function(id, ids) {
  var node = this.getBySemanticId(id);
  var nodes = ids.map(goog.bind(this.getBySemanticId, this));
  return new sre.Focus({nodes: nodes, primary: node});
};

/**
 * @override
 */
sre.SemanticWalker.prototype.up = function() {
  var parent = this.primaryAttribute(sre.EnrichMathml.Attribute.PARENT);
  if (!parent) return null;
  this.levels.pop();
  var found = this.levels.find(
      function(x) {
        for (var i = 0, node, nodes = x.getNodes(); node = nodes[i]; i++) {
          if (sre.WalkerUtil.getAttribute(
              node, sre.EnrichMathml.Attribute.ID) === parent) {
            return true;
          }
        }
        return false;
      });
  return found;
};

/**
 * @override
 */
sre.SemanticWalker.prototype.down = function() {
  var children = this.nextLevel_();
  if (children.length === 0) {
    return null;
  }
  this.levels.push(children);
  return children[0];
};

/**
 * Computes the next lower level from children and content.
 * @return {!Array.<sre.Focus>} The next lower level.
 * @private
 */
sre.SemanticWalker.prototype.nextLevel_ = function() {
  var children = sre.WalkerUtil.splitAttribute(
      this.primaryAttribute(sre.EnrichMathml.Attribute.CHILDREN));
  var content = sre.WalkerUtil.splitAttribute(
      this.primaryAttribute(sre.EnrichMathml.Attribute.CONTENT));
  if (children.length === 0) return [];
  var primary = /** @type {!Node} */ (this.getFocus().getPrimary());
  var type = sre.WalkerUtil.getAttribute(
      primary, sre.EnrichMathml.Attribute.TYPE);
  var role = sre.WalkerUtil.getAttribute(
      primary, sre.EnrichMathml.Attribute.ROLE);
  return this.combineContentChildren(
      /** @type {!sre.SemanticAttr.Type} */ (type),
      /** @type {!sre.SemanticAttr.Role} */ (role),
      content, children);
};

/**
 * Combines content and children lists depending on semantic type and role.
 * @param {!sre.SemanticAttr.Type} type The semantic type.
 * @param {!sre.SemanticAttr.Role} role The semantic role.
 * @param {!Array.<string>} content The list of content nodes.
 * @param {!Array.<string>} children The list of child nodes.
 * @return {!Array.<sre.Focus>} The list of focus elements.
 */
sre.SemanticWalker.prototype.combineContentChildren = function(
    type, role, content, children) {
  switch (type) {
    case sre.SemanticAttr.Type.RELSEQ:
    case sre.SemanticAttr.Type.INFIXOP:
    case sre.SemanticAttr.Type.MULTIREL:
      return this.makePairList(children, content);
    case sre.SemanticAttr.Type.PREFIXOP:
      return [this.focusFromId_(children[0], content.concat(children))];
    case sre.SemanticAttr.Type.POSTFIXOP:
      return [this.focusFromId_(children[0], children.concat(content))];
    case sre.SemanticAttr.Type.MATRIX:
    case sre.SemanticAttr.Type.VECTOR:
    case sre.SemanticAttr.Type.FENCED:
      return [this.focusFromId_(children[0],
          [content[0], children[0], content[1]])];
    case sre.SemanticAttr.Type.CASES:
      return [this.focusFromId_(children[0],
          [content[0], children[0]])];
    case sre.SemanticAttr.Type.PUNCTUATED:
      if (role === sre.SemanticAttr.Role.TEXT) {
        return children.map(goog.bind(this.singletonFocus_, this));
      }
      //TODO: That needs to be fixed!
      if (children.length === content.length) {
        return content.map(goog.bind(this.singletonFocus_, this));
      }
    console.log('here we are');
      var focusList = this.combinePunctuations(children, content, [], []);
      return focusList;
    case sre.SemanticAttr.Type.APPL:
      return [this.focusFromId_(children[0], [children[0], content[0]]),
        this.singletonFocus_(children[1])];
    case sre.SemanticAttr.Type.ROOT:
      return [this.singletonFocus_(children[1]),
              this.singletonFocus_(children[0])];
    default:
      return children.map(goog.bind(this.singletonFocus_, this));
  }
};

/**
 * Makes a focus list from children of a punctuated element.
 * @param {!Array.<string>} children Child node ids.
 * @param {!Array.<string>} content Content node ids.
 * @param {!Array.<string>} prepunct List of prefix punctuations.
 * @param {!Array.<sre.Focus>} acc Result accumulator.
 * @return {!Array.<sre.Focus>} The list of focuses with paired nodes.
 */
sre.SemanticWalker.prototype.combinePunctuations = function(
    children, content, prepunct, acc) {
  if (children.length === 0) {
    return acc;
  }
  var child = children.shift();
  var cont = content.shift();
  // Case first child element is punctuation.
  // We have a prefix punctuation.
  if (child === cont) {
    prepunct.push(cont);
    return this.combinePunctuations(children, content, prepunct, acc);
  } else {
    // Case first child is not punctuation.
    content.unshift(cont);
    prepunct.push(child);
    // Remaining children are all punctuations.
    if (children.length === content.length) {
      acc.push(this.focusFromId_(child, prepunct.concat(content)));
      return acc;
    } else {
      // Recurse
      acc.push(this.focusFromId_(child, prepunct));
      return this.combinePunctuations(children, content, [], acc);
    }
  }
};

/**
 * Makes pairwise focus structures from two lists.
 * @param {!Array.<string>} children Child nodes of length n.
 * @param {!Array.<string>} content Content nodes of length n - 1.
 * @return {!Array.<sre.Focus>} The list of focuses with paired nodes.
 */
sre.SemanticWalker.prototype.makePairList = function(children, content) {
  if (children.length === 0) return [];
  if (children.length === 1) {
    return [this.singletonFocus_(children[0])];
  }
  var result = [this.singletonFocus_(children.shift())];
  for (var i = 0, l = children.length; i < l; i++) {
    result.push(this.focusFromId_(children[i], [content[i], children[i]]));
  }
  return result;
};

/**
 * @override
 */
sre.SemanticWalker.prototype.left = function() {
  var index = this.levels.indexOf(this.getFocus()) - 1;
  var ids = this.levels.get(index);
  return ids ? ids : null;
};

/**
 * @override
 */
sre.SemanticWalker.prototype.right = function() {
  var index = this.levels.indexOf(this.getFocus()) + 1;
  var ids = this.levels.get(index);
  return ids ? ids : null;
};
<|endoftext|>