<commit_before>"use strict";

var util = require("./util_module.js");
var queue = require("./queue_module.js");
var ring = require("./ring_module.js");
var account = require("./session_entry_module.js");
var account_mgr = require("./session_mgr_module.js");
var link_mgr = require("./link_mgr_module.js");
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var state;

util.init();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + "/clients/util"));
app.use(express.static(__dirname + "/clients/go"));
app.post("/go_msg", processPost);
app.get("/go_msg", processGet);
app.use(processNotFount);
app.use(processFailure);
app.listen(8080);

function processPost(req, res) {
    var my_session, his_session;

    postLogit("processPost", "start");
    state = "processPost start";

    var my_session_id = Number(req.body.session_id);
    my_session = account_mgr.search(req.body.my_name, req.body.his_name, my_session_id);
    if (!my_session) {
        abend("processPost", "null my_session");
        return;
    }
    if (my_session.session_id === 0) {
        abend("processPost", "null my_session = 0");
        return;
    }
    logit("processPost", "link=" + req.body.link_id + " session=" + req.body.session_id + " "  + req.body.my_name + "=>" + req.body.his_name + " " + req.body.data + " " + req.body.xmt_seq + "=" + my_session.up_seq);
    if (req.body.my_name === req.body.his_name) {
        his_session = my_session;
    }
    else {
        his_session = account_mgr.search(req.body.his_name, req.body.my_name, -1);
        if (!his_session) {
            abend("processPost", "null his_session");
            return;
        }
        if (his_session.session_id === 0) {
            abend("processPost", "null his_session = 0");
            return;
        }
    }

    if (req.body.xmt_seq === my_session.up_seq) {
        queue.enqueue(his_session.queue, req.body.data);
        ring.enqueue(his_session.ring, req.body.data);
        my_session.up_seq += 1;
    } else if (req.body.xmt_seq < my_session.up_seq) {
         if (req.body.xmt_seq === 0) {
            queue.enqueue(his_session.queue, req.body.data);
            ring.enqueue(his_session.ring, req.body.data);
            my_session.up_seq = 1;
            logit("processPost", req.body.data + " post " + req.body.xmt_seq + " reset");
        } else {
            logit("processPost", req.body.data + " post " + req.body.xmt_seq + " dropped");
        }
    } else {
        logit("***abend: processPost", req.body.data + " post seq=" + req.body.xmt_seq + " dropped");
    }
    state = "processPost end";
}

function processGet (req, res) {
    if (req.headers.setup_link === "yes") {
        setupLink(req, res);
        return;
    }

    if (req.headers.setup_session === "yes") {
        setupSession(req, res);
        return;
    }

    //logit("processGet ", "link=" + req.headers.session_id + " "  + req.headers.his_name + "=>" + req.headers.my_name);
    state = "processGet start";
    var session_id = Number(req.headers.session_id);
    var my_session = account_mgr.search(req.headers.my_name, req.headers.his_name, session_id);
    if (!my_session) {
        abend("processGet", "null my_session");
        return;
    }
    if (my_session.session_id === 0) {
        abend("processGet", "null my_session = 0");
        return;
    }
    if (!my_session.queue) {
        abend("processGet", "null queue");
        return;
    }
    res.type('application/json');
    state = "get 2000";
    var data = queue.dequeue(my_session.queue);
    state = "get 3000";
    var data1 = ring.dequeue(my_session.ring);
    state = "get 4000";
    if (data !== data1) {
        logit("*****Abend: processGet", "queue and ring not match");
    }
    if (!data) {
        //logit("processGet", "null data");
        return;
    }
    if (!data1) {
        //logti("processGet", "null data1");
        return;
    }

    logit("processGet ", "link=" + req.headers.link_id + " session=" + req.headers.session_id + " "  + req.headers.his_name + "=>" + req.headers.my_name + " " + data);
    res.send(data);
    state = "processGet end";
}

function setupLink (req, res) {
    state = "setupLink start";
    var link, link_id_str;
    link = link_mgr.search_and_create(req.headers.my_name, 0);
    if (!link) {
        abend("setupLink", "null link");
        return;
    }
    link_id_str = "" + link.link_id;
    res.send(link_id_str);
    logit("setupLink  ", "my_name=" + req.headers.my_name + " link=" + link.link_id);
    state = "setupLink end";
}

function setupSession (req, res) {
    state = "setupSession start";
    var session, session_id_str;
    session = account_mgr.search_and_create(req.headers.my_name, req.headers.his_name, 0);
    if (!session) {
        abend("setupSession", "null session");
        return;
    }
    session_id_str = "" + session.session_id;
    res.send(session_id_str);
    logit("setupSession", req.headers.his_name + "=>" + req.headers.my_name);
    state = "setupSession end";
}

function processNotFount (req, res) {
    console.log("use" + req);
    res.type('text/plain');
    res.status(404);
    res.send('Not Found');
}

function processFailure (err, req, res, next) {
    console.log("express error: " + state);
}

function postLogit(str1_val, str2_val) {
    var debugPost = false;
    if (debugPost) {
        logit(str1_val, str2_val);
    }
}

function logit (str1_val, str2_val) {
    return util.utilLogit("NodeMain." + str1_val, str2_val);
}

function abend (str1_val, str2_val) {
    return util.utilAbend("NodeMain." + str1_val, str2_val);
}
<commit_msg>dummy<commit_after>"use strict";

var util = require("./util_module.js");
var queue = require("./queue_module.js");
var ring = require("./ring_module.js");
var account_mgr = require("./session_mgr_module.js");
var link_mgr = require("./link_mgr_module.js");
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var state;

util.init();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + "/clients/util"));
app.use(express.static(__dirname + "/clients/go"));
app.post("/go_msg", processPost);
app.get("/go_msg", processGet);
app.use(processNotFount);
app.use(processFailure);
app.listen(8080);

function processPost(req, res) {
    var my_session, his_session;

    postLogit("processPost", "start");
    state = "processPost start";

    var my_session_id = Number(req.body.session_id);
    my_session = account_mgr.search(req.body.my_name, req.body.his_name, my_session_id);
    if (!my_session) {
        abend("processPost", "null my_session");
        return;
    }
    if (my_session.session_id === 0) {
        abend("processPost", "null my_session = 0");
        return;
    }
    logit("processPost", "link=" + req.body.link_id + " session=" + req.body.session_id + " "  + req.body.my_name + "=>" + req.body.his_name + " " + req.body.data + " " + req.body.xmt_seq + "=" + my_session.up_seq);
    if (req.body.my_name === req.body.his_name) {
        his_session = my_session;
    }
    else {
        his_session = account_mgr.search(req.body.his_name, req.body.my_name, -1);
        if (!his_session) {
            abend("processPost", "null his_session");
            return;
        }
        if (his_session.session_id === 0) {
            abend("processPost", "null his_session = 0");
            return;
        }
    }

    if (req.body.xmt_seq === my_session.up_seq) {
        queue.enqueue(his_session.queue, req.body.data);
        ring.enqueue(his_session.ring, req.body.data);
        my_session.up_seq += 1;
    } else if (req.body.xmt_seq < my_session.up_seq) {
         if (req.body.xmt_seq === 0) {
            queue.enqueue(his_session.queue, req.body.data);
            ring.enqueue(his_session.ring, req.body.data);
            my_session.up_seq = 1;
            logit("processPost", req.body.data + " post " + req.body.xmt_seq + " reset");
        } else {
            logit("processPost", req.body.data + " post " + req.body.xmt_seq + " dropped");
        }
    } else {
        logit("***abend: processPost", req.body.data + " post seq=" + req.body.xmt_seq + " dropped");
    }
    state = "processPost end";
}

function processGet (req, res) {
    if (req.headers.setup_link === "yes") {
        setupLink(req, res);
        return;
    }

    if (req.headers.setup_session === "yes") {
        setupSession(req, res);
        return;
    }

    //logit("processGet ", "link=" + req.headers.session_id + " "  + req.headers.his_name + "=>" + req.headers.my_name);
    state = "processGet start";
    var session_id = Number(req.headers.session_id);
    var my_session = account_mgr.search(req.headers.my_name, req.headers.his_name, session_id);
    if (!my_session) {
        abend("processGet", "null my_session");
        return;
    }
    if (my_session.session_id === 0) {
        abend("processGet", "null my_session = 0");
        return;
    }
    if (!my_session.queue) {
        abend("processGet", "null queue");
        return;
    }
    res.type('application/json');
    state = "get 2000";
    var data = queue.dequeue(my_session.queue);
    state = "get 3000";
    var data1 = ring.dequeue(my_session.ring);
    state = "get 4000";
    if (data !== data1) {
        logit("*****Abend: processGet", "queue and ring not match");
    }
    if (!data) {
        //logit("processGet", "null data");
        return;
    }
    if (!data1) {
        //logti("processGet", "null data1");
        return;
    }

    logit("processGet ", "link=" + req.headers.link_id + " session=" + req.headers.session_id + " "  + req.headers.his_name + "=>" + req.headers.my_name + " " + data);
    res.send(data);
    state = "processGet end";
}

function setupLink (req, res) {
    state = "setupLink start";
    var link, link_id_str;
    link = link_mgr.search_and_create(req.headers.my_name, 0);
    if (!link) {
        abend("setupLink", "null link");
        return;
    }
    link_id_str = "" + link.link_id;
    res.send(link_id_str);
    logit("setupLink  ", "my_name=" + req.headers.my_name + " link=" + link.link_id);
    state = "setupLink end";
}

function setupSession (req, res) {
    state = "setupSession start";
    var session, session_id_str;
    session = account_mgr.search_and_create(req.headers.my_name, req.headers.his_name, 0);
    if (!session) {
        abend("setupSession", "null session");
        return;
    }
    session_id_str = "" + session.session_id;
    res.send(session_id_str);
    logit("setupSession", req.headers.his_name + "=>" + req.headers.my_name);
    state = "setupSession end";
}

function processNotFount (req, res) {
    console.log("use" + req);
    res.type('text/plain');
    res.status(404);
    res.send('Not Found');
}

function processFailure (err, req, res, next) {
    console.log("express error: " + state);
}

function postLogit(str1_val, str2_val) {
    var debugPost = false;
    if (debugPost) {
        logit(str1_val, str2_val);
    }
}

function logit (str1_val, str2_val) {
    return util.utilLogit("NodeMain." + str1_val, str2_val);
}

function abend (str1_val, str2_val) {
    return util.utilAbend("NodeMain." + str1_val, str2_val);
}
<|endoftext|>


<commit_before>/**
 * @module ol/source/GeoTIFF
 */
import DataTile from './DataTile.js';
import State from './State.js';
import TileGrid from '../tilegrid/TileGrid.js';
import {Pool, fromUrl as tiffFromUrl, fromUrls as tiffFromUrls} from 'geotiff';
import {create as createDecoderWorker} from '../worker/geotiff-decoder.js';
import {getIntersection} from '../extent.js';
import {get as getProjection} from '../proj.js';
import {toSize} from '../size.js';

