<commit_before>var pk = pk || {};
(function(pk) {
    // HELPERS FOR jQUERY+ANGULAR
    if (typeof jQuery === 'object') {
        // jquery available
        jQuery.fn.extend({
            pkScroll: function(axis) {
                pk.scroll({
                    element: this[0],
                    axis: axis
                });
            }
        });
    }
    if (typeof angular === 'object') {
        // angular available
        (

            function() {
                angular.module('pk-scroll', ['ng'])
                    .directive('pkScroll', function() {
                        return {
                            restrict: 'A',
                            link: function(scope, el) {
                                pk.scroll({
                                    element: el[0],
                                    axis: el[0].getAttribute('pk-scroll')
                                });
                            }
                        };
                    });
            })();
    }
    pk.scroll = function(opt) {

        var el = opt.element;
        // INIT SCROLL STRUCTURE

        var tpl = "
\
            <" + el.nodeName + " class='pk-scroll-content'>\
                " + el.innerHTML + "\
            </" + el.nodeName + ">\

\

\

\

\

\

\

";
        el.innerHTML = '';
        el = pk.replaceEl(el, tpl);
        var container = el.children[0],
            trackY = el.children[1],
            floatY = trackY.children[0],
            trackX = el.children[2],
            floatX = trackX.children[0];
        // INIT VARIABLES
        var
            floatYh = 0,
            floatXw = 0,
            allowY = false,
            allowX = false,
            percY = 0,
            percX = 0,
            contentH = 0,
            contentW = 0,
            containerH = 0,
            containerW = 0,
            contentWidth = 0,
            contentHeight = 0,
            containerWidth = 0,
            containerHeight = 0,
            scrollDir = opt.axis ? opt.axis.toLowerCase() : (pk.attribute(el, 'pk-scroll') ? pk.attribute(el, 'pk-scroll') : "y");
        if (pk.getStyle(el, 'position') === "static") {
            el.style.position = "relative";
        }

        pk.bindEvent("scroll", container, function() {
            percY = container.scrollTop / (contentH - containerH);
            percX = container.scrollLeft / (contentW - containerW);
            percY = percY < 0 ? 0 : percY > 1 ? 1 : percY;
            percX = percX < 0 ? 0 : percX > 1 ? 1 : percX;
            floatY.style.top = (containerH - floatYh) * percY + 'px';
            floatX.style.left = (containerW - floatXw) * percX + 'px';
        });

        function resolveDimensions() {
            contentH = container.scrollHeight;
            contentW = container.scrollWidth;
            containerH = el.offsetHeight;
            containerW = el.offsetWidth;
            if (scrollDir.indexOf("y") > -1 && contentH > containerH) {
                allowY = true;
                pk.addClass(el, 'pk-scroll-enableY');
                floatYh = floatY.offsetHeight;
                container.scrollTop = (contentH - containerH) * percY;
            } else {
                allowY = false;
                pk.removeClass(el, 'pk-scroll-enableY');
                container.scrollTop = 0;
            }
            if (scrollDir.indexOf("x") > -1 && contentW > containerW) {
                allowX = true;
                pk.addClass(el, 'pk-scroll-enableX');
                floatXw = floatX.offsetWidth;
                container.scrollLeft = (contentW - containerW) * percX;
            } else {
                allowX = false;
                pk.removeClass(el, 'pk-scroll-enableX');
                container.scrollLeft = 0;
            }
        }
        resolveDimensions();

        setInterval(function() {
            var widthContainer = el.offsetWidth,
                heightContainer = el.offsetHeight,
                widthContent = container.scrollWidth,
                heightContent = container.scrollHeight;
            if (widthContainer !== containerWidth || heightContainer !== containerHeight || widthContent !== contentWidth || heightContent !== contentHeight) {
                contentWidth = widthContent;
                contentHeight = heightContent;
                containerWidth = widthContainer;
                containerHeight = heightContainer;
                resolveDimensions();
            }
        }, 500);

        // DRAG HANDLERS

        if (allowY) {
            pk.drag({
                element: floatY,
                move: {
                    y: true
                },
                container: {
                    element: trackY
                },
                listeners: {
                    dragging: function() {
                        container.scrollTop = (contentH - containerH) * (floatY.offsetTop / (trackY.offsetHeight - floatY.offsetHeight));
                    }
                }
            });
        }
        if (allowX) {
            pk.drag({
                element: floatX,
                move: {
                    x: true
                },
                container: {
                    element: trackX
                },
                listeners: {
                    dragging: function() {

                        container.scrollLeft = (contentW - containerW) * (floatX.offsetLeft / (trackX.offsetWidth - floatX.offsetWidth));
                    }
                }
            });
        }
        pk.bindEvent("click", floatY, function(e) {
            pk.preventBubble(e);
        });
        pk.bindEvent("click", floatX, function(e) {
            pk.preventBubble(e);
        });

        // TRACK CLICKING HANDLERS
        pk.bindEvent("click", trackY, function(e) {
            container.scrollTop = ((e.pageY - el.getBoundingClientRect().top) / containerH * (contentH - containerH));
        });
        pk.bindEvent("click", trackX, function(e) {
            container.scrollLeft = ((e.pageX - el.getBoundingClientRect().left) / containerW * (contentW - containerW));
        });

        // MOUSE WHEEL HANDLERS
        function mouseScroll(e) {
            var offset = 0.1;
            if (e.wheelDelta > 0 || e.detail < 0) {
                offset = offset * -1;
            }
            if (allowY) {
                container.scrollTop = Math.round(container.scrollTop + (contentH - containerH) * offset);
            } else {
                container.scrollLeft = Math.round(container.scrollLeft + (contentW - containerW) * offset);
            }
            /* Stop wheel propogation (prevent parent scrolling) */
            pk.preventBubble(e);
        }

        pk.bindEvent("mousewheel", container, mouseScroll);

        // TOUCH EVENT HANDLERS

        function getXy(e) {
            // touch event
            if (e.targetTouches && (e.targetTouches.length >= 1)) {
                return {
                    x: e.targetTouches[0].clientX,
                    y: e.targetTouches[0].clientY
                };
            }
            // mouse event
            return {
                x: e.clientX,
                y: e.clientY
            };
        }

        var pressed = false,
            startPos = {};

        function tap(e) {
            pressed = true;
            startPos = getXy(e);
            e.preventDefault();
            e.stopPropagation();
            return false;
        }

        function release(e) {
            pressed = false;
            e.preventDefault();
            e.stopPropagation();
            return false;
        }

        function drag(e) {
            var endPos, deltaX, deltaY;
            if (pressed) {
                endPos = getXy(e);
                deltaY = startPos.y - endPos.y;
                deltaX = startPos.x - endPos.x;
                if (deltaY > 2 || deltaY < -2) {
                    startPos.y = endPos.y;
                    container.scrollTop += deltaY;

                }
                if (deltaX > 2 || deltaX < -2) {
                    startPos.x = endPos.x;
                    container.scrollLeft += deltaX;
                }
            }
            e.preventDefault();
            e.stopPropagation();
            return false;
        }
        if (typeof window.ontouchstart !== 'undefined') {
            pk.bindEvent('touchstart', container[0], tap);
            pk.bindEvent('touchmove', container[0], drag);
            pk.bindEvent('touchend', window, release);
        }

        // KEYBOARD HANDLERS
        container.setAttribute("tabindex", 0);
        pk.bindEvent('keydown', container, function(e) {
            if (allowY) {
                switch (e.keyCode) {
                    case 38: //up cursor
                        container.scrollTop -= containerH * 0.1;
                        break;
                    case 40: //down cursor
                    case 32: //spacebar
                        container.scrollTop += containerH * 0.1;
                        break;
                    case 33: //page up
                        container.scrollTop -= containerH;
                        break;
                    case 34: //page down
                        container.scrollTop += containerH;
                        break;
                    case 36: //home
                        container.scrollTop = 0;
                        break;
                    case 35: //end
                        container.scrollTop = contentH;
                        break;
                }
            }
            if (allowX) {
                switch (e.keyCode) {
                    case 37: //left cursor
                        container.scrollLeft -= containerW * 0.1;
                        break;
                    case 39: //right cursor
                        container.scrollLeft += containerW * 0.1;
                        break;
                }
            }
            pk.preventBubble(e);
        });
    };
    return pk;
})(pk);
<commit_msg>Update scroll.js<commit_after>var pk = pk || {};
(function(pk) {
    // HELPERS FOR jQUERY+ANGULAR
    if (typeof jQuery === 'object') {
        // jquery available
        jQuery.fn.extend({
            pkScroll: function(axis) {
                pk.scroll({
                    element: this[0],
                    axis: axis
                });
            }
        });
    }
    if (typeof angular === 'object') {
        // angular available
        (

            function() {
                angular.module('pk-scroll', ['ng'])
                    .directive('pkScroll', function() {
                        return {
                            restrict: 'A',
                            link: function(scope, el) {
                                pk.scroll({
                                    element: el[0],
                                    axis: el[0].getAttribute('pk-scroll')
                                });
                            }
                        };
                    });
            })();
    }
    pk.scroll = function(opt) {

        var el = opt.element;
        // INIT SCROLL STRUCTURE

        var tpl = "
\
            <" + el.nodeName + " class='pk-scroll-content'>\
                " + el.innerHTML + "\
            </" + el.nodeName + ">\

\

\

\

\

\

\

";
        el.innerHTML = '';
        el = pk.replaceEl(el, tpl);
        var container = el.children[0],
            trackY = el.children[1],
            floatY = trackY.children[0],
            trackX = el.children[2],
            floatX = trackX.children[0];
        // INIT VARIABLES
        var
            floatYh = 0,
            floatXw = 0,
            allowY = false,
            allowX = false,
            percY = 0,
            percX = 0,
            contentH = 0,
            contentW = 0,
            containerH = 0,
            containerW = 0,
            contentWidth = 0,
            contentHeight = 0,
            containerWidth = 0,
            containerHeight = 0,
            scrollDir = opt.axis ? opt.axis.toLowerCase() : (pk.attribute(el, 'pk-scroll') ? pk.attribute(el, 'pk-scroll') : "y");
        if (pk.getStyle(el, 'position') === "static") {
            el.style.position = "relative";
        }

        pk.bindEvent("scroll", container, function() {
            percY = container.scrollTop / (contentH - containerH);
            percX = container.scrollLeft / (contentW - containerW);
            percY = percY < 0 ? 0 : percY > 1 ? 1 : percY;
            percX = percX < 0 ? 0 : percX > 1 ? 1 : percX;
            floatY.style.top = (containerH - floatYh) * percY + 'px';
            floatX.style.left = (containerW - floatXw) * percX + 'px';
        });

        function resolveDimensions() {
            contentH = container.scrollHeight;
            contentW = container.scrollWidth;
            containerH = el.offsetHeight;
            containerW = el.offsetWidth;
            if (scrollDir.indexOf("y") > -1 && contentH > containerH) {
                allowY = true;
                pk.addClass(el, 'pk-scroll-enableY');
                floatYh = floatY.offsetHeight;
                container.scrollTop = (contentH - containerH) * percY;
            } else {
                allowY = false;
                pk.removeClass(el, 'pk-scroll-enableY');
                container.scrollTop = 0;
            }
            if (scrollDir.indexOf("x") > -1 && contentW > containerW) {
                allowX = true;
                pk.addClass(el, 'pk-scroll-enableX');
                floatXw = floatX.offsetWidth;
                container.scrollLeft = (contentW - containerW) * percX;
            } else {
                allowX = false;
                pk.removeClass(el, 'pk-scroll-enableX');
                container.scrollLeft = 0;
            }
        }
        resolveDimensions();

        setInterval(function() {
            var widthContainer = el.offsetWidth,
                heightContainer = el.offsetHeight,
                widthContent = container.scrollWidth,
                heightContent = container.scrollHeight;
            if (widthContainer !== containerWidth || heightContainer !== containerHeight || widthContent !== contentWidth || heightContent !== contentHeight) {
                contentWidth = widthContent;
                contentHeight = heightContent;
                containerWidth = widthContainer;
                containerHeight = heightContainer;
                resolveDimensions();
            }
        }, 500);

        // DRAG HANDLERS

        if (allowY) {
            pk.drag({
                element: floatY,
                move: {
                    y: true
                },
                container: {
                    element: trackY
                },
                listeners: {
                    dragging: function() {
                        container.scrollTop = (contentH - containerH) * (floatY.offsetTop / (trackY.offsetHeight - floatY.offsetHeight));
                    }
                }
            });
        }
        if (allowX) {
            pk.drag({
                element: floatX,
                move: {
                    x: true
                },
                container: {
                    element: trackX
                },
                listeners: {
                    dragging: function() {

                        container.scrollLeft = (contentW - containerW) * (floatX.offsetLeft / (trackX.offsetWidth - floatX.offsetWidth));
                    }
                }
            });
        }
        pk.bindEvent("click", floatY, function(e) {
            pk.preventBubble(e);
        });
        pk.bindEvent("click", floatX, function(e) {
            pk.preventBubble(e);
        });

        // TRACK CLICKING HANDLERS
        pk.bindEvent("click", trackY, function(e) {
            container.scrollTop = (e.offsetY / containerH * (contentH - containerH));
        });
        pk.bindEvent("click", trackX, function(e) {
            container.scrollLeft = (e.offsetX / containerW * (contentW - containerW));
        });

        // MOUSE WHEEL HANDLERS
        function mouseScroll(e) {
            var offset = 0.1;
            if (e.wheelDelta > 0 || e.detail < 0) {
                offset = offset * -1;
            }
            if (allowY) {
                container.scrollTop = Math.round(container.scrollTop + (contentH - containerH) * offset);
            } else {
                container.scrollLeft = Math.round(container.scrollLeft + (contentW - containerW) * offset);
            }
            /* Stop wheel propogation (prevent parent scrolling) */
            pk.preventBubble(e);
        }

        pk.bindEvent("mousewheel", container, mouseScroll);

        // TOUCH EVENT HANDLERS

        function getXy(e) {
            // touch event
            if (e.targetTouches && (e.targetTouches.length >= 1)) {
                return {
                    x: e.targetTouches[0].clientX,
                    y: e.targetTouches[0].clientY
                };
            }
            // mouse event
            return {
                x: e.clientX,
                y: e.clientY
            };
        }

        var pressed = false,
            startPos = {};

        function tap(e) {
            pressed = true;
            startPos = getXy(e);
            e.preventDefault();
            e.stopPropagation();
            return false;
        }

        function release(e) {
            pressed = false;
            e.preventDefault();
            e.stopPropagation();
            return false;
        }

        function drag(e) {
            var endPos, deltaX, deltaY;
            if (pressed) {
                endPos = getXy(e);
                deltaY = startPos.y - endPos.y;
                deltaX = startPos.x - endPos.x;
                if (deltaY > 2 || deltaY < -2) {
                    startPos.y = endPos.y;
                    container.scrollTop += deltaY;

                }
                if (deltaX > 2 || deltaX < -2) {
                    startPos.x = endPos.x;
                    container.scrollLeft += deltaX;
                }
            }
            e.preventDefault();
            e.stopPropagation();
            return false;
        }
        if (typeof window.ontouchstart !== 'undefined') {
            pk.bindEvent('touchstart', container[0], tap);
            pk.bindEvent('touchmove', container[0], drag);
            pk.bindEvent('touchend', window, release);
        }

        // KEYBOARD HANDLERS
        container.setAttribute("tabindex", 0);
        pk.bindEvent('keydown', container, function(e) {
            if (allowY) {
                switch (e.keyCode) {
                    case 38: //up cursor
                        container.scrollTop -= containerH * 0.1;
                        break;
                    case 40: //down cursor
                    case 32: //spacebar
                        container.scrollTop += containerH * 0.1;
                        break;
                    case 33: //page up
                        container.scrollTop -= containerH;
                        break;
                    case 34: //page down
                        container.scrollTop += containerH;
                        break;
                    case 36: //home
                        container.scrollTop = 0;
                        break;
                    case 35: //end
                        container.scrollTop = contentH;
                        break;
                }
            }
            if (allowX) {
                switch (e.keyCode) {
                    case 37: //left cursor
                        container.scrollLeft -= containerW * 0.1;
                        break;
                    case 39: //right cursor
                        container.scrollLeft += containerW * 0.1;
                        break;
                }
            }
            pk.preventBubble(e);
        });
    };
    return pk;
})(pk);
<|endoftext|>


