<commit_before>/* @flow */

import * as $logger from 'beaver-logger/client';

import { config, FPTI } from './config';
import { initLogger, checkForCommonErrors, setLogLevel, stringifyError } from './lib';
import { enableCheckoutIframe } from './components';
import { createPptmScript } from './lib/pptm';
import { isPayPalDomain, isEligible } from './lib';

import { ZalgoPromise } from 'zalgo-promise/src';

function domainToEnv(domain : string) : ?string {
    for (let env of Object.keys(config.paypalUrls)) {
        if (config.paypalUrls[env] === domain) {
            return env;
        }
    }
}

function setDomainEnv(domain : string) {
    let currentDomainEnv = domainToEnv(domain);

    if (currentDomainEnv && currentDomainEnv !== 'test') {
        config.env = currentDomainEnv;
    }
}

setDomainEnv(`${window.location.protocol}//${window.location.host}`);

initLogger();

ZalgoPromise.onPossiblyUnhandledException(err => {

    $logger.error('unhandled_error', {
        stack: stringifyError(err),
        errtype: ({}).toString.call(err)
    });

    $logger.track({
        [ FPTI.KEY.ERROR_CODE ]: 'checkoutjs_error',
        [ FPTI.KEY.ERROR_DESC ]: stringifyError(err)
    });

    $logger.flush().catch(err2 => {
        if (window.console) {
            try {
                if (window.console.error) {
                    window.console.error('Error flushing:', err2.stack || err2.toString());
                } else if (window.console.log) {
                    window.console.log('Error flushing:', err2.stack || err2.toString());
                }
            } catch (err3) {
                setTimeout(() => {
                    throw err3;
                }, 1);
            }
        }
    });
});

function getCurrentScript() : ? HTMLScriptElement {

    let scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));

    for (let script of scripts) {
        if (script.src && script.getAttribute('src') === config.scriptUrl || script.hasAttribute('data-paypal-checkout')) {
            return script;
        }

        if (script.src && script.src.indexOf('paypal.checkout.v4.js') !== -1) {
            return script;
        }
    }

    if (document.currentScript) {
        $logger.debug(`current_script_not_recognized`, { src: document.currentScript.src });
    }
}

let currentScript = getCurrentScript();
let currentProtocol = window.location.protocol.split(':')[0];

type SetupOptions = {
    env? : ?string,
    stage? : ?string,
    apiStage? : ?string,
    paypalUrl? : ?string,
    state? : ?string,
    ppobjects? : ?boolean,
    lightbox? : ?boolean,
    logLevel? : ?string
};

export function setup({ env, stage, apiStage, paypalUrl, state, ppobjects, lightbox, logLevel } : SetupOptions = {}) {

    if (!isEligible()) {
        $logger.warn('ineligible');
        return;
    }

    checkForCommonErrors();

    if (env) {
        if (!config.paypalUrls[env]) {
            throw new Error(`Invalid env: ${env}`);
        }

        delete config.env;
        config.env = env;
    }

    if (stage) {
        delete config.stage;
        config.stage = stage;
    }

    if (apiStage) {
        delete config.apiStage;
        config.apiStage = apiStage;
    }

    if (paypalUrl) {
        delete config.paypalUrl;
        config.paypalUrl = paypalUrl;
        setDomainEnv(config.paypalUrl);
    }

    if (state) {
        delete config.state;
        config.state = state;
    }

    if (ppobjects) {
        config.ppobjects = true;
    }

    if (lightbox) {
        enableCheckoutIframe();
    }

    if (logLevel) {
        setLogLevel(logLevel);
    } else {
        setLogLevel(config.logLevel);
    }

    if (!isPayPalDomain()) {
        createPptmScript();
    }

    $logger.info(`setup_${config.env}`);

    $logger.debug(`current_protocol_${currentProtocol}`);
}

$logger.track({
    [ FPTI.KEY.STATE ]: FPTI.STATE.LOAD,
    [ FPTI.KEY.TRANSITION ]: FPTI.TRANSITION.SCRIPT_LOAD
});

if (currentScript) {

    setup({
        env:        currentScript.getAttribute('data-env'),
        stage:      currentScript.getAttribute('data-stage'),
        apiStage:   currentScript.getAttribute('data-api-stage'),
        paypalUrl:  currentScript.getAttribute('data-paypal-url'),
        state:      currentScript.getAttribute('data-state'),
        lightbox:   currentScript.hasAttribute('data-enable-lightbox'),
        logLevel:   currentScript.getAttribute('data-log-level'),
        ppobjects:  true
    });

    let scriptProtocol = currentScript.src.split(':')[0];

    $logger.debug(`current_script_protocol_${scriptProtocol}`);
    $logger.debug(`current_script_${ currentProtocol === scriptProtocol ? 'match' : 'mismatch' }_protocol`);

} else {
    $logger.debug(`no_current_script`);

    if (document.currentScript) {
        $logger.debug(`current_script_not_recognized`, { src: document.currentScript.src });
    }
}
<commit_msg>Do not cancel setup for ineligible browsers<commit_after>/* @flow */

import * as $logger from 'beaver-logger/client';

import { config, FPTI } from './config';
import { initLogger, checkForCommonErrors, setLogLevel, stringifyError } from './lib';
import { enableCheckoutIframe } from './components';
import { createPptmScript } from './lib/pptm';
import { isPayPalDomain, isEligible } from './lib';

import { ZalgoPromise } from 'zalgo-promise/src';

function domainToEnv(domain : string) : ?string {
    for (let env of Object.keys(config.paypalUrls)) {
        if (config.paypalUrls[env] === domain) {
            return env;
        }
    }
}

function setDomainEnv(domain : string) {
    let currentDomainEnv = domainToEnv(domain);

    if (currentDomainEnv && currentDomainEnv !== 'test') {
        config.env = currentDomainEnv;
    }
}

setDomainEnv(`${window.location.protocol}//${window.location.host}`);

initLogger();

ZalgoPromise.onPossiblyUnhandledException(err => {

    $logger.error('unhandled_error', {
        stack: stringifyError(err),
        errtype: ({}).toString.call(err)
    });

    $logger.track({
        [ FPTI.KEY.ERROR_CODE ]: 'checkoutjs_error',
        [ FPTI.KEY.ERROR_DESC ]: stringifyError(err)
    });

    $logger.flush().catch(err2 => {
        if (window.console) {
            try {
                if (window.console.error) {
                    window.console.error('Error flushing:', err2.stack || err2.toString());
                } else if (window.console.log) {
                    window.console.log('Error flushing:', err2.stack || err2.toString());
                }
            } catch (err3) {
                setTimeout(() => {
                    throw err3;
                }, 1);
            }
        }
    });
});

function getCurrentScript() : ? HTMLScriptElement {

    let scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));

    for (let script of scripts) {
        if (script.src && script.getAttribute('src') === config.scriptUrl || script.hasAttribute('data-paypal-checkout')) {
            return script;
        }

        if (script.src && script.src.indexOf('paypal.checkout.v4.js') !== -1) {
            return script;
        }
    }

    if (document.currentScript) {
        $logger.debug(`current_script_not_recognized`, { src: document.currentScript.src });
    }
}

let currentScript = getCurrentScript();
let currentProtocol = window.location.protocol.split(':')[0];

type SetupOptions = {
    env? : ?string,
    stage? : ?string,
    apiStage? : ?string,
    paypalUrl? : ?string,
    state? : ?string,
    ppobjects? : ?boolean,
    lightbox? : ?boolean,
    logLevel? : ?string
};

export function setup({ env, stage, apiStage, paypalUrl, state, ppobjects, lightbox, logLevel } : SetupOptions = {}) {

    if (!isEligible()) {
        $logger.warn('ineligible');
    }

    checkForCommonErrors();

    if (env) {
        if (!config.paypalUrls[env]) {
            throw new Error(`Invalid env: ${env}`);
        }

        delete config.env;
        config.env = env;
    }

    if (stage) {
        delete config.stage;
        config.stage = stage;
    }

    if (apiStage) {
        delete config.apiStage;
        config.apiStage = apiStage;
    }

    if (paypalUrl) {
        delete config.paypalUrl;
        config.paypalUrl = paypalUrl;
        setDomainEnv(config.paypalUrl);
    }

    if (state) {
        delete config.state;
        config.state = state;
    }

    if (ppobjects) {
        config.ppobjects = true;
    }

    if (lightbox) {
        enableCheckoutIframe();
    }

    if (logLevel) {
        setLogLevel(logLevel);
    } else {
        setLogLevel(config.logLevel);
    }

    if (!isPayPalDomain()) {
        createPptmScript();
    }

    $logger.info(`setup_${config.env}`);

    $logger.debug(`current_protocol_${currentProtocol}`);
}

$logger.track({
    [ FPTI.KEY.STATE ]: FPTI.STATE.LOAD,
    [ FPTI.KEY.TRANSITION ]: FPTI.TRANSITION.SCRIPT_LOAD
});

if (currentScript) {

    setup({
        env:        currentScript.getAttribute('data-env'),
        stage:      currentScript.getAttribute('data-stage'),
        apiStage:   currentScript.getAttribute('data-api-stage'),
        paypalUrl:  currentScript.getAttribute('data-paypal-url'),
        state:      currentScript.getAttribute('data-state'),
        lightbox:   currentScript.hasAttribute('data-enable-lightbox'),
        logLevel:   currentScript.getAttribute('data-log-level'),
        ppobjects:  true
    });

    let scriptProtocol = currentScript.src.split(':')[0];

    $logger.debug(`current_script_protocol_${scriptProtocol}`);
    $logger.debug(`current_script_${ currentProtocol === scriptProtocol ? 'match' : 'mismatch' }_protocol`);

} else {
    $logger.debug(`no_current_script`);

    if (document.currentScript) {
        $logger.debug(`current_script_not_recognized`, { src: document.currentScript.src });
    }
}
<|endoftext|>


