<commit_before>/*jshint forin:false, eqnull:true*/
/* globals JSYG*/

(function(factory) {

    if (typeof define != "undefined" && define.amd) define("jsyg-weatherfront",["jsyg","jsyg-path","jsyg-container"],factory);
    else if (typeof JSYG != "undefined") {
        if (JSYG.Path && JSYG.Container) factory(JSYG,JSYG.Path,JSYG.Container);
        else throw new Error("You need JSYG.Path");
    }
    else throw new Error("JSYG is needed");

})(function(JSYG,Path,Container) {

    "use strict";

    function WeatherFront(arg) {

        this.container = new JSYG("<g>")[0];

        this.types = {
            "coldfront" : {
                color : "blue",
                path : "M-8,0 l8,-12 l8,12"
            },
            "warmfront" : {
                color : "red",
                path : "M-8,0 a8,8 0 0,1 16,0"
            },
            "occlusion" : {
                color : "darkviolet",
                path : "M-12,0 l6,-12 l6,12 a7,10 0 0,1 14,0"
            }
        };

        if (arg) this.setNode(arg);
    }

    WeatherFront.prototype = new JSYG.StdConstruct;

    WeatherFront.prototype.constructor = WeatherFront;

    WeatherFront.prototype.type = "coldfront";

    WeatherFront.prototype.patternSpacing = 50;

    WeatherFront.prototype.inverseAngle = false;

    WeatherFront.prototype._setHref = function(item) {

        item.attr("href",'#jsyg-'+this.type);

        return this;
    };

    WeatherFront.prototype._idDefs = "jsyg-weatherfronts";

    WeatherFront.prototype._createDefs = function() {

        var defs = new JSYG('<defs>').attr('id',this._idDefs),
            that = this;

        Object.keys(this.types).forEach(function(name) {

            var type = that.types[name];

            new JSYG('<path>').attr({
                id:"jsyg-"+name,
                d: type.path,
                fill: type.color
            })
            .appendTo(defs);
        });

        return defs[0];
    };

    WeatherFront.prototype._positionItem = function(item,length) {

        var path = new Path(this.node),
        point = path.getPointAtLength(i),
        angle = path.getRotateAtLength(i);

        if (this.inverseAngle) angle+=180;

	item.setCenter(point);
        item.setMtx(path.getMtx());
        item.rotate(angle);
        item.scale(this._scale);
        item.translateY(-dim.height/2);
    };

    WeatherFront.prototype._geDimItem = function() {

        var item = new JSYG('<use>'),
        dim;

        this._setHref(item);
        item.css("visibility","hidden");

        this.container.appendChild(item[0]);

        dim = item.getDim();

        this.container.removeChild(item[0]);

        return dim;
    };

    WeatherFront.prototype.display = false;

    WeatherFront.prototype._clearItems = function() {

        new JSYG(this.container).find('g > use').remove();

        return this;
    };

    WeatherFront.prototype.show = function() {

        if (!this.enabled) return this;

        this._clearItems();

        var jNode = new JSYG(this.node);

        this._originalColor = jNode.css("stroke");

        jNode.css("stroke", this.types[this.type].color );

        this.display = true;

        this.update();

        this.display = true;

        return this;
    };

    WeatherFront.prototype.update = function() {

        if (!this.display) return this;

        var dim = this._geDimItem();
        var path = new Path(this.node),
        length = path.getLength(),
        g = new JSYG(this.container).find('g'),
        strokeWidth = parseFloat( path.css("stroke-width") || 1 ),
        scale = 1 + (strokeWidth-1)/3,
        spacing = Number(this.patternSpacing),
        use, point,angle, i, cpt = 1;

        for (i=dim.width*scale/2 ; i<=length-dim.width*scale/2 ; i+=spacing) {

            point = path.getPointAtLength(i);
            angle = path.getRotateAtLength(i);

            if (this.inverseAngle) angle+=180;

            use = g.find('use:nth-child('+cpt+')');

            if (!use.length) use = new JSYG('<use>').appendTo(g);

            this._setHref(use);

            use.setCenter(point);
            use.setMtx(path.getMtx());
            use.rotate(angle);
            use.scale(scale);
            use.translateY(-dim.height/2);

            cpt++;
        }

        while (use = g[0].querySelector('use:nth-child('+cpt+')')) this.container.removeChild(use);

        return this;
    };

    WeatherFront.prototype.hide = function() {

        var jNode = new JSYG(this.node);

        if (this._originalColor) jNode.css("stroke",this._originalColor);

        this._clearItems();

        this.display = false;

        return this;
    };

    WeatherFront.prototype.enable = function(opt) {

        if (this.enabled) this.disable();

        if (opt) this.set(opt);

        var parent = this.node.parentNode,
        svg = this.node.nearestViewportElement,
        defs;

        this.container.appendChild(this.node);

        this.container.appendChild( new JSYG('<g>')[0] );

        parent.appendChild(this.container);

        if (!(defs = document.getElementById(this._idDefs))) {
            svg = this.node.farthestViewportElement;
            svg.insertBefore( this._createDefs(), svg.firstChild );
        }

        this.enabled = true;

        this.show();

        return this;
    };

    WeatherFront.prototype.removeDefs = function() {

        var def = document.getElementById(this._idDefs);

        if (def) this.node.nearestViewportElement.removeChild(document.getElementById(this._idDefs));

        return this;
    }

    WeatherFront.prototype.disable = function() {

        if (!this.enabled) return this;

        this.hide();

        new Container(this.container).freeItems(this.node).empty().remove();

        this.enabled = false;

        return this;
    };

    var plugin = JSYG.bindPlugin(WeatherFront);

    JSYG.prototype.weatherFront = function() { return plugin.apply(this,arguments); };

    JSYG.WeatherFront = WeatherFront;

    return WeatherFront;

});<commit_msg>Ajout de la propriété patternScale.<commit_after>/*jshint forin:false, eqnull:true*/
/* globals JSYG*/

(function(factory) {

    if (typeof define != "undefined" && define.amd) define("jsyg-weatherfront",["jsyg","jsyg-path","jsyg-container"],factory);
    else if (typeof JSYG != "undefined") {
        if (JSYG.Path && JSYG.Container) factory(JSYG,JSYG.Path,JSYG.Container);
        else throw new Error("You need JSYG.Path");
    }
    else throw new Error("JSYG is needed");

})(function(JSYG,Path,Container) {

    "use strict";

    function WeatherFront(arg,opt) {

        this.container = new JSYG("<g>")[0];

        this.types = {
            "coldfront" : {
                color : "blue",
                path : "M-8,0 l8,-12 l8,12"
            },
            "warmfront" : {
                color : "red",
                path : "M-8,0 a8,8 0 0,1 16,0"
            },
            "occlusion" : {
                color : "darkviolet",
                path : "M-12,0 l6,-12 l6,12 a7,10 0 0,1 14,0"
            }
        };

        if (arg) this.setNode(arg);

        if (opt) this.enable(opt);
    }

    WeatherFront.prototype = new JSYG.StdConstruct;

    WeatherFront.prototype.constructor = WeatherFront;

    WeatherFront.prototype.type = "coldfront";

    WeatherFront.prototype.className = "weatherFront";

    WeatherFront.prototype.patternSpacing = 50;

    WeatherFront.prototype.patternScale = 'auto';

    WeatherFront.prototype.inverseAngle = false;

    WeatherFront.prototype._setHref = function(item) {

        item.attr("href",'#jsyg-'+this.type);

        return this;
    };

    WeatherFront.prototype._idDefs = "jsyg-weatherfronts";

    WeatherFront.prototype._createDefs = function() {

        var defs = new JSYG('<defs>').attr('id',this._idDefs),
            that = this;

        Object.keys(this.types).forEach(function(name) {

            var type = that.types[name];

            new JSYG('<path>').attr({
                id:"jsyg-"+name,
                d: type.path,
                fill: type.color
            })
            .appendTo(defs);
        });

        return defs[0];
    };

    WeatherFront.prototype._positionItem = function(item,length) {

        var path = new Path(this.node),
        point = path.getPointAtLength(i),
        angle = path.getRotateAtLength(i);

        if (this.inverseAngle) angle+=180;

	item.setCenter(point);
        item.setMtx(path.getMtx());
        item.rotate(angle);
        item.scale(this._scale);
        item.translateY(-dim.height/2);
    };

    WeatherFront.prototype._geDimItem = function() {

        var item = new JSYG('<use>'),
        dim;

        this._setHref(item);
        item.css("visibility","hidden");

        this.container.appendChild(item[0]);

        dim = item.getDim();

        this.container.removeChild(item[0]);

        return dim;
    };

    WeatherFront.prototype.display = false;

    WeatherFront.prototype._clearItems = function() {

        new JSYG(this.container).find('g > use').remove();

        return this;
    };

    WeatherFront.prototype.show = function() {

        if (!this.enabled) return this;

        this._clearItems();

        var jNode = new JSYG(this.node);

        this._originalColor = jNode.css("stroke");

        jNode.css("stroke", this.types[this.type].color );

        this.display = true;

        this.update();

        this.display = true;

        return this;
    };

    WeatherFront.prototype.calculateSize = function() {

        if (JSYG.isNumeric(this.patternScale)) return this.patternScale;

        var path = new JSYG(this.node),
        strokeWidth = parseFloat( path.css("stroke-width") || 1 );
        return 1 + (strokeWidth-1)/3;
    }

    WeatherFront.prototype.update = function() {

        if (!this.display) return this;

        var dim = this._geDimItem();
        var path = new Path(this.node),
        length = path.getLength(),
        g = new JSYG(this.container).find('g'),
        scale = this.calculateSize(),
        spacing = Number(this.patternSpacing),
        use, point,angle, i, cpt = 1;

        for (i=dim.width*scale/2 ; i<=length-dim.width*scale/2 ; i+=spacing) {

            point = path.getPointAtLength(i);
            angle = path.getRotateAtLength(i);

            if (this.inverseAngle) angle+=180;

            use = g.find('use:nth-child('+cpt+')');

            if (!use.length) use = new JSYG('<use>').appendTo(g);

            this._setHref(use);

            use.setCenter(point);
            use.setMtx(path.getMtx());
            use.rotate(angle);
            use.scale(scale);
            use.translateY(-dim.height/2);

            cpt++;
        }

        while (use = g[0].querySelector('use:nth-child('+cpt+')')) this.container.removeChild(use);

        return this;
    };

    WeatherFront.prototype.hide = function() {

        var jNode = new JSYG(this.node);

        if (this._originalColor) jNode.css("stroke",this._originalColor);

        this._clearItems();

        this.display = false;

        return this;
    };

    WeatherFront.prototype.enable = function(opt) {

        if (this.enabled) this.disable();

        if (opt) this.set(opt);

        var parent = this.node.parentNode,
        svg = this.node.nearestViewportElement,
        defs;

        new JSYG(this.container)
            .addClass(this.className)
            .append(this.node)
            .append( new JSYG('<g>')[0] )
            .appendTo(parent);

        if (!(defs = document.getElementById(this._idDefs))) {
            svg = this.node.farthestViewportElement;
            svg.insertBefore( this._createDefs(), svg.firstChild );
        }

        this.enabled = true;

        this.show();

        return this;
    };

    WeatherFront.prototype.removeDefs = function() {

        var def = document.getElementById(this._idDefs);

        if (def) this.node.nearestViewportElement.removeChild(document.getElementById(this._idDefs));

        return this;
    }

    WeatherFront.prototype.disable = function() {

        if (!this.enabled) return this;

        this.hide();

        new Container(this.container).freeItems(this.node).empty().remove();

        this.enabled = false;

        return this;
    };

    var plugin = JSYG.bindPlugin(WeatherFront);

    JSYG.prototype.weatherFront = function() { return plugin.apply(this,arguments); };

    JSYG.WeatherFront = WeatherFront;

    return WeatherFront;

});<|endoftext|>