<commit_before>/*
 Seni
 Copyright (C) 2015  Inderjit Gill <email@indy.io>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import RenderPacket from './RenderPacket';
import GLRenderer from './GLRenderer';
import MatrixStack from './MatrixStack';
import MathUtil from './MathUtil';
import Colour from './Colour';
import Util from './Util';
import { mat4 } from 'gl-matrix';

const Format = Colour.Format;

class Renderer {
  constructor(canvasElement) {
    this.glRenderer = new GLRenderer(canvasElement);

    // matrix setup
    this.matrixStack = new MatrixStack();
    this.mvMatrix = mat4.create();
    this.pMatrix = mat4.create();
    mat4.ortho(this.pMatrix, 0, 1000, 0, 1000, 10, -10);

    this.renderPackets = [];
    this.renderPacket = new RenderPacket();
  }

  vectorToCanvasSpace(v2) {
    let res = this.matrixStack.transform2DVector(v2);
    // destructuring Float32Array as Arrays doesn't work in safari
    // so we have to build and return a normal JS array
    return [res[0], res[1]];
  }

  // ----------------------------------------------------------------------
  // functions beginning with cmd are commands.
  // perhaps split this out into a separate class?
  cmdMatrixPush() {
    return this.matrixStack.pushMatrix();
  }

  cmdMatrixPop() {
    return this.matrixStack.popMatrix();
  }

/*
 *  Seni
 *  Copyright (C) 2015  Inderjit Gill <email@indy.io>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

  cmdMatrixScale(x, y) {
    return this.matrixStack.scale(x, y);
  }

  cmdMatrixTranslate(x, y) {
    return this.matrixStack.translate(x, y);
  }

  cmdMatrixRotate(angle) {
    return this.matrixStack.rotate(angle);
  }

  cmdRenderRect(params) {
    return this.renderRect(params);
  }

  cmdRenderPoly(params) {
    return this.renderPoly(params);
  }

  cmdRenderPolySlice(params) {
    return this.renderPolySlice(params);
  }

  cmdRenderGradientPoly(params, sides) {
    return this.renderGradientPoly(params, sides);
  }

  cmdRenderBezier(params) {
    return this.renderCurve(params, MathUtil.bezierCoordinates);
  }

  cmdRenderQuadratic(params) {
    return this.renderCurve(params, MathUtil.quadraticCoordinates);
  }

  // ----------------------------------------------------------------------

  renderRect(params) {
    const {
      position,
      width,
      height,
      colour
    } = params;

    const [x, y] = position;
    const halfWidth = width / 2;
    const halfHeight = height / 2;

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    this.prepareToAddTriangleStrip(4, [x - halfWidth, y - halfHeight]);
    this.addVertex([x - halfWidth, y - halfHeight], colourArray);
    this.addVertex([x + halfWidth, y - halfHeight], colourArray);
    this.addVertex([x - halfWidth, y + halfHeight], colourArray);
    this.addVertex([x + halfWidth, y + halfHeight], colourArray);
  }

  renderPoly(params) {
    let {
      position,
      width,
      height,
      radius,
      tessellation,
      colour
    } = params;

    const [x, y] = position;

    if (radius !== undefined) {
      // use the radius for both width and height if it's given
      width = radius;
      height = radius;
    }

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    this.prepareToAddTriangleStrip((tessellation * 2) + 2, [x, y]);

    let twoPI = Math.PI * 2;
    let unitAngle = twoPI / tessellation;
    let angle, vx, vy;

    for(let i = 0; i < tessellation; i++) {

      angle = unitAngle * i;
      vx = (Math.sin(angle) * width) + x;
      vy = (Math.cos(angle) * height) + y;

      this.addVertex([x, y], colourArray);
      this.addVertex([vx, vy], colourArray);
    }

    // close up the polygon
    angle = 0.0;
    vx = (Math.sin(angle) * width) + x;
    vy = (Math.cos(angle) * height) + y;

    this.addVertex([x, y], colourArray);
    this.addVertex([vx, vy], colourArray);
  }

  renderPolySlice(params) {
    let {
      position,
      width,
      height,
      radius,
      tessellation,
      colour
    } = params;

    let angleStart = params['angle-start'];
    let angleEnd = params['angle-end'];

    const [x, y] = position;

    if (radius !== undefined) {
      // use the radius for both width and height if it's given
      width = radius;
      height = radius;
    }

    if(angleStart > angleEnd) {
      console.warn(`angleStart: ${angleStart} > angleEnd: ${angleEnd}`);
    }

    const rStart = MathUtil.degreesToRadians(angleStart);
    const rEnd = MathUtil.degreesToRadians(angleEnd);

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    this.prepareToAddTriangleStrip((tessellation * 2) + 2, [x, y]);

    //let twoPI = Math.PI * 2;
    let unitAngle = (rEnd - rStart) / tessellation;
    let angle, vx, vy;

    for(let i = 0; i < tessellation; i++) {

      angle = rStart + (unitAngle * i);
      vx = (Math.sin(angle) * width) + x;
      vy = (Math.cos(angle) * height) + y;

      this.addVertex([x, y], colourArray);
      this.addVertex([vx, vy], colourArray);
    }

    // close up the polygon
    angle = rEnd;
    vx = (Math.sin(angle) * width) + x;
    vy = (Math.cos(angle) * height) + y;

    this.addVertex([x, y], colourArray);
    this.addVertex([vx, vy], colourArray);
  }

  renderGradientPoly(params, n) {
    const {
      coords,
      colours
    } = params;

    let c;

    this.prepareToAddTriangleStrip(n, coords[0]);
    for(let i = 0; i < n; i++) {
      c = Colour.elementArray(Colour.cloneAs(colours[i], Format.RGB));
      this.addVertex(coords[i], c);
    }
  }

  renderCurve(params, coordFn) {

    const {
      colour,
      coords,
      tessellation
    } = params;
    const tStart = params['t-start'];
    const tEnd = params['t-end'];

    const tVals = MathUtil.stepsInclusive(tStart, tEnd, tessellation);

    const {
      xs,
      ys
    } = coordFn(tVals, coords);

    const {
      halfWidthEnd,
      remap
    } = this.getRemapAndHalfWidthEnd(params);

    this.addVerticesAsStrip({
      tVals,
      xs,
      ys,
      tessellation,
      remap,
      colour,
      halfWidthEnd
    });
  }

  getRemapAndHalfWidthEnd(params) {

    const lineWidth = params['line-width'];
    const lineWidthStart = params['line-width-start'];
    const lineWidthEnd = params['line-width-end'];
    const tStart = params['t-start'];
    const tEnd = params['t-end'];
    const lineWidthMapping = params['line-width-mapping'];

    let halfWidthEnd, remap;

    if (lineWidth !== undefined) {
      // user has given a constant lineWidth parameter
      halfWidthEnd = lineWidth / 2.0;
      remap = () => halfWidthEnd;
    } else {
      // use the default start and end line widths
      const halfWidthStart  = lineWidthStart / 2.0;
      halfWidthEnd = lineWidthEnd / 2.0;
      remap = MathUtil.remapFn({from: [tStart, tEnd],
                                to: [halfWidthStart, halfWidthEnd],
                                mapping: lineWidthMapping});

    }

    return {halfWidthEnd, remap};
  }

  addVerticesAsStrip(args) {

    const {
      tVals,
      xs,
      ys,
      tessellation,
      remap,
      colour,
      halfWidthEnd
    } = args;

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    let i, ix, iy, v1, v2, t, xn1, yn1, xn2, yn2;

    for (i = 0; i < tVals.length - 1; i++) {
      [[xn1, yn1], [xn2, yn2]] =
        MathUtil.normals(xs[i], ys[i], xs[i + 1], ys[i + 1]);

      ix = xs[i];
      iy = ys[i];

      t = tVals[i];

      v1 = [(xn1 * remap({val: t})) + ix, (yn1 * remap({val: t})) + iy];
      v2 = [(xn2 * remap({val: t})) + ix, (yn2 * remap({val: t})) + iy];

      if (i === 0) {
        this.prepareToAddTriangleStrip(tessellation * 2, v1);
      }

      this.addVertex(v1, colourArray);
      this.addVertex(v2, colourArray);
    }

    // final 2 vertices for the end point
    i = tVals.length - 2;
    [[xn1, yn1], [xn2, yn2]] =
      MathUtil.normals(xs[i], ys[i], xs[i + 1], ys[i + 1]);

    ix = xs[i + 1];
    iy = ys[i + 1];

    v1 = [(xn1 * halfWidthEnd) + ix, (yn1 * halfWidthEnd) + iy];
    v2 = [(xn2 * halfWidthEnd) + ix, (yn2 * halfWidthEnd) + iy];

    this.addVertex(v1, colourArray);
    this.addVertex(v2, colourArray);
  }

  getImageData() {
    return this.glRenderer.getImageData();
  }

  preDrawScene(destWidth, destHeight) {
    this.glRenderer.preDrawScene(destWidth, destHeight,
                                 this.pMatrix, this.mvMatrix);

    this.matrixStack.reset();

    this.renderPackets = [];
    this.renderPacket = new RenderPacket();
  }

  postDrawScene() {
    this.flushTriangles();

    Util.withTiming('drawRenderPackets', () => {
      this.glRenderer.drawRenderPackets(this.renderPackets);
    });
  }

  // --------------------------------------------------------------------------

  // buffer code...
  /**
   * make sure the buffer has enough space to add n vertices
   * which will be rendered as a triangle strip
   * @param numVertices
   * @param p0 the first vertex position
   */
  prepareToAddTriangleStrip(numVertices, p0) {

    if (this.renderPacket.canVerticesFit(numVertices) === false) {
      this.flushTriangles();
    }

    if (this.renderPacket.isRenderPacketEmpty() === false){
      const res = this.matrixStack.transform2DVector(p0);
      this.renderPacket.formDegenerateTriangle(res);
    }
  }

  /**
   * this assumes that the buffer will have enough space to add the vertex
   * @param p
   * @param c
   */
  addVertex(p, c) {
    const res = this.matrixStack.transform2DVector(p);
    this.renderPacket.addVertex(res, c);
  }

  flushTriangles() {

    if (this.renderPacket.isRenderPacketEmpty()) {
      return;
    }

    // add the current renderpacket into the renderpackets array
    this.renderPackets.push(this.renderPacket);
    this.renderPacket = new RenderPacket();
  }

}