/**
 * @typedef {Object} SourceInfo
 * @property {string} url URL for the source GeoTIFF.
 * @property {Array<string>} [overviews] List of any overview URLs.
 * @property {number} [min=0] The minimum source data value.  Rendered values are scaled from 0 to 1 based on
 * the configured min and max.
 * @property {number} [max] The maximum source data value.  Rendered values are scaled from 0 to 1 based on
 * the configured min and max.
 * @property {number} [nodata] Values to discard. When provided, an additional band (alpha) will be added
 * to the data.
 * @property {Array<number>} [bands] Indices of the bands to be read from. If not provided, all bands will
 * be read. If, for example, a GeoTIFF has red, green, blue and near-infrared bands and you only need the
 * infrared band, configure `bands: [3]`.
 */

let workerPool;
function getWorkerPool() {
  if (!workerPool) {
    workerPool = new Pool(undefined, createDecoderWorker());
  }
  return workerPool;
}

/**
 * @param {import("geotiff/src/geotiff.js").GeoTIFF|import("geotiff/src/geotiff.js").MultiGeoTIFF} tiff A GeoTIFF.
 * @return {Promise<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} Resolves to a list of images.
 */
function getImagesForTIFF(tiff) {
  return tiff.getImageCount().then(function (count) {
    const requests = new Array(count);
    for (let i = 0; i < count; ++i) {
      requests[i] = tiff.getImage(i);
    }
    return Promise.all(requests);
  });
}

/**
 * @param {SourceInfo} source The GeoTIFF source.
 * @return {Promise<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} Resolves to a list of images.
 */
function getImagesForSource(source) {
  let request;
  if (source.overviews) {
    request = tiffFromUrls(source.url, source.overviews);
  } else {
    request = tiffFromUrl(source.url);
  }
  return request.then(getImagesForTIFF);
}

/**
 * @param {number|Array<number>|Array<Array<number>>} expected Expected value.
 * @param {number|Array<number>|Array<Array<number>>} got Actual value.
 * @param {number} tolerance Accepted tolerance in fraction of expected between expected and got.
 * @param {string} message The error message.
 */
function assertEqual(expected, got, tolerance, message) {
  if (Array.isArray(expected)) {
    const length = expected.length;
    if (!Array.isArray(got) || length != got.length) {
      throw new Error(message);
    }
    for (let i = 0; i < length; ++i) {
      assertEqual(expected[i], got[i], tolerance, message);
    }
    return;
  }

  got = /** @type {number} */ (got);
  if (Math.abs(expected - got) > tolerance * expected) {
    throw new Error(message);
  }
}

/**
 * @param {Array} array The data array.
 * @return {number} The minimum value.
 */
function getMinForDataType(array) {
  if (array instanceof Int8Array) {
    return -128;
  }
  if (array instanceof Int16Array) {
    return -32768;
  }
  if (array instanceof Int32Array) {
    return -2147483648;
  }
  if (array instanceof Float32Array) {
    return 1.2e-38;
  }
  return 0;
}

/**
 * @param {Array} array The data array.
 * @return {number} The maximum value.
 */
function getMaxForDataType(array) {
  if (array instanceof Int8Array) {
    return 127;
  }
  if (array instanceof Uint8Array) {
    return 255;
  }
  if (array instanceof Uint8ClampedArray) {
    return 255;
  }
  if (array instanceof Int16Array) {
    return 32767;
  }
  if (array instanceof Uint16Array) {
    return 65535;
  }
  if (array instanceof Int32Array) {
    return 2147483647;
  }
  if (array instanceof Uint32Array) {
    return 4294967295;
  }
  if (array instanceof Float32Array) {
    return 3.4e38;
  }
  return 255;
}

/**
 * @typedef {Object} Options
 * @property {Array<SourceInfo>} sources List of information about GeoTIFF sources.
 * Multiple sources can be combined when their resolution sets are equal after applying a scale.
 * The list of sources defines a mapping between input bands as they are read from each GeoTIFF, and
 * the output bands that are provided by data tiles. To control which bands to read from each GeoTIFF,
 * use the {@link import("./GeoTIFF.js").SourceInfo bands} property. If, for example, you spedify two
 * sources, one with 3 bands and {@link import("./GeoTIFF.js").SourceInfo nodata} configured, and
 * another with 1 band, the resulting data tiles will have 5 bands: 3 from the first source, 1 alpha
 * band from the first source, and 1 band from the second source.
 */

/**
 * @classdesc
 * A source for working with GeoTIFF data.
 * @api
 */
class GeoTIFFSource extends DataTile {
  /**
   * @param {Options} options Data tile options.
   */
  constructor(options) {
    super({
      state: State.LOADING,
      tileGrid: null,
      projection: null,
    });

    /**
     * @type {Array<SourceInfo>}
     * @private
     */
    this.sourceInfo_ = options.sources;

    const numSources = this.sourceInfo_.length;

    /**
     * @type {Array<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>}
     * @private
     */
    this.sourceImagery_ = new Array(numSources);

    /**
     * @type {Array<number>}
     * @private
     */
    this.resolutionFactors_ = new Array(numSources);

    /**
     * @type {Array<number>}
     * @private
     */
    this.samplesPerPixel_;

    /**
     * @type {boolean}
     * @private
     */
    this.addAlpha_ = false;

    /**
     * @type {Error}
     * @private
     */
    this.error_ = null;

    this.setKey(this.sourceInfo_.map((source) => source.url).join(','));

    const self = this;
    const requests = new Array(numSources);
    for (let i = 0; i < numSources; ++i) {
      requests[i] = getImagesForSource(this.sourceInfo_[i]);
    }
    Promise.all(requests)
      .then(function (sources) {
        self.configure_(sources);
      })
      .catch(function (error) {
        self.error_ = error;
        self.setState(State.ERROR);
      });
  }

  /**
   * @return {Error} A source loading error. When the source state is `error`, use this function
   * to get more information about the error. To debug a faulty configuration, you may want to use
   * a listener like
   * ```js
   * geotiffSource.on('change', () => {
   *   if (geotiffSource.getState() === 'error') {
   *     console.error(geotiffSource.getError());
   *   }
   * });
   * ```
   */
  getError() {
    return this.error_;
  }

  /**
   * Configure the tile grid based on images within the source GeoTIFFs.  Each GeoTIFF
   * must have the same internal tiled structure.
   * @param {Array<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} sources Each source is a list of images
   * from a single GeoTIFF.
   * @private
   */
  configure_(sources) {
    let extent;
    let origin;
    let tileSizes;
    let resolutions;
    const samplesPerPixel = new Array(sources.length);
    let minZoom = 0;

    const sourceCount = sources.length;
    for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
      const images = sources[sourceIndex];
      const imageCount = images.length;

      let sourceExtent;
      let sourceOrigin;
      const sourceTileSizes = new Array(imageCount);
      const sourceResolutions = new Array(imageCount);

      for (let imageIndex = 0; imageIndex < imageCount; ++imageIndex) {
        const image = images[imageIndex];
        const wantedSamples = this.sourceInfo_[sourceIndex].bands;
        samplesPerPixel[sourceIndex] = wantedSamples
          ? wantedSamples.length
          : image.getSamplesPerPixel();
        const level = imageCount - (imageIndex + 1);

        if (!sourceExtent) {
          sourceExtent = image.getBoundingBox();
        }

        if (!sourceOrigin) {
          sourceOrigin = image.getOrigin().slice(0, 2);
        }

        sourceResolutions[level] = image.getResolution(images[0])[0];
        sourceTileSizes[level] = [image.getTileWidth(), image.getTileHeight()];
      }

      if (!extent) {
        extent = sourceExtent;
      } else {
        getIntersection(extent, sourceExtent);
      }

      if (!origin) {
        origin = sourceOrigin;
      } else {
        const message = `Origin mismatch for source ${sourceIndex}, got [${sourceOrigin}] but expected [${origin}]`;
        assertEqual(origin, sourceOrigin, 0, message);
      }

      if (!resolutions) {
        resolutions = sourceResolutions;
        this.resolutionFactors_[sourceIndex] = 1;
      } else {
        if (resolutions.length - minZoom > sourceResolutions.length) {
          minZoom = resolutions.length - sourceResolutions.length;
        }
        const resolutionFactor =
          resolutions[resolutions.length - 1] /
          sourceResolutions[sourceResolutions.length - 1];
        this.resolutionFactors_[sourceIndex] = resolutionFactor;
        const scaledSourceResolutions = sourceResolutions.map(
          (resolution) => (resolution *= resolutionFactor)
        );
        const message = `Resolution mismatch for source ${sourceIndex}, got [${scaledSourceResolutions}] but expected [${resolutions}]`;
        assertEqual(
          resolutions.slice(minZoom, resolutions.length),
          scaledSourceResolutions,
          0.005,
          message
        );
      }

      if (!tileSizes) {
        tileSizes = sourceTileSizes;
      } else {
        assertEqual(
          tileSizes.slice(minZoom, tileSizes.length),
          sourceTileSizes,
          0,
          `Tile size mismatch for source ${sourceIndex}`
        );
      }

      this.sourceImagery_[sourceIndex] = images.reverse();
    }

    for (let i = 0, ii = this.sourceImagery_.length; i < ii; ++i) {
      const sourceImagery = this.sourceImagery_[i];
      while (sourceImagery.length < resolutions.length) {
        sourceImagery.unshift(undefined);
      }
    }

    if (!this.getProjection()) {
      const firstImage = sources[0][0];
      if (firstImage.geoKeys) {
        const code =
          firstImage.geoKeys.ProjectedCSTypeGeoKey ||
          firstImage.geoKeys.GeographicTypeGeoKey;
        if (code) {
          this.projection = getProjection(`EPSG:${code}`);
        }
      }
    }