<commit_before>/*
 * This file contains common variables, datatypes and functions used by all
 * cellular automata in this folder.
 *
 * Copyright (c) 2015 Johannes Maibaum <jmaibaum@gmail.com>
 */

var Settings = {
    boardDivision: 0,
    boardSideLenght: 0,
    canvas: undefined,
    context: undefined,
    cellsPerLine: 50,        // Devides the canvas into 'n' cellsPerLine.
    cellSize: 0,
    cellColor: ["#ffffff"],  // Needs to be extended by final game with colors.
    cellToDraw: 1,           // Default cell type for drawing operations.
    intervalID: 0,
    speed: 100
};

// Wait for DOM, then initialize.
document.addEventListener("DOMContentLoaded", initialize, false);

// Custom datatypes for generic Cells and a playing Field:
var Cell = function ()
{
    this.state = 0;
    this.neighbours = 0;
}

var Field = function (rows, columns)
{
    this.rows  = rows;
    this.columns = columns;
    this.generation = 0;
    this.generationHTML = undefined;  // Needs to be set by initialize().
    this.population = 0;
    this.oldPopulaton = 0;
    this.populationHTML = undefined;  // Needs to be set by initialize().
    this.data = [];

    for (var i = 0; i < this.rows + 2; i++) {
        this.data[i] = [];

        for (var j = 0; j < this.columns + 2; j++)
            this.data[i].push(new Cell());
    }
}

Field.prototype.updateNeighbours = function (row, column, increment)
{
    this.data[row - 1][column - 1].neighbours += increment;
    this.data[row - 1][column].neighbours     += increment;
    this.data[row - 1][column + 1].neighbours += increment;
    this.data[row][column - 1].neighbours     += increment;
    this.data[row][column + 1].neighbours     += increment;
    this.data[row + 1][column - 1].neighbours += increment;
    this.data[row + 1][column].neighbours     += increment;
    this.data[row + 1][column + 1].neighbours += increment;
}

Field.prototype.resetAllNeighbours = function()
{
    for (var row in this.data)
        for (var column in this.data[row])
            this.data[row][column].neighbours = 0;
}

Field.prototype.increaseGeneration = function()
{
    this.generation++;
    this.generationHTML.innerHTML = this.generation;
}

Field.prototype.updatePopulationHTML = function ()
{
    if (this.population != this.oldPopulation) {
        this.populationHTML.innerHTML = this.population;
        this.oldPopulation = this.population;
    }
}

Field.prototype.clear = function ()
{
    for (var row in this.data)
        for (var column in this.data[row]) {
            this.createCell(row, column, 0);
            drawCell(row, column, 0);
            this.updatePopulationHTML();
        }

    // Reset generation counter.
    this.generation = 0;
    this.generationHTML.innerHTML = this.generation;
}

// Initialize the canvas and add the event listener.
function initialize()
{
    // Prepare canvas:
    Settings.canvas = document.getElementById("board");
    Settings.context = Settings.canvas.getContext("2d");
    field.generationHTML = document.getElementById("Generation");
    field.populationHTML = document.getElementById("Population");

    Settings.boardSideLength = Settings.canvas.width;  // Assume as quadratic.
    Settings.boardDivision = Math.floor(Settings.boardSideLength /
                                        Settings.cellsPerLine);
    Settings.cellSize = Settings.boardDivision - 2;

    // Draw cell grid:
    Settings.context.strokeStyle = "#cccccc";
    Settings.context.lineWidth = 2;

    for (var i = 0; i <= Settings.boardSideLength;
         i = i + Settings.boardDivision) {
        Settings.context.moveTo(0, i);
        Settings.context.lineTo(Settings.boardSideLength, i);
        Settings.context.moveTo(i, 0);
        Settings.context.lineTo(i, Settings.boardSideLength);
        Settings.context.stroke();
    }

    // Add event listeners:
    Settings.canvas.addEventListener("mousedown", getMousePositionOnCanvas,
                                     false);

    // Setup for dropping field files on the canvas:
    var dropZone = Settings.canvas;
    dropZone.addEventListener("dragenter", dragenter, false);
    dropZone.addEventListener("dragover", dragover, false);
    dropZone.addEventListener("drop", drop, false);
}

/*
 * Callback function to determine the mouse click coordinates on the canvas.
 * Adapted from:
 * http://miloq.blogspot.de/2011/05/coordinates-mouse-click-canvas.html
 */
function getMousePositionOnCanvas(event)
{
    var x = event.x;
    var y = event.y;

    // Firefox workaround:
    if (x == undefined && y == undefined) {
        x = event.clientX + document.body.scrollLeft +
            document.documentElement.scrollLeft;
        y = event.clientY + document.body.scrollTop +
            document.documentElement.scrollTop;
    }

    x -= Settings.canvas.offsetLeft;
    y -= Settings.canvas.offsetTop;

    var coords = convertClickToFieldCoordinates(x, y);
    var row    = coords[0];
    var column = coords[1];

    if (field.createCell(row, column, Settings.cellToDraw, 1))
        drawCell(row, column, Settings.cellToDraw);
    else {
        field.createCell(row, column, 0, -1);
        drawCell(row, column, 0);
    }
}

function convertClickToFieldCoordinates(x, y) {
    var row = Math.floor(y / Settings.boardDivision) + 1;
    var column = Math.floor(x / Settings.boardDivision) + 1;

    // Ensure that we get valid coordinates:
    if (row > field.rows)
        row--;

    if (column > field.columns)
        column--;

    return [row, column];
}

// Draw a cell using field coordinates:
function drawCell(row, column, state)
{
    // Set Cell color:
    Settings.context.fillStyle = Settings.cellColor[state];

    var cellx = Math.floor(column * Settings.boardDivision)
        - Settings.boardDivision + 1;
    var celly = Math.floor(row * Settings.boardDivision)
        - Settings.boardDivision + 1;

    Settings.context.fillRect(cellx, celly, Settings.cellSize,
                              Settings.cellSize);
}

// Wrapper for field.clear():
function clearField()
{
    field.clear();
}

// Wrapper for next generation method:
function nextGeneration()
{
    if (!Settings.intervalID)
        field.nextGeneration();
    else
        stopAutomata();
}

function changeSpeed(selectItem)
{
    Settings.speed = selectItem.value;

    if (Settings.intervalID) {
        stopAutomata();
        runAutomata();
    }
}

function nextGenerationFromInterval()
{
    field.nextGeneration();
}

function runAutomata()
{
    if (!Settings.intervalID)
        Settings.intervalID = window.setInterval(nextGenerationFromInterval,
                                                 Settings.speed);
}

function stopAutomata()
{
    window.clearInterval(Settings.intervalID);
    Settings.intervalID = 0;
}

/*
 * Save field to and load field from files.
 * Adapted from:
 * https://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-
 * saving-a-text-file-in-html5-using-javascrip/
 */
function saveFile()
{
    var textToWrite = '';

    // Loop over field to construct text string:
    for (var row = 1; row <= field.rows; row++) {
        for (var column = 1; column <= field.columns; column++) {
            textToWrite += field.generateChar(row, column);
        }
        textToWrite += '\n';
    }

    var fileName = document.getElementById("FileName").value;
    var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'});
    var downloadLink = document.createElement("a");
    downloadLink.download = fileName;
    downloadLink.innerHTML = "Download File";

    if (window.webkitURL != null) {
        // Chrome allows the link to be clicked without actually adding it to
        // the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
    } else {
        // Firefox requires the link to be added to the DOM before it can be
        // clicked.
        downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
        downloadLink.onclick = function (e) {
            document.body.removeChild(e.target);
        };
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }

    downloadLink.click();
}

function loadFile(files)
{
    var file = files[0];
    var textType = /text.*/;

    if (file.type.match(textType)) {
        var reader = new FileReader();

        reader.onload = function (e) {
            var row = 1, column = 1;
            field.clear();

            for (var charNr in reader.result) {
                field.parseChar(row, column, reader.result[charNr]);

                column++;
                if (column > field.columns) {
                    column = 0;
                    row++;
                }
            }

            field.countAllNeighbours();
            field.updatePopulationHTML();
        };

        reader.readAsText(file);
    } else {
        console.log("File not supported.")
    }
}

// Functions for drag and dop onto the canvas:
function dragenter(e)
{
    e.stopPropagation();
    e.preventDefault();
}

function dragover(e)
{
    e.stopPropagation();
    e.preventDefault();
}

function drop(e)
{
    e.stopPropagation();
    e.preventDefault();

    loadFile(e.dataTransfer.files);
}

// Function for submitting with enter from a text field:
function handleKeyPress(event, textField)
{
    if (event.keyCode === 13) {  // Enter key was pressed.
        if (textField == "FileName")
            saveFile();
        else if (textField == "RandomCells")
            fillWithRandomCells();
    }
}
<commit_msg>Rename getMousePositionOnCanvas() to drawCellFromMouseClick().<commit_after>/*
 * This file contains common variables, datatypes and functions used by all
 * cellular automata in this folder.
 *
 * Copyright (c) 2015 Johannes Maibaum <jmaibaum@gmail.com>
 */

var Settings = {
    boardDivision: 0,
    boardSideLenght: 0,
    canvas: undefined,
    context: undefined,
    cellsPerLine: 50,        // Devides the canvas into 'n' cellsPerLine.
    cellSize: 0,
    cellColor: ["#ffffff"],  // Needs to be extended by final game with colors.
    cellToDraw: 1,           // Default cell type for drawing operations.
    intervalID: 0,
    speed: 100
};

// Wait for DOM, then initialize.
document.addEventListener("DOMContentLoaded", initialize, false);