export default Renderer;
<commit_msg>wraparound bug in poly-slice<commit_after>/*
 Seni
 Copyright (C) 2015  Inderjit Gill <email@indy.io>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import RenderPacket from './RenderPacket';
import GLRenderer from './GLRenderer';
import MatrixStack from './MatrixStack';
import MathUtil from './MathUtil';
import Colour from './Colour';
import Util from './Util';
import { mat4 } from 'gl-matrix';

const Format = Colour.Format;

class Renderer {
  constructor(canvasElement) {
    this.glRenderer = new GLRenderer(canvasElement);

    // matrix setup
    this.matrixStack = new MatrixStack();
    this.mvMatrix = mat4.create();
    this.pMatrix = mat4.create();
    mat4.ortho(this.pMatrix, 0, 1000, 0, 1000, 10, -10);

    this.renderPackets = [];
    this.renderPacket = new RenderPacket();
  }

  vectorToCanvasSpace(v2) {
    let res = this.matrixStack.transform2DVector(v2);
    // destructuring Float32Array as Arrays doesn't work in safari
    // so we have to build and return a normal JS array
    return [res[0], res[1]];
  }

  // ----------------------------------------------------------------------
  // functions beginning with cmd are commands.
  // perhaps split this out into a separate class?
  cmdMatrixPush() {
    return this.matrixStack.pushMatrix();
  }

  cmdMatrixPop() {
    return this.matrixStack.popMatrix();
  }

/*
 *  Seni
 *  Copyright (C) 2015  Inderjit Gill <email@indy.io>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

  cmdMatrixScale(x, y) {
    return this.matrixStack.scale(x, y);
  }

  cmdMatrixTranslate(x, y) {
    return this.matrixStack.translate(x, y);
  }

  cmdMatrixRotate(angle) {
    return this.matrixStack.rotate(angle);
  }

  cmdRenderRect(params) {
    return this.renderRect(params);
  }

  cmdRenderPoly(params) {
    return this.renderPoly(params);
  }

  cmdRenderPolySlice(params) {
    return this.renderPolySlice(params);
  }

  cmdRenderGradientPoly(params, sides) {
    return this.renderGradientPoly(params, sides);
  }

  cmdRenderBezier(params) {
    return this.renderCurve(params, MathUtil.bezierCoordinates);
  }

  cmdRenderQuadratic(params) {
    return this.renderCurve(params, MathUtil.quadraticCoordinates);
  }

  // ----------------------------------------------------------------------

  renderRect(params) {
    const {
      position,
      width,
      height,
      colour
    } = params;

    const [x, y] = position;
    const halfWidth = width / 2;
    const halfHeight = height / 2;

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    this.prepareToAddTriangleStrip(4, [x - halfWidth, y - halfHeight]);
    this.addVertex([x - halfWidth, y - halfHeight], colourArray);
    this.addVertex([x + halfWidth, y - halfHeight], colourArray);
    this.addVertex([x - halfWidth, y + halfHeight], colourArray);
    this.addVertex([x + halfWidth, y + halfHeight], colourArray);
  }

  renderPoly(params) {
    let {
      position,
      width,
      height,
      radius,
      tessellation,
      colour
    } = params;

    const [x, y] = position;

    if (radius !== undefined) {
      // use the radius for both width and height if it's given
      width = radius;
      height = radius;
    }

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    this.prepareToAddTriangleStrip((tessellation * 2) + 2, [x, y]);

    let twoPI = Math.PI * 2;
    let unitAngle = twoPI / tessellation;
    let angle, vx, vy;

    for(let i = 0; i < tessellation; i++) {

      angle = unitAngle * i;
      vx = (Math.sin(angle) * width) + x;
      vy = (Math.cos(angle) * height) + y;

      this.addVertex([x, y], colourArray);
      this.addVertex([vx, vy], colourArray);
    }

    // close up the polygon
    angle = 0.0;
    vx = (Math.sin(angle) * width) + x;
    vy = (Math.cos(angle) * height) + y;

    this.addVertex([x, y], colourArray);
    this.addVertex([vx, vy], colourArray);
  }

  renderPolySlice(params) {
    let {
      position,
      width,
      height,
      radius,
      tessellation,
      colour
    } = params;

    let angleStart = params['angle-start'];
    let angleEnd = params['angle-end'];

    const degToRad = MathUtil.twoPI / 360;

    const [x, y] = position;

    if (radius !== undefined) {
      // use the radius for both width and height if it's given
      width = radius;
      height = radius;
    }

    if(angleStart > angleEnd) {
      console.warn(`angleStart: ${angleStart} > angleEnd: ${angleEnd}`);
    }

    const rStart = angleStart * degToRad;
    const rEnd = angleEnd * degToRad;

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    this.prepareToAddTriangleStrip((tessellation * 2) + 2, [x, y]);

    //let twoPI = Math.PI * 2;
    let unitAngle = (rEnd - rStart) / tessellation;
    let angle, vx, vy;

    for(let i = 0; i < tessellation; i++) {

      angle = rStart + (unitAngle * i);
      vx = (Math.sin(angle) * width) + x;
      vy = (Math.cos(angle) * height) + y;

      this.addVertex([x, y], colourArray);
      this.addVertex([vx, vy], colourArray);
    }

    // close up the polygon
    angle = rEnd;
    vx = (Math.sin(angle) * width) + x;
    vy = (Math.cos(angle) * height) + y;

    this.addVertex([x, y], colourArray);
    this.addVertex([vx, vy], colourArray);
  }

  renderGradientPoly(params, n) {
    const {
      coords,
      colours
    } = params;

    let c;

    this.prepareToAddTriangleStrip(n, coords[0]);
    for(let i = 0; i < n; i++) {
      c = Colour.elementArray(Colour.cloneAs(colours[i], Format.RGB));
      this.addVertex(coords[i], c);
    }
  }

  renderCurve(params, coordFn) {

    const {
      colour,
      coords,
      tessellation
    } = params;
    const tStart = params['t-start'];
    const tEnd = params['t-end'];

    const tVals = MathUtil.stepsInclusive(tStart, tEnd, tessellation);

    const {
      xs,
      ys
    } = coordFn(tVals, coords);

    const {
      halfWidthEnd,
      remap
    } = this.getRemapAndHalfWidthEnd(params);

    this.addVerticesAsStrip({
      tVals,
      xs,
      ys,
      tessellation,
      remap,
      colour,
      halfWidthEnd
    });
  }

  getRemapAndHalfWidthEnd(params) {

    const lineWidth = params['line-width'];
    const lineWidthStart = params['line-width-start'];
    const lineWidthEnd = params['line-width-end'];
    const tStart = params['t-start'];
    const tEnd = params['t-end'];
    const lineWidthMapping = params['line-width-mapping'];

    let halfWidthEnd, remap;

    if (lineWidth !== undefined) {
      // user has given a constant lineWidth parameter
      halfWidthEnd = lineWidth / 2.0;
      remap = () => halfWidthEnd;
    } else {
      // use the default start and end line widths
      const halfWidthStart  = lineWidthStart / 2.0;
      halfWidthEnd = lineWidthEnd / 2.0;
      remap = MathUtil.remapFn({from: [tStart, tEnd],
                                to: [halfWidthStart, halfWidthEnd],
                                mapping: lineWidthMapping});

    }

    return {halfWidthEnd, remap};
  }

  addVerticesAsStrip(args) {

    const {
      tVals,
      xs,
      ys,
      tessellation,
      remap,
      colour,
      halfWidthEnd
    } = args;

    const colourArray = Colour.elementArray(Colour.cloneAs(colour, Format.RGB));

    let i, ix, iy, v1, v2, t, xn1, yn1, xn2, yn2;

    for (i = 0; i < tVals.length - 1; i++) {
      [[xn1, yn1], [xn2, yn2]] =
        MathUtil.normals(xs[i], ys[i], xs[i + 1], ys[i + 1]);

      ix = xs[i];
      iy = ys[i];

      t = tVals[i];

      v1 = [(xn1 * remap({val: t})) + ix, (yn1 * remap({val: t})) + iy];
      v2 = [(xn2 * remap({val: t})) + ix, (yn2 * remap({val: t})) + iy];

      if (i === 0) {
        this.prepareToAddTriangleStrip(tessellation * 2, v1);
      }

      this.addVertex(v1, colourArray);
      this.addVertex(v2, colourArray);
    }

    // final 2 vertices for the end point
    i = tVals.length - 2;
    [[xn1, yn1], [xn2, yn2]] =
      MathUtil.normals(xs[i], ys[i], xs[i + 1], ys[i + 1]);

    ix = xs[i + 1];
    iy = ys[i + 1];

    v1 = [(xn1 * halfWidthEnd) + ix, (yn1 * halfWidthEnd) + iy];
    v2 = [(xn2 * halfWidthEnd) + ix, (yn2 * halfWidthEnd) + iy];

    this.addVertex(v1, colourArray);
    this.addVertex(v2, colourArray);
  }

  getImageData() {
    return this.glRenderer.getImageData();
  }

  preDrawScene(destWidth, destHeight) {
    this.glRenderer.preDrawScene(destWidth, destHeight,
                                 this.pMatrix, this.mvMatrix);

    this.matrixStack.reset();

    this.renderPackets = [];
    this.renderPacket = new RenderPacket();
  }

  postDrawScene() {
    this.flushTriangles();

    Util.withTiming('drawRenderPackets', () => {
      this.glRenderer.drawRenderPackets(this.renderPackets);
    });
  }

  // --------------------------------------------------------------------------

  // buffer code...
  /**
   * make sure the buffer has enough space to add n vertices
   * which will be rendered as a triangle strip
   * @param numVertices
   * @param p0 the first vertex position
   */
  prepareToAddTriangleStrip(numVertices, p0) {

    if (this.renderPacket.canVerticesFit(numVertices) === false) {
      this.flushTriangles();
    }

    if (this.renderPacket.isRenderPacketEmpty() === false){
      const res = this.matrixStack.transform2DVector(p0);
      this.renderPacket.formDegenerateTriangle(res);
    }
  }

  /**
   * this assumes that the buffer will have enough space to add the vertex
   * @param p
   * @param c
   */
  addVertex(p, c) {
    const res = this.matrixStack.transform2DVector(p);
    this.renderPacket.addVertex(res, c);
  }

  flushTriangles() {

    if (this.renderPacket.isRenderPacketEmpty()) {
      return;
    }

    // add the current renderpacket into the renderpackets array
    this.renderPackets.push(this.renderPacket);
    this.renderPacket = new RenderPacket();
  }

}