    this.samplesPerPixel_ = samplesPerPixel;
    const sourceInfo = this.sourceInfo_;
    for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
      if (sourceInfo[sourceIndex].nodata !== undefined) {
        this.addAlpha_ = true;
        break;
      }
    }
    const additionalBands = this.addAlpha_ ? 1 : 0;
    this.bandCount =
      samplesPerPixel.reduce((accumulator, value) => {
        accumulator += value;
        return accumulator;
      }, 0) + additionalBands;

    const tileGrid = new TileGrid({
      extent: extent,
      minZoom: minZoom,
      origin: origin,
      resolutions: resolutions,
      tileSizes: tileSizes,
    });

    this.tileGrid = tileGrid;

    this.setLoader(this.loadTile_.bind(this));
    this.setState(State.READY);
  }

  loadTile_(z, x, y) {
    const size = toSize(this.tileGrid.getTileSize(z));

    const sourceCount = this.sourceImagery_.length;
    const requests = new Array(sourceCount);
    const addAlpha = this.addAlpha_;
    const bandCount = this.bandCount;
    const samplesPerPixel = this.samplesPerPixel_;
    const sourceInfo = this.sourceInfo_;
    for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
      const source = sourceInfo[sourceIndex];
      const resolutionFactor = this.resolutionFactors_[sourceIndex];
      const pixelBounds = [
        Math.round(x * (size[0] * resolutionFactor)),
        Math.round(y * (size[1] * resolutionFactor)),
        Math.round((x + 1) * (size[0] * resolutionFactor)),
        Math.round((y + 1) * (size[1] * resolutionFactor)),
      ];
      const image = this.sourceImagery_[sourceIndex][z];
      requests[sourceIndex] = image.readRasters({
        window: pixelBounds,
        width: size[0],
        height: size[1],
        samples: source.bands,
        fillValue: source.nodata,
        pool: getWorkerPool(),
      });
    }

    const pixelCount = size[0] * size[1];
    const dataLength = pixelCount * bandCount;

    return Promise.all(requests).then(function (sourceSamples) {
      const data = new Uint8ClampedArray(dataLength);
      let dataIndex = 0;
      for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) {
        let transparent = addAlpha;
        for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
          const source = sourceInfo[sourceIndex];
          let min = source.min;
          if (min === undefined) {
            min = getMinForDataType(sourceSamples[sourceIndex][0]);
          }
          let max = source.max;
          if (max === undefined) {
            max = getMaxForDataType(sourceSamples[sourceIndex][0]);
          }

          const gain = 255 / (max - min);
          const bias = -min * gain;

          const nodata = source.nodata;

          for (
            let sampleIndex = 0;
            sampleIndex < samplesPerPixel[sourceIndex];
            ++sampleIndex
          ) {
            const sourceValue =
              sourceSamples[sourceIndex][sampleIndex][pixelIndex];

            const value = gain * sourceValue + bias;
            if (!addAlpha) {
              data[dataIndex] = value;
            } else {
              if (sourceValue !== nodata) {
                transparent = false;
                data[dataIndex] = value;
              }
            }
            dataIndex++;
          }
        }
        if (addAlpha) {
          if (!transparent) {
            data[dataIndex] = 255;
          }
          dataIndex++;
        }
      }

      return data;
    });
  }
}

export default GeoTIFFSource;
<commit_msg>Modify the source extent<commit_after>/**
 * @module ol/source/GeoTIFF
 */
import DataTile from './DataTile.js';
import State from './State.js';
import TileGrid from '../tilegrid/TileGrid.js';
import {Pool, fromUrl as tiffFromUrl, fromUrls as tiffFromUrls} from 'geotiff';
import {create as createDecoderWorker} from '../worker/geotiff-decoder.js';
import {getIntersection} from '../extent.js';
import {get as getProjection} from '../proj.js';
import {toSize} from '../size.js';

/**
 * @typedef {Object} SourceInfo
 * @property {string} url URL for the source GeoTIFF.
 * @property {Array<string>} [overviews] List of any overview URLs.
 * @property {number} [min=0] The minimum source data value.  Rendered values are scaled from 0 to 1 based on
 * the configured min and max.
 * @property {number} [max] The maximum source data value.  Rendered values are scaled from 0 to 1 based on
 * the configured min and max.
 * @property {number} [nodata] Values to discard. When provided, an additional band (alpha) will be added
 * to the data.
 * @property {Array<number>} [bands] Indices of the bands to be read from. If not provided, all bands will
 * be read. If, for example, a GeoTIFF has red, green, blue and near-infrared bands and you only need the
 * infrared band, configure `bands: [3]`.
 */

let workerPool;
function getWorkerPool() {
  if (!workerPool) {
    workerPool = new Pool(undefined, createDecoderWorker());
  }
  return workerPool;
}

/**
 * @param {import("geotiff/src/geotiff.js").GeoTIFF|import("geotiff/src/geotiff.js").MultiGeoTIFF} tiff A GeoTIFF.
 * @return {Promise<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} Resolves to a list of images.
 */
function getImagesForTIFF(tiff) {
  return tiff.getImageCount().then(function (count) {
    const requests = new Array(count);
    for (let i = 0; i < count; ++i) {
      requests[i] = tiff.getImage(i);
    }
    return Promise.all(requests);
  });
}

/**
 * @param {SourceInfo} source The GeoTIFF source.
 * @return {Promise<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} Resolves to a list of images.
 */
function getImagesForSource(source) {
  let request;
  if (source.overviews) {
    request = tiffFromUrls(source.url, source.overviews);
  } else {
    request = tiffFromUrl(source.url);
  }
  return request.then(getImagesForTIFF);
}

/**
 * @param {number|Array<number>|Array<Array<number>>} expected Expected value.
 * @param {number|Array<number>|Array<Array<number>>} got Actual value.
 * @param {number} tolerance Accepted tolerance in fraction of expected between expected and got.
 * @param {string} message The error message.
 */
function assertEqual(expected, got, tolerance, message) {
  if (Array.isArray(expected)) {
    const length = expected.length;
    if (!Array.isArray(got) || length != got.length) {
      throw new Error(message);
    }
    for (let i = 0; i < length; ++i) {
      assertEqual(expected[i], got[i], tolerance, message);
    }
    return;
  }

  got = /** @type {number} */ (got);
  if (Math.abs(expected - got) > tolerance * expected) {
    throw new Error(message);
  }
}

/**
 * @param {Array} array The data array.
 * @return {number} The minimum value.
 */
function getMinForDataType(array) {
  if (array instanceof Int8Array) {
    return -128;
  }
  if (array instanceof Int16Array) {
    return -32768;
  }
  if (array instanceof Int32Array) {
    return -2147483648;
  }
  if (array instanceof Float32Array) {
    return 1.2e-38;
  }
  return 0;
}

/**
 * @param {Array} array The data array.
 * @return {number} The maximum value.
 */
function getMaxForDataType(array) {
  if (array instanceof Int8Array) {
    return 127;
  }
  if (array instanceof Uint8Array) {
    return 255;
  }
  if (array instanceof Uint8ClampedArray) {
    return 255;
  }
  if (array instanceof Int16Array) {
    return 32767;
  }
  if (array instanceof Uint16Array) {
    return 65535;
  }
  if (array instanceof Int32Array) {
    return 2147483647;
  }
  if (array instanceof Uint32Array) {
    return 4294967295;
  }
  if (array instanceof Float32Array) {
    return 3.4e38;
  }
  return 255;
}

/**
 * @typedef {Object} Options
 * @property {Array<SourceInfo>} sources List of information about GeoTIFF sources.
 * Multiple sources can be combined when their resolution sets are equal after applying a scale.
 * The list of sources defines a mapping between input bands as they are read from each GeoTIFF, and
 * the output bands that are provided by data tiles. To control which bands to read from each GeoTIFF,
 * use the {@link import("./GeoTIFF.js").SourceInfo bands} property. If, for example, you spedify two
 * sources, one with 3 bands and {@link import("./GeoTIFF.js").SourceInfo nodata} configured, and
 * another with 1 band, the resulting data tiles will have 5 bands: 3 from the first source, 1 alpha
 * band from the first source, and 1 band from the second source.
 */

/**
 * @classdesc
 * A source for working with GeoTIFF data.
 * @api
 */
class GeoTIFFSource extends DataTile {
  /**
   * @param {Options} options Data tile options.
   */
  constructor(options) {
    super({
      state: State.LOADING,
      tileGrid: null,
      projection: null,
    });

    /**
     * @type {Array<SourceInfo>}
     * @private
     */
    this.sourceInfo_ = options.sources;

    const numSources = this.sourceInfo_.length;

    /**
     * @type {Array<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>}
     * @private
     */
    this.sourceImagery_ = new Array(numSources);

    /**
     * @type {Array<number>}
     * @private
     */
    this.resolutionFactors_ = new Array(numSources);

    /**
     * @type {Array<number>}
     * @private
     */
    this.samplesPerPixel_;

    /**
     * @type {boolean}
     * @private
     */
    this.addAlpha_ = false;

    /**
     * @type {Error}
     * @private
     */
    this.error_ = null;

    this.setKey(this.sourceInfo_.map((source) => source.url).join(','));

    const self = this;
    const requests = new Array(numSources);
    for (let i = 0; i < numSources; ++i) {
      requests[i] = getImagesForSource(this.sourceInfo_[i]);
    }
    Promise.all(requests)
      .then(function (sources) {
        self.configure_(sources);
      })
      .catch(function (error) {
        self.error_ = error;
        self.setState(State.ERROR);
      });
  }

  /**
   * @return {Error} A source loading error. When the source state is `error`, use this function
   * to get more information about the error. To debug a faulty configuration, you may want to use
   * a listener like
   * ```js
   * geotiffSource.on('change', () => {
   *   if (geotiffSource.getState() === 'error') {
   *     console.error(geotiffSource.getError());
   *   }
   * });
   * ```
   */
  getError() {
    return this.error_;
  }

  /**
   * Configure the tile grid based on images within the source GeoTIFFs.  Each GeoTIFF
   * must have the same internal tiled structure.
   * @param {Array<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} sources Each source is a list of images
   * from a single GeoTIFF.
   * @private
   */
  configure_(sources) {
    let extent;
    let origin;
    let tileSizes;
    let resolutions;
    const samplesPerPixel = new Array(sources.length);
    let minZoom = 0;

    const sourceCount = sources.length;
    for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
      const images = sources[sourceIndex];
      const imageCount = images.length;

      let sourceExtent;
      let sourceOrigin;
      const sourceTileSizes = new Array(imageCount);
      const sourceResolutions = new Array(imageCount);

      for (let imageIndex = 0; imageIndex < imageCount; ++imageIndex) {
        const image = images[imageIndex];
        const wantedSamples = this.sourceInfo_[sourceIndex].bands;
        samplesPerPixel[sourceIndex] = wantedSamples
          ? wantedSamples.length
          : image.getSamplesPerPixel();
        const level = imageCount - (imageIndex + 1);

        if (!sourceExtent) {
          sourceExtent = image.getBoundingBox();
        }

        if (!sourceOrigin) {
          sourceOrigin = image.getOrigin().slice(0, 2);
        }

        sourceResolutions[level] = image.getResolution(images[0])[0];
        sourceTileSizes[level] = [image.getTileWidth(), image.getTileHeight()];
      }

      if (!extent) {
        extent = sourceExtent;
      } else {
        getIntersection(extent, sourceExtent, extent);
      }

      if (!origin) {
        origin = sourceOrigin;
      } else {
        const message = `Origin mismatch for source ${sourceIndex}, got [${sourceOrigin}] but expected [${origin}]`;
        assertEqual(origin, sourceOrigin, 0, message);
      }

      if (!resolutions) {
        resolutions = sourceResolutions;
        this.resolutionFactors_[sourceIndex] = 1;
      } else {
        if (resolutions.length - minZoom > sourceResolutions.length) {
          minZoom = resolutions.length - sourceResolutions.length;
        }
        const resolutionFactor =
          resolutions[resolutions.length - 1] /
          sourceResolutions[sourceResolutions.length - 1];
        this.resolutionFactors_[sourceIndex] = resolutionFactor;
        const scaledSourceResolutions = sourceResolutions.map(
          (resolution) => (resolution *= resolutionFactor)
        );
        const message = `Resolution mismatch for source ${sourceIndex}, got [${scaledSourceResolutions}] but expected [${resolutions}]`;
        assertEqual(
          resolutions.slice(minZoom, resolutions.length),
          scaledSourceResolutions,
          0.005,
          message
        );
      }

      if (!tileSizes) {
        tileSizes = sourceTileSizes;
      } else {
        assertEqual(
          tileSizes.slice(minZoom, tileSizes.length),
          sourceTileSizes,
          0,
          `Tile size mismatch for source ${sourceIndex}`
        );
      }

      this.sourceImagery_[sourceIndex] = images.reverse();
    }