// Custom datatypes for generic Cells and a playing Field:
var Cell = function ()
{
    this.state = 0;
    this.neighbours = 0;
}

var Field = function (rows, columns)
{
    this.rows  = rows;
    this.columns = columns;
    this.generation = 0;
    this.generationHTML = undefined;  // Needs to be set by initialize().
    this.population = 0;
    this.oldPopulaton = 0;
    this.populationHTML = undefined;  // Needs to be set by initialize().
    this.data = [];

    for (var i = 0; i < this.rows + 2; i++) {
        this.data[i] = [];

        for (var j = 0; j < this.columns + 2; j++)
            this.data[i].push(new Cell());
    }
}

Field.prototype.updateNeighbours = function (row, column, increment)
{
    this.data[row - 1][column - 1].neighbours += increment;
    this.data[row - 1][column].neighbours     += increment;
    this.data[row - 1][column + 1].neighbours += increment;
    this.data[row][column - 1].neighbours     += increment;
    this.data[row][column + 1].neighbours     += increment;
    this.data[row + 1][column - 1].neighbours += increment;
    this.data[row + 1][column].neighbours     += increment;
    this.data[row + 1][column + 1].neighbours += increment;
}

Field.prototype.resetAllNeighbours = function()
{
    for (var row in this.data)
        for (var column in this.data[row])
            this.data[row][column].neighbours = 0;
}

Field.prototype.increaseGeneration = function()
{
    this.generation++;
    this.generationHTML.innerHTML = this.generation;
}

Field.prototype.updatePopulationHTML = function ()
{
    if (this.population != this.oldPopulation) {
        this.populationHTML.innerHTML = this.population;
        this.oldPopulation = this.population;
    }
}

Field.prototype.clear = function ()
{
    for (var row in this.data)
        for (var column in this.data[row]) {
            this.createCell(row, column, 0);
            drawCell(row, column, 0);
            this.updatePopulationHTML();
        }

    // Reset generation counter.
    this.generation = 0;
    this.generationHTML.innerHTML = this.generation;
}

// Initialize the canvas and add the event listener.
function initialize()
{
    // Prepare canvas:
    Settings.canvas = document.getElementById("board");
    Settings.context = Settings.canvas.getContext("2d");
    field.generationHTML = document.getElementById("Generation");
    field.populationHTML = document.getElementById("Population");

    Settings.boardSideLength = Settings.canvas.width;  // Assume as quadratic.
    Settings.boardDivision = Math.floor(Settings.boardSideLength /
                                        Settings.cellsPerLine);
    Settings.cellSize = Settings.boardDivision - 2;

    // Draw cell grid:
    Settings.context.strokeStyle = "#cccccc";
    Settings.context.lineWidth = 2;

    for (var i = 0; i <= Settings.boardSideLength;
         i = i + Settings.boardDivision) {
        Settings.context.moveTo(0, i);
        Settings.context.lineTo(Settings.boardSideLength, i);
        Settings.context.moveTo(i, 0);
        Settings.context.lineTo(i, Settings.boardSideLength);
        Settings.context.stroke();
    }

    // Add event listeners:
    Settings.canvas.addEventListener("mousedown", drawCellFromMouseClick,
                                     false);

    // Setup for dropping field files on the canvas:
    var dropZone = Settings.canvas;
    dropZone.addEventListener("dragenter", dragenter, false);
    dropZone.addEventListener("dragover", dragover, false);
    dropZone.addEventListener("drop", drop, false);
}

/*
 * Callback function to determine the mouse click coordinates on the canvas.
 * Adapted from:
 * http://miloq.blogspot.de/2011/05/coordinates-mouse-click-canvas.html
 */
function drawCellFromMouseClick(event)
{
    var x = event.x;
    var y = event.y;

    // Firefox workaround:
    if (x == undefined && y == undefined) {
        x = event.clientX + document.body.scrollLeft +
            document.documentElement.scrollLeft;
        y = event.clientY + document.body.scrollTop +
            document.documentElement.scrollTop;
    }

    x -= Settings.canvas.offsetLeft;
    y -= Settings.canvas.offsetTop;

    var coords = convertClickToFieldCoordinates(x, y);
    var row    = coords[0];
    var column = coords[1];

    if (field.createCell(row, column, Settings.cellToDraw, 1))
        drawCell(row, column, Settings.cellToDraw);
    else {
        field.createCell(row, column, 0, -1);
        drawCell(row, column, 0);
    }
}

function convertClickToFieldCoordinates(x, y) {
    var row = Math.floor(y / Settings.boardDivision) + 1;
    var column = Math.floor(x / Settings.boardDivision) + 1;

    // Ensure that we get valid coordinates:
    if (row > field.rows)
        row--;

    if (column > field.columns)
        column--;

    return [row, column];
}

// Draw a cell using field coordinates:
function drawCell(row, column, state)
{
    // Set Cell color:
    Settings.context.fillStyle = Settings.cellColor[state];

    var cellx = Math.floor(column * Settings.boardDivision)
        - Settings.boardDivision + 1;
    var celly = Math.floor(row * Settings.boardDivision)
        - Settings.boardDivision + 1;

    Settings.context.fillRect(cellx, celly, Settings.cellSize,
                              Settings.cellSize);
}

// Wrapper for field.clear():
function clearField()
{
    field.clear();
}

// Wrapper for next generation method:
function nextGeneration()
{
    if (!Settings.intervalID)
        field.nextGeneration();
    else
        stopAutomata();
}

function changeSpeed(selectItem)
{
    Settings.speed = selectItem.value;

    if (Settings.intervalID) {
        stopAutomata();
        runAutomata();
    }
}

function nextGenerationFromInterval()
{
    field.nextGeneration();
}

function runAutomata()
{
    if (!Settings.intervalID)
        Settings.intervalID = window.setInterval(nextGenerationFromInterval,
                                                 Settings.speed);
}

function stopAutomata()
{
    window.clearInterval(Settings.intervalID);
    Settings.intervalID = 0;
}

/*
 * Save field to and load field from files.
 * Adapted from:
 * https://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-
 * saving-a-text-file-in-html5-using-javascrip/
 */
function saveFile()
{
    var textToWrite = '';

    // Loop over field to construct text string:
    for (var row = 1; row <= field.rows; row++) {
        for (var column = 1; column <= field.columns; column++) {
            textToWrite += field.generateChar(row, column);
        }
        textToWrite += '\n';
    }

    var fileName = document.getElementById("FileName").value;
    var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'});
    var downloadLink = document.createElement("a");
    downloadLink.download = fileName;
    downloadLink.innerHTML = "Download File";

    if (window.webkitURL != null) {
        // Chrome allows the link to be clicked without actually adding it to
        // the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
    } else {
        // Firefox requires the link to be added to the DOM before it can be
        // clicked.
        downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
        downloadLink.onclick = function (e) {
            document.body.removeChild(e.target);
        };
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }

    downloadLink.click();
}

function loadFile(files)
{
    var file = files[0];
    var textType = /text.*/;

    if (file.type.match(textType)) {
        var reader = new FileReader();

        reader.onload = function (e) {
            var row = 1, column = 1;
            field.clear();

            for (var charNr in reader.result) {
                field.parseChar(row, column, reader.result[charNr]);

                column++;
                if (column > field.columns) {
                    column = 0;
                    row++;
                }
            }

            field.countAllNeighbours();
            field.updatePopulationHTML();
        };

        reader.readAsText(file);
    } else {
        console.log("File not supported.")
    }
}

// Functions for drag and dop onto the canvas:
function dragenter(e)
{
    e.stopPropagation();
    e.preventDefault();
}

function dragover(e)
{
    e.stopPropagation();
    e.preventDefault();
}

function drop(e)
{
    e.stopPropagation();
    e.preventDefault();

    loadFile(e.dataTransfer.files);
}

// Function for submitting with enter from a text field:
function handleKeyPress(event, textField)
{
    if (event.keyCode === 13) {  // Enter key was pressed.
        if (textField == "FileName")
            saveFile();
        else if (textField == "RandomCells")
            fillWithRandomCells();
    }
}
<|endoftext|>


<commit_before>/**
 * @overview Layouter Lib
 * @module layouter
 * @author Dominik Sigmund
 * @version 0.1
 * @description Positions Images on Layouts
 * @memberof resilienz
 * @requires module:database
 * @requires module:fs
 * @requires module:child_process
 * @requires bin:imagemagick
 */
var fs = require('fs')
var mkdirp = require('mkdirp')
const execSync = require('child_process').execSync
function Layouter (layoutpath, imagepath, pagespath, database) {
  var self = {}
  self.imagepath = imagepath
  self.database = database
  self.pagespath = pagespath
  self.layoutpath = layoutpath
  self.createPage = createPage
  self.rescaleImage = rescaleImage
  self.getPage = getPage
  return self
}
function rescaleImage (image, x, y, width, height, callback) {
  var cmd = 'convert ' + image + ' -crop ' + width + 'x' + height + '' + '+' + x + '+' + y + ' ' + image
  console.log(cmd)
  var output = execSync(cmd, true)
  if (output.stderr || output.stdout) {
    console.log(output.stdout)
    console.error(output.stderr)
    callback(output)
  } else {
    callback(null)
  }
}
function createPage (actionid, language, page, callback) {
  var self = this
  mkdirp(self.pagespath + '/' + actionid + '/', function (error) {
    if (error) {
      callback(error)
    } else {
      self.database.getLayoutInfo(actionid, page, function (error, information) {
        if (error) {
          callback(error)
        } else {
          var cmd = ''
          var output = ''
          if (page === 2) {
            cmd = 'cp ' + self.layoutpath + '/' + language + '/02_inhalt.png' + self.pagespath + '/' + actionid + '/' + page + '_two.png'
            output = execSync(cmd)
          } else if (page === 44) {
            cmd = 'cp ' + '/' + language + '/16_ruecken.png' + self.pagespath + '/' + actionid + '/' + page + '.png'
            output = execSync(cmd)
          } else {
            for (var i = 0; i < information.length; i++) {
              var info = information[i]
              if (info.image === '') {
                info.image = self.layoutpath + '/placeholder.png'
              } else {
                info.image = self.imagepath + '/' + info.image
              }
              var target = ''
              if (page === 1 || page === '1') {
                target = self.pagespath + '/' + actionid + '/' + page + '.png'
              } else {
                target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
              }
              var bg = ''
              if (i === 0) {
                bg = self.layoutpath + '/' + language + '/' + info.background
              } else {
                bg = target
              }

              cmd = ''
              if (info.spin !== 0) {
                cmd = 'convert ' + bg + ' null: \\( ' + info.image + ' -sample ' + info.width + 'x' + info.height + '! -background None -rotate ' + info.spin + ' \\) -geometry \'+' + info.x + '+' + info.y + '\' -layers Composite ' + target
              } else {
                cmd = 'composite -geometry \'' + info.width + 'x' + info.height + '!+' + info.x + '+' + info.y + '\' ' + info.image + ' ' + bg + ' ' + target
              }
              console.log(cmd)
              output = execSync(cmd, true)
              if (output.stderr || output.stdout) {
                console.log(output.stdout)
                console.error(output.stderr)
                callback(null, false)
              }
            }
          }
          if (output) {
            callback(null, false)
          } else {
            callback(null, true)
          }
        }
      })
    }
  })
}