export default Renderer;
<|endoftext|>


<commit_before>/*
 * routes.js
 *
 * contains routes for the express node server
 *
 * */

import gladSadOrUnknown from './HappySadUnknown'

var routes = {
  happysad: {
    method: 'get',
    fn: function(req, res) {
      console.log(gladSadOrUnknown(req.query.text));
      res.json({
        output: gladSadOrUnknown(req.query.text)
      });
    }
  }
};

module.exports = routes;
<commit_msg>Remove console.log of answer<commit_after>/*
 * routes.js
 *
 * contains routes for the express node server
 *
 * */

import gladSadOrUnknown from './HappySadUnknown'

var routes = {
  happysad: {
    method: 'get',
    fn: function(req, res) {
      res.json({
        output: gladSadOrUnknown(req.query.text)
      });
    }
  }
};

module.exports = routes;
<|endoftext|>


<commit_before>import path from 'path';
import _ from 'lodash';
import fs from 'fs';
import pdf from 'html-pdf';
import moment from 'moment';
import pages from './pages';
import { translateApiUrl } from '../lib/utils';
import { getCloudinaryUrl } from './lib/utils';
import request from 'request';
import controllers from './controllers';
import * as mw from './middlewares';
import express from 'express';

module.exports = (server, app) => {

  server.get('*', mw.ga, (req, res, next) => {
    req.app = app;
    return next();
  });

  // By default, we cache all GET calls for 30s at the CDN level (cloudflare) => we should increase this over time
  // note: only for production/staging (NextJS overrides this in development env)
  server.get('*', mw.maxAge(30));

  server.get('/static/*', mw.maxAge(7200));

  server.get('/favicon.*', mw.maxAge(300000), (req, res) => {
    return res.sendFile(path.join(__dirname, '../public/images/favicon.ico.png'));
  });

  server.all('/api/*', (req, res) => {
    console.log(">>> api request", translateApiUrl(req.url));
    req
      .pipe(request(translateApiUrl(req.url), { followRedirect: false }))
      .on('error', (e) => {
        console.error("error calling api", translateApiUrl(req.url), e);
        res.status(500).send(e);
      })
      .pipe(res);
  });

  /**
   * Proxy all images so that we can serve them from the opencollective.com domain
   * and we can cache them at cloudflare level (to reduce bandwidth at cloudinary level)
   * Format: /proxy/images?src=:encoded_url&width=:width
   */
  server.get('/proxy/images', mw.maxAge(7200), (req, res) => {
    const { src, width, height, query } = req.query;

    const url = getCloudinaryUrl(src, { width, height, query });

    req
      .pipe(request(url, { followRedirect: false }))
      .on('error', (e) => {
        console.error("error proxying ", url, e);
        res.status(500).send(e);
      })
      .pipe(res);
  });

  /**
   * Prevent indexation from search engines
   * (out of 'production' environment)
   */
  server.get('/robots.txt', (req, res, next) => {
    res.setHeader('Content-Type', 'text/plain');
    if (process.env.NODE_ENV === 'production') {
      res.send("User-agent: *\Allow: /");
    } else {
      res.send("User-agent: *\nDisallow: /");
    }
    next();
  });

  /**
   * For backward compatibility.
   * Ideally we should consolidate those routes under:
   * `/:collectiveSlug/members/:backerType(all|users|organizations)`
   */
  server.use('/public', express.static(path.join(__dirname, `../public`), { maxAge: '1d' }));

  server.get('/:collectiveSlug/:image(avatar|logo).:format(txt|png|jpg|gif|svg)', mw.maxAge(7200), controllers.collectives.logo);
  server.get('/:collectiveSlug/:backerType.svg', controllers.collectives.banner);
  server.get('/:collectiveSlug/:backerType/badge.svg', controllers.collectives.badge);
  server.get('/:collectiveSlug/:backerType/:position/avatar(.:format(png|jpg|svg))?', mw.maxAge(7200), mw.ga, controllers.collectives.avatar);
  server.get('/:collectiveSlug/:backerType/:position/website(.:format(png|jpg|svg))?', mw.ga, controllers.collectives.website);

  server.get('/:collectiveSlug/tiers/:tierSlug.:format(png|jpg|svg)', controllers.collectives.banner);
  server.get('/:collectiveSlug.:format(json)', controllers.collectives.info);
  server.get('/:collectiveSlug/members.:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/members/:backerType(all|users|organizations).:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/tiers/:tierSlug/:backerType(all|users|organizations).:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/tiers/:tierSlug/badge.svg', controllers.collectives.badge);
  server.get('/:collectiveSlug/tiers/:tierSlug/:position/avatar(.:format(png|jpg|svg))?', mw.maxAge(7200), mw.ga, controllers.collectives.avatar);
  server.get('/:collectiveSlug/tiers/:tierSlug/:position/website(.:format(png|jpg|svg))?', mw.ga, controllers.collectives.website);
  server.get('/:collectiveSlug/invoices/:invoiceSlug.:format(html|pdf|json)', mw.ga, controllers.transactions.invoice);

  server.get('/:collectiveSlug/:verb(contribute|donate)/button:size(|@2x).png', (req, res) => {
    const color = (req.query.color === 'blue') ? 'blue' : 'white';
    res.sendFile(path.join(__dirname, `../static/images/buttons/${req.params.verb}-button-${color}${req.params.size}.png`));
  });

  server.get('/:collectiveSlug/events.:format(json)', controllers.events.list);
  server.get('/:collectiveSlug/events/:eventSlug.:format(json)', controllers.events.info);
  server.get('/:collectiveSlug/events/:eventSlug/:role(attendees|followers|organizers|all).:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/events/:eventSlug/nametags.:format(pdf|html)', (req, res, next) => {
    const { collectiveSlug, eventSlug, pageFormat, format } = req.params;
    const params = {...req.params, ...req.query};
    app.renderToHTML(req, res, `/nametags`, params)
      .then((html) => {
        if (format === 'html') {
          return res.send(html);
        }

        const options = {
          pageFormat: (pageFormat === 'A4') ? 'A4' : 'Letter',
          renderDelay: 3000
        };
        // html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,'');
        const filename = `${moment().format('YYYYMMDD')}-${collectiveSlug}-${eventSlug}-attendees.pdf`;

        res.setHeader('content-type','application/pdf');
        res.setHeader('content-disposition', `inline; filename="${filename}"`); // or attachment?
        pdf.create(html, options).toStream((err, stream) => {
          if (err) {
            console.log(">>> error while generating pdf", req.url, err);
            return next(err);
          }
          stream.pipe(res);
        });
      });
  })

  server.get('/:collectiveSlug/:verb(contribute|donate)/button.js', (req, res) => {
    const content = fs.readFileSync(path.join(__dirname,'../templates/button.js'), 'utf8');
    _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
    const compiled = _.template(content);
    res.setHeader('content-type', 'application/javascript');
    res.send(compiled({
      collectiveSlug: req.params.collectiveSlug,
      verb: req.params.verb,
      host: process.env.WEBSITE_URL || `http://localhost:${process.env.PORT || 3000}`
    }))
  });

  server.get('/:collectiveSlug/:widget(widget|events|collectives|banner).js', (req, res) => {
    const content = fs.readFileSync(path.join(__dirname,'../templates/widget.js'), 'utf8');
    _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
    const compiled = _.template(content);
    res.setHeader('content-type', 'application/javascript');
    res.send(compiled({
      style: "{}",
      ...req.query,
      collectiveSlug: req.params.collectiveSlug,
      widget: req.params.widget,
      host: process.env.WEBSITE_URL || `http://localhost:${process.env.PORT || 3000}`
    }))
  });

  return pages.getRequestHandler(server.next);

}
<commit_msg>missing \n<commit_after>import path from 'path';
import _ from 'lodash';
import fs from 'fs';
import pdf from 'html-pdf';
import moment from 'moment';
import pages from './pages';
import { translateApiUrl } from '../lib/utils';
import { getCloudinaryUrl } from './lib/utils';
import request from 'request';
import controllers from './controllers';
import * as mw from './middlewares';
import express from 'express';