    for (let i = 0, ii = this.sourceImagery_.length; i < ii; ++i) {
      const sourceImagery = this.sourceImagery_[i];
      while (sourceImagery.length < resolutions.length) {
        sourceImagery.unshift(undefined);
      }
    }

    if (!this.getProjection()) {
      const firstImage = sources[0][0];
      if (firstImage.geoKeys) {
        const code =
          firstImage.geoKeys.ProjectedCSTypeGeoKey ||
          firstImage.geoKeys.GeographicTypeGeoKey;
        if (code) {
          this.projection = getProjection(`EPSG:${code}`);
        }
      }
    }

    this.samplesPerPixel_ = samplesPerPixel;
    const sourceInfo = this.sourceInfo_;
    for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
      if (sourceInfo[sourceIndex].nodata !== undefined) {
        this.addAlpha_ = true;
        break;
      }
    }
    const additionalBands = this.addAlpha_ ? 1 : 0;
    this.bandCount =
      samplesPerPixel.reduce((accumulator, value) => {
        accumulator += value;
        return accumulator;
      }, 0) + additionalBands;

    const tileGrid = new TileGrid({
      extent: extent,
      minZoom: minZoom,
      origin: origin,
      resolutions: resolutions,
      tileSizes: tileSizes,
    });

    this.tileGrid = tileGrid;

    this.setLoader(this.loadTile_.bind(this));
    this.setState(State.READY);
  }

  loadTile_(z, x, y) {
    const size = toSize(this.tileGrid.getTileSize(z));

    const sourceCount = this.sourceImagery_.length;
    const requests = new Array(sourceCount);
    const addAlpha = this.addAlpha_;
    const bandCount = this.bandCount;
    const samplesPerPixel = this.samplesPerPixel_;
    const sourceInfo = this.sourceInfo_;
    for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
      const source = sourceInfo[sourceIndex];
      const resolutionFactor = this.resolutionFactors_[sourceIndex];
      const pixelBounds = [
        Math.round(x * (size[0] * resolutionFactor)),
        Math.round(y * (size[1] * resolutionFactor)),
        Math.round((x + 1) * (size[0] * resolutionFactor)),
        Math.round((y + 1) * (size[1] * resolutionFactor)),
      ];
      const image = this.sourceImagery_[sourceIndex][z];
      requests[sourceIndex] = image.readRasters({
        window: pixelBounds,
        width: size[0],
        height: size[1],
        samples: source.bands,
        fillValue: source.nodata,
        pool: getWorkerPool(),
      });
    }

    const pixelCount = size[0] * size[1];
    const dataLength = pixelCount * bandCount;

    return Promise.all(requests).then(function (sourceSamples) {
      const data = new Uint8ClampedArray(dataLength);
      let dataIndex = 0;
      for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) {
        let transparent = addAlpha;
        for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
          const source = sourceInfo[sourceIndex];
          let min = source.min;
          if (min === undefined) {
            min = getMinForDataType(sourceSamples[sourceIndex][0]);
          }
          let max = source.max;
          if (max === undefined) {
            max = getMaxForDataType(sourceSamples[sourceIndex][0]);
          }

          const gain = 255 / (max - min);
          const bias = -min * gain;

          const nodata = source.nodata;

          for (
            let sampleIndex = 0;
            sampleIndex < samplesPerPixel[sourceIndex];
            ++sampleIndex
          ) {
            const sourceValue =
              sourceSamples[sourceIndex][sampleIndex][pixelIndex];

            const value = gain * sourceValue + bias;
            if (!addAlpha) {
              data[dataIndex] = value;
            } else {
              if (sourceValue !== nodata) {
                transparent = false;
                data[dataIndex] = value;
              }
            }
            dataIndex++;
          }
        }
        if (addAlpha) {
          if (!transparent) {
            data[dataIndex] = 255;
          }
          dataIndex++;
        }
      }

      return data;
    });
  }
}

export default GeoTIFFSource;
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

(function(scope) {

  function consumeShadow(string) {
    var shadow = {
      inset: false,
      lengths: [],
      color: null,
    };
    function consumePart(string) {
      var result = scope.consumeToken(/^inset/i, string);
      if (result) {
        shadow.inset = true;
        return result;
      }
      var result = scope.consumeLengthOrPercent(string);
      if (result) {
        shadow.lengths.push(result[0]);
        return result;
      }
      var result = scope.consumeColor(string);
      if (result) {
        shadow.color = result[0];
        return result;
      }
    }
    var result = scope.consumeRepeated(consumePart, /^/, string);
    if (result && result[0].length) {
      return [shadow, result[1]];
    }
  }

  function parseShadowList(string) {
    var result = scope.consumeRepeated(consumeShadow, /^,/, string);
    if (result && result[1] == '') {
      return result[0];
    }
  }

  function mergeShadow(left, right) {
    while(left.lengths.length < Math.max(left.lengths.length, right.lengths.length))
      left.lengths.push({px: 0});
    while(right.lengths.length < Math.max(left.lengths.length, right.lengths.length))
      right.lengths.push({px: 0});

    if (left.inset != right.inset || !!left.color != !!right.color) {
      return;
    }
    var lengthReconstitution = [];
    var colorReconstitution;
    var matchingLeft = [[], 0];
    var matchingRight = [[], 0];
    for (var i = 0; i < left.lengths.length; i++) {
      var mergedDimensions = scope.mergeDimensions(left.lengths[i], right.lengths[i], i == 2);
      matchingLeft[0].push(mergedDimensions[0]);
      matchingRight[0].push(mergedDimensions[1]);
      lengthReconstitution.push(mergedDimensions[2]);
    }
    if (left.color && right.color) {
      var mergedColor = scope.mergeColors(left.color, right.color);
      matchingLeft[1] = mergedColor[0];
      matchingRight[1] = mergedColor[1];
      colorReconstitution = mergedColor[2];
    }
    return [matchingLeft, matchingRight, function(value) {
      var result = left.inset ? 'inset ' : ' ';
      for (var i = 0; i < lengthReconstitution.length; i++) {
        result += lengthReconstitution[i](value[0][i]) + ' ';
      }
      if (colorReconstitution) {
        result += colorReconstitution(value[1]);
      }
      return result;
    }];
  }

  var mergeShadowList = scope.mergeNestedRepeatedShadow.bind(null, mergeShadow, ', ');
  scope.addPropertiesHandler(parseShadowList, mergeShadowList, ['box-shadow', 'text-shadow']);

})(webAnimationsMinifill);
<commit_msg>Linter<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

(function(scope) {

  function consumeShadow(string) {
    var shadow = {
      inset: false,
      lengths: [],
      color: null,
    };
    function consumePart(string) {
      var result = scope.consumeToken(/^inset/i, string);
      if (result) {
        shadow.inset = true;
        return result;
      }
      var result = scope.consumeLengthOrPercent(string);
      if (result) {
        shadow.lengths.push(result[0]);
        return result;
      }
      var result = scope.consumeColor(string);
      if (result) {
        shadow.color = result[0];
        return result;
      }
    }
    var result = scope.consumeRepeated(consumePart, /^/, string);
    if (result && result[0].length) {
      return [shadow, result[1]];
    }
  }

  function parseShadowList(string) {
    var result = scope.consumeRepeated(consumeShadow, /^,/, string);
    if (result && result[1] == '') {
      return result[0];
    }
  }

  function mergeShadow(left, right) {
    while (left.lengths.length < Math.max(left.lengths.length, right.lengths.length))
      left.lengths.push({px: 0});
    while (right.lengths.length < Math.max(left.lengths.length, right.lengths.length))
      right.lengths.push({px: 0});

    if (left.inset != right.inset || !!left.color != !!right.color) {
      return;
    }
    var lengthReconstitution = [];
    var colorReconstitution;
    var matchingLeft = [[], 0];
    var matchingRight = [[], 0];
    for (var i = 0; i < left.lengths.length; i++) {
      var mergedDimensions = scope.mergeDimensions(left.lengths[i], right.lengths[i], i == 2);
      matchingLeft[0].push(mergedDimensions[0]);
      matchingRight[0].push(mergedDimensions[1]);
      lengthReconstitution.push(mergedDimensions[2]);
    }
    if (left.color && right.color) {
      var mergedColor = scope.mergeColors(left.color, right.color);
      matchingLeft[1] = mergedColor[0];
      matchingRight[1] = mergedColor[1];
      colorReconstitution = mergedColor[2];
    }
    return [matchingLeft, matchingRight, function(value) {
      var result = left.inset ? 'inset ' : ' ';
      for (var i = 0; i < lengthReconstitution.length; i++) {
        result += lengthReconstitution[i](value[0][i]) + ' ';
      }
      if (colorReconstitution) {
        result += colorReconstitution(value[1]);
      }
      return result;
    }];
  }

  var mergeShadowList = scope.mergeNestedRepeatedShadow.bind(null, mergeShadow, ', ');
  scope.addPropertiesHandler(parseShadowList, mergeShadowList, ['box-shadow', 'text-shadow']);

})(webAnimationsMinifill);
<|endoftext|>


<commit_before>/**
 * Created by BK on 21/06/16.
 *
 * @flow
 */

 'use strict';

 import React, { Component } from 'react';
 import {
     Text,
     View,
     Image,
     ListView,
     TouchableHighlight,
     StyleSheet
 } from 'react-native';

type Props = {
    row: {
        thumb: string,
        title: string,
        desc: string,
        timestamp: Date
    }
}

export default class NotificationsRow extends Component {
    props: Props;

    render() {
        return (
            <View>
                <TouchableHighlight>
                    <View style={styles.container}>
                        <View style={styles.thumbContainer}>
                            <Image
                                style={styles.thumb}
                                source={{uri: this.props.row.thumb}}
                            />
                        </View>
                        <View style={styles.textContainer}>
                            <Text style={styles.title}>{this.props.row.title}</Text>
                            <Text style={styles.desc}>{this.props.row.desc}</Text>
                            <Text style={styles.reward}>{this.props.row.timestamp}</Text>
                        </View>
                    </View>
                </TouchableHighlight>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        backgroundColor: '#dedede'
    },
    thumbContainer: {
        flex: 1,
        backgroundColor: '#ededed',
        justifyContent: 'center',
        alignItems: 'center'
    },
    textContainer: {
        flex: 4,
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center'
    },
    title: {
        fontSize: 20,
    },
    desc: {

    },
    timestamp: {

    },
    thumb: {
        height: 45,
        width: 45,
        borderRadius: 22, // why dafuq is 22 circular??
    },
})
<commit_msg>Change timestamp type to `string`<commit_after>/**
 * Created by BK on 21/06/16.
 *
 * @flow
 */

 'use strict';

 import React, { Component } from 'react';
 import {
     Text,
     View,
     Image,
     ListView,
     TouchableHighlight,
     StyleSheet
 } from 'react-native';