function getPage (actionid, language, page, callback) {
  var self = this
  var target = ''
  if (page === 1 || page === 44) {
    target = self.pagespath + '/' + actionid + '/' + page + '.png'
  } else {
    target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
  }
  fs.access(target, fs.constants.R_OK | fs.constants.W_OK, function (error) {
    if (error) {
      self.createPage(actionid, language, page, function (error, result) {
        if (error) {
          callback(error)
        } else {
          if (result) {
            callback(null, target)
          } else {
            callback({msg: 'Error creating Image'})
          }
        }
      })
    } else {
      callback(null, target)
    }
  })
}

module.exports = Layouter
<commit_msg>back-fix<commit_after>/**
 * @overview Layouter Lib
 * @module layouter
 * @author Dominik Sigmund
 * @version 0.1
 * @description Positions Images on Layouts
 * @memberof resilienz
 * @requires module:database
 * @requires module:fs
 * @requires module:child_process
 * @requires bin:imagemagick
 */
var fs = require('fs')
var mkdirp = require('mkdirp')
const execSync = require('child_process').execSync
function Layouter (layoutpath, imagepath, pagespath, database) {
  var self = {}
  self.imagepath = imagepath
  self.database = database
  self.pagespath = pagespath
  self.layoutpath = layoutpath
  self.createPage = createPage
  self.rescaleImage = rescaleImage
  self.getPage = getPage
  return self
}
function rescaleImage (image, x, y, width, height, callback) {
  var cmd = 'convert ' + image + ' -crop ' + width + 'x' + height + '' + '+' + x + '+' + y + ' ' + image
  console.log(cmd)
  var output = execSync(cmd, true)
  if (output.stderr || output.stdout) {
    console.log(output.stdout)
    console.error(output.stderr)
    callback(output)
  } else {
    callback(null)
  }
}
function createPage (actionid, language, page, callback) {
  var self = this
  mkdirp(self.pagespath + '/' + actionid + '/', function (error) {
    if (error) {
      callback(error)
    } else {
      self.database.getLayoutInfo(actionid, page, function (error, information) {
        if (error) {
          callback(error)
        } else {
          var cmd = ''
          var output = ''
          if (page === 2) {
            cmd = 'cp ' + self.layoutpath + '/' + language + '/02_inhalt.png' + self.pagespath + '/' + actionid + '/' + page + '_two.png'
            output = execSync(cmd)
          } else if (page === 44) {
            cmd = 'cp ' + self.layoutpath + '/' + language + '/16_ruecken.png ' + self.pagespath + '/' + actionid + '/' + page + '.png'
            output = execSync(cmd)
          } else {
            for (var i = 0; i < information.length; i++) {
              var info = information[i]
              if (info.image === '') {
                info.image = self.layoutpath + '/placeholder.png'
              } else {
                info.image = self.imagepath + '/' + info.image
              }
              var target = ''
              if (page === 1 || page === '1') {
                target = self.pagespath + '/' + actionid + '/' + page + '.png'
              } else {
                target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
              }
              var bg = ''
              if (i === 0) {
                bg = self.layoutpath + '/' + language + '/' + info.background
              } else {
                bg = target
              }

              cmd = ''
              if (info.spin !== 0) {
                cmd = 'convert ' + bg + ' null: \\( ' + info.image + ' -sample ' + info.width + 'x' + info.height + '! -background None -rotate ' + info.spin + ' \\) -geometry \'+' + info.x + '+' + info.y + '\' -layers Composite ' + target
              } else {
                cmd = 'composite -geometry \'' + info.width + 'x' + info.height + '!+' + info.x + '+' + info.y + '\' ' + info.image + ' ' + bg + ' ' + target
              }
              console.log(cmd)
              output = execSync(cmd, true)
              if (output.stderr || output.stdout) {
                console.log(output.stdout)
                console.error(output.stderr)
                callback(null, false)
              }
            }
          }
          if (output) {
            callback(null, false)
          } else {
            callback(null, true)
          }
        }
      })
    }
  })
}

function getPage (actionid, language, page, callback) {
  var self = this
  var target = ''
  if (page === 1 || page === 44) {
    target = self.pagespath + '/' + actionid + '/' + page + '.png'
  } else {
    target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
  }
  fs.access(target, fs.constants.R_OK | fs.constants.W_OK, function (error) {
    if (error) {
      self.createPage(actionid, language, page, function (error, result) {
        if (error) {
          callback(error)
        } else {
          if (result) {
            callback(null, target)
          } else {
            callback({msg: 'Error creating Image'})
          }
        }
      })
    } else {
      callback(null, target)
    }
  })
}

module.exports = Layouter
<|endoftext|>


<commit_before>// k / (150 * size)
createCanvas = (w, h) => {
   var c = document.createElement('canvas');
   c.width = w
   c.height = h
   return c
}
drawSakura = (size) => {
   var canvas = createCanvas(size, size)
   let scale = 150 / size
   if (canvas.getContext) {
      var ctx = canvas.getContext('2d')
      ctx.scale_bezierCurveTo = (x1, y1, x2, y2, ex, ey) => {
         ctx.bezierCurveTo(x1 / scale, y1 / scale, x2 / scale, y2 / scale, ex / scale, ey / scale)
      }
      ctx.scale_moveTo = (x1, y1) => ctx.moveTo(x1 / scale, y1 / scale)
      ctx.fillColor = (color) => {
         var k = ctx.fillStyle
         ctx.fillStyle = color
         ctx.fill()
         ctx.fillStyle = k
      }
      ctx.beginPath();
      ctx.scale_moveTo(75, 40)
      ctx.scale_bezierCurveTo(75, 40, 70, 25, 50, 25)
      ctx.scale_bezierCurveTo(15, 25, 20, 62.5, 20, 62.5)
      ctx.scale_bezierCurveTo(20, 80, 40, 102, 75, 120)

      ctx.scale_bezierCurveTo(110, 102, 130, 80, 130, 62.5)
      ctx.scale_bezierCurveTo(130, 62.5, 130, 25, 100, 25)
      ctx.scale_bezierCurveTo(85, 25, 75, 37, 75, 40)
      ctx.fillColor("#FEDFE1")
   }
   return canvas
}

var canvas = createCanvas(100, 100)
document.body.appendChild(canvas)
canvas.getContext('2d').drawImage(drawSakura(50), 0, 0)<commit_msg>Script commit at 08/08/2017  0:00:11 UTC+8<commit_after><|endoftext|>


<commit_before>/**
 * @overview Layouter Lib
 * @module layouter
 * @author Dominik Sigmund
 * @version 0.1
 * @description Positions Images on Layouts
 * @memberof resilienz
 * @requires module:database
 * @requires module:fs
 * @requires module:child_process
 * @requires bin:imagemagick
 */
var fs = require('fs')
var mkdirp = require('mkdirp')
const execSync = require('child_process').execSync
function Layouter (layoutpath, imagepath, pagespath, database, maxPages) {
  var self = {}
  self.maxPages = maxPages
  self.imagepath = imagepath
  self.database = database
  self.pagespath = pagespath
  self.layoutpath = layoutpath
  self.createPage = createPage
  self.printNumbers = printNumbers
  self.rescaleImage = rescaleImage
  self.getPage = getPage
  return self
}
function rescaleImage (image, x, y, width, height, callback) {
  var cmd = 'convert ' + image + ' -crop ' + width + 'x' + height + '' + '+' + x + '+' + y + ' ' + image
  console.log(cmd)
  var output = execSync(cmd, true)
  if (output.stderr || output.stdout) {
    console.log(output.stdout)
    console.error(output.stderr)
    callback(output)
  } else {
    callback(null)
  }
}
function createPage (actionid, language, page, callback) {
  if (page === 0) {
    return callback(null, false)
  }
  var self = this
  mkdirp(self.pagespath + '/' + actionid + '/', function (error) {
    if (error) {
      callback(error)
    } else {
      self.database.getLayoutInfo(actionid, page, function (error, information) {
        if (error) {
          callback(error)
        } else {
          var cmd = ''
          var output = {}
          if (page === 2) {
            cmd = 'cp ' + self.layoutpath + '/' + language + '/02_inhalt.png ' + self.pagespath + '/' + actionid + '/' + page + '_two.png'
            output = execSync(cmd, true)
            if (output.stderr) {
              callback(null, false)
            } else {
              self.printNumbers(self.pagespath + '/' + actionid + '/' + page + '_two.png', page, function(error) {
                if (error) {
                  callback(null, false)
                } else {
                  callback(null, true)
                }
              })
            }
          } else if (page === self.maxPages) {
            cmd = 'cp ' + self.layoutpath + '/' + language + '/16_ruecken.png ' + self.pagespath + '/' + actionid + '/' + page + '.png'
            output = execSync(cmd, true)
            if (output.stderr) {
              callback(null, false)
            } else {
              callback(null, true)
            }
          } else {
            var target = ''
            if (page === 1 || page === '1') {
              target = self.pagespath + '/' + actionid + '/' + page + '.png'
            } else {
              target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
            }
            for (var i = 0; i < information.length; i++) {
              var info = information[i]
              if (info.image === '') {
                info.image = self.layoutpath + '/placeholder_print.png'
              } else {
                info.image = self.imagepath + '/' + info.image
              }
              var bg = ''
              if (i === 0) {
                bg = self.layoutpath + '/' + language + '/' + info.background
              } else {
                bg = target
              }

              cmd = ''
              if (info.spin !== 0) {
                cmd = 'convert ' + bg + ' null: \\( ' + info.image + ' -sample ' + info.width + 'x' + info.height + '! -background None -rotate ' + info.spin + ' \\) -geometry \'+' + info.x + '+' + info.y + '\' -layers Composite ' + target
              } else {
                cmd = 'composite -geometry \'' + info.width + 'x' + info.height + '!+' + info.x + '+' + info.y + '\' ' + info.image + ' ' + bg + ' ' + target
              }
              console.log(cmd)
              output = execSync(cmd, true)
            }
            if (output.stderr || output.stdout) {
              console.log(output.stdout)
              console.error(output.stderr)
              callback(null, false)
            } else {
              self.printNumbers(target, page, function(error) {
                if (error) {
                  callback(null, false)
                } else {
                  callback(null, true)
                }
              })
            }
          }
        }
      })
    }
  })
}