<commit_before>// Description:
//   join all channels
//

var slackAPI = require('slackbotapi');
var token = process.env.WEB_SLACK_TOKEN;
var slack = new slackAPI({
    'token': token,
    'autoReconnect': true
});

module.exports = (robot => {
    robot.respond(/join all/i, res => {
        let bot = slackAPI.getUser(robot.name);
        slack.reqAPI("channels.list",{
            exclude_archived: 1
        }, (listResponse) => {
            if(!listResponse.ok) {
                robot.logger.error(`something ocuured ${listResponse}`);
                return;
            }
            listResponse.channels
                .filter((ch) => (ch.substring(0, 1) === 'C') )
                .forEach((ch) => {
                    slack.reqAPI("channels.invite", {
                        channel: ch.id,
                        user: bot.id
                    }, (inviteResponse) => {
                        if( inviteResponse.ok ) {
                            res.send(`joined #${ch.name}`)
                        } else {
                            robot.logger.error(`failed to join to ${ch}`);
                            robot.logger.error(inviteResponse);
                        }
                    });
                });
        });
    })
})
<commit_msg>Add option<commit_after>// Description:
//   join all channels
//

var slackAPI = require('slackbotapi');
var token = process.env.WEB_SLACK_TOKEN;
var slack = new slackAPI({
    'token': token,
    'logging': false,
    'autoReconnect': true
});

module.exports = (robot => {
    robot.respond(/join all/i, res => {
        let bot = slackAPI.getUser(robot.name);
        slack.reqAPI("channels.list",{
            exclude_archived: 1
        }, (listResponse) => {
            if(!listResponse.ok) {
                robot.logger.error(`something ocuured ${listResponse}`);
                return;
            }
            listResponse.channels
                .filter((ch) => (ch.substring(0, 1) === 'C') )
                .forEach((ch) => {
                    slack.reqAPI("channels.invite", {
                        channel: ch.id,
                        user: bot.id
                    }, (inviteResponse) => {
                        if( inviteResponse.ok ) {
                            res.send(`joined #${ch.name}`)
                        } else {
                            robot.logger.error(`failed to join to ${ch}`);
                            robot.logger.error(inviteResponse);
                        }
                    });
                });
        });
    })
})
<|endoftext|>


<commit_before>import Rx from 'rx';
import { h } from '@cycle/dom';
import styles from './app.css';
//import vdCss  from './css-modules-vdom';
import hh from 'hyperscript-helpers';

const { div, h2, textarea, img, a, ul, li } = hh(h);

//const h2 = vdCss(styles);

function generateAnswer(url, isUrlEncoded = true) {
	const nameStart = url.lastIndexOf('/') === -1 ? 0 : (url.lastIndexOf('/') + 1);
	const nameEnd = url.lastIndexOf('.') === -1 ? (url.length) : url.lastIndexOf('.');
	if (isUrlEncoded) {
		return decodeURIComponent(url.substring(nameStart, nameEnd));
	} else {
		return url.substring(nameStart, nameEnd);
	}
}

function dragenter(e) {
	console.log('dragenter', e);
	e.stopPropagation();
	e.preventDefault();
}

function dragover(e) {
	console.log('dragover', e);
	e.stopPropagation();
	e.preventDefault();
}

export function setup({ DOM }) {

	const written$ = DOM.select(`textarea`).events('change')
		.map(ev => ev.target.value.split(/\n/))
		.map(values => values.filter(v => !!v.trim()))
		.map(values => values.map(v => ({ url: v, answer: generateAnswer(v, true) })))
		.do((values) => console.log('written', values))
		.startWith([]);

	const dragEnter$ = DOM.select('.' + styles['drop-target']).events('dragenter').map(dragenter).startWith(undefined);
	const dragOver$ = DOM.select('.' + styles['drop-target']).events('dragover').map(dragover).startWith(undefined);

	const dropped$ = DOM.select('.' + styles['drop-target']).events('drop')
		.map(e => {
			e.preventDefault();
			e.stopPropagation();
			return Array.from(e.dataTransfer.files);
		})
		.do(files => console.log('drop', files))
		.map(files => files.map(file => ({ url: URL.createObjectURL(file), answer: generateAnswer(file.name, false) })))
		.startWith([]);

	const value$ = written$
		.combineLatest(dropped$, (written, dropped) => written.concat(dropped))
		.do((...args) => console.log('setup images', ...args));

	const showFiles = (images) => {
		if (images && images.length > 0) {
			return ul(
				images.map(image => li([
					a({ href: image.url, target: '_blank' }, image.answer)
				]))
			);
		} else {
			return '';
		}
	};

	const vtree$ = Rx.Observable.combineLatest(value$, written$, dropped$, dragEnter$, dragOver$, (value, written, dropped) =>
		div(`.setup`, [
			h2('.label', [
				'Kuvat'
			]),
			div(`.${styles['drop-target']}.drop-target`, ['Raahaa tiedostot tähän ', showFiles(dropped)]),
			div(`.${styles['image-list']}.image-list`, value.map(image => img({ src: image.url, title: image.answer }))),
			div('.textarea-hint', 'Tai syötä kuvien URL:t alle'),
			textarea(`.${styles.images}`, {
				value: written.map(v => v.url).join('\n')
			})
		])
	);

	return {
		DOM: vtree$,
		value$
	};
}
<commit_msg>add quick setup instructions<commit_after>import Rx from 'rx';
import { h } from '@cycle/dom';
import styles from './app.css';
//import vdCss  from './css-modules-vdom';
import hh from 'hyperscript-helpers';

const { div, h2, textarea, img, a, ol, ul, li } = hh(h);

//const h2 = vdCss(styles);

function generateAnswer(url, isUrlEncoded = true) {
	const nameStart = url.lastIndexOf('/') === -1 ? 0 : (url.lastIndexOf('/') + 1);
	const nameEnd = url.lastIndexOf('.') === -1 ? (url.length) : url.lastIndexOf('.');
	if (isUrlEncoded) {
		return decodeURIComponent(url.substring(nameStart, nameEnd));
	} else {
		return url.substring(nameStart, nameEnd);
	}
}

function dragenter(e) {
	console.log('dragenter', e);
	e.stopPropagation();
	e.preventDefault();
}

function dragover(e) {
	console.log('dragover', e);
	e.stopPropagation();
	e.preventDefault();
}

export function setup({ DOM }) {

	const written$ = DOM.select(`textarea`).events('change')
		.map(ev => ev.target.value.split(/\n/))
		.map(values => values.filter(v => !!v.trim()))
		.map(values => values.map(v => ({ url: v, answer: generateAnswer(v, true) })))
		.do((values) => console.log('written', values))
		.startWith([]);

	const dragEnter$ = DOM.select('.' + styles['drop-target']).events('dragenter').map(dragenter).startWith(undefined);
	const dragOver$ = DOM.select('.' + styles['drop-target']).events('dragover').map(dragover).startWith(undefined);

	const dropped$ = DOM.select('.' + styles['drop-target']).events('drop')
		.map(e => {
			e.preventDefault();
			e.stopPropagation();
			return Array.from(e.dataTransfer.files);
		})
		.do(files => console.log('drop', files))
		.map(files => files.map(file => ({ url: URL.createObjectURL(file), answer: generateAnswer(file.name, false) })))
		.startWith([]);

	const value$ = written$
		.combineLatest(dropped$, (written, dropped) => written.concat(dropped))
		.do((...args) => console.log('setup images', ...args));

	const showFiles = (images) => {
		if (images && images.length > 0) {
			return ul(
				images.map(image => li([
					a({ href: image.url, target: '_blank' }, image.answer)
				]))
			);
		} else {
			return '';
		}
	};

	const vtree$ = Rx.Observable.combineLatest(value$, written$, dropped$, dragEnter$, dragOver$, (value, written, dropped) =>
		div(`.setup`, [
			h2('.label', [
				'Kuvat'
			]),
			ol(`.instructions`, [
				li('.instructions-entry', 'Nimeä kuvat siten, että tiedostonimi on haluamasi vastaus (esim. jos kuvan oikea vastaus on "hauki", muuta tiedoston nimeksi hauki.jpg)'),
				li('.instructions-entry', 'Raahaa kaikki haluamasi kuvat alla olevaan laatikkoon'),
				li('.instructions-entry', 'Paina yläpuolelta Peli-nappia')
			]),
			div(`.${styles['drop-target']}.drop-target`, ['Raahaa tiedostot tähän ', showFiles(dropped)]),
			div(`.${styles['image-list']}.image-list`, value.map(image => img({ src: image.url, title: image.answer }))),
			div('.textarea-hint', 'Tai syötä kuvien URL:t alle'),
			textarea(`.${styles.images}`, {
				value: written.map(v => v.url).join('\n')
			})
		])
	);

	return {
		DOM: vtree$,
		value$
	};
}
<|endoftext|>


<commit_before>import { Constants } from './constants.js';
import { Events } from './events.js';
import { Matrix } from './matrix.js';
import { Vector } from './vector.js';

/**
 * @name Two.Shape
 * @class
 * @extends Two.Events
 * @description The foundational transformation object for the Two.js scenegraph.
 */
export class Shape extends Events {

  /**
   * @name Two.Shape#_id
   * @private
   * @property {Boolean} - Determines whether the id needs updating.
   */
  _flagId = true;

  /**
   * @name Two.Shape#_flagMatrix
   * @private
   * @property {Boolean} - Determines whether the matrix needs updating.
   */
  _flagMatrix = true;