module.exports = (server, app) => {

  server.get('*', mw.ga, (req, res, next) => {
    req.app = app;
    return next();
  });

  // By default, we cache all GET calls for 30s at the CDN level (cloudflare) => we should increase this over time
  // note: only for production/staging (NextJS overrides this in development env)
  server.get('*', mw.maxAge(30));

  server.get('/static/*', mw.maxAge(7200));

  server.get('/favicon.*', mw.maxAge(300000), (req, res) => {
    return res.sendFile(path.join(__dirname, '../public/images/favicon.ico.png'));
  });

  server.all('/api/*', (req, res) => {
    console.log(">>> api request", translateApiUrl(req.url));
    req
      .pipe(request(translateApiUrl(req.url), { followRedirect: false }))
      .on('error', (e) => {
        console.error("error calling api", translateApiUrl(req.url), e);
        res.status(500).send(e);
      })
      .pipe(res);
  });

  /**
   * Proxy all images so that we can serve them from the opencollective.com domain
   * and we can cache them at cloudflare level (to reduce bandwidth at cloudinary level)
   * Format: /proxy/images?src=:encoded_url&width=:width
   */
  server.get('/proxy/images', mw.maxAge(7200), (req, res) => {
    const { src, width, height, query } = req.query;

    const url = getCloudinaryUrl(src, { width, height, query });

    req
      .pipe(request(url, { followRedirect: false }))
      .on('error', (e) => {
        console.error("error proxying ", url, e);
        res.status(500).send(e);
      })
      .pipe(res);
  });

  /**
   * Prevent indexation from search engines
   * (out of 'production' environment)
   */
  server.get('/robots.txt', (req, res, next) => {
    res.setHeader('Content-Type', 'text/plain');
    if (process.env.NODE_ENV === 'production') {
      res.send("User-agent: *\nAllow: /");
    } else {
      res.send("User-agent: *\nDisallow: /");
    }
    next();
  });

  /**
   * For backward compatibility.
   * Ideally we should consolidate those routes under:
   * `/:collectiveSlug/members/:backerType(all|users|organizations)`
   */
  server.use('/public', express.static(path.join(__dirname, `../public`), { maxAge: '1d' }));

  server.get('/:collectiveSlug/:image(avatar|logo).:format(txt|png|jpg|gif|svg)', mw.maxAge(7200), controllers.collectives.logo);
  server.get('/:collectiveSlug/:backerType.svg', controllers.collectives.banner);
  server.get('/:collectiveSlug/:backerType/badge.svg', controllers.collectives.badge);
  server.get('/:collectiveSlug/:backerType/:position/avatar(.:format(png|jpg|svg))?', mw.maxAge(7200), mw.ga, controllers.collectives.avatar);
  server.get('/:collectiveSlug/:backerType/:position/website(.:format(png|jpg|svg))?', mw.ga, controllers.collectives.website);

  server.get('/:collectiveSlug/tiers/:tierSlug.:format(png|jpg|svg)', controllers.collectives.banner);
  server.get('/:collectiveSlug.:format(json)', controllers.collectives.info);
  server.get('/:collectiveSlug/members.:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/members/:backerType(all|users|organizations).:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/tiers/:tierSlug/:backerType(all|users|organizations).:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/tiers/:tierSlug/badge.svg', controllers.collectives.badge);
  server.get('/:collectiveSlug/tiers/:tierSlug/:position/avatar(.:format(png|jpg|svg))?', mw.maxAge(7200), mw.ga, controllers.collectives.avatar);
  server.get('/:collectiveSlug/tiers/:tierSlug/:position/website(.:format(png|jpg|svg))?', mw.ga, controllers.collectives.website);
  server.get('/:collectiveSlug/invoices/:invoiceSlug.:format(html|pdf|json)', mw.ga, controllers.transactions.invoice);

  server.get('/:collectiveSlug/:verb(contribute|donate)/button:size(|@2x).png', (req, res) => {
    const color = (req.query.color === 'blue') ? 'blue' : 'white';
    res.sendFile(path.join(__dirname, `../static/images/buttons/${req.params.verb}-button-${color}${req.params.size}.png`));
  });

  server.get('/:collectiveSlug/events.:format(json)', controllers.events.list);
  server.get('/:collectiveSlug/events/:eventSlug.:format(json)', controllers.events.info);
  server.get('/:collectiveSlug/events/:eventSlug/:role(attendees|followers|organizers|all).:format(json|csv)', controllers.members.list);
  server.get('/:collectiveSlug/events/:eventSlug/nametags.:format(pdf|html)', (req, res, next) => {
    const { collectiveSlug, eventSlug, pageFormat, format } = req.params;
    const params = {...req.params, ...req.query};
    app.renderToHTML(req, res, `/nametags`, params)
      .then((html) => {
        if (format === 'html') {
          return res.send(html);
        }

        const options = {
          pageFormat: (pageFormat === 'A4') ? 'A4' : 'Letter',
          renderDelay: 3000
        };
        // html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,'');
        const filename = `${moment().format('YYYYMMDD')}-${collectiveSlug}-${eventSlug}-attendees.pdf`;

        res.setHeader('content-type','application/pdf');
        res.setHeader('content-disposition', `inline; filename="${filename}"`); // or attachment?
        pdf.create(html, options).toStream((err, stream) => {
          if (err) {
            console.log(">>> error while generating pdf", req.url, err);
            return next(err);
          }
          stream.pipe(res);
        });
      });
  })

  server.get('/:collectiveSlug/:verb(contribute|donate)/button.js', (req, res) => {
    const content = fs.readFileSync(path.join(__dirname,'../templates/button.js'), 'utf8');
    _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
    const compiled = _.template(content);
    res.setHeader('content-type', 'application/javascript');
    res.send(compiled({
      collectiveSlug: req.params.collectiveSlug,
      verb: req.params.verb,
      host: process.env.WEBSITE_URL || `http://localhost:${process.env.PORT || 3000}`
    }))
  });

  server.get('/:collectiveSlug/:widget(widget|events|collectives|banner).js', (req, res) => {
    const content = fs.readFileSync(path.join(__dirname,'../templates/widget.js'), 'utf8');
    _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
    const compiled = _.template(content);
    res.setHeader('content-type', 'application/javascript');
    res.send(compiled({
      style: "{}",
      ...req.query,
      collectiveSlug: req.params.collectiveSlug,
      widget: req.params.widget,
      host: process.env.WEBSITE_URL || `http://localhost:${process.env.PORT || 3000}`
    }))
  });

  return pages.getRequestHandler(server.next);

}
<|endoftext|>


<commit_before>import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import Icon from '../icon';
import InputMetaPropTypes from '../input/InputMetaPropTypes';
import NavigationBar from './NavigationBar';
import WeekDay from './WeekDay';
import { convertModifiersToClassnames, isSelectingFirstDay } from './utils';
import { DateUtils } from 'react-day-picker/lib/src/index';
import { IconCalendarSmallOutline, IconWarningBadgedSmallFilled } from '@teamleader/ui-icons';
import { TextSmall } from '../typography';
import cx from 'classnames';
import omit from 'lodash.omit';
import theme from './theme.css';

class DatePickerInputRange extends PureComponent {
  state = {
    selectedStartDate: null,
    selectedEndDate: null,
    mouseEnteredEndDate: null,
    inputHasFocus: false,
  };

  static getDerivedStateFromProps(props, state) {
    if (
      props.selectedRange !== undefined &&
      (props.selectedRange.selectedStartDate !== state.selectedStartDate ||
        props.selectedRange.selectedEndDate !== state.selectedEndDate)
    ) {
      return {
        selectedStartDate: props.selectedRange.selectedStartDate,
        selectedEndDate: props.selectedRange.selectedEndDate,
        mouseEnteredEndDate: props.selectedRange.selectedEndDate,
      };
    }

    return null;
  }

  componentWillUnmount() {
    clearTimeout(this.timeout);
  }

  focusFrom = () => {
    this.timeout = setTimeout(() => this.startDate.getInput().focus(), 100);
  };

  focusTo = () => {
    this.timeout = setTimeout(() => this.endDate.getInput().focus(), 0);
  };

  handleFromBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleFromFocus = () => {
    this.setState({ inputHasFocus: true });
  };

  handleFromChange = day => {
    this.setState({ selectedStartDate: day }, () => {
      const { selectedEndDate } = this.state;
      this.focusTo();
      this.props.onChange({ selectedStartDate: day, selectedEndDate });
    });
  };

  handleToChange = day => {
    this.setState({ selectedEndDate: day, mouseEnteredEndDate: day }, () => {
      const { selectedStartDate } = this.state;
      this.showFromMonth();
      this.props.onChange({ selectedStartDate, selectedEndDate: day });
    });
  };

  handleToBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleToFocus = () => {
    this.setState({ inputHasFocus: true });

    if (!this.state.selectedStartDate) {
      this.focusFrom();
    }
  };

  hasError = () => {
    const { meta } = this.props;
    return Boolean(meta && meta.error && meta.touched);
  };