function getPage (actionid, language, page, callback) {
  var self = this
  var target = ''
  if (page === 1 || page === self.maxPages) {
    target = self.pagespath + '/' + actionid + '/' + page + '.png'
  } else {
    target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
  }
  fs.access(target, fs.constants.R_OK | fs.constants.W_OK, function (error) {
    if (error) {
      self.createPage(actionid, language, page, function (error, result) {
        if (error) {
          callback(error)
        } else {
          if (result) {
            callback(null, target)
          } else {
            callback({msg: 'Error creating Image'})
          }
        }
      })
    } else {
      callback(null, target)
    }
  })
}

function printNumbers(target, page,callback) {
  cmd1 = 'convert ' + target + ' -font Helvetica -pointsize 24 -gravity southwest -stroke \'#000C\' -strokewidth 2 -annotate +50+10 \'' + page + '\' -stroke none -fill white -annotate +50+10 \'' + page + '\' ' + target
  output1 = execSync(cmd1, true)
  cmd2 = 'convert ' + target + ' -font Helvetica -pointsize 24 -gravity southeast -stroke \'#000C\' -strokewidth 2 -annotate +50+10 \'' + (page+1) + '\' -stroke none -fill white -annotate +50+10 \'' + (page+1) + '\' ' + target
  output2 = execSync(cmd2, true)
  if (output1.stderr || output1.stdout || output2.stderr || output2.stdout) {
    callback({msg:'Error'})
  } else {
    callback(null)
  }
}

module.exports = Layouter
<commit_msg>sync of number printing<commit_after>/**
 * @overview Layouter Lib
 * @module layouter
 * @author Dominik Sigmund
 * @version 0.1
 * @description Positions Images on Layouts
 * @memberof resilienz
 * @requires module:database
 * @requires module:fs
 * @requires module:child_process
 * @requires bin:imagemagick
 */
var fs = require('fs')
var mkdirp = require('mkdirp')
const execSync = require('child_process').execSync
function Layouter (layoutpath, imagepath, pagespath, database, maxPages) {
  var self = {}
  self.maxPages = maxPages
  self.imagepath = imagepath
  self.database = database
  self.pagespath = pagespath
  self.layoutpath = layoutpath
  self.createPage = createPage
  self.printNumbers = printNumbers
  self.rescaleImage = rescaleImage
  self.getPage = getPage
  return self
}
function rescaleImage (image, x, y, width, height, callback) {
  var cmd = 'convert ' + image + ' -crop ' + width + 'x' + height + '' + '+' + x + '+' + y + ' ' + image
  console.log(cmd)
  var output = execSync(cmd, true)
  if (output.stderr || output.stdout) {
    console.log(output.stdout)
    console.error(output.stderr)
    callback(output)
  } else {
    callback(null)
  }
}
function createPage (actionid, language, page, callback) {
  if (page === 0) {
    return callback(null, false)
  }
  var self = this
  mkdirp(self.pagespath + '/' + actionid + '/', function (error) {
    if (error) {
      callback(error)
    } else {
      self.database.getLayoutInfo(actionid, page, function (error, information) {
        if (error) {
          callback(error)
        } else {
          var cmd = ''
          var output = {}
          if (page === 2) {
            cmd = 'cp ' + self.layoutpath + '/' + language + '/02_inhalt.png ' + self.pagespath + '/' + actionid + '/' + page + '_two.png'
            output = execSync(cmd, true)
            if (output.stderr) {
              callback(null, false)
            } else {
              callback(null, self.printNumbers(self.pagespath + '/' + actionid + '/' + page + '_two.png', page))
            }
          } else if (page === self.maxPages) {
            cmd = 'cp ' + self.layoutpath + '/' + language + '/16_ruecken.png ' + self.pagespath + '/' + actionid + '/' + page + '.png'
            output = execSync(cmd, true)
            if (output.stderr) {
              callback(null, false)
            } else {
              callback(null, true)
            }
          } else {
            var target = ''
            if (page === 1 || page === '1') {
              target = self.pagespath + '/' + actionid + '/' + page + '.png'
            } else {
              target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
            }
            for (var i = 0; i < information.length; i++) {
              var info = information[i]
              if (info.image === '') {
                info.image = self.layoutpath + '/placeholder_print.png'
              } else {
                info.image = self.imagepath + '/' + info.image
              }
              var bg = ''
              if (i === 0) {
                bg = self.layoutpath + '/' + language + '/' + info.background
              } else {
                bg = target
              }
              cmd = ''
              if (info.spin !== 0) {
                cmd = 'convert ' + bg + ' null: \\( ' + info.image + ' -sample ' + info.width + 'x' + info.height + '! -background None -rotate ' + info.spin + ' \\) -geometry \'+' + info.x + '+' + info.y + '\' -layers Composite ' + target
              } else {
                cmd = 'composite -geometry \'' + info.width + 'x' + info.height + '!+' + info.x + '+' + info.y + '\' ' + info.image + ' ' + bg + ' ' + target
              }
              console.log(cmd)
              output = execSync(cmd, true)
            }
            if (output.stderr || output.stdout) {
              console.log(output.stdout)
              console.error(output.stderr)
              callback(null, false)
            } else {
              callback(null, self.printNumbers(target, page))
            }
          }
        }
      })
    }
  })
}

function getPage (actionid, language, page, callback) {
  var self = this
  var target = ''
  if (page === 1 || page === self.maxPages) {
    target = self.pagespath + '/' + actionid + '/' + page + '.png'
  } else {
    target = self.pagespath + '/' + actionid + '/' + page + '_two.png'
  }
  fs.access(target, fs.constants.R_OK | fs.constants.W_OK, function (error) {
    if (error) {
      self.createPage(actionid, language, page, function (error, result) {
        if (error) {
          callback(error)
        } else {
          if (result) {
            callback(null, target)
          } else {
            callback({msg: 'Error creating Image'})
          }
        }
      })
    } else {
      callback(null, target)
    }
  })
}

function printNumbers(target, page) {
  cmd1 = 'convert ' + target + ' -font Helvetica -pointsize 24 -gravity southwest -stroke \'#000C\' -strokewidth 2 -annotate +50+10 \'' + page + '\' -stroke none -fill white -annotate +50+10 \'' + page + '\' ' + target
  output1 = execSync(cmd1, true)
  cmd2 = 'convert ' + target + ' -font Helvetica -pointsize 24 -gravity southeast -stroke \'#000C\' -strokewidth 2 -annotate +50+10 \'' + (page+1) + '\' -stroke none -fill white -annotate +50+10 \'' + (page+1) + '\' ' + target
  output2 = execSync(cmd2, true)
  if (output1.stderr || output1.stdout || output2.stderr || output2.stdout) {
    return false
  } else {
    return true
  }
}

module.exports = Layouter
<|endoftext|>


<commit_before>import vdom from "virtual-dom";

var {h, diff, patch, create} = vdom;

export class Renderer {

  static default() { return this._default || new this() }

  constructor(world, rootNode) {
    if (!world || !world.isMorph)
      throw new Error(`Trying to initialize renderer with an invalid world morph: ${world}`)
    if (!rootNode || !("nodeType" in rootNode))
      throw new Error(`Trying to initialize renderer with an invalid root node: ${rootNode}`)
    this.worldMorph = world;
    world._isWorld = true; // for world() method
    this.rootNode = rootNode;
    this.domNode = null;
    this.renderMap = new WeakMap();
    this.renderWorldLoopProcess = null;
  }

  clear() {
    this.stopRenderWorldLoop();
    this.domNode.parentNode.removeChild(this.domNode);
    this.domNode = null;
    this.renderMap = new WeakMap();
  }

  startRenderWorldLoop() {
    this.renderWorld();
    this.renderWorldLoopProcess = requestAnimationFrame(() =>
      this.renderWorldLoop());
  }

  stopRenderWorldLoop() {
    window.cancelAnimationFrame(this.renderWorldLoopProcess);
    this.renderWorldLoopProcess = null;
  }

  renderWorld() {
    var world = this.worldMorph;

    if (!world.needsRerender()) return;

    var tree = this.renderMap.get(world) || this.renderMorph(world),
        domNode = this.domNode || (this.domNode = create(tree)),
        newTree = this.renderMorph(world),
        patches = diff(tree, newTree);

    if (!domNode.parentNode)
      this.rootNode.appendChild(domNode);

    patch(domNode, patches);
  }

  renderMorph(morph) {
    if (!morph.needsRerender()) {
      var rendered = this.renderMap.get(morph);
      if (rendered) return rendered;
    }
    morph.aboutToRender();

    const shapedStyle = Object.assign({
        position: "absolute",
        left: morph.position.x + 'px',
        top: morph.position.y + 'px',
        width: morph.extent.x + 'px',
        height: morph.extent.y + 'px',
        backgroundColor: morph.fill ? morph.fill.toString() : "",
        overflow: morph.clipMode
    }, morph.shape().style);

    const attributes = Object.assign(
                  morph.shape(),
                  {id: morph.id,
                   style: shapedStyle});

    var tree = h(morph._nodeType,
                attributes,
                morph.submorphs.map(m => this.renderMorph(m)));

    this.renderMap.set(morph, tree);
    return tree;
  }

  getNodeForMorph(morph) {
    // Hmm, this also finds dom nodes not associated with this renderer, its
    // domNode... Is this a problem?
    return document.getElementById(morph.id);
  }

  getMorphForNode(node) {
    return this.worldMorph ?
      this.worldMorph.withAllSubmorphsDetect(morph => morph.id === node.id) :
      null;
  }
}
<commit_msg>fix startRenderWorldLoop<commit_after>import vdom from "virtual-dom";

var {h, diff, patch, create} = vdom;

export class Renderer {

  static default() { return this._default || new this() }

  constructor(world, rootNode) {
    if (!world || !world.isMorph)
      throw new Error(`Trying to initialize renderer with an invalid world morph: ${world}`)
    if (!rootNode || !("nodeType" in rootNode))
      throw new Error(`Trying to initialize renderer with an invalid root node: ${rootNode}`)
    this.worldMorph = world;
    world._isWorld = true; // for world() method
    this.rootNode = rootNode;
    this.domNode = null;
    this.renderMap = new WeakMap();
    this.renderWorldLoopProcess = null;
  }

  clear() {
    this.stopRenderWorldLoop();
    this.domNode.parentNode.removeChild(this.domNode);
    this.domNode = null;
    this.renderMap = new WeakMap();
  }

  startRenderWorldLoop() {
    this.renderWorld();
    this.renderWorldLoopProcess = requestAnimationFrame(() =>
      this.startRenderWorldLoop());
  }