  /**
   * @name Two.Shape#_flagScale
   * @private
   * @property {Boolean} - Determines whether the scale needs updating.
   */
  _flagScale = false;

  /**
   * @name Two.Shape#_flagClassName
   * @private
   * @property {Boolean} - Determines whether the {@link Two.Group#className} need updating.
   */
  _flagClassName = false;

  // Underlying Properties

  _renderer = {};

  _id = '';

  /**
   * @name Two.Shape#_position
   * @private
   * @property {Two.Vector} - The translation values as a {@link Two.Vector}.
   */
  _position = null;

  /**
   * @name Two.Shape#_rotation
   * @private
   * @property {Number} - The rotation value in Number.
   */
  _rotation = 0;

  /**
   * @name Two.Shape#_scale
   * @private
   * @property {Number|Two.Vector} - The scale value in Number. Can be a vector for non-uniform scaling.
   */
  _scale = 1;

  /**
   * @name Two.Shape#_skewX
   * @private
   * @property {Number} - The rotation value in Number.
   */
  _skewX = 0;

  /**
   * @name Two.Shape#_skewY
   * @private
   * @property {Number} - The rotation value in Number.
   */
  _skewY = 0;

  /**
   * @name Two.Shape#className
   * @property {String} - A class to be applied to the element to be compatible with CSS styling.
   * @nota-bene Only available for the SVG renderer.
   */
  _className = '';

  constructor() {

    super();

    for (let prop in proto) {
      Object.defineProperty(this, prop, proto[prop]);
    }

    /**
     * @name Two.Shape#renderer
     * @property {Object}
     * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
     * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
     */
    this._renderer.flagMatrix = FlagMatrix.bind(this);
    this.isShape = true;

    /**
     * @name Two.Shape#id
     * @property {String} - Session specific unique identifier.
     * @nota-bene In the {@link Two.SvgRenderer} change this to change the underlying SVG element's id too.
     */
    this.id = Constants.Identifier + Constants.uniqueId();

    /**
     * @name Two.Shape#classList
     * @property {String[]}
     * @description A list of class strings stored if imported / interpreted  from an SVG element.
     */
    this.classList = [];

    /**
     * @name Two.Shape#matrix
     * @property {Two.Matrix}
     * @description The transformation matrix of the shape.
     * @nota-bene {@link Two.Shape#position}, {@link Two.Shape#rotation}, {@link Two.Shape#scale}, {@link Two.Shape#skewX}, and {@link Two.Shape#skewY} apply their values to the matrix when changed. The matrix is what is sent to the renderer to be drawn.
     */
    this.matrix = new Matrix();

    /**
     * @name Two.Shape#position
     * @property {Two.Vector} - The x and y value for where the shape is placed relative to its parent.
     */
    this.position = new Vector();

    /**
     * @name Two.Shape#rotation
     * @property {Number} - The value in Number for how much the shape is rotated relative to its parent.
     */
    this.rotation = 0;

    /**
     * @name Two.Shape#scale
     * @property {Number} - The value for how much the shape is scaled relative to its parent.
     * @nota-bene This value can be replaced with a {@link Two.Vector} to do non-uniform scaling. e.g: `shape.scale = new Two.Vector(2, 1);`
     */
    this.scale = 1;

    /**
     * @name Two.Shape#skewX
     * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
     * @description Skew the shape by an angle in the x axis direction.
     */
    this.skewX = 0;

    /**
     * @name Two.Shape#skewY
     * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
     * @description Skew the shape by an angle in the y axis direction.
     */
    this.skewY = 0;

  }

  get renderer() {
    return this._renderer;
  }
  set renderer(v) {
    this._renderer = v;
  }

  /**
   * @name Two.Shape#translation
   * @description Alias for {@link Two.Shape#position}.
   */
  get translation() {
    return proto.position.get.apply(this, arguments);
  }
  set translation(v) {
    proto.position.set.apply(this, arguments);
  }

  /**
   * @name Two.Shape#addTo
   * @function
   * @param {Two.Group} group - The parent the shape adds itself to.
   * @description Convenience method to add itself to the scenegraph.
   */
  addTo(group) {
    group.add(this);
    return this;
  }

  /**
   * @name Two.Text#remove
   * @function
   * @description Remove self from the scene / parent.
   */
  remove() {

    if (!this.parent) {
      return this;
    }

    this.parent.remove(this);

    return this;

  }

  /**
   * @name Two.Shape#clone
   * @function
   * @param {Two.Group} [parent] - Optional argument to automatically add the shape to a scenegraph.
   * @returns {Two.Shape}
   * @description Create a new {@link Two.Shape} with the same values as the current shape.
   */
  clone(parent) {

    const clone = new Shape();

    clone.position.copy(this.position);
    clone.rotation = this.rotation;
    clone.scale = this.scale;
    clone.skewX = this.skewX;
    clone.skewY = this.skewY;

    if (this.matrix.manual) {
      clone.matrix.copy(this.matrix);
    }

    if (parent) {
      parent.add(clone);
    }

    return clone._update();

  }

  /**
   * @name Two.Shape#_update
   * @function
   * @private
   * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
   * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
   * @nota-bene Try not to call this method more than once a frame.
   */
  _update(bubbles) {

    if (!this._matrix.manual && this._flagMatrix) {

      this._matrix
        .identity()
        .translate(this.position.x, this.position.y);

        if (this._scale instanceof Vector) {
          this._matrix.scale(this._scale.x, this._scale.y);
        } else {
          this._matrix.scale(this._scale);
        }

        this._matrix.rotate(this.rotation);
        this._matrix.skewX(this.skewX);
        this._matrix.skewY(this.skewY);
    }

    if (bubbles) {
      if (this.parent && this.parent._update) {
        this.parent._update();
      }
    }

    return this;

  }

  /**
   * @name Two.Shape#flagReset
   * @function
   * @private
   * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
   */
  flagReset() {

    this._flagId = this._flagMatrix = this._flagScale =
      this._flagClassName = false;

    return this;

  }

}

const proto = {
  position: {
    enumerable: true,
    get: function() {
      return this._position;
    },
    set: function(v) {
      if (this._position) {
        this._position.unbind(Events.Types.change, this._renderer.flagMatrix);
      }
      this._position = v;
      this._position.bind(Events.Types.change, this._renderer.flagMatrix);
      FlagMatrix.call(this);
    }
  },
  rotation: {
    enumerable: true,
    get: function() {
      return this._rotation;
    },
    set: function(v) {
      this._rotation = v;
      this._flagMatrix = true;
    }
  },
  scale: {
    enumerable: true,
    get: function() {
      return this._scale;
    },
    set: function(v) {
      if (this._scale instanceof Vector) {
        this._scale.unbind(Events.Types.change, this._renderer.flagMatrix);
      }
      this._scale = v;
      if (this._scale instanceof Vector) {
        this._scale.bind(Events.Types.change, this._renderer.flagMatrix);
      }
      this._flagMatrix = true;
      this._flagScale = true;
    }
  },
  skewX: {
    enumerable: true,
    get: function() {
      return this._skewX;
    },
    set: function(v) {
      this._skewX = v;
      this._flagMatrix = true;
    }
  },
  skewY: {
    enumerable: true,
    get: function() {
      return this._skewY;
    },
    set: function(v) {
      this._skewY = v;
      this._flagMatrix = true;
    }
  },
  matrix: {
    enumerable: true,
    get: function() {
      return this._matrix;
    },
    set: function(v) {
      this._matrix = v;
      this._flagMatrix = true;
    }
  },

  id: {
    enumerable: true,
    get: function() {
      return this._id;
    },
    set: function(v) {
      const id = this._id;
      if (v === this._id) {
        return;
      }
      this._id = v;
      this._flagId = true;
      if (this.parent) {
        delete this.parent.children.ids[id];
        this.parent.children.ids[this._id] = this;
      }
    }
  },

  className: {
    enumerable: true,
    get: function() {
      return this._className;
    },
    set: function(v) {
      this._flagClassName = this._className !== v;
      if (this._flagClassName) {
        const prev = this._className.split(/\s+?/);
        const dest = v.split(/\s+?/);
        for (let i = 0; i < prev.length; i++) {
          const className = prev[i];
          const index = Array.prototype.indexOf.call(this.classList, className);
          if (index >= 0) {
            this.classList.splice(index, 1);
          }
        }
        this.classList = this.classList.concat(dest);
      }
      this._className = v;
    }
  }
};

/**
 * @name FlagMatrix
 * @function
 * @private
 * @description Utility function used in conjunction with event handlers to update the flagMatrix of a shape.
 */
function FlagMatrix() {
  this._flagMatrix = true;
}
<commit_msg>Added Renderer as a Property<commit_after>import { Constants } from './constants.js';
import { Events } from './events.js';
import { Matrix } from './matrix.js';
import { Vector } from './vector.js';

/**
 * @name Two.Shape
 * @class
 * @extends Two.Events
 * @description The foundational transformation object for the Two.js scenegraph.
 */
export class Shape extends Events {

  /**
   * @name Two.Shape#_id
   * @private
   * @property {Boolean} - Determines whether the id needs updating.
   */
  _flagId = true;

  /**
   * @name Two.Shape#_flagMatrix
   * @private
   * @property {Boolean} - Determines whether the matrix needs updating.
   */
  _flagMatrix = true;

  /**
   * @name Two.Shape#_flagScale
   * @private
   * @property {Boolean} - Determines whether the scale needs updating.
   */
  _flagScale = false;

  /**
   * @name Two.Shape#_flagClassName
   * @private
   * @property {Boolean} - Determines whether the {@link Two.Group#className} need updating.
   */
  _flagClassName = false;