  renderDayPickerInput = () => {
    const {
      className,
      dayPickerProps,
      dayPickerFromProps,
      dayPickerToProps,
      disabled,
      inputProps,
      inputStartDateProps,
      inputEndDateProps,
      readOnly,
      size,
      valueFrom,
      valueTo,
      ...others
    } = this.props;

    const { selectedStartDate, selectedEndDate, mouseEnteredEndDate } = this.state;
    const modifiers = { from: selectedStartDate, to: mouseEnteredEndDate };
    const selectedDays = [selectedStartDate, { from: selectedStartDate, to: mouseEnteredEndDate }];

    const dayPickerClassNames = cx(theme['date-picker'], theme['has-range'], theme[`is-${size}`], className);

    const commonDayPickerProps = {
      className: dayPickerClassNames,
      classNames: theme,
      modifiers: convertModifiersToClassnames(modifiers, theme),
      selectedDays,
      navbarElement: <NavigationBar size={size} />,
      weekdayElement: <WeekDay size={size} />,
      ...dayPickerProps,
    };

    const commonDayPickerInputProps = {
      classNames: theme,
      hideOnDayClick: false,
    };

    const commonInputProps = {
      disabled: disabled || readOnly,
      ...inputProps,
    };

    const rest = omit(others, ['helpText', 'meta', 'onBlur', 'onChange', 'onFocus']);

    return (
      <Fragment>
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { after: selectedEndDate },
            toMonth: selectedEndDate,
            ...commonDayPickerProps,
            ...dayPickerFromProps,
          }}
          onDayChange={this.handleFromChange}
          inputProps={{
            onBlur: this.handleFromBlur,
            onFocus: this.handleFromFocus,
            ...commonInputProps,
            ...inputStartDateProps,
          }}
          ref={el => (this.startDate = el)}
          value={valueFrom}
          {...commonDayPickerInputProps}
          {...rest}
        />
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { before: selectedStartDate },
            month: selectedStartDate,
            fromMonth: selectedStartDate,
            onDayMouseEnter: this.handleDayMouseEnter,
            ...commonDayPickerProps,
            ...dayPickerToProps,
          }}
          onDayChange={this.handleToChange}
          inputProps={{
            onBlur: this.handleToBlur,
            onFocus: this.handleToFocus,
            ...commonInputProps,
            ...inputEndDateProps,
          }}
          ref={el => (this.endDate = el)}
          value={valueTo}
          {...commonDayPickerInputProps}
          {...rest}
        />
      </Fragment>
    );
  };

  renderIcon = () => {
    const { inverse } = this.props;

    return (
      <Icon
        className={theme['input-icon']}
        color={inverse ? 'teal' : 'neutral'}
        tint={inverse ? 'light' : 'darkest'}
        marginHorizontal={2}
      >
        <IconCalendarSmallOutline />
      </Icon>
    );
  };

  renderHelpText = () => {
    const { helpText, inverse } = this.props;

    if (helpText) {
      return (
        <TextSmall color={inverse ? 'white' : 'neutral'} marginTop={1} soft>
          {helpText}
        </TextSmall>
      );
    }
  };

  renderValidationMessage = () => {
    return (
      <Box marginTop={2}>
        <IconWarningBadgedSmallFilled className={theme['validation-icon']} />
        <TextSmall className={theme['validation-text']} element="span" marginLeft={1}>
          {this.props.meta.error}
        </TextSmall>
      </Box>
    );
  };

  showFromMonth = () => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!selectedStartDate) {
      return;
    }

    this.endDate.getDayPicker().showMonth(DateUtils.addMonths(selectedEndDate, -1));
  };

  handleDayMouseEnter = day => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!isSelectingFirstDay(selectedStartDate, selectedEndDate, day)) {
      this.setState({
        mouseEnteredEndDate: day,
      });
    }
  };

  render() {
    const { bold, disabled, inverse, readOnly, size } = this.props;

    const classNames = cx(theme['date-picker-input-range'], theme[`is-${size}`], {
      [theme['is-bold']]: bold,
      [theme['is-disabled']]: disabled,
      [theme['is-inverse']]: inverse,
      [theme['is-read-only']]: readOnly,
      [theme['has-error']]: this.hasError(),
      [theme['has-focus']]: this.state.inputHasFocus,
    });

    return (
      <Box className={classNames}>

          {this.renderIcon()}
          {this.renderDayPickerInput()}

        {this.hasError() ? this.renderValidationMessage() : this.renderHelpText()}
      </Box>
    );
  }
}

DatePickerInputRange.propTypes = {
  bold: PropTypes.bool,
  className: PropTypes.string,
  disabled: PropTypes.bool,
  helpText: PropTypes.string,
  inverse: PropTypes.bool,
  inputProps: PropTypes.object,
  inputStartDateProps: PropTypes.object,
  inputEndDateProps: PropTypes.object,
  meta: InputMetaPropTypes,
  modifiers: PropTypes.object,
  dayPickerProps: PropTypes.object,
  dayPickerFromProps: PropTypes.object,
  dayPickerToProps: PropTypes.object,
  onChange: PropTypes.func,
  readOnly: PropTypes.bool,
  selectedRange: PropTypes.object,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  valueFrom: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
  valueTo: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
};

DatePickerInputRange.defaultProps = {
  bold: false,
  disabled: false,
  inverse: false,
  readOnly: false,
  size: 'medium',
};

export default DatePickerInputRange;
<commit_msg>Rename props so we can eliminate the words 'from' and 'to'<commit_after>import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import Icon from '../icon';
import InputMetaPropTypes from '../input/InputMetaPropTypes';
import NavigationBar from './NavigationBar';
import WeekDay from './WeekDay';
import { convertModifiersToClassnames, isSelectingFirstDay } from './utils';
import { DateUtils } from 'react-day-picker/lib/src/index';
import { IconCalendarSmallOutline, IconWarningBadgedSmallFilled } from '@teamleader/ui-icons';
import { TextSmall } from '../typography';
import cx from 'classnames';
import omit from 'lodash.omit';
import theme from './theme.css';

class DatePickerInputRange extends PureComponent {
  state = {
    selectedStartDate: null,
    selectedEndDate: null,
    mouseEnteredEndDate: null,
    inputHasFocus: false,
  };

  static getDerivedStateFromProps(props, state) {
    if (
      props.selectedRange !== undefined &&
      (props.selectedRange.selectedStartDate !== state.selectedStartDate ||
        props.selectedRange.selectedEndDate !== state.selectedEndDate)
    ) {
      return {
        selectedStartDate: props.selectedRange.selectedStartDate,
        selectedEndDate: props.selectedRange.selectedEndDate,
        mouseEnteredEndDate: props.selectedRange.selectedEndDate,
      };
    }

    return null;
  }

  componentWillUnmount() {
    clearTimeout(this.timeout);
  }

  focusFrom = () => {
    this.timeout = setTimeout(() => this.startDate.getInput().focus(), 100);
  };

  focusTo = () => {
    this.timeout = setTimeout(() => this.endDate.getInput().focus(), 0);
  };

  handleFromBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleFromFocus = () => {
    this.setState({ inputHasFocus: true });
  };

  handleFromChange = day => {
    this.setState({ selectedStartDate: day }, () => {
      const { selectedEndDate } = this.state;
      this.focusTo();
      this.props.onChange({ selectedStartDate: day, selectedEndDate });
    });
  };

  handleToChange = day => {
    this.setState({ selectedEndDate: day, mouseEnteredEndDate: day }, () => {
      const { selectedStartDate } = this.state;
      this.showFromMonth();
      this.props.onChange({ selectedStartDate, selectedEndDate: day });
    });
  };

  handleToBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleToFocus = () => {
    this.setState({ inputHasFocus: true });

    if (!this.state.selectedStartDate) {
      this.focusFrom();
    }
  };

  hasError = () => {
    const { meta } = this.props;
    return Boolean(meta && meta.error && meta.touched);
  };

  renderDayPickerInput = () => {
    const {
      className,
      dayPickerProps,
      dayPickerStartDateProps,
      dayPickerEndDateProps,
      disabled,
      inputProps,
      inputStartDateProps,
      inputEndDateProps,
      readOnly,
      size,
      valueFrom,
      valueTo,
      ...others
    } = this.props;

    const { selectedStartDate, selectedEndDate, mouseEnteredEndDate } = this.state;
    const modifiers = { from: selectedStartDate, to: mouseEnteredEndDate };
    const selectedDays = [selectedStartDate, { from: selectedStartDate, to: mouseEnteredEndDate }];

    const dayPickerClassNames = cx(theme['date-picker'], theme['has-range'], theme[`is-${size}`], className);

    const commonDayPickerProps = {
      className: dayPickerClassNames,
      classNames: theme,
      modifiers: convertModifiersToClassnames(modifiers, theme),
      selectedDays,
      navbarElement: <NavigationBar size={size} />,
      weekdayElement: <WeekDay size={size} />,
      ...dayPickerProps,
    };

    const commonDayPickerInputProps = {
      classNames: theme,
      hideOnDayClick: false,
    };

    const commonInputProps = {
      disabled: disabled || readOnly,
      ...inputProps,
    };

    const rest = omit(others, ['helpText', 'meta', 'onBlur', 'onChange', 'onFocus']);

    return (
      <Fragment>
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { after: selectedEndDate },
            toMonth: selectedEndDate,
            ...commonDayPickerProps,
            ...dayPickerStartDateProps,
          }}
          onDayChange={this.handleFromChange}
          inputProps={{
            onBlur: this.handleFromBlur,
            onFocus: this.handleFromFocus,
            ...commonInputProps,
            ...inputStartDateProps,
          }}
          ref={el => (this.startDate = el)}
          value={valueFrom}
          {...commonDayPickerInputProps}
          {...rest}
        />
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { before: selectedStartDate },
            month: selectedStartDate,
            fromMonth: selectedStartDate,
            onDayMouseEnter: this.handleDayMouseEnter,
            ...commonDayPickerProps,
            ...dayPickerEndDateProps,
          }}
          onDayChange={this.handleToChange}
          inputProps={{
            onBlur: this.handleToBlur,
            onFocus: this.handleToFocus,
            ...commonInputProps,
            ...inputEndDateProps,
          }}
          ref={el => (this.endDate = el)}
          value={valueTo}
          {...commonDayPickerInputProps}
          {...rest}
        />
      </Fragment>
    );
  };

  renderIcon = () => {
    const { inverse } = this.props;

    return (
      <Icon
        className={theme['input-icon']}
        color={inverse ? 'teal' : 'neutral'}
        tint={inverse ? 'light' : 'darkest'}
        marginHorizontal={2}
      >
        <IconCalendarSmallOutline />
      </Icon>
    );
  };

  renderHelpText = () => {
    const { helpText, inverse } = this.props;

    if (helpText) {
      return (
        <TextSmall color={inverse ? 'white' : 'neutral'} marginTop={1} soft>
          {helpText}
        </TextSmall>
      );
    }
  };

  renderValidationMessage = () => {
    return (
      <Box marginTop={2}>
        <IconWarningBadgedSmallFilled className={theme['validation-icon']} />
        <TextSmall className={theme['validation-text']} element="span" marginLeft={1}>
          {this.props.meta.error}
        </TextSmall>
      </Box>
    );
  };

  showFromMonth = () => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!selectedStartDate) {
      return;
    }

    this.endDate.getDayPicker().showMonth(DateUtils.addMonths(selectedEndDate, -1));
  };

  handleDayMouseEnter = day => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!isSelectingFirstDay(selectedStartDate, selectedEndDate, day)) {
      this.setState({
        mouseEnteredEndDate: day,
      });
    }
  };

  render() {
    const { bold, disabled, inverse, readOnly, size } = this.props;

    const classNames = cx(theme['date-picker-input-range'], theme[`is-${size}`], {
      [theme['is-bold']]: bold,
      [theme['is-disabled']]: disabled,
      [theme['is-inverse']]: inverse,
      [theme['is-read-only']]: readOnly,
      [theme['has-error']]: this.hasError(),
      [theme['has-focus']]: this.state.inputHasFocus,
    });

    return (
      <Box className={classNames}>

          {this.renderIcon()}
          {this.renderDayPickerInput()}

        {this.hasError() ? this.renderValidationMessage() : this.renderHelpText()}
      </Box>
    );
  }
}