  stopRenderWorldLoop() {
    window.cancelAnimationFrame(this.renderWorldLoopProcess);
    this.renderWorldLoopProcess = null;
  }

  renderWorld() {
    var world = this.worldMorph;

    if (!world.needsRerender()) return;

    var tree = this.renderMap.get(world) || this.renderMorph(world),
        domNode = this.domNode || (this.domNode = create(tree)),
        newTree = this.renderMorph(world),
        patches = diff(tree, newTree);

    if (!domNode.parentNode)
      this.rootNode.appendChild(domNode);

    patch(domNode, patches);
  }

  renderMorph(morph) {
    if (!morph.needsRerender()) {
      var rendered = this.renderMap.get(morph);
      if (rendered) return rendered;
    }
    morph.aboutToRender();

    const shapedStyle = Object.assign({
        position: "absolute",
        left: morph.position.x + 'px',
        top: morph.position.y + 'px',
        width: morph.extent.x + 'px',
        height: morph.extent.y + 'px',
        backgroundColor: morph.fill ? morph.fill.toString() : "",
        overflow: morph.clipMode
    }, morph.shape().style);

    const attributes = Object.assign(
                  morph.shape(),
                  {id: morph.id,
                   style: shapedStyle});

    var tree = h(morph._nodeType,
                attributes,
                morph.submorphs.map(m => this.renderMorph(m)));

    this.renderMap.set(morph, tree);
    return tree;
  }

  getNodeForMorph(morph) {
    // Hmm, this also finds dom nodes not associated with this renderer, its
    // domNode... Is this a problem?
    return document.getElementById(morph.id);
  }

  getMorphForNode(node) {
    return this.worldMorph ?
      this.worldMorph.withAllSubmorphsDetect(morph => morph.id === node.id) :
      null;
  }
}
<|endoftext|>


<commit_before>// renderer.js

const zerorpc  = require("zerorpc")
const chokidar = require("chokidar")
const path     = require("path")
const queue    = require("queue")
const bunyan   = require('bunyan')
const fs       = require("fs")
const notifier = require('node-notifier');
const electron = require('electron')
const remote   = electron.remote

let opts        = remote.getCurrentWindow().opts
let concurrency = opts.options.concurrency ? opts.options.concurrency : 1
let watchDepth  = opts.options.depth       ? opts.options.depth : 2
let logfile     = opts.options.log         ? opts.options.log   : "baserunner.log"
let fastqfile   = opts.options.ofq         ? opts.options.ofq   : "out.fastq"
const loglines  = 16
let logstream   = bunyan.createLogger({
    name: "baserunner",
    streams: [{
        path: logfile
    }]
})
let fastqstream = null

/* zerorpc setup */
let client = new zerorpc.Client()
client.connect("tcp://127.0.0.1:4242")

/* logging setup */
let logTranscript = document.querySelector("#log")
logTranscript.innerHTML = (new Array(loglines)).join("\n")

const log = (str) => {
    let tmp                 = logTranscript.innerHTML
    logTranscript.innerHTML = logTranscript.innerHTML.split(/\n/).splice(1, loglines).join("\n") + str + "\n"
    logstream.info(str)
}

/* log configuration information */
log("watch depth=" + watchDepth)
log("worker concurrency=" + concurrency)
log("output fastq=" + fastqfile)
log("logfile=" + logfile)

/* average processing time per read */
let avgTime      = 0
let etaIndicator = document.querySelector("#etaCounter")

/* progress indicator setup */
let stateIndicator       = document.querySelector("#state")
stateIndicator.innerHTML = "stopped"

const setupSelectionAction = (selection) => {
    folderSelection            = selection
    let folder_indicator       = document.querySelector("#folders")
    folder_indicator.innerHTML = folderSelection //.join(",")
    start.removeAttribute("disabled", "disabled")
    log("selected " + folderSelection)
}

/* setup button action */
let setup = document.querySelector("#setup")
let folderSelection = null
setup.addEventListener('click', () => {
    let selection = remote.dialog.showOpenDialog(null, {
	properties: ['openDirectory']
    })

    if(!selection) {
	return
    }

    setupSelectionAction(selection[0]) // only keep the first selection
})

let watcher      = null
let workWaiting  = new Array()
let successCount = 0
let failureCount = 0
let progress     = document.querySelector("#progress")
let counters     = {
    success: document.querySelector("#successCounter"),
    failure: document.querySelector("#failureCounter"),
    total:   document.querySelector("#totalCounter"),
    queued:  document.querySelector("#queuedCounter"),
}
let workQueue    = queue({
    concurrency: concurrency,
    autostart: 1
})

const notify = (msg, title) => {
    return notifier.notify({
	title: title ? title : "baserunner",
	icon: path.join(__dirname, 'assets/baserunner80x80.png'),
	message: msg
    });
}

const workIndicatorUpdate = () => {
    let perc  = 100 * (successCount + failureCount) / (workWaiting.length + successCount + failureCount)
    let percS = 100 * (successCount) / (workWaiting.length + successCount + failureCount)
    let percF = 100 * (failureCount) / (workWaiting.length + successCount + failureCount)
//    let bar  = document.querySelector("#workProgress .progress")
//    let pxw  = bar.parentElement.offsetWidth * perc / 100
//    bar.style.setProperty('width', pxw + "px")

    let barS  = document.querySelector("#workProgress .success")
    let pxwS  = barS.parentElement.offsetWidth * percS / 100
    barS.style.setProperty('width', pxwS + "px")

    let barF  = document.querySelector("#workProgress .failure")
    let pxwF  = barF.parentElement.offsetWidth * percF / 100
    barF.style.setProperty('width', pxwF + "px")

    document.querySelector("#workProgress .label").innerHTML = perc.toFixed(2) + "%"

    counters.success.innerHTML = successCount
    counters.failure.innerHTML = failureCount
    counters.total.innerHTML   = successCount + failureCount
    counters.queued.innerHTML  = workWaiting.length
}

const short_path = (str) => {
    return str.replace(folderSelection,"").replace(/^\/?/,"")
}

let workIndicatorInterval = null

const etaDate = () => {
    return new Date((new Date()).getTime() + avgTime * workWaiting.length)
}

const checkWork = (qcb) => {

    if(workWaiting.length === 0 &&
       (new Date()) > etaDate()) {
	/* autostop */
	notify("termination condition reached")
	log("autostopping")
	stopAction()
	qcb() // come back and recheck state in a bit
    }

    let cb = () => {
	workIndicatorUpdate()
	if(stateIndicator.innerHTML !== "stopped") {
	    workQueue.push(checkWork) // self-perpetuating
	}
	qcb()
    }

    let len = workWaiting.length
    if(!len) {
	/* no work to do. wait for a bit */
	log("nothing to do")
	setTimeout( () => { cb(); }, 5000)
	return
    }

    let path = workWaiting.shift()
    log("begin " + short_path(path))
    let startTime = new Date()

    client.invoke("process_read", path, (error, res) => {
	let endTime = new Date()
	let dTime   = endTime-startTime;
	avgTime     = ((successCount + failureCount) * avgTime + dTime) / (1 + successCount + failureCount)
	etaIndicator.innerHTML = etaDate().toLocaleString()

	if(error) {
	    log("error " + short_path(path))
	    log("message " + error)
	    console.error(error)
	    failureCount++
	    return cb()
	}

	let fastq   = res[0];
	let failure = res[1];
	if(failure) {
	    log(failure.toString() + " " + short_path(path))
	    failureCount++
	} else {
	    log("end " + short_path(path))
	    fastqstream.write(fastq.toString())
	    successCount++
	}
	/* immediately check for more work */
	return cb()
    })
}

/* start button action */
const startAction = () => {
    if(!folderSelection) {
	alert("please set up a folder")
	return
    }
    log("selected " + folderSelection)

    fastqstream = fs.createWriteStream(fastqfile)
    workDone    = 0
    workFailed  = 0
    workIndicatorInterval = setInterval(workIndicatorUpdate, 5000)

    setup.setAttribute("disabled", "disabled")
    start.setAttribute("disabled", "disabled")
    stop.removeAttribute("disabled")

    let tmp = [folderSelection].map(function(o) {
	return path.join(o, "**", "*.fast5")
    })

    watcher = chokidar.watch(tmp, {
	depth: watchDepth,
	ignored: /(^|[\/\\])\../
    })
	.on('add', (path, stats) => {
	    log("queued " + short_path(path))
	    workWaiting.push(path)
	})
    stateIndicator.innerHTML = "running"

    /* kick off */
    checkWork(() => { })
    notify("starting")
}

/* stop button action */
const stopAction = () => {
    if(!watcher) {
	alert("already stopped")
	return
    }

    log("stopping file watcher")
    watcher.close()

    log("stopping workers")
    workQueue.end("stopping")

    log("emptying queue")
    workWaiting=[]

    log("stopping indicators")
    workIndicatorUpdate()
    clearInterval(workIndicatorInterval)

    setup.removeAttribute("disabled")
    start.removeAttribute("disabled")
    stop.setAttribute("disabled", "disabled")

    log("closing fastq stream")
    fastqstream.end()

    stateIndicator.innerHTML="stopped"

    notify("stopped")
    log("stopped")
}

let start = document.querySelector("#start")
start.addEventListener('click', startAction)

let stop = document.querySelector("#stop")
stop.addEventListener('click', stopAction)

/* initial button state */
setup.removeAttribute("disabled")
start.setAttribute("disabled", "disabled")
stop.setAttribute("disabled", "disabled")

/* additional commandline arg handling */
if(opts.options.input) {
    setupSelectionAction(opts.options.input)
}

if(opts.options.autostart) {
    startAction()
}
<commit_msg>drop teh infoz<commit_after>// renderer.js

const zerorpc  = require("zerorpc")
const chokidar = require("chokidar")
const path     = require("path")
const queue    = require("queue")
const bunyan   = require('bunyan')
const fs       = require("fs")
const notifier = require('node-notifier');
const electron = require('electron')
const remote   = electron.remote

let opts        = remote.getCurrentWindow().opts
let concurrency = opts.options.concurrency ? opts.options.concurrency : 1
let watchDepth  = opts.options.depth       ? opts.options.depth : 2
let logfile     = opts.options.log         ? opts.options.log   : "baserunner.log"
let fastqfile   = opts.options.ofq         ? opts.options.ofq   : "out.fastq"
const loglines  = 16
let logstream   = bunyan.createLogger({
    name: "baserunner",
    streams: [{
        path: logfile
    }]
})
let fastqstream = null

/* zerorpc setup */
let client = new zerorpc.Client()
client.connect("tcp://127.0.0.1:4242")

/* logging setup */
let logTranscript = document.querySelector("#log")
logTranscript.innerHTML = (new Array(loglines)).join("\n")