  // Underlying Properties

  _renderer = {};

  _id = '';

  /**
   * @name Two.Shape#_position
   * @private
   * @property {Two.Vector} - The translation values as a {@link Two.Vector}.
   */
  _position = null;

  /**
   * @name Two.Shape#_rotation
   * @private
   * @property {Number} - The rotation value in Number.
   */
  _rotation = 0;

  /**
   * @name Two.Shape#_scale
   * @private
   * @property {Number|Two.Vector} - The scale value in Number. Can be a vector for non-uniform scaling.
   */
  _scale = 1;

  /**
   * @name Two.Shape#_skewX
   * @private
   * @property {Number} - The rotation value in Number.
   */
  _skewX = 0;

  /**
   * @name Two.Shape#_skewY
   * @private
   * @property {Number} - The rotation value in Number.
   */
  _skewY = 0;

  /**
   * @name Two.Shape#className
   * @property {String} - A class to be applied to the element to be compatible with CSS styling.
   * @nota-bene Only available for the SVG renderer.
   */
  _className = '';

  constructor() {

    super();

    for (let prop in proto) {
      Object.defineProperty(this, prop, proto[prop]);
    }

    /**
     * @name Two.Shape#renderer
     * @property {Object}
     * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
     * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
     */
    this._renderer.flagMatrix = FlagMatrix.bind(this);
    this.isShape = true;

    /**
     * @name Two.Shape#id
     * @property {String} - Session specific unique identifier.
     * @nota-bene In the {@link Two.SvgRenderer} change this to change the underlying SVG element's id too.
     */
    this.id = Constants.Identifier + Constants.uniqueId();

    /**
     * @name Two.Shape#classList
     * @property {String[]}
     * @description A list of class strings stored if imported / interpreted  from an SVG element.
     */
    this.classList = [];

    /**
     * @name Two.Shape#matrix
     * @property {Two.Matrix}
     * @description The transformation matrix of the shape.
     * @nota-bene {@link Two.Shape#position}, {@link Two.Shape#rotation}, {@link Two.Shape#scale}, {@link Two.Shape#skewX}, and {@link Two.Shape#skewY} apply their values to the matrix when changed. The matrix is what is sent to the renderer to be drawn.
     */
    this.matrix = new Matrix();

    /**
     * @name Two.Shape#position
     * @property {Two.Vector} - The x and y value for where the shape is placed relative to its parent.
     */
    this.position = new Vector();

    /**
     * @name Two.Shape#rotation
     * @property {Number} - The value in Number for how much the shape is rotated relative to its parent.
     */
    this.rotation = 0;

    /**
     * @name Two.Shape#scale
     * @property {Number} - The value for how much the shape is scaled relative to its parent.
     * @nota-bene This value can be replaced with a {@link Two.Vector} to do non-uniform scaling. e.g: `shape.scale = new Two.Vector(2, 1);`
     */
    this.scale = 1;

    /**
     * @name Two.Shape#skewX
     * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
     * @description Skew the shape by an angle in the x axis direction.
     */
    this.skewX = 0;

    /**
     * @name Two.Shape#skewY
     * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
     * @description Skew the shape by an angle in the y axis direction.
     */
    this.skewY = 0;

  }

  get renderer() {
    return this._renderer;
  }
  set renderer(v) {
    this._renderer = v;
  }

  /**
   * @name Two.Shape#translation
   * @description Alias for {@link Two.Shape#position}.
   */
  get translation() {
    return proto.position.get.apply(this, arguments);
  }
  set translation(v) {
    proto.position.set.apply(this, arguments);
  }

  /**
   * @name Two.Shape#addTo
   * @function
   * @param {Two.Group} group - The parent the shape adds itself to.
   * @description Convenience method to add itself to the scenegraph.
   */
  addTo(group) {
    group.add(this);
    return this;
  }

  /**
   * @name Two.Text#remove
   * @function
   * @description Remove self from the scene / parent.
   */
  remove() {

    if (!this.parent) {
      return this;
    }

    this.parent.remove(this);

    return this;

  }

  /**
   * @name Two.Shape#clone
   * @function
   * @param {Two.Group} [parent] - Optional argument to automatically add the shape to a scenegraph.
   * @returns {Two.Shape}
   * @description Create a new {@link Two.Shape} with the same values as the current shape.
   */
  clone(parent) {

    const clone = new Shape();

    clone.position.copy(this.position);
    clone.rotation = this.rotation;
    clone.scale = this.scale;
    clone.skewX = this.skewX;
    clone.skewY = this.skewY;

    if (this.matrix.manual) {
      clone.matrix.copy(this.matrix);
    }

    if (parent) {
      parent.add(clone);
    }

    return clone._update();

  }

  /**
   * @name Two.Shape#_update
   * @function
   * @private
   * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
   * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
   * @nota-bene Try not to call this method more than once a frame.
   */
  _update(bubbles) {

    if (!this._matrix.manual && this._flagMatrix) {

      this._matrix
        .identity()
        .translate(this.position.x, this.position.y);

        if (this._scale instanceof Vector) {
          this._matrix.scale(this._scale.x, this._scale.y);
        } else {
          this._matrix.scale(this._scale);
        }

        this._matrix.rotate(this.rotation);
        this._matrix.skewX(this.skewX);
        this._matrix.skewY(this.skewY);
    }

    if (bubbles) {
      if (this.parent && this.parent._update) {
        this.parent._update();
      }
    }

    return this;

  }

  /**
   * @name Two.Shape#flagReset
   * @function
   * @private
   * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
   */
  flagReset() {

    this._flagId = this._flagMatrix = this._flagScale =
      this._flagClassName = false;

    return this;

  }

}

const proto = {
  renderer: {
    enumerable: true,
    get: function() {
      return this._renderer;
    },
    set: function(obj) {
      this._renderer = obj;
    }
  },
  position: {
    enumerable: true,
    get: function() {
      return this._position;
    },
    set: function(v) {
      if (this._position) {
        this._position.unbind(Events.Types.change, this._renderer.flagMatrix);
      }
      this._position = v;
      this._position.bind(Events.Types.change, this._renderer.flagMatrix);
      FlagMatrix.call(this);
    }
  },
  rotation: {
    enumerable: true,
    get: function() {
      return this._rotation;
    },
    set: function(v) {
      this._rotation = v;
      this._flagMatrix = true;
    }
  },
  scale: {
    enumerable: true,
    get: function() {
      return this._scale;
    },
    set: function(v) {
      if (this._scale instanceof Vector) {
        this._scale.unbind(Events.Types.change, this._renderer.flagMatrix);
      }
      this._scale = v;
      if (this._scale instanceof Vector) {
        this._scale.bind(Events.Types.change, this._renderer.flagMatrix);
      }
      this._flagMatrix = true;
      this._flagScale = true;
    }
  },
  skewX: {
    enumerable: true,
    get: function() {
      return this._skewX;
    },
    set: function(v) {
      this._skewX = v;
      this._flagMatrix = true;
    }
  },
  skewY: {
    enumerable: true,
    get: function() {
      return this._skewY;
    },
    set: function(v) {
      this._skewY = v;
      this._flagMatrix = true;
    }
  },
  matrix: {
    enumerable: true,
    get: function() {
      return this._matrix;
    },
    set: function(v) {
      this._matrix = v;
      this._flagMatrix = true;
    }
  },

  id: {
    enumerable: true,
    get: function() {
      return this._id;
    },
    set: function(v) {
      const id = this._id;
      if (v === this._id) {
        return;
      }
      this._id = v;
      this._flagId = true;
      if (this.parent) {
        delete this.parent.children.ids[id];
        this.parent.children.ids[this._id] = this;
      }
    }
  },

  className: {
    enumerable: true,
    get: function() {
      return this._className;
    },
    set: function(v) {
      this._flagClassName = this._className !== v;
      if (this._flagClassName) {
        const prev = this._className.split(/\s+?/);
        const dest = v.split(/\s+?/);
        for (let i = 0; i < prev.length; i++) {
          const className = prev[i];
          const index = Array.prototype.indexOf.call(this.classList, className);
          if (index >= 0) {
            this.classList.splice(index, 1);
          }
        }
        this.classList = this.classList.concat(dest);
      }
      this._className = v;
    }
  }
};

/**
 * @name FlagMatrix
 * @function
 * @private
 * @description Utility function used in conjunction with event handlers to update the flagMatrix of a shape.
 */
function FlagMatrix() {
  this._flagMatrix = true;
}
<|endoftext|>


<commit_before>/* @flow */
/* eslint-disable */

import React from "react";
import Relay from "react-relay/classic";
import JSURL from "jsurl";
import queryString from "query-string";

import { Row } from "@ncigdc/uikit/Flex";
import Button from "@ncigdc/uikit/Button";
import withRouter from "@ncigdc/utils/withRouter";
import TabbedLinks from "@ncigdc/components/TabbedLinks";
import AnnotationsLink from "@ncigdc/components/Links/AnnotationsLink";

import CasesTable from "./CasesTable";
import FileTable from "./FileTable";

declare var _: Object;
declare var angular: Object;

_.pluck = _.map;

const angularBootstrapHtml = `
  <smart-search-wrapper></smart-search-wrapper>
`;

class SmartSearchComponent extends React.Component {
  static contextTypes = {
    router: React.PropTypes.object
  };