type Props = {
    row: {
        thumb: string,
        title: string,
        desc: string,
        timestamp: string
    }
}

export default class NotificationsRow extends Component {
    props: Props;

    render() {
        return (
            <View>
                <TouchableHighlight>
                    <View style={styles.container}>
                        <View style={styles.thumbContainer}>
                            <Image
                                style={styles.thumb}
                                source={{uri: this.props.row.thumb}}
                            />
                        </View>
                        <View style={styles.textContainer}>
                            <Text style={styles.title}>{this.props.row.title}</Text>
                            <Text style={styles.desc}>{this.props.row.desc}</Text>
                            <Text style={styles.reward}>{this.props.row.timestamp}</Text>
                        </View>
                    </View>
                </TouchableHighlight>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        backgroundColor: '#dedede'
    },
    thumbContainer: {
        flex: 1,
        backgroundColor: '#ededed',
        justifyContent: 'center',
        alignItems: 'center'
    },
    textContainer: {
        flex: 4,
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center'
    },
    title: {
        fontSize: 20,
    },
    desc: {

    },
    timestamp: {

    },
    thumb: {
        height: 45,
        width: 45,
        borderRadius: 22, // why dafuq is 22 circular??
    },
})
<|endoftext|>


<commit_before>const getStackFamily = require('./stack-family');
const getChangeSetFamily = require('./change-set-family');
const deltaArrow = require('./delta-arrow');
const deltaValue = require('./delta-value');

/**
 * Returns a multi-line string describing the parameters that have changed
 * @param {ParameterDeltas} deltas
 * @returns {String}
 */
function parameterDeltasList(deltas) {
  if (!deltas.length) {
    return 'This change set contained no meaningful parameter deltas.';
  }

  // Text blocks within attachments have a 3000 character limit. If the text is
  // too large, try creating the list without links to reduce the size.
  const withLinks = deltas
    .map((d) => {
      const oldValue = deltaValue(d.parameter, d.stackValue);
      const arrow = deltaArrow(d);
      const newValue = deltaValue(d.parameter, d.changeSetValue);

      const label = d.stackName.includes('-root-')
        ? d.parameter
        : `${d.stackName}::${d.parameter}`;

      return `*${label}*: ${oldValue} ${arrow} ${newValue}`;
    })
    .join('\n');

  if (withLinks.length < 2900) {
    return withLinks;
  } else {
    return deltas
      .map((d) => {
        const oldValue = deltaValue(d.parameter, d.stackValue, true);
        const arrow = deltaArrow(d, true);
        const newValue = deltaValue(d.parameter, d.changeSetValue, true);

        return `*${d.stackName}::${d.parameter}*: ${oldValue} ${arrow} ${newValue}`;
      })
      .join('\n');
  }
}