const log = (str) => {
    let tmp                 = logTranscript.innerHTML
    logTranscript.innerHTML = logTranscript.innerHTML.split(/\n/).splice(1, loglines).join("\n") + str + "\n"
    logstream.info(str)
}

/* log configuration information */
log("watch depth=" + watchDepth)
log("worker concurrency=" + concurrency)
log("output fastq=" + fastqfile)
log("logfile=" + logfile)

/* average processing time per read */
let avgTime      = 0
let etaIndicator = document.querySelector("#etaCounter")

/* progress indicator setup */
let stateIndicator       = document.querySelector("#state")
stateIndicator.innerHTML = "stopped"

const setupSelectionAction = (selection) => {
    folderSelection            = selection
    let folder_indicator       = document.querySelector("#folders")
    folder_indicator.innerHTML = folderSelection + " FastQ: " + fastqfile + " Log: " + logfile//.join(",")
    start.removeAttribute("disabled", "disabled")
    log("selected " + folderSelection)
}

/* setup button action */
let setup = document.querySelector("#setup")
let folderSelection = null
setup.addEventListener('click', () => {
    let selection = remote.dialog.showOpenDialog(null, {
	properties: ['openDirectory']
    })

    if(!selection) {
	return
    }

    setupSelectionAction(selection[0]) // only keep the first selection
})

let watcher      = null
let workWaiting  = new Array()
let successCount = 0
let failureCount = 0
let progress     = document.querySelector("#progress")
let counters     = {
    success: document.querySelector("#successCounter"),
    failure: document.querySelector("#failureCounter"),
    total:   document.querySelector("#totalCounter"),
    queued:  document.querySelector("#queuedCounter"),
}
let workQueue    = queue({
    concurrency: concurrency,
    autostart: 1
})

const notify = (msg, title) => {
    return notifier.notify({
	title: title ? title : "baserunner",
	icon: path.join(__dirname, 'assets/baserunner80x80.png'),
	message: msg
    });
}

const workIndicatorUpdate = () => {
    let perc  = 100 * (successCount + failureCount) / (workWaiting.length + successCount + failureCount)
    let percS = 100 * (successCount) / (workWaiting.length + successCount + failureCount)
    let percF = 100 * (failureCount) / (workWaiting.length + successCount + failureCount)
//    let bar  = document.querySelector("#workProgress .progress")
//    let pxw  = bar.parentElement.offsetWidth * perc / 100
//    bar.style.setProperty('width', pxw + "px")

    let barS  = document.querySelector("#workProgress .success")
    let pxwS  = barS.parentElement.offsetWidth * percS / 100
    barS.style.setProperty('width', pxwS + "px")

    let barF  = document.querySelector("#workProgress .failure")
    let pxwF  = barF.parentElement.offsetWidth * percF / 100
    barF.style.setProperty('width', pxwF + "px")

    document.querySelector("#workProgress .label").innerHTML = perc.toFixed(2) + "%"

    counters.success.innerHTML = successCount
    counters.failure.innerHTML = failureCount
    counters.total.innerHTML   = successCount + failureCount
    counters.queued.innerHTML  = workWaiting.length
}

const short_path = (str) => {
    return str.replace(folderSelection,"").replace(/^\/?/,"")
}

let workIndicatorInterval = null

const etaDate = () => {
    return new Date((new Date()).getTime() + avgTime * workWaiting.length)
}

const checkWork = (qcb) => {

    if(workWaiting.length === 0 &&
       (new Date()) > etaDate()) {
	/* autostop */
	notify("termination condition reached")
	log("autostopping")
	stopAction()
	qcb() // come back and recheck state in a bit
    }

    let cb = () => {
	workIndicatorUpdate()
	if(stateIndicator.innerHTML !== "stopped") {
	    workQueue.push(checkWork) // self-perpetuating
	}
	qcb()
    }

    let len = workWaiting.length
    if(!len) {
	/* no work to do. wait for a bit */
	log("nothing to do")
	setTimeout( () => { cb(); }, 5000)
	return
    }

    let path = workWaiting.shift()
    log("begin " + short_path(path))
    let startTime = new Date()

    client.invoke("process_read", path, (error, res) => {
	let endTime = new Date()
	let dTime   = endTime-startTime;
	avgTime     = ((successCount + failureCount) * avgTime + dTime) / (1 + successCount + failureCount)
	etaIndicator.innerHTML = etaDate().toLocaleString()

	if(error) {
	    log("error " + short_path(path))
	    log("message " + error)
	    console.error(error)
	    failureCount++
	    return cb()
	}

	let fastq   = res[0];
	let failure = res[1];
	if(failure) {
	    log(failure.toString() + " " + short_path(path))
	    failureCount++
	} else {
	    log("end " + short_path(path))
	    fastqstream.write(fastq.toString())
	    successCount++
	}
	/* immediately check for more work */
	return cb()
    })
}

/* start button action */
const startAction = () => {
    if(!folderSelection) {
	alert("please set up a folder")
	return
    }
    log("selected " + folderSelection)

    fastqstream = fs.createWriteStream(fastqfile)
    workDone    = 0
    workFailed  = 0
    workIndicatorInterval = setInterval(workIndicatorUpdate, 5000)

    setup.setAttribute("disabled", "disabled")
    start.setAttribute("disabled", "disabled")
    stop.removeAttribute("disabled")

    let tmp = [folderSelection].map(function(o) {
	return path.join(o, "**", "*.fast5")
    })

    watcher = chokidar.watch(tmp, {
	depth: watchDepth,
	ignored: /(^|[\/\\])\../
    })
	.on('add', (path, stats) => {
	    log("queued " + short_path(path))
	    workWaiting.push(path)
	})
    stateIndicator.innerHTML = "running"

    /* kick off */
    checkWork(() => { })
    notify("starting")
}

/* stop button action */
const stopAction = () => {
    if(!watcher) {
	alert("already stopped")
	return
    }

    log("stopping file watcher")
    watcher.close()

    log("stopping workers")
    workQueue.end("stopping")

    log("emptying queue")
    workWaiting=[]

    log("stopping indicators")
    workIndicatorUpdate()
    clearInterval(workIndicatorInterval)

    setup.removeAttribute("disabled")
    start.removeAttribute("disabled")
    stop.setAttribute("disabled", "disabled")

    log("closing fastq stream")
    fastqstream.end()

    stateIndicator.innerHTML="stopped"

    notify("stopped")
    log("stopped")
}

let start = document.querySelector("#start")
start.addEventListener('click', startAction)

let stop = document.querySelector("#stop")
stop.addEventListener('click', stopAction)

/* initial button state */
setup.removeAttribute("disabled")
start.setAttribute("disabled", "disabled")
stop.setAttribute("disabled", "disabled")

/* additional commandline arg handling */
if(opts.options.input) {
    setupSelectionAction(opts.options.input)
}

if(opts.options.autostart) {
    startAction()
}
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var deepEqual = require('deep-equal');
var makeMockFunction = require('./makeMockFunction');

module.exports = function makeMock(object, type) {

  var args = [];
  var mockObj = function mockObj() {};
  var prop;

  for (prop in object) {
    console.log('Prop: ', prop);
    var mocked = getMockForProp(prop, object);
    mockObj[prop] = mocked;
  }

  for (prop in object.prototype) {
    mockObj.prototype[prop] = makeMockFunction(args, prop);
  }

  mockObj.prototype.reset = reset;
  mockObj.prototype.getArgs = getArgs;
  mockObj.reset = reset;
  mockObj.getArgs = getArgs;

  function reset() {
    for (prop in args) {
      if (args.hasOwnProperty(prop)) {
        args[prop] = [];
      }
    }
  }

  function getArgs() {
    return args;
  }

  function getMockForProp(prop, object) {
    // Mock the function
    if (typeof object[prop] === 'function') {
      return makeMockFunction(args, prop);
    }
    // Recursively iterate through object mocking all properties
    else if (typeof object[prop] === 'object') {
      var mockInterface = {};
      for (var propName in object[prop]) {
        mockInterface[propName] = getMockForProp(propName, object[prop]);
      }
      return mockInterface;
    }
    // Return the property if not a function or object
    return object[prop];
  }

  return mockObj;
};

<commit_msg>remove logging statement<commit_after>var assert = require('chai').assert;
var deepEqual = require('deep-equal');
var makeMockFunction = require('./makeMockFunction');

module.exports = function makeMock(object, type) {

  var args = [];
  var mockObj = function mockObj() {};
  var prop;

  for (prop in object) {
    var mocked = getMockForProp(prop, object);
    mockObj[prop] = mocked;
  }

  for (prop in object.prototype) {
    mockObj.prototype[prop] = makeMockFunction(args, prop);
  }

  mockObj.prototype.reset = reset;
  mockObj.prototype.getArgs = getArgs;
  mockObj.reset = reset;
  mockObj.getArgs = getArgs;

  function reset() {
    for (prop in args) {
      if (args.hasOwnProperty(prop)) {
        args[prop] = [];
      }
    }
  }

  function getArgs() {
    return args;
  }

  function getMockForProp(prop, object) {
    // Mock the function
    if (typeof object[prop] === 'function') {
      return makeMockFunction(args, prop);
    }
    // Recursively iterate through object mocking all properties
    else if (typeof object[prop] === 'object') {
      var mockInterface = {};
      for (var propName in object[prop]) {
        mockInterface[propName] = getMockForProp(propName, object[prop]);
      }
      return mockInterface;
    }
    // Return the property if not a function or object
    return object[prop];
  }

  return mockObj;
};

<|endoftext|>


<commit_before>#!/usr/bin/env node

const fs = require('fs')
const url = require('url')

const _ = require('lodash')
const express = require('express')
const httpProxy = require('http-proxy')
const tunnel = require('tunnel')
const argv = require('yargs')
  .usage('Usage: $0 --local local_dir1 [--local local_dir2]')

  .demand('l')
  .alias('l', 'local')
  .nargs('l', 1)
  .describe('l', `Local directory. You can provide more than one, files
            will be looked up in the order they were added`)

  .number('p')
  .alias('p', 'port')
  .default('p', 8080)
  .describe('p', 'Listen on this port')

  .string('a')
  .alias('a', 'address')
  .default('a', '0.0.0.0')
  .describe('a', 'Listen on this address')

  .string('r')
  .alias('r', 'remote')
  .describe('r', 'Remote url to forward all non-local resources')

  .string('proxy')
  .describe('proxy', 'Proxy to connect to remote resources')

  .boolean('allow-invalid-cert')
  .describe('allow-invalid-cert', 'Accept invalid or self-signed SSL certs')

  .boolean('strip-cookie-domain')
  .describe('strip-cookie-domain', 'Remove `Domain` from cookies set from proxyed remotes')
  .default('strip-cookie-domain', true)

  .help('h')
  .alias('h', 'help')
  .argv