  componentDidMount() {
    const router = this.context.router;
    angular
      .module("legacyAngularWrapper", ["ngApp"])
      .config([
        "$locationProvider",
        "RestangularProvider",
        ($locationProvider, RestangularProvider) => {
          $locationProvider.html5Mode(false);
          RestangularProvider.setBaseUrl(process.env.REACT_APP_API);
        }
      ])
      .run([
        "$browser",
        $browser => {
          // angular dirty checks the browser url and messes with routing in other pages
          let pendingLocation = null;
          $browser.url = function(url, replace, state) {
            if (url) {
              pendingLocation = url;
              return $browser;
            } else {
              return pendingLocation || location.href.replace(/%27/g, "'");
            }
          };
        }
      ])
      .directive("smartSearchWrapper", [
        "LocationService",
        LocationService => ({
          controller() {
            this.setQuery = () => {
              const { query, filters } = queryString.parse(
                window.location.search
              );
              const currentQuery =
                query ||
                (filters && LocationService.filter2query(JSURL.parse(filters)));

              if (typeof currentQuery === "string") {
                this.query = currentQuery;
              }
            };
            this.sendQuery = () => {
              const gql = this.gql || {};
              const filters = { op: "and", content: [gql.filters] };

              const data = {
                query: this.query,
                filters: gql.filters && JSURL.stringify(filters)
              };

              router.push(
                `/query?${queryString.stringify(_.omitBy(data, _.isEmpty))}`
              );
            };
            this.resetQuery = () => {
              this.query = "";
              this.gql = null;
              this.Error = null;
              router.push("/query");
            };

            this.query = "";
            this.gql = "";
            this.Error = null;

            this.setQuery();

            document.querySelector(".btn-search-query").onclick = () => {
              const gql = this.gql || {};
              const filters = gql.filters.op === "and"
                ? gql.filters
                : { op: "and", content: [gql.filters] };

              const { filters: f, query: q, ...search } = queryString.parse(
                router.location.search
              );

              const data = {
                ...search,
                filters: gql.filters && JSURL.stringify(filters)
              };
              router.push(
                `/repository?${queryString.stringify(_.omitBy(data, _.isEmpty))}`
              );
            };
          },
          controllerAs: "sb",
          templateUrl: "components/ui/search/templates/search-bar.html"
        })
      ]);
    angular.bootstrap(this.container, ["legacyAngularWrapper"]);
  }

  render(): void {
    return (

 {
            this.container = c;
          }}
          dangerouslySetInnerHTML={{ __html: angularBootstrapHtml }}
        />

        <TabbedLinks
          queryParam="searchTableTab"
          defaultIndex={0}
          tabToolbar={
            <Row spacing="2rem" style={{ alignItems: "center" }}>
              <AnnotationsLink>
                <Button leftIcon={}>
                  Browse Annotations
                </Button>
              </AnnotationsLink>
            </Row>
          }
          links={[
            {
              id: "cases",
              text: `Cases (${this.props.viewer.repository.cases.hits.total.toLocaleString()})`,
              component: (
                <CasesTable hits={this.props.viewer.repository.cases.hits} />
              )
            },
            {
              id: "files",
              text: `Files (${this.props.viewer.repository.files.hits.total.toLocaleString()})`,
              component: (
                <FileTable hits={this.props.viewer.repository.files.hits} />
              )
            }
          ]}
        />

    );
  }
}

export const SmartSearchQuery = {
  initialVariables: {
    cases_offset: null,
    cases_size: null,
    cases_sort: null,
    files_offset: null,
    files_size: null,
    files_sort: null,
    filters: null
  },
  fragments: {
    viewer: () => Relay.QL`
      fragment on Root {
        repository {
          cases {
            hits(first: $cases_size offset: $cases_offset, filters: $filters) {
              ${CasesTable.getFragment("hits")}
              total
            }
          }
          files {
            hits(first: $files_size offset: $files_offset, filters: $filters) {
              ${FileTable.getFragment("hits")}
              total
            }
          }
        }
      }
    `
  }
};

const SmartSearchPage = Relay.createContainer(
  withRouter(SmartSearchComponent),
  SmartSearchQuery
);

export default SmartSearchPage;
<commit_msg>🐛 PRTL-1271 Back to Facet Search issues: does nothing or shows empty page (#1760)<commit_after>/* @flow */
/* eslint-disable */

import React from "react";
import Relay from "react-relay/classic";
import JSURL from "jsurl";
import queryString from "query-string";

import { Row } from "@ncigdc/uikit/Flex";
import Button from "@ncigdc/uikit/Button";
import withRouter from "@ncigdc/utils/withRouter";
import TabbedLinks from "@ncigdc/components/TabbedLinks";
import AnnotationsLink from "@ncigdc/components/Links/AnnotationsLink";

import CasesTable from "./CasesTable";
import FileTable from "./FileTable";

declare var _: Object;
declare var angular: Object;

_.pluck = _.map;

const angularBootstrapHtml = `
  <smart-search-wrapper></smart-search-wrapper>
`;

class SmartSearchComponent extends React.Component {
  static contextTypes = {
    router: React.PropTypes.object
  };

  componentDidMount() {
    const router = this.context.router;
    angular
      .module("legacyAngularWrapper", ["ngApp"])
      .config([
        "$locationProvider",
        "RestangularProvider",
        ($locationProvider, RestangularProvider) => {
          $locationProvider.html5Mode(false);
          RestangularProvider.setBaseUrl(process.env.REACT_APP_API);
        }
      ])
      .run([
        "$browser",
        $browser => {
          // angular dirty checks the browser url and messes with routing in other pages
          let pendingLocation = null;
          $browser.url = function(url, replace, state) {
            if (url) {
              pendingLocation = url;
              return $browser;
            } else {
              return pendingLocation || location.href.replace(/%27/g, "'");
            }
          };
        }
      ])
      .directive("smartSearchWrapper", [
        "LocationService",
        LocationService => ({
          controller() {
            this.setQuery = () => {
              const { query, filters } = queryString.parse(
                window.location.search
              );
              const currentQuery =
                query ||
                (filters && LocationService.filter2query(JSURL.parse(filters)));

              if (typeof currentQuery === "string") {
                this.query = currentQuery;
              }
            };
            this.sendQuery = () => {
              const gql = this.gql || {};
              const filters = { op: "and", content: [gql.filters] };

              const data = {
                query: this.query,
                filters: gql.filters && JSURL.stringify(filters)
              };

              router.push(
                `/query?${queryString.stringify(_.omitBy(data, _.isEmpty))}`
              );
            };
            this.resetQuery = () => {
              this.query = "";
              this.gql = null;
              this.Error = null;
              router.push("/query");
            };

            this.query = "";
            this.gql = "";
            this.Error = null;

            this.setQuery();

            document.querySelector(".btn-search-query").onclick = () => {
              router.push(
                `/repository`
              );
            };
          },
          controllerAs: "sb",
          templateUrl: "components/ui/search/templates/search-bar.html"
        })
      ]);
    angular.bootstrap(this.container, ["legacyAngularWrapper"]);
  }

  render(): void {
    return (

 {
            this.container = c;
          }}
          dangerouslySetInnerHTML={{ __html: angularBootstrapHtml }}
        />

        <TabbedLinks
          queryParam="searchTableTab"
          defaultIndex={0}
          tabToolbar={
            <Row spacing="2rem" style={{ alignItems: "center" }}>
              <AnnotationsLink>
                <Button leftIcon={}>
                  Browse Annotations
                </Button>
              </AnnotationsLink>
            </Row>
          }
          links={[
            {
              id: "cases",
              text: `Cases (${this.props.viewer.repository.cases.hits.total.toLocaleString()})`,
              component: (
                <CasesTable hits={this.props.viewer.repository.cases.hits} />
              )
            },
            {
              id: "files",
              text: `Files (${this.props.viewer.repository.files.hits.total.toLocaleString()})`,
              component: (
                <FileTable hits={this.props.viewer.repository.files.hits} />
              )
            }
          ]}
        />

    );
  }
}

export const SmartSearchQuery = {
  initialVariables: {
    cases_offset: null,
    cases_size: null,
    cases_sort: null,
    files_offset: null,
    files_size: null,
    files_sort: null,
    filters: null
  },
  fragments: {
    viewer: () => Relay.QL`
      fragment on Root {
        repository {
          cases {
            hits(first: $cases_size offset: $cases_offset, filters: $filters) {
              ${CasesTable.getFragment("hits")}
              total
            }
          }
          files {
            hits(first: $files_size offset: $files_offset, filters: $filters) {
              ${FileTable.getFragment("hits")}
              total
            }
          }
        }
      }
    `
  }
};

const SmartSearchPage = Relay.createContainer(
  withRouter(SmartSearchComponent),
  SmartSearchQuery
);

export default SmartSearchPage;
<|endoftext|>


<commit_before>var compress = require('compression')
var cors = require('cors')
var debug = require('debug')('webtorrent-www:web')
var downgrade = require('downgrade')
var express = require('express')
var fs = require('fs')
var highlight = require('highlight.js')
var http = require('http')
var jade = require('jade')
var marked = require('marked')
var multer = require('multer')
var path = require('path')
var unlimited = require('unlimited')
var url = require('url')

var config = require('../config')

var APP_VERSION = require('webtorrent-desktop/package.json').version
var RELEASE_PATH = 'https://github.com/feross/webtorrent-desktop/releases/download'

unlimited()

var app = express()
var server = http.createServer(app)

jade.filters.markdown = marked

marked.setOptions({
  highlight: function (code, lang) {
    var h = lang
      ? highlight.highlight(lang, code)
      : highlight.highlightAuto(code)
    return '
' + h.value + '
'
  }
})

// Templating
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'jade')
app.set('x-powered-by', false)
app.engine('jade', jade.renderFile)

// Trust the X-Forwarded-* headers from http-proxy
app.enable('trust proxy')

app.use(compress())