module.exports = {
  async nestedParameterDeltaText(stackName, changeSetName) {
    let stackFamily = await getStackFamily(stackName);
    const changeSetFamily = await getChangeSetFamily(stackName, changeSetName);
    const changeSetFamilyStackIds = changeSetFamily.map((c) => c.StackId);

    // When there's only a single change set, it likely means that nested
    // change sets was disabled for the given change set. In these cases, only
    // the root stack's parameters should be included in the deltas, because
    // there won't be anything to compare the child stacks to, and all
    // parameters will look like they've changed.
    if (changeSetFamily.length === 1) {
      stackFamily = [stackFamily[0]];
    }

    /** @type {ParameterDeltas} */
    const deltas = [];

    // Iterate through all existing stack parameters and create a delta for
    // each one, which includes the current value.
    for (const stack of stackFamily) {
      // Not all nested stacks are guaranteed to be have a change set. If a
      // stack in the stack family does not have a corresponding change set,
      // and the deltas are determined strictly by finding matching values in
      // the stack and change set families, all parameters for that stack would
      // appear to be unmatched. So, if there is no corresponding change set
      // for a given stack, that stack's parameters should not be included in
      // the deltas. (If there is a change set with no corresponding stack,
      // those deltas *will* still be included below.)
      if (changeSetFamilyStackIds.includes(stack.StackId)) {
        for (const param of stack.Parameters || []) {
          deltas.push({
            stackName: stack.StackName,
            stackId: stack.StackId,
            parameter: param.ParameterKey,
            stackValue: param.ResolvedValue || param.ParameterValue,
            changeSetValue: null,
          });
        }
      }
    }

    // Iterate through all the change set parameters. If a delta already exists
    // for a given stack+parameter key, add the value from the change set to
    // that delta. If not, make a new delta.
    for (const changeSet of changeSetFamily) {
      for (const param of changeSet.Parameters || []) {
        const delta = deltas.find(
          (d) =>
            param.ParameterKey === d.parameter &&
            changeSet.StackName === d.stackName,
        );

        if (delta) {
          delta.changeSetValue = param.ResolvedValue || param.ParameterValue;
        } else {
          deltas.push({
            stackName: changeSet.StackName,
            stackId: changeSet.StackId,
            parameter: param.ParameterKey,
            stackValue: null,
            changeSetValue: param.ResolvedValue || param.ParameterValue,
          });
        }
      }
    }

    // Filter down to only deltas where the values are different
    const changeDeltas = deltas.filter(
      (d) => d.stackValue !== d.changeSetValue,
    );

    // When using nested change sets, not all parameters in nested stacks are
    // correctly resolved. Any parameter values that depend on a stack or
    // resource output will be included in the change set parameters with an
    // unresolved value that looks like "{{IntrinsicFunction:…". Unless or until
    // AWS makes nested change sets smarter, we have to just ignore these,
    // because there's no way to compare the actual existing value from the stack
    // to the hypothetical future value that will be resolved when the change set
    // executes.
    //
    // Any parameters effected by this limitation are filtered out.
    const cleanedDeltas = changeDeltas.filter(
      (d) => !(d.changeSetValue || '').match(/\{\{IntrinsicFunction\:/),
    );

    // Some additional parameters that don't make sense to display in Slack are
    // also filtered out.
    const allowedDeltas = cleanedDeltas.filter(
      (d) =>
        !['PipelineExecutionNonce', 'TemplateUrlBase'].includes(d.parameter),
    );

    return parameterDeltasList(allowedDeltas);
  },
};
<commit_msg>Improve parameter delta labels<commit_after>const getStackFamily = require('./stack-family');
const getChangeSetFamily = require('./change-set-family');
const deltaArrow = require('./delta-arrow');
const deltaValue = require('./delta-value');

/**
 * Returns a multi-line string describing the parameters that have changed
 * @param {ParameterDeltas} deltas
 * @returns {String}
 */
function parameterDeltasList(deltas) {
  if (!deltas.length) {
    return 'This change set contained no meaningful parameter deltas.';
  }

  // Text blocks within attachments have a 3000 character limit. If the text is
  // too large, try creating the list without links to reduce the size.
  const withLinks = deltas
    .map((d) => {
      const oldValue = deltaValue(d.parameter, d.stackValue);
      const arrow = deltaArrow(d);
      const newValue = deltaValue(d.parameter, d.changeSetValue);

      let label;

      if (
        [
          'infrastructure-cd-root-staging',
          'infrastructure-cd-root-production',
        ].includes(d.stackName)
      ) {
        // For root stack parameters, label with just the parameter name
        label = d.parameter;
      } else {
        // For nested stacks, try to extract some meaningful part of the stack
        // name that is useful to include
        const nickname = d.stackName.split('-').at(-2);
        label = `${nickname}::${d.parameter}`;
      }

      return `*${label}*: ${oldValue} ${arrow} ${newValue}`;
    })
    .join('\n');

  if (withLinks.length < 2900) {
    return withLinks;
  } else {
    return deltas
      .map((d) => {
        const oldValue = deltaValue(d.parameter, d.stackValue, true);
        const arrow = deltaArrow(d, true);
        const newValue = deltaValue(d.parameter, d.changeSetValue, true);

        return `*${d.stackName}::${d.parameter}*: ${oldValue} ${arrow} ${newValue}`;
      })
      .join('\n');
  }
}

module.exports = {
  async nestedParameterDeltaText(stackName, changeSetName) {
    let stackFamily = await getStackFamily(stackName);
    const changeSetFamily = await getChangeSetFamily(stackName, changeSetName);
    const changeSetFamilyStackIds = changeSetFamily.map((c) => c.StackId);

    // When there's only a single change set, it likely means that nested
    // change sets was disabled for the given change set. In these cases, only
    // the root stack's parameters should be included in the deltas, because
    // there won't be anything to compare the child stacks to, and all
    // parameters will look like they've changed.
    if (changeSetFamily.length === 1) {
      stackFamily = [stackFamily[0]];
    }

    /** @type {ParameterDeltas} */
    const deltas = [];

    // Iterate through all existing stack parameters and create a delta for
    // each one, which includes the current value.
    for (const stack of stackFamily) {
      // Not all nested stacks are guaranteed to be have a change set. If a
      // stack in the stack family does not have a corresponding change set,
      // and the deltas are determined strictly by finding matching values in
      // the stack and change set families, all parameters for that stack would
      // appear to be unmatched. So, if there is no corresponding change set
      // for a given stack, that stack's parameters should not be included in
      // the deltas. (If there is a change set with no corresponding stack,
      // those deltas *will* still be included below.)
      if (changeSetFamilyStackIds.includes(stack.StackId)) {
        for (const param of stack.Parameters || []) {
          deltas.push({
            stackName: stack.StackName,
            stackId: stack.StackId,
            parameter: param.ParameterKey,
            stackValue: param.ResolvedValue || param.ParameterValue,
            changeSetValue: null,
          });
        }
      }
    }

    // Iterate through all the change set parameters. If a delta already exists
    // for a given stack+parameter key, add the value from the change set to
    // that delta. If not, make a new delta.
    for (const changeSet of changeSetFamily) {
      for (const param of changeSet.Parameters || []) {
        const delta = deltas.find(
          (d) =>
            param.ParameterKey === d.parameter &&
            changeSet.StackName === d.stackName,
        );

        if (delta) {
          delta.changeSetValue = param.ResolvedValue || param.ParameterValue;
        } else {
          deltas.push({
            stackName: changeSet.StackName,
            stackId: changeSet.StackId,
            parameter: param.ParameterKey,
            stackValue: null,
            changeSetValue: param.ResolvedValue || param.ParameterValue,
          });
        }
      }
    }

    // Filter down to only deltas where the values are different
    const changeDeltas = deltas.filter(
      (d) => d.stackValue !== d.changeSetValue,
    );

    // When using nested change sets, not all parameters in nested stacks are
    // correctly resolved. Any parameter values that depend on a stack or
    // resource output will be included in the change set parameters with an
    // unresolved value that looks like "{{IntrinsicFunction:…". Unless or until
    // AWS makes nested change sets smarter, we have to just ignore these,
    // because there's no way to compare the actual existing value from the stack
    // to the hypothetical future value that will be resolved when the change set
    // executes.
    //
    // Any parameters effected by this limitation are filtered out.
    const cleanedDeltas = changeDeltas.filter(
      (d) => !(d.changeSetValue || '').match(/\{\{IntrinsicFunction\:/),
    );

    // Some additional parameters that don't make sense to display in Slack are
    // also filtered out.
    const allowedDeltas = cleanedDeltas.filter(
      (d) =>
        !['PipelineExecutionNonce', 'TemplateUrlBase'].includes(d.parameter),
    );

    return parameterDeltasList(allowedDeltas);
  },
};
<|endoftext|>


<commit_before>/* eslint-disable no-template-curly-in-string */
export default {
  orders: {
    accomodation: 'Accomodation',
    accomodationHelp: 'You pay for accomodation separately on the festival checkin and in cash. Basic accomodation is included in signup price.',
    accountNumberCzech: 'Account number',
    amountToPay: 'Price to pay',
    assigned: 'Assigned to workshop',
    cancelled: 'Cancelled by user',
    continue: 'Continue',
    dinner: 'Dinner',
    expiresIn: 'Expires in ${duration}',
    food: 'Food',
    foodHelp: 'You can choose if you want lunch per each day. The festival food menu will be released before the festival starts.',
    foodNotOrdered: 'Not ordered',
    foodNotSelected: 'Not chosen',
    history: 'History',
    lunch: 'Lunch',
    mainCourse: 'Main course',
    noAccomodation: 'Default Accomodation',
    noWorkshop: 'Signup without workshop',
    notRegisteredToWorkshop: 'Not registered on workshop',
    number: 'Signup ${symvar}',
    orderExpiresHelp: 'If your registration expires before we get the payment, your spot will be offered to other participants.',
    overpaid: 'Overpaid',
    paid: 'Paid',
    paymentCancelled: 'Cancelled',
    paymentMethod: 'Payment method',
    paymentMethodHelp: 'It is possible to pay only by account transfer at this moment. Confirm the order details in the next step.',
    priceToPay: 'Price to pay',
    registerToWorkshop: 'Register to workshop',
    soup: 'Soup',
    status: 'Signup status',
    symvar: 'Variable symbol',
    timedOut: 'Expired',
    unconfirmed: 'Unconfirmed',
    unpaid: 'Not paid',
    waitingToBeAssigned: 'Paid, waiting to be assigned',
    waitingToBePaid: 'Expecting payment',
    workshopHeading: 'Workshop registration',
    workshopHelp: 'Pick one workshop, you cannot attend more on Imprtřesk. Your spot on the workshop will be confirmed when the payment arrives to our account.',
    workshop: 'Pick workshop',
    register: 'Registration',
  },
};
<commit_msg>Add missing locales<commit_after>/* eslint-disable no-template-curly-in-string */
export default {
  orders: {
    accomodation: 'Accomodation',
    accomodationHelp: 'You pay for accomodation separately on the festival checkin and in cash. Basic accomodation is included in signup price.',
    accountNumberCzech: 'Account number',
    amountToPay: 'Price to pay',
    assigned: 'Assigned to workshop',
    cancelled: 'Cancelled by user',
    continue: 'Continue',
    dinner: 'Dinner',
    expiresIn: 'Expires in ${duration}',
    food: 'Food',
    foodHelp: 'You can choose if you want lunch per each day. The festival food menu will be released before the festival starts.',
    foodNotOrdered: 'Not ordered',
    foodNotSelected: 'Not chosen',
    history: 'History',
    howLongStay: 'How long will you stay?',
    changeFood: 'Change food',
    lunch: 'Lunch',
    mainCourse: 'Main course',
    noAccomodation: 'Default Accomodation',
    notRegisteredToWorkshop: 'Not registered on workshop',
    noWorkshop: 'Signup without workshop',
    number: 'Signup ${symvar}',
    orderExpiresHelp: 'If your registration expires before we get the payment, your spot will be offered to other participants.',
    overpaid: 'Overpaid',
    paid: 'Paid',
    paymentCancelled: 'Cancelled',
    paymentMethod: 'Payment method',
    paymentMethodHelp: 'It is possible to pay only by account transfer at this moment. Confirm the order details in the next step.',
    priceToPay: 'Price to pay',
    register: 'Registration',
    registerToWorkshop: 'Register to workshop',
    soup: 'Soup',
    status: 'Signup status',
    symvar: 'Variable symbol',
    timedOut: 'Expired',
    totalPrice: 'Total price',
    unconfirmed: 'Unconfirmed',
    unpaid: 'Not paid',
    waitingToBeAssigned: 'Paid, waiting to be assigned',
    waitingToBePaid: 'Expecting payment',
    workshop: 'Pick workshop',
    workshopHeading: 'Workshop registration',
    workshopHelp: 'Pick one workshop, you cannot attend more on Imprtřesk. Your spot on the workshop will be confirmed when the payment arrives to our account.',
  },
};
<|endoftext|>


<commit_before>foam.CLASS({
  package: 'org.chartjs',
  name: 'Line2',
  extends: 'foam.graphics.CView',
  requires: [
    'org.chartjs.Lib',
  ],
  properties: [
    'chart',
    {
      name: 'data',
      factory: function() {
        return {
          datasets: []
        };
      },
      postSet: function() {
        this.update();
      }
    },
    {
      name: 'config',
      factory: function() {
        return {
          type: 'line',
          data: this.data,
          options: {
            responsive: false,
            maintainAspectRatio: false
          }
        };
      }
    }
  ],
  reactions: [
    ['', 'propertyChange.data', 'update' ],
  ],
  methods: [
    function initCView(x) {
      this.chart = new this.Lib.CHART(x, this.config);
      this.update();
    },
    function paintSelf(x) {
      this.chart.render();
    }
  ],
  listeners: [
    {
      name: 'update',
      isFramed: true,
      code: function() {
        if ( ! this.chart ) return;

        this.chart.data = this.data;
        this.chart.update();
      }
    }
  ]
});
<commit_msg>chartjs.Line2: Let user override xAxis configuration.<commit_after>foam.CLASS({
  package: 'org.chartjs',
  name: 'Line2',
  extends: 'foam.graphics.CView',
  requires: [
    'org.chartjs.Lib',
  ],
  properties: [
    'chart',
    {
      name: 'data',
      factory: function() {
        return {
          datasets: []
        };
      },
      postSet: function() {
        this.update();
      }
    },
    {
      name: 'xAxis',
      postSet: function(_, v) {
        if ( this.chart ) {
          this.chart.options.scales.xAxes = [v];
        }
      }
    },
    {
      name: 'config',
      factory: function() {
        return {
          type: 'line',
          data: this.data,
          options: {
            responsive: false,
            maintainAspectRatio: false,
            scales: {
              xAxes: this.xAxis ? [ this.xAxis ] : []
            }
          }
        };
      }
    }
  ],
  reactions: [
    ['', 'propertyChange.data', 'update' ],
  ],
  methods: [
    function initCView(x) {
      this.chart = new this.Lib.CHART(x, this.config);
      this.update();
    },
    function paintSelf(x) {
      this.chart.render();
    }
  ],
  listeners: [
    {
      name: 'update',
      isFramed: true,
      code: function() {
        if ( ! this.chart ) return;

        this.chart.data = this.data;
        this.chart.update();
      }
    }
  ]
});
<|endoftext|>


<commit_before>/*
Copyright 2010, Russell Haering <russellhaering@gmail.com>. All rights
reserved.  Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including without
limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
 */

var http = require('http');
var htmlparser = require("./lib/node-htmlparser/node-htmlparser");
var url = require('url');

var routes = {
    '/':        getNews,
    '/newest':  getNewest,
    '/best':    getBest,
    '/item':    getItem,
};

function getNews(req, res) {
    getList(req, res, '/');
};

function getNewest(req, res) {
    getList(req, res, '/newest');
};

function getBest(req, res) {
    getList(req, res, '/best');
}

function getItem(req, res) {
    res.end();
};

function getList(req, res, path) {
    var hn = http.createClient(80, "news.ycombinator.com");
    var request = hn.request("GET", path, {
        'host': 'news.ycombinator.com',
    });
    request.end();
    request.addListener("response", function(response) {
        var body = "";
        var handler = new htmlparser.DefaultHandler(function (error, dom) {
            // Grab the table that contains the list of articles
            var rows = dom[0]['children'][1]['children'][0]['children'][0]['children'][2]['children'][0]['children'][0]['children'];
            var data = [];

            // Each article takes 3 rows, and the last two rows aren't affiliated with articles
            for (var i = 0; i < (rows.length - 2)/3; i++) {
                // Parse out various article details
                var article = {
                    'id':           rows[i*3 + 1]['children'][1]['children'][4]['attribs']['href'].split('=')[1],
                    'headline':     rows[i*3]['children'][2]['children'][0]['children'][0]['data'],
                    'url':          rows[i*3]['children'][2]['children'][0]['attribs']['href'],
                    'score':        rows[i*3 + 1]['children'][1]['children'][0]['children'][0]['data'].split(' ')[0],
                    'submitter':    rows[i*3 + 1]['children'][1]['children'][2]['attribs']['href'].split('=')[1],
                    'comments':     rows[i*3 + 1]['children'][1]['children'][4]['children'][0]['data'].split(' ')[0],
                    'age':          rows[i*3 + 1]['children'][1]['children'][3]['data'].split(' |')[0].replace(/^\s*|\s*$/g, ""),
                };

                if (article['comments'] == 'discuss') {
                    article['comments'] = '0';
                }

                data[i] = article;
            }

            // Return a list of JSON articles
            var text = JSON.stringify(data);
            res.writeHead(200, {
                'Content-Type': 'application/json',
                'Content-Length': text.length,
            });
            res.end(text);
        });
        var parser = new htmlparser.Parser(handler);

        response.setEncoding("utf8");
        response.addListener("data", function(chunk) {
            parser.parseChunk(chunk);
        });

        response.addListener("end", function() {
            parser.done();
        });
    });
};

http.createServer(function (req, res) {
    var pathname = url.parse(req.url, true)['pathname'];
    var method = routes[pathname];
    if (method != undefined) {
        method(req, res);
    }
}).listen(8124, "127.0.0.1");
<commit_msg>Begin adding basic comment retrieval support. Still missing comment metadata<commit_after>/*
Copyright 2010, Russell Haering <russellhaering@gmail.com>. All rights
reserved.  Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including without
limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
 */

var http = require('http');
var htmlparser = require("./lib/node-htmlparser/node-htmlparser");
var url = require('url');

var routes = {
    '/':        getNews,
    '/newest':  getNewest,
    '/best':    getBest,
    '/item':    getItem,
};

function getNews(req, res) {
    getList(req, res, '/');
};

function getNewest(req, res) {
    getList(req, res, '/newest');
};

function getBest(req, res) {
    getList(req, res, '/best');
}

function getItem(req, res) {
    var id = url.parse(req.url, true)['query']['id'];
    var hn = http.createClient(80, "news.ycombinator.com");
    var request = hn.request("GET", "/item?id=" + id, {
        'host': 'news.ycombinator.com',
    });
    request.end();
    request.addListener("response", function(response) {
        var body = "";
        var handler = new htmlparser.DefaultHandler(function (error, dom) {
            // Grab the table that contains the list of articles
            var header =   dom[0]['children'][1]['children'][0]['children'][0]['children'][2]['children'][0]['children'][0]['children'];
            var comments = dom[0]['children'][1]['children'][0]['children'][0]['children'][2]['children'][0]['children'][3]['children'];

            var here = comments[0]['children'][0]['children'][0]['children'][0]['children'][2]['children'][2];

            var article = {
                'id':           header[1]['children'][1]['children'][4]['attribs']['href'].split('=')[1],
                'headline':     header[0]['children'][1]['children'][0]['children'][0]['data'],
                'url':          header[0]['children'][1]['children'][0]['attribs']['href'],
                'score':        header[1]['children'][1]['children'][0]['children'][0]['data'].split(' ')[0],
                'submitter':    header[1]['children'][1]['children'][2]['attribs']['href'].split('=')[1],
                'comments':     header[1]['children'][1]['children'][4]['children'][0]['data'].split(' ')[0],
                'age':          header[1]['children'][1]['children'][3]['data'].split(' |')[0].replace(/^\s*|\s*$/g, ""),
                'children':     [],
            };

            for (var i = 0; i < comments.length; i++) {
                var comment = {
                    'depth':    parseInt(comments[i]['children'][0]['children'][0]['children'][0]['children'][0]['children'][0]['attribs']['width'])/40,
                    'html':     toHTML(comments[i]['children'][0]['children'][0]['children'][0]['children'][2]['children'][2]),
                };
                article['children'][i] = comment;
            }

            var text = JSON.stringify(article);
            res.writeHead(200, {
                'Content-Type': 'application/json',
                'Content-Length': text.length,
            });
            res.end(text);
        }, { ignoreWhitespace: true});
        var parser = new htmlparser.Parser(handler);

        response.setEncoding("utf8");
        response.addListener("data", function(chunk) {
            parser.parseChunk(chunk);
        });

        response.addListener("end", function() {
            parser.done();
        });
    });
};

function getList(req, res, path) {
    var hn = http.createClient(80, "news.ycombinator.com");
    var request = hn.request("GET", path, {
        'host': 'news.ycombinator.com',
    });
    request.end();
    request.addListener("response", function(response) {
        var body = "";
        var handler = new htmlparser.DefaultHandler(function (error, dom) {
            // Grab the table that contains the list of articles
            var rows = dom[0]['children'][1]['children'][0]['children'][0]['children'][2]['children'][0]['children'][0]['children'];
            var data = [];

            // Each article takes 3 rows, and the last two rows aren't affiliated with articles
            for (var i = 0; i < (rows.length - 2)/3; i++) {
                // Parse out various article details
                var article = {
                    'id':           rows[i*3 + 1]['children'][1]['children'][4]['attribs']['href'].split('=')[1],
                    'headline':     rows[i*3]['children'][2]['children'][0]['children'][0]['data'],
                    'url':          rows[i*3]['children'][2]['children'][0]['attribs']['href'],
                    'score':        rows[i*3 + 1]['children'][1]['children'][0]['children'][0]['data'].split(' ')[0],
                    'submitter':    rows[i*3 + 1]['children'][1]['children'][2]['attribs']['href'].split('=')[1],
                    'comments':     rows[i*3 + 1]['children'][1]['children'][4]['children'][0]['data'].split(' ')[0],
                    'age':          rows[i*3 + 1]['children'][1]['children'][3]['data'].split(' |')[0].replace(/^\s*|\s*$/g, ""),
                };

                if (article['comments'] == 'discuss') {
                    article['comments'] = '0';
                }

                data[i] = article;
            }

            // Return a list of JSON articles
            var text = JSON.stringify(data);
            res.writeHead(200, {
                'Content-Type': 'application/json',
                'Content-Length': text.length,
            });
            res.end(text);
        });
        var parser = new htmlparser.Parser(handler);

        response.setEncoding("utf8");
        response.addListener("data", function(chunk) {
            parser.parseChunk(chunk);
        });

        response.addListener("end", function() {
            parser.done();
        });
    });
};

http.createServer(function (req, res) {
    var pathname = url.parse(req.url)['pathname'];
    var method = routes[pathname];
    if (method != undefined) {
        method(req, res);
    }
}).listen(8124, "127.0.0.1");

// Sort of a ghetto way to turn a comment back into HTML
function toHTML(node) {
    var HTML = "";
    if (node['type'] == 'tag') {
        HTML += "<" + node['raw'] + ">";
        if (node['children'] != undefined) {
            for (var i = 0; i < node['children'].length; i++) {
                HTML += toHTML(node['children'][i]);
            }
        }
        if (node['name'] != 'p') {
            HTML += "</" + node['name'] + ">";
        }
    }
    else if (node['type'] == 'text') {
        HTML += node['raw'];
    }
    return HTML;
}
<|endoftext|>


<commit_before>/**
* Copyright 2012-2015, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Plotly = require('../plotly'),
    d3 = require('d3');

module.exports = function toSVG(gd, format) {

    // make background color a rect in the svg, then revert after scraping
    // all other alterations have been dealt with by properly preparing the svg
    // in the first place... like setting cursors with css classes so we don't
    // have to remove them, and providing the right namespaces in the svg to
    // begin with
    var fullLayout = gd._fullLayout,
        svg = fullLayout._paper,
        size = fullLayout._size,
        domain,
        i;

    svg.insert('rect', ':first-child')
        .call(Plotly.Drawing.setRect, 0, 0, fullLayout.width, fullLayout.height)
        .call(Plotly.Color.fill, fullLayout.paper_bgcolor);

    /* Grab the 3d scenes and rasterize em. Calculate their positions,
     * then insert them into the SVG element as images */
    var sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d'),
        scene;

    for(i = 0; i < sceneIds.length; i++) {
        scene = fullLayout[sceneIds[i]];
        domain = scene.domain;
        insertGlImage(fullLayout, scene._scene, {
            x: size.l + size.w * domain.x[0],
            y: size.t + size.h * (1 - domain.y[1]),
            width: size.w * (domain.x[1] - domain.x[0]),
            height: size.h * (domain.y[1] - domain.y[0])
        });
    }

    // similarly for 2d scenes
    var subplotIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl2d'),
        subplot;

    for(i = 0; i < subplotIds.length; i++) {
        subplot = fullLayout._plots[subplotIds[i]];
        insertGlImage(fullLayout, subplot._scene2d, {
            x: size.l,
            y: size.t,
            width: size.w,
            height: size.h
        });
    }

    // Grab the geos off the geo-container and place them in geoimages
    var geoIds = Plotly.Plots.getSubplotIds(fullLayout, 'geo'),
        geoLayout,
        geoFramework;

    for(i = 0; i < geoIds.length; i++) {
        geoLayout = fullLayout[geoIds[i]];
        domain = geoLayout.domain;
        geoFramework = geoLayout._geo.framework;

        geoFramework.attr('style', null);
        geoFramework
            .attr({
                x: size.l + size.w * domain.x[0] + geoLayout._marginX,
                y: size.t + size.h * (1 - domain.y[1]) + geoLayout._marginY,
                width: geoLayout._width,
                height: geoLayout._height
            });

        fullLayout._geoimages.node()
            .appendChild(geoFramework.node());
    }

    // now that we've got the 3d images in the right layer, add top items above them
    // assumes everything in toppaper is a group, and if it's empty (like hoverlayer)
    // we can ignore it
    if(fullLayout._toppaper) {
        var topGroups = fullLayout._toppaper.node().childNodes,
            topGroup;
        for(i = 0; i < topGroups.length; i++) {
            topGroup = topGroups[i];
            if(topGroup.childNodes.length) svg.node().appendChild(topGroup);
        }
    }

    // in case the svg element had an explicit background color, remove this
    // we want the rect to get the color so it's the right size; svg bg will
    // fill whatever container it's displayed in regardless of plot size.
    svg.node().style.background = '';

    svg.selectAll('text')
        .attr({'data-unformatted': null})
        .each(function() {
            // hidden text is pre-formatting mathjax, the browser ignores it but it can still confuse batik
            var txt = d3.select(this);
            if(txt.style('visibility') === 'hidden') {
                txt.remove();
                return;
            }

            // I've seen font-family styles with non-escaped double quotes in them - breaks the
            // serialized svg because the style attribute itself is double-quoted!
            // Is this an IE thing? Any other attributes or style elements that can have quotes in them?
            // TODO: this looks like a noop right now - what happened to it?
            var ff = txt.style('font-family');
            if(ff && ff.indexOf('"') !== -1) txt.style('font-family', ff.replace(/"/g, '"'));
        });

    if(format === 'pdf' || format === 'eps') {
        // these formats make the extra line MathJax adds around symbols look super thick in some cases
        // it looks better if this is removed entirely.
        svg.selectAll('#MathJax_SVG_glyphs path')
            .attr('stroke-width', 0);
    }

    // fix for IE namespacing quirk?
    // http://stackoverflow.com/questions/19610089/unwanted-namespaces-on-svg-markup-when-using-xmlserializer-in-javascript-with-ie
    svg.node().setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg');
    svg.node().setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');

    var s = new window.XMLSerializer().serializeToString(svg.node());
    s = Plotly.util.html_entity_decode(s);
    s = Plotly.util.xml_entity_encode(s);

    return s;
};

function insertGlImage(fullLayout, scene, opts) {
    var imageData = scene.toImage('png');

    fullLayout._glimages.append('svg:image')
        .attr({
            xmlns:'http://www.w3.org/2000/svg',
            'xlink:xlink:href': imageData, // odd d3 quirk, need namespace twice
            x: opts.x,
            y: opts.y,
            width: opts.width,
            height: opts.height,
            preserveAspectRatio: 'none'
        });

   scene.destroy();
}
<commit_msg>replace " for \' when wrapping font-family in to-svg step<commit_after>/**
* Copyright 2012-2015, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Plotly = require('../plotly'),
    d3 = require('d3');

module.exports = function toSVG(gd, format) {

    // make background color a rect in the svg, then revert after scraping
    // all other alterations have been dealt with by properly preparing the svg
    // in the first place... like setting cursors with css classes so we don't
    // have to remove them, and providing the right namespaces in the svg to
    // begin with
    var fullLayout = gd._fullLayout,
        svg = fullLayout._paper,
        size = fullLayout._size,
        domain,
        i;

    svg.insert('rect', ':first-child')
        .call(Plotly.Drawing.setRect, 0, 0, fullLayout.width, fullLayout.height)
        .call(Plotly.Color.fill, fullLayout.paper_bgcolor);

    /* Grab the 3d scenes and rasterize em. Calculate their positions,
     * then insert them into the SVG element as images */
    var sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d'),
        scene;

    for(i = 0; i < sceneIds.length; i++) {
        scene = fullLayout[sceneIds[i]];
        domain = scene.domain;
        insertGlImage(fullLayout, scene._scene, {
            x: size.l + size.w * domain.x[0],
            y: size.t + size.h * (1 - domain.y[1]),
            width: size.w * (domain.x[1] - domain.x[0]),
            height: size.h * (domain.y[1] - domain.y[0])
        });
    }

    // similarly for 2d scenes
    var subplotIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl2d'),
        subplot;

    for(i = 0; i < subplotIds.length; i++) {
        subplot = fullLayout._plots[subplotIds[i]];
        insertGlImage(fullLayout, subplot._scene2d, {
            x: size.l,
            y: size.t,
            width: size.w,
            height: size.h
        });
    }

    // Grab the geos off the geo-container and place them in geoimages
    var geoIds = Plotly.Plots.getSubplotIds(fullLayout, 'geo'),
        geoLayout,
        geoFramework;

    for(i = 0; i < geoIds.length; i++) {
        geoLayout = fullLayout[geoIds[i]];
        domain = geoLayout.domain;
        geoFramework = geoLayout._geo.framework;

        geoFramework.attr('style', null);
        geoFramework
            .attr({
                x: size.l + size.w * domain.x[0] + geoLayout._marginX,
                y: size.t + size.h * (1 - domain.y[1]) + geoLayout._marginY,
                width: geoLayout._width,
                height: geoLayout._height
            });

        fullLayout._geoimages.node()
            .appendChild(geoFramework.node());
    }

    // now that we've got the 3d images in the right layer, add top items above them
    // assumes everything in toppaper is a group, and if it's empty (like hoverlayer)
    // we can ignore it
    if(fullLayout._toppaper) {
        var topGroups = fullLayout._toppaper.node().childNodes,
            topGroup;
        for(i = 0; i < topGroups.length; i++) {
            topGroup = topGroups[i];
            if(topGroup.childNodes.length) svg.node().appendChild(topGroup);
        }
    }

    // in case the svg element had an explicit background color, remove this
    // we want the rect to get the color so it's the right size; svg bg will
    // fill whatever container it's displayed in regardless of plot size.
    svg.node().style.background = '';

    svg.selectAll('text')
        .attr({'data-unformatted': null})
        .each(function() {
            // hidden text is pre-formatting mathjax, the browser ignores it but it can still confuse batik
            var txt = d3.select(this);
            if(txt.style('visibility') === 'hidden') {
                txt.remove();
                return;
            }

            // I've seen font-family styles with non-escaped double quotes in them - breaks the
            // serialized svg because the style attribute itself is double-quoted!
            // Is this an IE thing? Any other attributes or style elements that can have quotes in them?
            // TODO: this looks like a noop right now - what happened to it?
            var ff = txt.style('font-family');
            if(ff && ff.indexOf('"') !== -1) txt.style('font-family', ff.replace(/"/g, '\\\''));
        });

    if(format === 'pdf' || format === 'eps') {
        // these formats make the extra line MathJax adds around symbols look super thick in some cases
        // it looks better if this is removed entirely.
        svg.selectAll('#MathJax_SVG_glyphs path')
            .attr('stroke-width', 0);
    }

    // fix for IE namespacing quirk?
    // http://stackoverflow.com/questions/19610089/unwanted-namespaces-on-svg-markup-when-using-xmlserializer-in-javascript-with-ie
    svg.node().setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg');
    svg.node().setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');

    var s = new window.XMLSerializer().serializeToString(svg.node());
    s = Plotly.util.html_entity_decode(s);
    s = Plotly.util.xml_entity_encode(s);

    return s;
};

function insertGlImage(fullLayout, scene, opts) {
    var imageData = scene.toImage('png');

    fullLayout._glimages.append('svg:image')
        .attr({
            xmlns:'http://www.w3.org/2000/svg',
            'xlink:xlink:href': imageData, // odd d3 quirk, need namespace twice
            x: opts.x,
            y: opts.y,
            width: opts.width,
            height: opts.height,
            preserveAspectRatio: 'none'
        });

   scene.destroy();
}
<|endoftext|>


<commit_before>snd.WaveShaper = function (id) {
    snd.AudioUnit.apply(this, arguments);

    this._output = snd.AUDIO_CONTEXT.createGain();
    this._connector = snd.AUDIO_CONTEXT.createGain();
    this._shaper = snd.AUDIO_CONTEXT.createWaveShaper();

    this._connector.connect(this._shaper);
    this._shaper.connect(this._output);

    /* DEFINE PROPERTIES */
Object.defineProperties(this, {
    channelCount: {
          get: function () {
                return this._status.channelCount;
          },
          set: function (val) {
                this._output.channelCount = val;
                this._connector.channelCount = val;
                this._shaper.channelCount = val;
                this._status.channelCount = val;
          }
    },
    channelCountMode: {
          get: function () {
                return this._status.channelCountMode;

          },
          set: function (val) {
                this._output.channelCountMode = val;
                this._connector.channelCountMode = val;
                this._shaper.channelCountMode = val;
                this._status.channelCountMode = val;
          }
    },
    channelInterpretation: {
          get: function () {
                return this._status.channelInterpretation;
          },
          set: function (val) {
                this._output.channelInterpretation = val;
                this._connector.channelInterpretation = val;
                this._shaper.channelInterpretation = val;
                this._status.channelInterpretation = val;
          }
    },
    curve: {
          get: function () {
                return this._shaper.curve;
          },
          set: function (val) {
                this._shaper.curve = val;
                this._status.curve = val;
          }
    },
    oversample: {
          get: function () {
                return this._shaper.oversample;
          },
          set: function (val) {
                this._shaper.oversample = val;
                this._status.oversample = val;
          }
    }
});
};
snd.WaveShaper.prototype = Object.create(snd.AudioUnit.prototype);
snd.WaveShaper.prototype.constructor = snd.Gain;

snd.WaveShaper.prototype.connect = function (connectTo, indexIn, indexOut, id) {
    snd.AudioUnit.prototype.connect.apply(this, arguments);
    if (connectTo.getConnector != null) {
        this._output.connect(connectTo.getConnector(), indexIn, indexOut);
    } else {
        this._output.connect(connectTo, indexIn, indexOut);
    }
};
snd.WaveShaper.prototype.disconnect = function (disconnectFrom, indexIn, id) {
    snd.AudioUnit.prototype.disconnect.apply(this, arguments);
    if (disconnectFrom.getConnector != null) {
        this._output.disconnect(disconnectFrom.getConnector(), indexIn);
    } else {
        this._output.disconnect(disconnectFrom, indexIn);
    }
};
snd.WaveShaper.prototype.createStatus = function () {
    return new snd.WaveShaper.Status();
};
snd.WaveShaper.prototype.getConnector = function () {
    return this._connector;
};
snd.WaveShaper.prototype.loadData = function (data) {
    snd.AudioUnit.prototype.loadData.apply(this, arguments);

    this.curve = data.curve;
    this.oversample = data.oversample;
};

snd.WaveShaper.Status = function () {
    snd.AudioUnit.Status.apply(this, arguments);

    this.curve = null;
    this.oversample = snd.WaveShaper.OVERSAMPLE_NONE;
};
snd.WaveShaper.Status.prototype = Object.create(snd.AudioUnit.Status.prototype);
snd.WaveShaper.Status.prototype.constructor = snd.WaveShaper.Status;
<commit_msg>WaveShaperにgainプロパティを追加<commit_after>snd.WaveShaper = function (id) {
    snd.AudioUnit.apply(this, arguments);

    this._output = snd.AUDIO_CONTEXT.createGain();
    this._connector = snd.AUDIO_CONTEXT.createGain();
    this._shaper = snd.AUDIO_CONTEXT.createWaveShaper();

    this._connector.connect(this._shaper);
    this._shaper.connect(this._output);

    /* DEFINE PROPERTIES */
Object.defineProperties(this, {
    channelCount: {
          get: function () {
                return this._status.channelCount;
          },
          set: function (val) {
                this._output.channelCount = val;
                this._connector.channelCount = val;
                this._shaper.channelCount = val;
                this._status.channelCount = val;
          }
    },
    channelCountMode: {
          get: function () {
                return this._status.channelCountMode;

          },
          set: function (val) {
                this._output.channelCountMode = val;
                this._connector.channelCountMode = val;
                this._shaper.channelCountMode = val;
                this._status.channelCountMode = val;
          }
    },
    channelInterpretation: {
          get: function () {
                return this._status.channelInterpretation;
          },
          set: function (val) {
                this._output.channelInterpretation = val;
                this._connector.channelInterpretation = val;
                this._shaper.channelInterpretation = val;
                this._status.channelInterpretation = val;
          }
    },
    curve: {
          get: function () {
                return this._shaper.curve;
          },
          set: function (val) {
                this._shaper.curve = val;
                this._status.curve = val;
          }
    },
    oversample: {
        get: function () {
            return this._shaper.oversample;
        },
        set: function (val) {
            this._shaper.oversample = val;
            this._status.oversample = val;
        }
    },
    gain: {
        get: function() {
            return this._output.gain.value;
        },
        set: function(val) {
            this._output.gain.value = val;
            this._status.gain = val;
        }
    }
});
};
snd.WaveShaper.prototype = Object.create(snd.AudioUnit.prototype);
snd.WaveShaper.prototype.constructor = snd.Gain;

snd.WaveShaper.prototype.connect = function (connectTo, indexIn, indexOut, id) {
    snd.AudioUnit.prototype.connect.apply(this, arguments);
    if (connectTo.getConnector != null) {
        this._output.connect(connectTo.getConnector(), indexIn, indexOut);
    } else {
        this._output.connect(connectTo, indexIn, indexOut);
    }
};
snd.WaveShaper.prototype.disconnect = function (disconnectFrom, indexIn, id) {
    snd.AudioUnit.prototype.disconnect.apply(this, arguments);
    if (disconnectFrom.getConnector != null) {
        this._output.disconnect(disconnectFrom.getConnector(), indexIn);
    } else {
        this._output.disconnect(disconnectFrom, indexIn);
    }
};
snd.WaveShaper.prototype.createStatus = function () {
    return new snd.WaveShaper.Status();
};
snd.WaveShaper.prototype.getConnector = function () {
    return this._connector;
};
snd.WaveShaper.prototype.loadData = function (data) {
    snd.AudioUnit.prototype.loadData.apply(this, arguments);

    this.curve = data.curve;
    this.oversample = data.oversample;
};

snd.WaveShaper.Status = function () {
    snd.AudioUnit.Status.apply(this, arguments);

    this.curve = null;
    this.oversample = snd.WaveShaper.OVERSAMPLE_NONE;
    this.gain = 1.0;
};
snd.WaveShaper.Status.prototype = Object.create(snd.AudioUnit.Status.prototype);
snd.WaveShaper.Status.prototype.constructor = snd.WaveShaper.Status;
<|endoftext|>