DatePickerInputRange.propTypes = {
  bold: PropTypes.bool,
  className: PropTypes.string,
  disabled: PropTypes.bool,
  helpText: PropTypes.string,
  inverse: PropTypes.bool,
  inputProps: PropTypes.object,
  inputStartDateProps: PropTypes.object,
  inputEndDateProps: PropTypes.object,
  meta: InputMetaPropTypes,
  modifiers: PropTypes.object,
  dayPickerProps: PropTypes.object,
  dayPickerStartDateProps: PropTypes.object,
  dayPickerEndDateProps: PropTypes.object,
  onChange: PropTypes.func,
  readOnly: PropTypes.bool,
  selectedRange: PropTypes.object,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  valueFrom: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
  valueTo: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
};

DatePickerInputRange.defaultProps = {
  bold: false,
  disabled: false,
  inverse: false,
  readOnly: false,
  size: 'medium',
};

export default DatePickerInputRange;
<|endoftext|>


<commit_before>/* eslint-disable consistent-return */
import path from 'path';
import compression from 'compression';
import express from 'express';
import favicon from 'serve-favicon';
import winston from 'winston';
import expressWinston from 'express-winston';
import cookieParser from 'cookie-parser';
import { host, port, logLevel, isEnvProduction, ssl } from '../../config/consts';
import createSSR from './SSR/createSSR';

export default function (parameters) {
  const app = express();

  if (isEnvProduction) {
    app.use(compression());
  }
  app.disable('etag');
  app.disable('x-powered-by');
  app.use(cookieParser());
  app.use('/', express.static('public', { etag: false }));
  app.use(favicon(path.join('public', 'favicons', 'icon-48x48.png')));
  app.use((req, res, next) => {
    res.set('X-Frame-Options', 'DENY');
    next();
  });
  if (ssl) {
    app.use((req, res, next) => {
      if (req.headers['x-forwarded-proto'] !== 'https') {
        res.redirect(302, `https://${req.hostname}${req.originalUrl}`);
      } else {
        next();
      }
    });
  }
  app.get('/api/users', (req, res) => {
    res.json({
      records: [
        { id: 2, name: 'Justin Timberlake' },
        { id: 1, name: 'Kanye West' },
      ],
    });
  });
  if (logLevel) {
    const loggerOptions = {
      level: logLevel,
      transports: [
        new winston.transports.Console({
          json: true,
          colorize: true,
        }),
      ],
    };
    app.use(expressWinston.logger(loggerOptions));
  }

  app.get('*', createSSR(parameters && parameters.chunks()));
  console.log('port!!!!!!!!!!!! ', port);
  const server = app.listen(port, (err) => {
    if (err) {
      return console.error(err);
    }
    if (host && port) {
      console.info(`Listening at ${host}:${port}`);
    }
  });

  return {
    server,
    app,
  };
}
<commit_msg>fix(heroku): fix heroku<commit_after>/* eslint-disable consistent-return */
import path from 'path';
import compression from 'compression';
import express from 'express';
import favicon from 'serve-favicon';
import winston from 'winston';
import expressWinston from 'express-winston';
import cookieParser from 'cookie-parser';
import { host, port, logLevel, isEnvProduction, ssl } from '../../config/consts';
import createSSR from './SSR/createSSR';

export default function (parameters) {
  const app = express();

  if (isEnvProduction) {
    app.use(compression());
  }
  app.disable('etag');
  app.disable('x-powered-by');
  app.use(cookieParser());
  app.use('/', express.static('public', { etag: false }));
  app.use(favicon(path.join('public', 'favicons', 'icon-48x48.png')));
  app.use((req, res, next) => {
    res.set('X-Frame-Options', 'DENY');
    next();
  });
  if (ssl) {
    app.use((req, res, next) => {
      if (req.headers['x-forwarded-proto'] !== 'https') {
        res.redirect(302, `https://${req.hostname}${req.originalUrl}`);
      } else {
        next();
      }
    });
  }
  app.get('/api/users', (req, res) => {
    res.json({
      records: [
        { id: 2, name: 'Justin Timberlake' },
        { id: 1, name: 'Kanye West' },
      ],
    });
  });
  if (logLevel) {
    const loggerOptions = {
      level: logLevel,
      transports: [
        new winston.transports.Console({
          json: true,
          colorize: true,
        }),
      ],
    };
    app.use(expressWinston.logger(loggerOptions));
  }

  app.get('*', createSSR(parameters && parameters.chunks()));
  console.log('port!!!!!!!!!!!! 2', port);
  console.log('port!!!!!!!!!!!! 1', process.env.PORT);
  const server = app.listen(process.env.PORT, (err) => {
    if (err) {
      return console.error(err);
    }
    if (host && port) {
      console.info(`Listening at ${host}:${port}`);
    }
  });

  return {
    server,
    app,
  };
}
<|endoftext|>


<commit_before>import angular from 'angular';

const modName = 'app.services.midi';

class Midi {
  constructor() {
    this.init();
  }

  init() {
    navigator.requestMIDIAccess()
      .then(this.onMIDISuccess, this.onMIDIFailure);
    this.inputs = null;
  }

  onMIDISuccess(access) {
    console.log(access);
  }

  onMIDIFailure(msg) {
    console.log("oh... midi failed");
    console.log(msg);
  }

  onMIDIEvent(e) {
    console.log("catch midi event");
    console.log(e);
  }
}

angular.module(modName, [])
.factory('midi', () => {
  return new Midi();
});

export default modName;
<commit_msg>(faet): add onMidiEvent<commit_after>import angular from 'angular';

const modName = 'app.services.midi';

class Midi {
  constructor() {
    this.init();
    this.inputs = [];
  }

  init() {
    navigator.requestMIDIAccess()
      .then(this.onMIDISuccess.bind(this), this.onMIDIFailure.bind(this));
  }

  onMIDISuccess(access) {
    const input = access.inputs.values();

    for (var o = input.next(); !o.done; o = input.next()) {
      this.inputs.push(o.value);
    }
    for (var cnt = 0; cnt < this.inputs.length; cnt++) {
      this.inputs[cnt].onmidimessage = this.onMIDIEvent;
    }
  }

  onMIDIFailure(msg) {
    console.log("oh... midi failed");
    console.log(msg);
  }

  onMIDIEvent(e) {
    const statusByte = e.data[0].toString(16).substring(0, 1);
    if (statusByte === "8") {
      console.log("note off");
    }
    if (statusByte === "9") {
      console.log("note on");
    }
  }
}

angular.module(modName, [])
.factory('midi', () => {
  return new Midi();
});

export default modName;
<|endoftext|>


<commit_before>var Lines=require('../lines.js');
var LodShape=require('./lodshape.js');