app.use(function (req, res, next) {
  // Force SSL
  if (config.isProd && req.protocol !== 'https') {
    return res.redirect('https://' + (req.hostname || 'webtorrent.io') + req.url)
  }

  // Redirect www to non-www
  if (config.isProd && req.hostname === 'www.webtorrent.io') {
    return res.redirect('https://webtorrent.io' + req.url)
  }

  // Use HTTP Strict Transport Security
  // Lasts 1 year, incl. subdomains, allow browser preload list
  if (config.isProd) {
    res.header(
      'Strict-Transport-Security',
      'max-age=31536000; includeSubDomains; preload'
    )
  }

  // Add cross-domain header for fonts, required by spec, Firefox, and IE.
  var extname = path.extname(url.parse(req.url).pathname)
  if (['.eot', '.ttf', '.otf', '.woff'].indexOf(extname) >= 0) {
    res.header('Access-Control-Allow-Origin', '*')
  }

  // Prevents IE and Chrome from MIME-sniffing a response. Reduces exposure to
  // drive-by download attacks on sites serving user uploaded content.
  res.header('X-Content-Type-Options', 'nosniff')

  // Prevent rendering of site within a frame.
  res.header('X-Frame-Options', 'DENY')

  // Enable the XSS filter built into most recent web browsers. It's usually
  // enabled by default anyway, so role of this headers is to re-enable for this
  // particular website if it was disabled by the user.
  res.header('X-XSS-Protection', '1; mode=block')

  // Force IE to use latest rendering engine or Chrome Frame
  res.header('X-UA-Compatible', 'IE=Edge,chrome=1')

  next()
})

/**
 * Enable CORS preflight, and cache it for 1 hour. This is necessary to support
 * requests from another domain with the "Range" HTTP header.
 */
app.options('/torrents/*', cors({ maxAge: 60 * 60 }))

app.get('/torrents/*', cors(), express.static(path.join(__dirname, '../static')))

app.use(express.static(path.join(__dirname, '../static')))

app.get('/', function (req, res) {
  res.render('home', { rawTitle: 'WebTorrent - Streaming browser torrent client' })
})

app.get('/desktop', function (req, res) {
  res.render('desktop', { rawTitle: 'WebTorrent Desktop', version: APP_VERSION })
})

app.get('/intro', function (req, res) {
  res.render('intro', { rawTitle: 'WebTorrent Tutorial - Get Started' })
})

app.get('/docs', function (req, res) {
  res.render('docs', { rawTitle: 'WebTorrent API Documentation' })
})

app.get('/faq', function (req, res) {
  res.render('faq', { rawTitle: 'WebTorrent FAQ' })
})

app.get('/create', function (req, res) {
  res.render('create', { title: 'Create a .torrent file' })
})

app.get('/logs', function (req, res) {
  res.redirect(301, 'https://botbot.me/freenode/webtorrent/')
})

var crashReportsPath = path.join(__dirname, '..', 'crash-reports')
var upload = multer({ dest: crashReportsPath }).single('upload_file_minidump')

app.post('/desktop/crash-report', upload, function (req, res) {
  req.body.filename = req.file.filename
  var crashLog = JSON.stringify(req.body, undefined, 2)

  fs.writeFile(req.file.path + '.json', crashLog, function (err) {
    if (err) return console.error('Error saving crash report: ' + err.message)
    console.log('Saved crash report:\n\t' + crashLog)
  })

  res.end()
})

// Deprecated: WebTorrent Desktop v0.0.0 - 0.2.0 use this update URL
app.get('/app/update/?*', function (req, res) {
  res.redirect(301, req.url.replace('/app/', '/desktop/'))
})

// WebTorrent.app OS X auto-update endpoint
app.get('/desktop/update', function (req, res) {
  var version = req.query.version
  logUpdateCheck({
    platform: 'darwin',
    version: version,
    ip: req.ip
  })
  if (version === APP_VERSION) {
    // No update required. User is on latest app version.
    res.status(204).end()
  } else {
    // Update is required. Send update JSON.
    // Response format docs: https://github.com/Squirrel/Squirrel.Mac#update-json-format
    res.status(200).send({
      name: 'WebTorrent v' + APP_VERSION,
      url: `${RELEASE_PATH}/v${APP_VERSION}/WebTorrent-v${APP_VERSION}-darwin.zip`,
      version: APP_VERSION
    })
  }
})

// WebTorrent.app Windows auto-update endpoint
app.get('/desktop/update/*', function (req, res) {
  logUpdateCheck({
    platform: 'win32',
    version: req.query.version,
    ip: req.ip
  })
  var pathname = url.parse(req.url).pathname
  var file = pathname.replace(/^\/desktop\/update\//i, '')
  var fileVersion
  if (file === 'RELEASES') {
    fileVersion = APP_VERSION
  } else {
    var match = /-(\d+\.\d+\.\d+)-/.exec(file)
    fileVersion = match && match[1]
  }
  if (!fileVersion) {
    return res.status(404).end()
  }
  var redirectURL = `${RELEASE_PATH}/v${fileVersion}/${file}`
  res.redirect(302, redirectURL)
})

function logUpdateCheck (log) {
  console.log('UPDATE CHECK: ' + JSON.stringify(log))
}

app.get('*', function (req, res) {
  res.status(404).render('error', {
    title: '404 Not Found',
    message: '404 Not Found'
  })
})

// error handling middleware
app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).render('error', {
    title: '500 Server Error',
    message: '500 Server Error'
  })
})

server.listen(config.ports.web, function () {
  debug('listening on port ' + server.address().port)
  downgrade()
  process.send('ready')
})
<commit_msg>log update check date<commit_after>var compress = require('compression')
var cors = require('cors')
var debug = require('debug')('webtorrent-www:web')
var downgrade = require('downgrade')
var express = require('express')
var fs = require('fs')
var highlight = require('highlight.js')
var http = require('http')
var jade = require('jade')
var marked = require('marked')
var multer = require('multer')
var path = require('path')
var unlimited = require('unlimited')
var url = require('url')

var config = require('../config')

var APP_VERSION = require('webtorrent-desktop/package.json').version
var RELEASE_PATH = 'https://github.com/feross/webtorrent-desktop/releases/download'

unlimited()

var app = express()
var server = http.createServer(app)

jade.filters.markdown = marked

marked.setOptions({
  highlight: function (code, lang) {
    var h = lang
      ? highlight.highlight(lang, code)
      : highlight.highlightAuto(code)
    return '
' + h.value + '
'
  }
})

// Templating
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'jade')
app.set('x-powered-by', false)
app.engine('jade', jade.renderFile)

// Trust the X-Forwarded-* headers from http-proxy
app.enable('trust proxy')

app.use(compress())

app.use(function (req, res, next) {
  // Force SSL
  if (config.isProd && req.protocol !== 'https') {
    return res.redirect('https://' + (req.hostname || 'webtorrent.io') + req.url)
  }

  // Redirect www to non-www
  if (config.isProd && req.hostname === 'www.webtorrent.io') {
    return res.redirect('https://webtorrent.io' + req.url)
  }

  // Use HTTP Strict Transport Security
  // Lasts 1 year, incl. subdomains, allow browser preload list
  if (config.isProd) {
    res.header(
      'Strict-Transport-Security',
      'max-age=31536000; includeSubDomains; preload'
    )
  }

  // Add cross-domain header for fonts, required by spec, Firefox, and IE.
  var extname = path.extname(url.parse(req.url).pathname)
  if (['.eot', '.ttf', '.otf', '.woff'].indexOf(extname) >= 0) {
    res.header('Access-Control-Allow-Origin', '*')
  }

  // Prevents IE and Chrome from MIME-sniffing a response. Reduces exposure to
  // drive-by download attacks on sites serving user uploaded content.
  res.header('X-Content-Type-Options', 'nosniff')

  // Prevent rendering of site within a frame.
  res.header('X-Frame-Options', 'DENY')

  // Enable the XSS filter built into most recent web browsers. It's usually
  // enabled by default anyway, so role of this headers is to re-enable for this
  // particular website if it was disabled by the user.
  res.header('X-XSS-Protection', '1; mode=block')

  // Force IE to use latest rendering engine or Chrome Frame
  res.header('X-UA-Compatible', 'IE=Edge,chrome=1')

  next()
})

/**
 * Enable CORS preflight, and cache it for 1 hour. This is necessary to support
 * requests from another domain with the "Range" HTTP header.
 */
app.options('/torrents/*', cors({ maxAge: 60 * 60 }))

app.get('/torrents/*', cors(), express.static(path.join(__dirname, '../static')))

app.use(express.static(path.join(__dirname, '../static')))

app.get('/', function (req, res) {
  res.render('home', { rawTitle: 'WebTorrent - Streaming browser torrent client' })
})

app.get('/desktop', function (req, res) {
  res.render('desktop', { rawTitle: 'WebTorrent Desktop', version: APP_VERSION })
})

app.get('/intro', function (req, res) {
  res.render('intro', { rawTitle: 'WebTorrent Tutorial - Get Started' })
})

app.get('/docs', function (req, res) {
  res.render('docs', { rawTitle: 'WebTorrent API Documentation' })
})

app.get('/faq', function (req, res) {
  res.render('faq', { rawTitle: 'WebTorrent FAQ' })
})

app.get('/create', function (req, res) {
  res.render('create', { title: 'Create a .torrent file' })
})

app.get('/logs', function (req, res) {
  res.redirect(301, 'https://botbot.me/freenode/webtorrent/')
})

var crashReportsPath = path.join(__dirname, '..', 'crash-reports')
var upload = multer({ dest: crashReportsPath }).single('upload_file_minidump')