const app = express()
const localPaths = _.isArray(argv.local) ? argv.local : [ argv.local ]
localPaths.forEach(addLocal)

if (argv.allowInvalidCert) process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
if (argv.remote) app.use(forwardTo(argv.remote))

console.log(`Listening on ${argv.address}:${argv.port}`)
app.listen(argv.port, argv.address)

function addLocal(path) {
  // FIXME: better error handling, until then: throw
  fs.accessSync(path, fs.F_R_OK)
  app.use(express.static(path))
}

function forwardTo(target) {
  const proxy = createProxy(target)
  if (argv.stripCookieDomain)
    stripCookieDomain(proxy)

  return (req, res) => {
    proxy.web(req, res)
  }
}

function stripCookieDomain(proxy) {
  proxy.on('proxyRes', (proxyRes) => {
    const setCookie = proxyRes.headers['set-cookie']
    if (setCookie)
      proxyRes.headers['set-cookie'] = setCookie.map(cookie => cookie.replace(/Domain=[^;]+;?/, ''))
  })
}

function createProxy(target) {
  const config = {
    target: target,
    changeOrigin: true,
    autoRewrite: true,
    secure: false // usually the local name won't compatible with remote cert
  }
  if (argv.proxy) {
    config.agent = getProxyedAgent(argv.proxy, target)
    config.toProxy = true
  }

  return httpProxy.createProxyServer(config)
}

function getProxyedAgent(proxy, target) {
  const urlParts = url.parse(proxy)
  const config = {
    proxy: {
      host: urlParts.hostname,
      port: urlParts.port
    }
  }
  const isHttps = url.parse(target).protocol === 'https:'

  return isHttps ?  tunnel.httpsOverHttp(config) : tunnel.httpOverHttp(config)
}

<commit_msg>Rename refs<commit_after>#!/usr/bin/env node

const fs = require('fs')
const url = require('url')

const _ = require('lodash')
const express = require('express')
const httpProxy = require('http-proxy')
const tunnel = require('tunnel')
const options = require('yargs')
  .usage('Usage: $0 --local local_dir1 [--local local_dir2] [--remote https://example.com]')

  .demand('l')
  .alias('l', 'local')
  .nargs('l', 1)
  .describe('l', `Local directory. You can provide more than one, files
            will be looked up in the order they were added`)

  .number('p')
  .alias('p', 'port')
  .default('p', 8080)
  .describe('p', 'Listen on this port')

  .string('a')
  .alias('a', 'address')
  .default('a', '0.0.0.0')
  .describe('a', 'Listen on this address')

  .string('r')
  .alias('r', 'remote')
  .describe('r', 'Remote url to forward all non-local resources')

  .string('proxy')
  .describe('proxy', 'Proxy to connect to remote resources')

  .boolean('allow-invalid-cert')
  .describe('allow-invalid-cert', 'Accept invalid or self-signed SSL certs')

  .boolean('strip-cookie-domain')
  .describe('strip-cookie-domain', 'Remove `Domain` from cookies set from proxyed remotes')
  .default('strip-cookie-domain', true)

  .help('h')
  .alias('h', 'help')
  .argv

const app = express()
const localPaths = _.isArray(options.local) ? options.local : [ options.local ]
localPaths.forEach(addLocal)

if (options.allowInvalidCert)
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'

if (options.remote)
  app.use(forwardTo(options.remote))

console.log(`Listening on ${options.address}:${options.port}`)
app.listen(options.port, options.address)

function addLocal(path) {
  // FIXME: better error handling, until then: throw
  fs.accessSync(path, fs.F_R_OK)
  app.use(express.static(path))
}

function forwardTo(target) {
  const proxy = createProxy(target)
  if (options.stripCookieDomain)
    stripCookieDomain(proxy)

  return (req, res) => {
    proxy.web(req, res)
  }
}

function stripCookieDomain(proxy) {
  proxy.on('proxyRes', (proxyRes) => {
    const setCookie = proxyRes.headers['set-cookie']
    if (setCookie)
      proxyRes.headers['set-cookie'] = setCookie.map(cookie => cookie.replace(/Domain=[^;]+;?/, ''))
  })
}

function createProxy(target) {
  const config = {
    target: target,
    changeOrigin: true,
    autoRewrite: true,
    secure: false // usually the local name won't compatible with remote cert
  }
  if (options.proxy) {
    config.agent = sslAgentWithProxy(options.proxy, target)
    config.toProxy = true
  }

  return httpProxy.createProxyServer(config)
}

function sslAgentWithProxy(proxy, target) {
  const urlParts = url.parse(proxy)
  const config = {
    proxy: {
      host: urlParts.hostname,
      port: urlParts.port
    }
  }
  const isHttps = url.parse(target).protocol === 'https:'

  return isHttps ?  tunnel.httpsOverHttp(config) : tunnel.httpOverHttp(config)
}

<|endoftext|>


<commit_before>(function () {
    "use strict";

    /*jshint node: true*/
    /*eslint-env node*/

    // http://krasimirtsonev.com/blog/article/Nodejs-managing-child-processes-starting-stopping-exec-spawn

    var childProcess = require("child_process"),
        psTree = require("ps-tree");

    if (/^win/.test(process.platform)) {
        module.exports = function (pid) {
            childProcess.exec("taskkill /PID " + pid + " /T /F");
        };

    } else {
        module.exports = function (pid) {
            psTree(pid, function (err, children) { // eslint-disable-line handle-callback-err
                [pid].concat(
                    children.map(function (p) {
                        return p.PID;
                    })
                ).forEach(function (tpid) {
                    try {
                        process.kill(tpid, "SIGKILL");
                    } catch (ex) {
                        // ignore
                    }
                });
            });
        };

    }

}());
<commit_msg>Remove unused kill<commit_after><|endoftext|>


<commit_before>/*
 * netcheck
 * Will monitor Internet and local network connectivity and inform about their state.
 * https://github.com/INSIGHTReplay/netcheck
 *
 * Copyright ©2015 Insight Replay, Inc.
 * Licensed under the MIT license.
 * @author Thanasis Polychronakis
 */
var _ = require('lodash');
var Promise = require('bluebird');
var network = require('network');
var isOnline = require('is-online');

var monitor = require('monitor').getInstance();

/**
 * @fileOverview netcheck Base.
 */
var netcheck = module.exports = {};

netcheck.on = monitor.on.bind(monitor);
netcheck.once = monitor.once.bind(monitor);
netcheck.removeListener = monitor.removeListener.bind(monitor);
netcheck.removeAllListener = monitor.removeAllListeners.bind(monitor);

/**
 * Start the network monitors.
 *
 */
netcheck.init = function() {
  monitor.init();
};

/**
 * Setup netcheck.
 *
 * @param {Object} options User defined options.
 */
netcheck.setup = function(options) {
  _.defaults(options, monitor.options);
};

/**
 * Checks if Internet connectivity exists.
 *
 * @return {Promise(Boolean)} A Promise with the boolean result.
 */
netcheck.hasInternet = Promise.method(function() {
  if (monitor.isActive) {
    // Monitor is active, check if tests are complete or wait for them.
    if (monitor.internetTestComplete) {
      return monitor.hasInternet;
    } else {
      return new Promise(function(resolve) {
        monitor.once('internet', function(isConnected) {
          resolve(isConnected);
        });
      });
    }
  } else {
    // Monitor is not running, invoke the test here.
    return new Promise(function(resolve) {
      isOnline(function(err, online) {
        resolve(!!online);
      });
    });
  }
});

/**
 * Checks if Local Network connectivity exists.
 *
 * @return {Promise(Boolean)} A Promise with the boolean result.
 */
netcheck.hasLocal = Promise.method(function() {
  if (monitor.isActive) {
    // Monitor is active, check if tests are complete or wait for them.
    if (monitor.localTestComplete) {
      return monitor.hasLocal;
    } else {
      return new Promise(function(resolve) {
        monitor.once('local', function(isConnected) {
          resolve(isConnected);
        });
      });
    }
  } else {
    // Monitor is not running, invoke the test here.
    return new Promise(function(resolve) {
      /* jshint camelcase:false */
      network.get_private_ip(function(err) {
        resolve(!err);
      });
    });
  }
});
<commit_msg>fix paths<commit_after>/*
 * netcheck
 * Will monitor Internet and local network connectivity and inform about their state.
 * https://github.com/INSIGHTReplay/netcheck
 *
 * Copyright ©2015 Insight Replay, Inc.
 * Licensed under the MIT license.
 * @author Thanasis Polychronakis
 */
var _ = require('lodash');
var Promise = require('bluebird');
var network = require('network');
var isOnline = require('is-online');

var monitor = require('./monitor').getInstance();

/**
 * @fileOverview netcheck Base.
 */
var netcheck = module.exports = {};

netcheck.on = monitor.on.bind(monitor);
netcheck.once = monitor.once.bind(monitor);
netcheck.removeListener = monitor.removeListener.bind(monitor);
netcheck.removeAllListeners = monitor.removeAllListeners.bind(monitor);

/**
 * Start the network monitors.
 *
 */
netcheck.init = function() {
  monitor.init();
};

/**
 * Setup netcheck.
 *
 * @param {Object} options User defined options.
 */
netcheck.setup = function(options) {
  _.defaults(options, monitor.options);
};

/**
 * Checks if Internet connectivity exists.
 *
 * @return {Promise(Boolean)} A Promise with the boolean result.
 */
netcheck.hasInternet = Promise.method(function() {
  if (monitor.isActive) {
    // Monitor is active, check if tests are complete or wait for them.
    if (monitor.internetTestComplete) {
      return monitor.hasInternet;
    } else {
      return new Promise(function(resolve) {
        monitor.once('internet', function(isConnected) {
          resolve(isConnected);
        });
      });
    }
  } else {
    // Monitor is not running, invoke the test here.
    return new Promise(function(resolve) {
      isOnline(function(err, online) {
        resolve(!!online);
      });
    });
  }
});

/**
 * Checks if Local Network connectivity exists.
 *
 * @return {Promise(Boolean)} A Promise with the boolean result.
 */
netcheck.hasLocal = Promise.method(function() {
  if (monitor.isActive) {
    // Monitor is active, check if tests are complete or wait for them.
    if (monitor.localTestComplete) {
      return monitor.hasLocal;
    } else {
      return new Promise(function(resolve) {
        monitor.once('local', function(isConnected) {
          resolve(isConnected);
        });
      });
    }
  } else {
    // Monitor is not running, invoke the test here.
    return new Promise(function(resolve) {
      /* jshint camelcase:false */
      network.get_private_ip(function(err) {
        resolve(!err);
      });
    });
  }
});
<|endoftext|>