var Gasket=function(elementIndexBits,shaderType,lod){
	LodShape.call(this,elementIndexBits,shaderType,lod);
};
Gasket.prototype=Object.create(LodShape.prototype);
Gasket.prototype.constructor=Gasket;
Gasket.prototype.getDistinctVertexCount=function(lodSymbol){
	return "(Math.pow(3,"+lodSymbol+"+1)+3)/2";
};
Gasket.prototype.getFaceVertexCount=function(lodSymbol){
	return "Math.pow(3,"+lodSymbol+")*3";
};
Gasket.prototype.getTotalVertexCount=function(lodSymbol){
	return "Math.pow(3,"+lodSymbol+")*3";
};
Gasket.prototype.writeStoreShapeWithElements=function(c,cv){
	function writePushVertex() {
		var lines=new Lines;
		lines.a(
			"vertices[nextIndexIntoVertices++]=p[0];",
			"vertices[nextIndexIntoVertices++]=p[1];"
		);
		if (c) {
			if (this.shaderType=='face') {
				lines.a(
					"var c=colors[nextIndexIntoColors];"
				);
			} else {
				lines.a(
					"var c=colors[nextElement%colors.length];"
				);
			}
			lines.a(
				"vertices[nextIndexIntoVertices++]=c[0];",
				"vertices[nextIndexIntoVertices++]=c[1];",
				"vertices[nextIndexIntoVertices++]=c[2];"
			);
		}
		lines.a(
			"return nextElement++;"
		);
		return lines.wrap(
			"function pushVertex(p) {",
			"}"
		);
	}
	function writeTriangle() {
		var lines=new Lines;
		lines.a(
			"if (depth<=0) {"
		);
		if (this.shaderType=='face') {
			lines.a(
				"	pushElement(pushVertex(p0));",
				"	pushElement(pushVertex(p1));",
				"	pushElement(pushVertex(p2));",
				"	nextIndexIntoColors=(nextIndexIntoColors+1)%colors.length;"
			);
		} else {
			lines.a(
				"	if (es[0]===null) es[0]=pushVertex(p0);",
				"	if (es[1]===null) es[1]=pushVertex(p1);",
				"	if (es[2]===null) es[2]=pushVertex(p2);",
				"	pushElement(es[0]);",
				"	pushElement(es[1]);",
				"	pushElement(es[2]);",
				"	return es;"
			);
		}
		lines.a(
			"} else {",
			"	var p01=mix(p0,p1);",
			"	var p12=mix(p1,p2);",
			"	var p20=mix(p2,p0);"
		);
		if (this.shaderType=='face') {
			lines.a(
				"	var es0=triangle(depth-1,p0,p01,p20);",
				"	var es1=triangle(depth-1,p1,p12,p01);",
				"	var es2=triangle(depth-1,p2,p20,p12);"
			);
		} else {
			lines.a(
				"	var es0=triangle(depth-1,p0,p01,p20,[es[0],null,null]);",
				"	var es1=triangle(depth-1,p1,p12,p01,[es[1],null,es0[1]]);",
				"	var es2=triangle(depth-1,p2,p20,p12,[es[2],es0[2],es1[1]]);",
				"	return [es0[0],es1[0],es2[0]];"
			);
		}
		lines.a(
			"}"
		);
		if (this.shaderType=='face') {
			return lines.wrap(
				"function triangle(depth,p0,p1,p2) {",
				"}"
			);
		} else {
			return lines.wrap(
				"function triangle(depth,p0,p1,p2,es) {",
				"}"
			);
		}
	}
	function writeInitialTriangleCall() {
		var lines=new Lines;
		lines.a(
			"shapeLod,",
			"[-Math.sin(0/3*Math.PI),Math.cos(0/3*Math.PI)],",
			"[-Math.sin(2/3*Math.PI),Math.cos(2/3*Math.PI)],",
			"[-Math.sin(4/3*Math.PI),Math.cos(4/3*Math.PI)]"
		);
		if (this.shaderType!='face') {
			lines.t(
				",","[null,null,null]"
			);
		}
		return lines.wrap(
			"triangle(",
			");"
		);
	}
	var lines=new Lines;
	lines.a(
		"var nextIndexIntoVertices=0;",
		"var nextIndexIntoElements=0;",
		"var nextElement=0;"
	);
	if (c) {
		lines.a(
			"// p = position, c = color, e = element, es = elements",
			"var colors=[",
			"	[1.0, 0.0, 0.0],",
			"	[0.0, 1.0, 0.0],",
			"	[0.0, 0.0, 1.0],",
			"	[1.0, 1.0, 0.0],",
			"];"
		);
		if (this.shaderType=='face') {
			lines.a(
				"var nextIndexIntoColors=0;"
			);
		}
	} else {
		lines.a(
			"// p = position, e = element, es = elements"
		);
	}
	lines.a(
		writePushVertex.call(this),
		"function pushElement(e) {",
		"	elements[nextIndexIntoElements++]=e;",
		"}",
		"function mix(pa,pb) {",
		"	return [",
		"		(pa[0]+pb[0])/2,",
		"		(pa[1]+pb[1])/2,",
		"	];",
		"}",
		writeTriangle.call(this),
		writeInitialTriangleCall.call(this)
	);
	return lines;
}
Gasket.prototype.writeStoreShapeWithoutElements=function(c,cv){
	var lines=new Lines;
	lines.a(
		"var iv=0;"
	);
	if (this.shaderType=='face') {
		lines.a(
			"var ic=0;",
			"var colors=[",
			"	[1.0, 0.0, 0.0],",
			"	[0.0, 1.0, 0.0],",
			"	[0.0, 0.0, 1.0],",
			"	[1.0, 1.0, 0.0],",
			"];"
		);
	}
	if (this.shaderType=='vertex') {
		lines.a(
			"function pushVertex(v,r,g,b) {",
			"	vertices[iv++]=v[0]; vertices[iv++]=v[1];",
			"	vertices[iv++]=r; vertices[iv++]=g; vertices[iv++]=b;",
			"}"
		);
	} else if (this.shaderType=='face') {
		lines.a(
			"function pushVertex(v,c) {",
			"	vertices[iv++]=v[0]; vertices[iv++]=v[1];",
			"	vertices[iv++]=c[0]; vertices[iv++]=c[1]; vertices[iv++]=c[2];",
			"}"
		);
	} else {
		lines.a(
			"function pushVertex(v) {",
			"	vertices[iv++]=v[0]; vertices[iv++]=v[1];",
			"}"
		);
	}
	lines.a(
		"function mix(a,b,m) {",
		"	return [",
		"		a[0]*(1-m)+b[0]*m,",
		"		a[1]*(1-m)+b[1]*m,",
		"	];",
		"}",
		"function triangle(depth,a,b,c) {",
		"	if (depth<=0) {"
	);
	if (this.shaderType=='vertex') {
		lines.a(
			"		pushVertex(a,1.0,0.0,0.0);",
			"		pushVertex(b,0.0,1.0,0.0);",
			"		pushVertex(c,0.0,0.0,1.0);"
		);
	} else if (this.shaderType=='face') {
		lines.a(
			"		pushVertex(a,colors[ic]);",
			"		pushVertex(b,colors[ic]);",
			"		pushVertex(c,colors[ic]);",
			"		ic=(ic+1)%colors.length;"
		);
	} else {
		lines.a(
			"		pushVertex(a);",
			"		pushVertex(b);",
			"		pushVertex(c);"
		);
	}
	lines.a(
		"	} else {",
		"		var ab=mix(a,b,0.5);",
		"		var bc=mix(b,c,0.5);",
		"		var ca=mix(c,a,0.5);",
		"		triangle(depth-1,a,ab,ca);",
		"		triangle(depth-1,b,bc,ab);",
		"		triangle(depth-1,c,ca,bc);",
		"	}",
		"}",
		"triangle(",
		"	shapeLod,",
		"	[-Math.sin(0/3*Math.PI),Math.cos(0/3*Math.PI)],",
		"	[-Math.sin(2/3*Math.PI),Math.cos(2/3*Math.PI)],",
		"	[-Math.sin(4/3*Math.PI),Math.cos(4/3*Math.PI)]",
		");"
	);
	return lines;
};
Gasket.prototype.writeStoreShape=function(c,cv){
	if (this.usesElements()) {
		return this.writeStoreShapeWithElements(c,cv);
	} else {
		return this.writeStoreShapeWithoutElements(c,cv);
	}
};

module.exports=Gasket;
<commit_msg>unified writeStoreShape() for gasket<commit_after>var Lines=require('../lines.js');
var LodShape=require('./lodshape.js');

var Gasket=function(elementIndexBits,shaderType,lod){
	LodShape.call(this,elementIndexBits,shaderType,lod);
};
Gasket.prototype=Object.create(LodShape.prototype);
Gasket.prototype.constructor=Gasket;
Gasket.prototype.getDistinctVertexCount=function(lodSymbol){
	return "(Math.pow(3,"+lodSymbol+"+1)+3)/2";
};
Gasket.prototype.getFaceVertexCount=function(lodSymbol){
	return "Math.pow(3,"+lodSymbol+")*3";
};
Gasket.prototype.getTotalVertexCount=function(lodSymbol){
	return "Math.pow(3,"+lodSymbol+")*3";
};
Gasket.prototype.writeStoreShape=function(c,cv){
	function writePushVertex() {
		var lines=new Lines;
		lines.a(
			"vertices[nextIndexIntoVertices++]=p[0];",
			"vertices[nextIndexIntoVertices++]=p[1];"
		);
		if (c) {
			if (!this.usesElements() || this.shaderType=='face') {
				lines.a(
					"var c=colors[nextIndexIntoColors];"
				);
			} else {
				lines.a(
					"var c=colors[nextElement%colors.length];"
				);
			}
			lines.a(
				"vertices[nextIndexIntoVertices++]=c[0];",
				"vertices[nextIndexIntoVertices++]=c[1];",
				"vertices[nextIndexIntoVertices++]=c[2];"
			);
		}
		if (this.usesElements()) {
			lines.a(
				"return nextElement++;"
			);
		}
		return lines.wrap(
			"function pushVertex(p) {",
			"}"
		);
	}
	function writeTriangle() {
		var lines=new Lines;
		lines.a(
			"if (depth<=0) {"
		);
		if (!this.usesElements()) {
			if (this.shaderType=='face') {
				lines.a(
					"	pushVertex(p0);",
					"	pushVertex(p1);",
					"	pushVertex(p2);",
					"	nextIndexIntoColors=(nextIndexIntoColors+1)%colors.length;"
				);
			} else if (this.shaderType=='vertex') {
				lines.a(
					"	pushVertex(p0);",
					"	nextIndexIntoColors=(nextIndexIntoColors+1)%colors.length;",
					"	pushVertex(p1);",
					"	nextIndexIntoColors=(nextIndexIntoColors+1)%colors.length;",
					"	pushVertex(p2);",
					"	nextIndexIntoColors=(nextIndexIntoColors+1)%colors.length;"
				);
			} else {
				lines.a(
					"	pushVertex(p0);",
					"	pushVertex(p1);",
					"	pushVertex(p2);"
				);
			}
		} else {
			if (this.shaderType=='face') {
				lines.a(
					"	pushElement(pushVertex(p0));",
					"	pushElement(pushVertex(p1));",
					"	pushElement(pushVertex(p2));",
					"	nextIndexIntoColors=(nextIndexIntoColors+1)%colors.length;"
				);
			} else {
				lines.a(
					"	if (es[0]===null) es[0]=pushVertex(p0);",
					"	if (es[1]===null) es[1]=pushVertex(p1);",
					"	if (es[2]===null) es[2]=pushVertex(p2);",
					"	pushElement(es[0]);",
					"	pushElement(es[1]);",
					"	pushElement(es[2]);",
					"	return es;"
				);
			}
		}
		lines.a(
			"} else {",
			"	var p01=mix(p0,p1);",
			"	var p12=mix(p1,p2);",
			"	var p20=mix(p2,p0);"
		);
		if (!this.usesElements()) {
			lines.a(
				"	triangle(depth-1,p0,p01,p20);",
				"	triangle(depth-1,p1,p12,p01);",
				"	triangle(depth-1,p2,p20,p12);"
			);
		} else if (this.shaderType=='face') {
			lines.a(
				"	var es0=triangle(depth-1,p0,p01,p20);",
				"	var es1=triangle(depth-1,p1,p12,p01);",
				"	var es2=triangle(depth-1,p2,p20,p12);"
			);
		} else {
			lines.a(
				"	var es0=triangle(depth-1,p0,p01,p20,[es[0],null,null]);",
				"	var es1=triangle(depth-1,p1,p12,p01,[es[1],null,es0[1]]);",
				"	var es2=triangle(depth-1,p2,p20,p12,[es[2],es0[2],es1[1]]);",
				"	return [es0[0],es1[0],es2[0]];"
			);
		}
		lines.a(
			"}"
		);
		if (!this.usesElements() || this.shaderType=='face') {
			return lines.wrap(
				"function triangle(depth,p0,p1,p2) {",
				"}"
			);
		} else {
			return lines.wrap(
				"function triangle(depth,p0,p1,p2,es) {",
				"}"
			);
		}
	}
	function writeInitialTriangleCall() {
		var lines=new Lines;
		lines.a(
			"shapeLod,",
			"[-Math.sin(0/3*Math.PI),Math.cos(0/3*Math.PI)],",
			"[-Math.sin(2/3*Math.PI),Math.cos(2/3*Math.PI)],",
			"[-Math.sin(4/3*Math.PI),Math.cos(4/3*Math.PI)]"
		);
		if (this.usesElements() && this.shaderType!='face') {
			lines.t(
				",","[null,null,null]"
			);
		}
		return lines.wrap(
			"triangle(",
			");"
		);
	}
	var lines=new Lines;
	lines.a(
		"var nextIndexIntoVertices=0;"
	);
	if (this.usesElements()) {
	lines.a(
			"var nextIndexIntoElements=0;",
			"var nextElement=0;"
		);
	}
	if (c) {
		lines.a(
			"// p = position, c = color, e = element, es = elements",
			"var colors=[",
			"	[1.0, 0.0, 0.0],",
			"	[0.0, 1.0, 0.0],",
			"	[0.0, 0.0, 1.0],",
			"	[1.0, 1.0, 0.0],",
			"];"
		);
		if (!this.usesElements() || this.shaderType=='face') {
			lines.a(
				"var nextIndexIntoColors=0;"
			);
		}
	} else {
		lines.a(
			"// p = position, e = element, es = elements"
		);
	}
	lines.a(
		writePushVertex.call(this)
	);
	if (this.usesElements()) {
		lines.a(
			"function pushElement(e) {",
			"	elements[nextIndexIntoElements++]=e;",
			"}"
		);
	}
	lines.a(
		"function mix(pa,pb) {",
		"	return [",
		"		(pa[0]+pb[0])/2,",
		"		(pa[1]+pb[1])/2,",
		"	];",
		"}",
		writeTriangle.call(this),
		writeInitialTriangleCall.call(this)
	);
	return lines;
}

module.exports=Gasket;
<|endoftext|>