app.post('/desktop/crash-report', upload, function (req, res) {
  req.body.filename = req.file.filename
  var crashLog = JSON.stringify(req.body, undefined, 2)

  fs.writeFile(req.file.path + '.json', crashLog, function (err) {
    if (err) return console.error('Error saving crash report: ' + err.message)
    console.log('Saved crash report:\n\t' + crashLog)
  })

  res.end()
})

// Deprecated: WebTorrent Desktop v0.0.0 - 0.2.0 use this update URL
app.get('/app/update/?*', function (req, res) {
  res.redirect(301, req.url.replace('/app/', '/desktop/'))
})

// WebTorrent.app OS X auto-update endpoint
app.get('/desktop/update', function (req, res) {
  var version = req.query.version
  logUpdateCheck({
    date: (new Date()).toString(),
    platform: 'darwin',
    version: version,
    ip: req.ip
  })
  if (version === APP_VERSION) {
    // No update required. User is on latest app version.
    res.status(204).end()
  } else {
    // Update is required. Send update JSON.
    // Response format docs: https://github.com/Squirrel/Squirrel.Mac#update-json-format
    res.status(200).send({
      name: 'WebTorrent v' + APP_VERSION,
      url: `${RELEASE_PATH}/v${APP_VERSION}/WebTorrent-v${APP_VERSION}-darwin.zip`,
      version: APP_VERSION
    })
  }
})

// WebTorrent.app Windows auto-update endpoint
app.get('/desktop/update/*', function (req, res) {
  logUpdateCheck({
    date: (new Date()).toString(),
    platform: 'win32',
    version: req.query.version,
    ip: req.ip
  })
  var pathname = url.parse(req.url).pathname
  var file = pathname.replace(/^\/desktop\/update\//i, '')
  var fileVersion
  if (file === 'RELEASES') {
    fileVersion = APP_VERSION
  } else {
    var match = /-(\d+\.\d+\.\d+)-/.exec(file)
    fileVersion = match && match[1]
  }
  if (!fileVersion) {
    return res.status(404).end()
  }
  var redirectURL = `${RELEASE_PATH}/v${fileVersion}/${file}`
  res.redirect(302, redirectURL)
})

function logUpdateCheck (log) {
  console.log('UPDATE CHECK: ' + JSON.stringify(log))
}

app.get('*', function (req, res) {
  res.status(404).render('error', {
    title: '404 Not Found',
    message: '404 Not Found'
  })
})

// error handling middleware
app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).render('error', {
    title: '500 Server Error',
    message: '500 Server Error'
  })
})

server.listen(config.ports.web, function () {
  debug('listening on port ' + server.address().port)
  downgrade()
  process.send('ready')
})
<|endoftext|>


<commit_before>/* eslint-disable dot-notation */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */
import { pageInfoStrings, programStrings, tableStrings } from '../../localization';
import { MODAL_KEYS, formatDate } from '../../utilities';
import { ROUTES } from '../../navigation/constants';
import { PageActions } from './actions';

/**
 * PageInfo rows/columns for use with the PageInfo component.
 *
 *
 * To add a page, add the pages routeName (see: pages/index.js)
 * and a 2d array of page info rows to PER_PAGE_INFO_COLUMNS,
 * of the desired pageinfo rows needed on the page.
 *
 * To use in the new page: use the usePageReducer hook.
 * usePageReducer will inject a your pages reducer with a field
 * pageInfo - a function returned by getPageInfo. Passing
 * this function the particular pages base object - i.e,
 * transaction, requisition or stock and it's dispatch will return the
 * required pageInfo columns for the page.
 */

const PER_PAGE_INFO_COLUMNS = {
  [ROUTES.CUSTOMER_INVOICE]: [
    ['entryDate', 'confirmDate', 'enteredBy'],
    ['customer', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_INVOICE]: [
    ['entryDate', 'confirmDate'],
    ['otherParty', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION]: [
    ['entryDate', 'enteredBy'],
    ['otherParty', 'editableMonthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION_WITH_PROGRAM]: [
    ['program', 'orderType', 'entryDate', 'enteredBy'],
    ['period', 'otherParty', 'monthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.STOCKTAKE_EDITOR]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.STOCKTAKE_EDITOR_WITH_REASONS]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.CUSTOMER_REQUISITION]: [
    ['monthsToSupply', 'entryDate'],
    ['customer', 'requisitionComment'],
  ],
  [ROUTES.PRESCRIPTION]: [
    ['entryDate', 'enteredBy'],
    ['customer', 'transactionComment', 'prescriber'],
  ],
  [ROUTES.CASH_REGISTER]: [
    ['number', 'name', 'type', 'reason', 'comment', 'amount', 'confirmDate', 'status'],
  ],
  stocktakeBatchEditModal: [['itemName']],
  stocktakeBatchEditModalWithReasons: [['itemName']],
};

const PAGE_INFO_ROWS = (pageObject, dispatch, route) => ({
  entryDate: {
    title: `${pageInfoStrings.entry_date}:`,
    info: formatDate(pageObject.entryDate) || 'N/A',
  },
  confirmDate: {
    title: `${pageInfoStrings.confirm_date}:`,
    info: formatDate(pageObject.confirmDate),
  },
  enteredBy: {
    title: `${pageInfoStrings.entered_by}:`,
    info: pageObject.enteredBy && pageObject.enteredBy.username,
  },
  customer: {
    title: `${pageInfoStrings.customer}:`,
    info: pageObject.otherPartyName,
  },
  theirRef: {
    title: `${pageInfoStrings.their_ref}:`,
    info: pageObject.theirRef,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.THEIR_REF_EDIT, route)),
    editableType: 'text',
  },
  transactionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.TRANSACTION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  stocktakeComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  requisitionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.REQUISITION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  otherParty: {
    title: `${pageInfoStrings.supplier}:`,
    info: pageObject.otherPartyName,
  },
  program: {
    title: `${programStrings.program}:`,
    info: pageObject.program && pageObject.program.name,
  },
  orderType: {
    title: `${programStrings.order_type}:`,
    info: pageObject.orderType,
  },
  editableMonthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.SELECT_MONTH, route)),
    editableType: 'selectable',
  },
  period: {
    title: `${programStrings.period}:`,
    info: pageObject.period && pageObject.period.toInfoString(),
  },
  monthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
  },
  stocktakeName: {
    title: `${pageInfoStrings.stocktake_name}:`,
    info: pageObject.name,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_NAME_EDIT, route)),
    editableType: 'text',
  },
  itemName: {
    title: `${tableStrings.item_name}`,
    info: pageObject.itemName,
    onPress: null,
  },
  prescriber: {
    title: 'Prescriber',
    info: pageObject?.prescriber?.firstName,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.SELECT_PRESCRIBER, route)),
  },
  number: {
    title: 'Number',
    info: pageObject.number,
    onPress: null,
  },
  name: {
    title: 'Name',
    info: pageObject.name,
    onPress: null,
  },
  type: {
    title: 'Type',
    info: pageObject.type,
    onPress: null,
  },
  reason: {
    title: 'Defined Reason',
    info: pageObject.reason,
    onPress: null,
  },
  comment: {
    title: 'Comment',
    info: pageObject.comment,
    onPress: null,
  },
  status: {
    title: 'Status',
    info: pageObject.status,
    onPress: null,
  },
});

const getPageInfoColumns = page => {
  const pageInfoColumns = PER_PAGE_INFO_COLUMNS[page];

  if (!pageInfoColumns) return null;
  return (pageObjectParameter, dispatch, route) => {
    const pageInfoRows = PAGE_INFO_ROWS(pageObjectParameter, dispatch, route);
    return pageInfoColumns.map(pageInfoColumn =>
      pageInfoColumn.map(pageInfoKey => pageInfoRows[pageInfoKey])
    );
  };
};

export default getPageInfoColumns;
<commit_msg>Fix cash register info columns incorrect reason key<commit_after>/* eslint-disable dot-notation */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */
import { pageInfoStrings, programStrings, tableStrings } from '../../localization';
import { MODAL_KEYS, formatDate } from '../../utilities';
import { ROUTES } from '../../navigation/constants';
import { PageActions } from './actions';

/**
 * PageInfo rows/columns for use with the PageInfo component.
 *
 *
 * To add a page, add the pages routeName (see: pages/index.js)
 * and a 2d array of page info rows to PER_PAGE_INFO_COLUMNS,
 * of the desired pageinfo rows needed on the page.
 *
 * To use in the new page: use the usePageReducer hook.
 * usePageReducer will inject a your pages reducer with a field
 * pageInfo - a function returned by getPageInfo. Passing
 * this function the particular pages base object - i.e,
 * transaction, requisition or stock and it's dispatch will return the
 * required pageInfo columns for the page.
 */

const PER_PAGE_INFO_COLUMNS = {
  [ROUTES.CUSTOMER_INVOICE]: [
    ['entryDate', 'confirmDate', 'enteredBy'],
    ['customer', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_INVOICE]: [
    ['entryDate', 'confirmDate'],
    ['otherParty', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION]: [
    ['entryDate', 'enteredBy'],
    ['otherParty', 'editableMonthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION_WITH_PROGRAM]: [
    ['program', 'orderType', 'entryDate', 'enteredBy'],
    ['period', 'otherParty', 'monthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.STOCKTAKE_EDITOR]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.STOCKTAKE_EDITOR_WITH_REASONS]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.CUSTOMER_REQUISITION]: [
    ['monthsToSupply', 'entryDate'],
    ['customer', 'requisitionComment'],
  ],
  [ROUTES.PRESCRIPTION]: [
    ['entryDate', 'enteredBy'],
    ['customer', 'transactionComment', 'prescriber'],
  ],
  [ROUTES.CASH_REGISTER]: [
    ['number', 'name', 'type', 'reason', 'comment', 'amount', 'confirmDate', 'status'],
  ],
  stocktakeBatchEditModal: [['itemName']],
  stocktakeBatchEditModalWithReasons: [['itemName']],
};

const PAGE_INFO_ROWS = (pageObject, dispatch, route) => ({
  entryDate: {
    title: `${pageInfoStrings.entry_date}:`,
    info: formatDate(pageObject.entryDate) || 'N/A',
  },
  confirmDate: {
    title: `${pageInfoStrings.confirm_date}:`,
    info: formatDate(pageObject.confirmDate),
  },
  enteredBy: {
    title: `${pageInfoStrings.entered_by}:`,
    info: pageObject.enteredBy && pageObject.enteredBy.username,
  },
  customer: {
    title: `${pageInfoStrings.customer}:`,
    info: pageObject.otherPartyName,
  },
  theirRef: {
    title: `${pageInfoStrings.their_ref}:`,
    info: pageObject.theirRef,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.THEIR_REF_EDIT, route)),
    editableType: 'text',
  },
  transactionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.TRANSACTION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  stocktakeComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  requisitionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.REQUISITION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  otherParty: {
    title: `${pageInfoStrings.supplier}:`,
    info: pageObject.otherPartyName,
  },
  program: {
    title: `${programStrings.program}:`,
    info: pageObject.program && pageObject.program.name,
  },
  orderType: {
    title: `${programStrings.order_type}:`,
    info: pageObject.orderType,
  },
  editableMonthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.SELECT_MONTH, route)),
    editableType: 'selectable',
  },
  period: {
    title: `${programStrings.period}:`,
    info: pageObject.period && pageObject.period.toInfoString(),
  },
  monthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
  },
  stocktakeName: {
    title: `${pageInfoStrings.stocktake_name}:`,
    info: pageObject.name,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_NAME_EDIT, route)),
    editableType: 'text',
  },
  itemName: {
    title: `${tableStrings.item_name}`,
    info: pageObject.itemName,
    onPress: null,
  },
  prescriber: {
    title: 'Prescriber',
    info: pageObject?.prescriber?.firstName,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.SELECT_PRESCRIBER, route)),
  },
  number: {
    title: 'Number',
    info: pageObject.number,
    onPress: null,
  },
  name: {
    title: 'Name',
    info: pageObject.name,
    onPress: null,
  },
  type: {
    title: 'Type',
    info: pageObject.type,
    onPress: null,
  },
  reason: {
    title: 'Defined Reason',
    info: pageObject.reasonTitle,
    onPress: null,
  },
  comment: {
    title: 'Comment',
    info: pageObject.comment,
    onPress: null,
  },
  status: {
    title: 'Status',
    info: pageObject.status,
    onPress: null,
  },
});

const getPageInfoColumns = page => {
  const pageInfoColumns = PER_PAGE_INFO_COLUMNS[page];

  if (!pageInfoColumns) return null;
  return (pageObjectParameter, dispatch, route) => {
    const pageInfoRows = PAGE_INFO_ROWS(pageObjectParameter, dispatch, route);
    return pageInfoColumns.map(pageInfoColumn =>
      pageInfoColumn.map(pageInfoKey => pageInfoRows[pageInfoKey])
    );
  };
};

export default getPageInfoColumns;
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/**
 * Method using a factory pattern variant to get a reducer
 * for a particular page or page style.
 *
 * For a new page - create a constant object with the
 * methods from reducerMethods which are composed to create
 * a reducer. Add to PAGE_REDUCERS.
 *
 * Each key value pair in a reducer object should be in the form
 * action type: reducer function, returning a new state object
 *
 */

import {
  filterData,
  editTotalQuantity,
  focusNextCell,
  selectRow,
  deselectRow,
  deselectAll,
  focusCell,
  sortData,
  openBasicModal,
  closeBasicModal,
  addMasterListItems,
  addItem,
  editTheirRef,
  editComment,
  deleteRecordsById,
  refreshData,
  editBatchExpiry,
} from './reducerMethods';

/**
 * Used for actions that should be in all pages using a data table.
 */
const BASE_TABLE_PAGE_REDUCER = {
  focusNextCell,
  focusCell,
  sortData,
};

const customerInvoice = {
  ...BASE_TABLE_PAGE_REDUCER,
  filterData,
  editTotalQuantity,
  selectRow,
  deselectRow,
  deselectAll,
  openBasicModal,
  closeBasicModal,
  addMasterListItems,
  addItem,
  editTheirRef,
  editComment,
  deleteRecordsById,
  refreshData,
};

const customerInvoices = {
  ...BASE_TABLE_PAGE_REDUCER,
  filterData,
  selectRow,
  deselectRow,
  deselectAll,
  openBasicModal,
  closeBasicModal,
  deleteRecordsById,
};

const supplierInvoice = {
  ...BASE_TABLE_PAGE_REDUCER,
  filterData,
  selectRow,
  deselectRow,
  deselectAll,
  closeBasicModal,
  openBasicModal,
  editTheirRef,
  editComment,
  refreshData,
  addItem,
  editTotalQuantity,
  deleteRecordsById,
  editBatchExpiry,
};

const supplierRequisitions = {
  sortData,
  filterData,
  selectRow,
  deselectRow,
  deselectAll,
  openBasicModal,
  closeBasicModal,
  refreshData,
  deleteRecordsById,
};

const PAGE_REDUCERS = {
  customerInvoice,
  customerInvoices,
  supplierInvoice,
  supplierRequisitions,
};

const getReducer = page => {
  const reducer = PAGE_REDUCERS[page];
  return (state, action) => {
    const { type } = action;
    if (!reducer[type]) return state;
    return reducer[type](state, action);
  };
};

export default getReducer;
<commit_msg>Add SupplierRequisitions basic reducer<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/**
 * Method using a factory pattern variant to get a reducer
 * for a particular page or page style.
 *
 * For a new page - create a constant object with the
 * methods from reducerMethods which are composed to create
 * a reducer. Add to PAGE_REDUCERS.
 *
 * Each key value pair in a reducer object should be in the form
 * action type: reducer function, returning a new state object
 *
 */

import {
  filterData,
  editTotalQuantity,
  focusNextCell,
  selectRow,
  deselectRow,
  deselectAll,
  focusCell,
  sortData,
  openBasicModal,
  closeBasicModal,
  addMasterListItems,
  addItem,
  editTheirRef,
  editComment,
  deleteRecordsById,
  refreshData,
  editBatchExpiry,
} from './reducerMethods';

/**
 * Used for actions that should be in all pages using a data table.
 */
const BASE_TABLE_PAGE_REDUCER = {
  focusNextCell,
  focusCell,
  sortData,
};

const customerInvoice = {
  ...BASE_TABLE_PAGE_REDUCER,
  filterData,
  editTotalQuantity,
  selectRow,
  deselectRow,
  deselectAll,
  openBasicModal,
  closeBasicModal,
  addMasterListItems,
  addItem,
  editTheirRef,
  editComment,
  deleteRecordsById,
  refreshData,
};

const customerInvoices = {
  ...BASE_TABLE_PAGE_REDUCER,
  filterData,
  selectRow,
  deselectRow,
  deselectAll,
  openBasicModal,
  closeBasicModal,
  deleteRecordsById,
};

const supplierInvoice = {
  ...BASE_TABLE_PAGE_REDUCER,
  filterData,
  selectRow,
  deselectRow,
  deselectAll,
  closeBasicModal,
  openBasicModal,
  editTheirRef,
  editComment,
  refreshData,
  addItem,
  editTotalQuantity,
  deleteRecordsById,
  editBatchExpiry,
};

const supplierRequisitions = {
  sortData,
  filterData,
  selectRow,
  deselectRow,
  deselectAll,
  openBasicModal,
  closeBasicModal,
  refreshData,
  deleteRecordsById,
};

const supplierRequisitions = {
  sortData,
  filterData,
  selectRow,
  deselectRow,
  openBasicModal,
  closeBasicModal,
};

const PAGE_REDUCERS = {
  customerInvoice,
  customerInvoices,
  supplierInvoice,
  supplierRequisitions,
};

const getReducer = page => {
  const reducer = PAGE_REDUCERS[page];
  return (state, action) => {
    const { type } = action;
    if (!reducer[type]) return state;
    return reducer[type](state, action);
  };
};

export default getReducer;
<|endoftext|>


<commit_before>/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2010-2011 Sebastian Werner
==================================================================================================
*/

/**
 * Just a dump placeholder for environments without "console" object.
 */
(function(global)
{
	var methods = "log,clear,assert,debug,error,warn,info,trace".split(",");
	var console = global.console || (global.console = {});
	var log = console.log || new Function;

	for (var i=0, l=methods.length; i<l; i++)
	{
		var name = methods[i];
		if (!console[name]) {
			console[name] = log;
		}
	}
})(this);
<commit_msg>Reduced number of emulated methods. Better assert() emulation.<commit_after>/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2010-2011 Sebastian Werner
==================================================================================================
*/

/**
 * Just a dump placeholder for environments without "console" object.
 *
 * Emulates just the basic logging methods with an empty function. Maps missing functions
 * to `console.log` automatically.
 */
(function(global)
{
	var methods = "log,debug,error,warn,info".split(",");
	var console = global.console || (global.console = {});
	var log = console.log || new Function;

	for (var i=0, l=methods.length; i<l; i++)
	{
		var name = methods[i];
		if (!console[name]) {
			console[name] = log;
		}
	}

	if (!console.assert)
	{
		console.assert = function(expression)
		{
			if (!expression) {
				throw new Error(Array.prototype.slice.call(arguments, 1).join(" "));
			}
		}
	}
})(this);
<|endoftext|>