<commit_before>/*global define*/
define([
        './defaultValue',
        './defined',
        './DeveloperError',
        './Math',
        './Cartesian3',
        './Cartesian4',
        './Quaternion',
        './Matrix3'
    ], function(
        defaultValue,
        defined,
        DeveloperError,
        CesiumMath,
        Cartesian3,
        Cartesian4,
        Quaternion,
        Matrix3) {
    "use strict";

    function _computeEllipseQuadrant(cb, cbRadius, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                     thetaPts, thetaPtsIndex, offset, clockDir, ellipsePts, ellipsePtsIndex, numPts) {
        var angle;
        var theta;
        var radius;
        var azimuth;
        var temp;
        var temp2;
        var rotAxis;
        var tempVec;

        for (var i = 0; i < numPts; i++, thetaPtsIndex += clockDir, ++ellipsePtsIndex) {
            theta = (clockDir > 0) ? (thetaPts[thetaPtsIndex] + offset) : (offset - thetaPts[thetaPtsIndex]);

            azimuth = theta + bearing;

            temp = -Math.cos(azimuth);

            rotAxis = Cartesian3.multiplyByScalar(eastVec, temp);

            temp = Math.sin(azimuth);
            tempVec = Cartesian3.multiplyByScalar(northVec, temp);

            rotAxis = Cartesian3.add(rotAxis, tempVec, rotAxis);

            temp = Math.cos(theta);
            temp = temp * temp;

            temp2 = Math.sin(theta);
            temp2 = temp2 * temp2;

            radius = ab / Math.sqrt(bSqr * temp + aSqr * temp2);
            angle = radius / cbRadius;

            // Create the quaternion to rotate the position vector to the boundary of the ellipse.
            temp = Math.sin(angle / 2.0);

            var unitQuat = Quaternion.normalize(new Quaternion(rotAxis.x * temp, rotAxis.y * temp, rotAxis.z * temp, Math.cos(angle / 2.0)));
            var rotMtx = Matrix3.fromQuaternion(unitQuat);

            var tmpEllipsePts = rotMtx.multiplyByVector(unitPos);
            var unitCart = Cartesian3.normalize(tmpEllipsePts);
            tmpEllipsePts = Cartesian3.multiplyByScalar(unitCart, cbRadius);
            ellipsePts[ellipsePtsIndex] = tmpEllipsePts;
        }
    }

    /**
     * Functions to compute the boundary positions for shapes, such as circles,
     * drawn on the ellipsoid.
     *
     * @exports Shapes
     *
     * @demo Cesium Sandcastle Circles and Ellipses Demo
     */
    var Shapes = {
        /**
         * Computes boundary points for a circle on the ellipsoid.
         *

         * The granularity determines the number of points
         * in the boundary.  A lower granularity results in more points and a more
         * exact circle.
         *

         * An outlined circle is rendered by passing the result of this function call to
         * {@link Polyline#setPositions}.  A filled circle is rendered by passing
         * the result to {@link Polygon#setPositions}.
         *
         * @param {Ellipsoid} ellipsoid The ellipsoid the circle will be on.
         * @param {Cartesian3} center The circle's center point in the fixed frame.
         * @param {Number} radius The radius in meters.
         * @param {Number} [granularity] The angular distance between points on the circle.
         *
         * @exception {DeveloperError} ellipsoid, center, and radius are required.
         * @exception {DeveloperError} radius must be greater than zero.
         * @exception {DeveloperError} granularity must be greater than zero.
         *
         * @see Polyline#setPositions
         * @see Polygon#setPositions
         *
         * @example
         * // Create a polyline of a circle
         * var polyline = new Polyline();
         * polyline.setPositions(Shapes.computeCircleBoundary(
         *   ellipsoid, ellipsoid.cartographicToCartesian(
         *     Cartographic.fromDegrees(-75.59777, 40.03883, 0.0)), 100000.0));
         */
        computeCircleBoundary : function(ellipsoid, center, radius, granularity) {
            if (!defined(ellipsoid) || !defined(center) || !defined(radius)) {
                throw new DeveloperError('ellipsoid, center, and radius are required.');
            }

            if (radius <= 0.0) {
                throw new DeveloperError('radius must be greater than zero.');
            }

            granularity = defaultValue(granularity, CesiumMath.RADIANS_PER_DEGREE);
            if (granularity <= 0.0) {
                throw new DeveloperError('granularity must be greater than zero.');
            }

            return this.computeEllipseBoundary(ellipsoid, center, radius, radius, 0, granularity);
        },

        /**
         * Computes boundary points for an ellipse on the ellipsoid.
         *

         * The granularity determines the number of points
         * in the boundary.  A lower granularity results in more points and a more
         * exact circle.
         *

         * An outlined ellipse is rendered by passing the result of this function call to
         * {@link Polyline#setPositions}.  A filled ellipse is rendered by passing
         * the result to {@link Polygon#setPositions}.
         *
         * @param {Ellipsoid} ellipsoid The ellipsoid the ellipse will be on.
         * @param {Cartesian3} center The ellipse's center point in the fixed frame.
         * @param {Number} semiMajorAxis The length of the ellipse's semi-major axis in meters.
         * @param {Number} semiMinorAxis The length of the ellipse's semi-minor axis in meters.
         * @param {Number} [bearing] The angle from north (clockwise) in radians. The default is zero.
         * @param {Number} [granularity] The angular distance between points on the circle.
         *
         * @exception {DeveloperError} ellipsoid, center, semiMajorAxis, and semiMinorAxis are required.
         * @exception {DeveloperError} Semi-major and semi-minor axes must be greater than zero.
         * @exception {DeveloperError} granularity must be greater than zero.
         *
         * @see Polyline#setPositions
         * @see Polygon#setPositions
         *
         * @returns The set of points that form the ellipse's boundary.
         *
         * @example
         * // Create a filled ellipse.
         * var polygon = new Polygon();
         * polygon.setPositions(Shapes.computeEllipseBoundary(
         *   ellipsoid, ellipsoid.cartographicToCartesian(
         *      Cartographic.fromDegrees(-75.59777, 40.03883)), 500000.0, 300000.0, Math.toRadians(60)));
         */
        computeEllipseBoundary : function(ellipsoid, center, semiMajorAxis, semiMinorAxis, bearing, granularity) {
            if (!defined(ellipsoid) || !defined(center) || !defined(semiMajorAxis) || !defined(semiMinorAxis)) {
                throw new DeveloperError('ellipsoid, center, semiMajorAxis, and semiMinorAxis are required.');
            }

            if (semiMajorAxis <= 0.0 || semiMinorAxis <= 0.0) {
                throw new DeveloperError('Semi-major and semi-minor axes must be greater than zero.');
            }

            bearing = bearing || 0.0;
            granularity = defaultValue(granularity, CesiumMath.RADIANS_PER_DEGREE);

            if (granularity <= 0.0) {
                throw new DeveloperError('granularity must be greater than zero.');
            }

            if (semiMajorAxis < semiMinorAxis) {
               var t = semiMajorAxis;
               semiMajorAxis = semiMinorAxis;
               semiMinorAxis = t;
            }

            var MAX_ANOMALY_LIMIT = 2.31;

            var aSqr = semiMajorAxis * semiMajorAxis;
            var bSqr = semiMinorAxis * semiMinorAxis;
            var ab = semiMajorAxis * semiMinorAxis;

            var value = 1.0 - (bSqr / aSqr);
            var ecc = Math.sqrt(value);

            var surfPos = Cartesian3.clone(center);
            var surfPosMag = Cartesian3.magnitude(surfPos);

            var tempVec = new Cartesian3(0.0, 0.0, 1);
            var temp = 1.0 / surfPosMag;

            var unitPos = Cartesian3.multiplyByScalar(surfPos, temp);
            var eastVec = Cartesian3.normalize(Cartesian3.cross(tempVec, surfPos));
            var northVec = Cartesian3.cross(unitPos, eastVec);

            var numQuadrantPts = 1 + Math.ceil(CesiumMath.PI_OVER_TWO / granularity);
            var deltaTheta = MAX_ANOMALY_LIMIT / (numQuadrantPts - 1);
            var thetaPts = [];
            var thetaPtsIndex = 0;

            var sampleTheta = 0.0;
            for (var i = 0; i < numQuadrantPts; i++, sampleTheta += deltaTheta, ++thetaPtsIndex) {
                thetaPts[thetaPtsIndex] = sampleTheta - ecc * Math.sin(sampleTheta);
                if (thetaPts[thetaPtsIndex] >= CesiumMath.PI_OVER_TWO) {
                    thetaPts[thetaPtsIndex] = CesiumMath.PI_OVER_TWO;
                    numQuadrantPts = i + 1;
                    break;
                }
            }

            var ellipsePts = [];

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, 0.0, 0.0, 1, ellipsePts, 0, numQuadrantPts - 1);

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, numQuadrantPts - 1, Math.PI, -1, ellipsePts, numQuadrantPts - 1, numQuadrantPts - 1);

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, 0.0, Math.PI, 1, ellipsePts, (2 * numQuadrantPts) - 2, numQuadrantPts - 1);

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, numQuadrantPts - 1, CesiumMath.TWO_PI, -1, ellipsePts, (3 * numQuadrantPts) - 3, numQuadrantPts);

            ellipsePts.push(ellipsePts[0].clone()); // Duplicates first and last point for polyline

            return ellipsePts;
        }
    };

    return Shapes;
});
<commit_msg>Removed unnecessary include<commit_after>/*global define*/
define([
        './defaultValue',
        './defined',
        './DeveloperError',
        './Math',
        './Cartesian3',
        './Quaternion',
        './Matrix3'
    ], function(
        defaultValue,
        defined,
        DeveloperError,
        CesiumMath,
        Cartesian3,
        Quaternion,
        Matrix3) {
    "use strict";

    function _computeEllipseQuadrant(cb, cbRadius, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                     thetaPts, thetaPtsIndex, offset, clockDir, ellipsePts, ellipsePtsIndex, numPts) {
        var angle;
        var theta;
        var radius;
        var azimuth;
        var temp;
        var temp2;
        var rotAxis;
        var tempVec;

        for (var i = 0; i < numPts; i++, thetaPtsIndex += clockDir, ++ellipsePtsIndex) {
            theta = (clockDir > 0) ? (thetaPts[thetaPtsIndex] + offset) : (offset - thetaPts[thetaPtsIndex]);

            azimuth = theta + bearing;

            temp = -Math.cos(azimuth);

            rotAxis = Cartesian3.multiplyByScalar(eastVec, temp);

            temp = Math.sin(azimuth);
            tempVec = Cartesian3.multiplyByScalar(northVec, temp);

            rotAxis = Cartesian3.add(rotAxis, tempVec, rotAxis);

            temp = Math.cos(theta);
            temp = temp * temp;

            temp2 = Math.sin(theta);
            temp2 = temp2 * temp2;

            radius = ab / Math.sqrt(bSqr * temp + aSqr * temp2);
            angle = radius / cbRadius;

            // Create the quaternion to rotate the position vector to the boundary of the ellipse.
            temp = Math.sin(angle / 2.0);

            var unitQuat = Quaternion.normalize(new Quaternion(rotAxis.x * temp, rotAxis.y * temp, rotAxis.z * temp, Math.cos(angle / 2.0)));
            var rotMtx = Matrix3.fromQuaternion(unitQuat);

            var tmpEllipsePts = rotMtx.multiplyByVector(unitPos);
            var unitCart = Cartesian3.normalize(tmpEllipsePts);
            tmpEllipsePts = Cartesian3.multiplyByScalar(unitCart, cbRadius);
            ellipsePts[ellipsePtsIndex] = tmpEllipsePts;
        }
    }

    /**
     * Functions to compute the boundary positions for shapes, such as circles,
     * drawn on the ellipsoid.
     *
     * @exports Shapes
     *
     * @demo Cesium Sandcastle Circles and Ellipses Demo
     */
    var Shapes = {
        /**
         * Computes boundary points for a circle on the ellipsoid.
         *

         * The granularity determines the number of points
         * in the boundary.  A lower granularity results in more points and a more
         * exact circle.
         *

         * An outlined circle is rendered by passing the result of this function call to
         * {@link Polyline#setPositions}.  A filled circle is rendered by passing
         * the result to {@link Polygon#setPositions}.
         *
         * @param {Ellipsoid} ellipsoid The ellipsoid the circle will be on.
         * @param {Cartesian3} center The circle's center point in the fixed frame.
         * @param {Number} radius The radius in meters.
         * @param {Number} [granularity] The angular distance between points on the circle.
         *
         * @exception {DeveloperError} ellipsoid, center, and radius are required.
         * @exception {DeveloperError} radius must be greater than zero.
         * @exception {DeveloperError} granularity must be greater than zero.
         *
         * @see Polyline#setPositions
         * @see Polygon#setPositions
         *
         * @example
         * // Create a polyline of a circle
         * var polyline = new Polyline();
         * polyline.setPositions(Shapes.computeCircleBoundary(
         *   ellipsoid, ellipsoid.cartographicToCartesian(
         *     Cartographic.fromDegrees(-75.59777, 40.03883, 0.0)), 100000.0));
         */
        computeCircleBoundary : function(ellipsoid, center, radius, granularity) {
            if (!defined(ellipsoid) || !defined(center) || !defined(radius)) {
                throw new DeveloperError('ellipsoid, center, and radius are required.');
            }

            if (radius <= 0.0) {
                throw new DeveloperError('radius must be greater than zero.');
            }

            granularity = defaultValue(granularity, CesiumMath.RADIANS_PER_DEGREE);
            if (granularity <= 0.0) {
                throw new DeveloperError('granularity must be greater than zero.');
            }

            return this.computeEllipseBoundary(ellipsoid, center, radius, radius, 0, granularity);
        },

        /**
         * Computes boundary points for an ellipse on the ellipsoid.
         *

         * The granularity determines the number of points
         * in the boundary.  A lower granularity results in more points and a more
         * exact circle.
         *

         * An outlined ellipse is rendered by passing the result of this function call to
         * {@link Polyline#setPositions}.  A filled ellipse is rendered by passing
         * the result to {@link Polygon#setPositions}.
         *
         * @param {Ellipsoid} ellipsoid The ellipsoid the ellipse will be on.
         * @param {Cartesian3} center The ellipse's center point in the fixed frame.
         * @param {Number} semiMajorAxis The length of the ellipse's semi-major axis in meters.
         * @param {Number} semiMinorAxis The length of the ellipse's semi-minor axis in meters.
         * @param {Number} [bearing] The angle from north (clockwise) in radians. The default is zero.
         * @param {Number} [granularity] The angular distance between points on the circle.
         *
         * @exception {DeveloperError} ellipsoid, center, semiMajorAxis, and semiMinorAxis are required.
         * @exception {DeveloperError} Semi-major and semi-minor axes must be greater than zero.
         * @exception {DeveloperError} granularity must be greater than zero.
         *
         * @see Polyline#setPositions
         * @see Polygon#setPositions
         *
         * @returns The set of points that form the ellipse's boundary.
         *
         * @example
         * // Create a filled ellipse.
         * var polygon = new Polygon();
         * polygon.setPositions(Shapes.computeEllipseBoundary(
         *   ellipsoid, ellipsoid.cartographicToCartesian(
         *      Cartographic.fromDegrees(-75.59777, 40.03883)), 500000.0, 300000.0, Math.toRadians(60)));
         */
        computeEllipseBoundary : function(ellipsoid, center, semiMajorAxis, semiMinorAxis, bearing, granularity) {
            if (!defined(ellipsoid) || !defined(center) || !defined(semiMajorAxis) || !defined(semiMinorAxis)) {
                throw new DeveloperError('ellipsoid, center, semiMajorAxis, and semiMinorAxis are required.');
            }

            if (semiMajorAxis <= 0.0 || semiMinorAxis <= 0.0) {
                throw new DeveloperError('Semi-major and semi-minor axes must be greater than zero.');
            }

            bearing = bearing || 0.0;
            granularity = defaultValue(granularity, CesiumMath.RADIANS_PER_DEGREE);

            if (granularity <= 0.0) {
                throw new DeveloperError('granularity must be greater than zero.');
            }

            if (semiMajorAxis < semiMinorAxis) {
               var t = semiMajorAxis;
               semiMajorAxis = semiMinorAxis;
               semiMinorAxis = t;
            }

            var MAX_ANOMALY_LIMIT = 2.31;

            var aSqr = semiMajorAxis * semiMajorAxis;
            var bSqr = semiMinorAxis * semiMinorAxis;
            var ab = semiMajorAxis * semiMinorAxis;

            var value = 1.0 - (bSqr / aSqr);
            var ecc = Math.sqrt(value);

            var surfPos = Cartesian3.clone(center);
            var surfPosMag = Cartesian3.magnitude(surfPos);

            var tempVec = new Cartesian3(0.0, 0.0, 1);
            var temp = 1.0 / surfPosMag;

            var unitPos = Cartesian3.multiplyByScalar(surfPos, temp);
            var eastVec = Cartesian3.normalize(Cartesian3.cross(tempVec, surfPos));
            var northVec = Cartesian3.cross(unitPos, eastVec);

            var numQuadrantPts = 1 + Math.ceil(CesiumMath.PI_OVER_TWO / granularity);
            var deltaTheta = MAX_ANOMALY_LIMIT / (numQuadrantPts - 1);
            var thetaPts = [];
            var thetaPtsIndex = 0;

            var sampleTheta = 0.0;
            for (var i = 0; i < numQuadrantPts; i++, sampleTheta += deltaTheta, ++thetaPtsIndex) {
                thetaPts[thetaPtsIndex] = sampleTheta - ecc * Math.sin(sampleTheta);
                if (thetaPts[thetaPtsIndex] >= CesiumMath.PI_OVER_TWO) {
                    thetaPts[thetaPtsIndex] = CesiumMath.PI_OVER_TWO;
                    numQuadrantPts = i + 1;
                    break;
                }
            }

            var ellipsePts = [];

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, 0.0, 0.0, 1, ellipsePts, 0, numQuadrantPts - 1);

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, numQuadrantPts - 1, Math.PI, -1, ellipsePts, numQuadrantPts - 1, numQuadrantPts - 1);

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, 0.0, Math.PI, 1, ellipsePts, (2 * numQuadrantPts) - 2, numQuadrantPts - 1);

            _computeEllipseQuadrant(ellipsoid, surfPosMag, aSqr, bSqr, ab, ecc, unitPos, eastVec, northVec, bearing,
                                   thetaPts, numQuadrantPts - 1, CesiumMath.TWO_PI, -1, ellipsePts, (3 * numQuadrantPts) - 3, numQuadrantPts);

            ellipsePts.push(ellipsePts[0].clone()); // Duplicates first and last point for polyline

            return ellipsePts;
        }
    };

    return Shapes;
});
<|endoftext|>


<commit_before>/* jshint esnext: true */
import { APP_NAME, $document, $html, isDebug, $pjaxWrapper, $window } from '../utils/environment';
import { EVENT as APP_EVENT } from '../App';

//List here all of your transitions
import * as transitions from './transitions';

const MODULE_NAME = 'Transition';
const EVENT_NAMESPACE = `${APP_NAME}.${MODULE_NAME}`;

const EVENT = {
    CLICK: `click.${EVENT_NAMESPACE}`,
    READYTOREMOVE: `readyToRemove.${EVENT_NAMESPACE}`,
    READYTODESTROY: `readyToDestroy.${EVENT_NAMESPACE}`
};

/*

@todo :

- ✅ get data-transition on clicked link -> launch() and add switch(){}
- ❌ add goto listener
- ❌ add newPageReady functon with google analytics send (maybe pjax do that?)
- ✅ add overrideClass system for all transitions
- ✅ add base class manager like old DefaultTransition (dom-is-loaded, dom-is-loading etc..)

======= SCHEMA =======

[] : listener
* : trigger event

[pjax:send] -> (transition) launch()

[pjax:switch] (= new view is loaded) -> (transition) hideView()-> hide animations & *readyToRemove

[readyToRemove] -> remove() -> delete modules
                            -> remove oldView from the DOM, and innerHTMl newView
                            -> display()

display() -> (transition) displayView() -> display animations & *readyToDestroy
          -> init new modules

[readyToRemove] -> reinit()

*/

export default class {
    constructor() {

        // jQuery ondomready
        $window.on('load',() => {
            this.load();
        });

        this.transition = new transitions['BaseTransition']({
            wrapper: this.wrapper
        });

        /*
        ===== PJAX CONFIGURATION =====
        */

        this.containerClass = '.js-pjax-container';
        this.wrapperId = 'js-pjax-wrapper';
        this.noPjaxRequestClass = 'no-transition';
        this.wrapper = document.getElementById(this.wrapperId);

        this.options = {
            debug: false,
            cacheBust: false,
            elements: [`a:not(.${this.noPjaxRequestClass})`,'form[action]'],
            selectors: ['title',`${this.containerClass}`],
            switches: {}
        };
        this.options.switches[this.containerClass] = (oldEl, newEl, options) => this.switch(oldEl, newEl, options)
        this.pjax = new Pjax(this.options);

        /*
        ===== LISTENERS =====
        */

        document.addEventListener('pjax:send',(e) => this.send(e));

        $document.on(EVENT.READYTOREMOVE,(event) => {
            this.remove(event.oldView, event.newView);
        });
        $document.on(EVENT.READYTODESTROY,(event) => {
            this.reinit();
        });
    }

    /**
     * (PJAX) Launch when pjax receive a request
     * get & manage data-transition,init and launch it
     * @param  {event}
     * @return void
     */
    send(e) {
        if(isDebug) {
            console.log("---- Launch request 🙌 -----");
        }

        let el = e.triggerElement;

        let transition = el.getAttribute('data-transition') ? el.getAttribute('data-transition') : 'BaseTransition';
        $html.attr('data-transition',transition);

        // options available : wrapper, overrideClass
        this.transition = new transitions[transition]({
            wrapper: this.wrapper,
            clickedLink: el
        });

        this.transition.launch();

    }

    /**
     * (PJAX) Launch when new page is loaded
     * @param  {js dom element},
     * @param  {js dom element}
     * @param  {options : pjax options}
     * @return void
     */
    switch(oldView, newView, options) {
        if(isDebug) {
            console.log('---- Next view loaded 👌 -----');
        }
        this.transition.hideView(oldView, newView);
    }

    /**
     * Launch when you trigger EVENT.READYTOREMOVE in your transition -> hideView(), at the end
     * after oldView hidden, delete modules and launch this.display()
     * @param  {js dom element},
     * @param  {js dom element}
     * @return void
     */
    remove(oldView, newView) {

        $document.triggerHandler({
            type: APP_EVENT.DELETE_SCOPED_MODULES,
            $scope: $pjaxWrapper
        });

        oldView.remove();

        this.display(newView);
    }

    /**
     * launch after this.remove()
     * @param  {js dom element},
     * @return void
     */
    display(view) {
        this.wrapper.innerHTML = view.outerHTML;

        // Fetch any inline script elements.
        const scripts = view.querySelectorAll('script.js-inline');

        if (scripts instanceof window.NodeList) {
            let i = 0;
            let len = scripts.length;
            for (; i < len; i++) {
                eval(scripts[i].innerHTML);
            }
        }

        $document.triggerHandler({
            type: APP_EVENT.INIT_SCOPED_MODULES,
            isPjax: true
        });

        this.pjax.onSwitch();

        this.transition.displayView(view);

    }

    /**
     * Launch when you trigger EVENT.READYTODESTROY in your transition -> displayView(), at the end
     * @return void
     */
    reinit() {
        this.transition.destroy();
        $html.attr('data-transition','');
        this.transition = new transitions['BaseTransition']({
            wrapper: this.wrapper
        });
    }

    /**
     * DOM is loaded
     *
     * @return {void}
     */
    load() {
        $html.addClass('dom-is-loaded');
        $html.removeClass('dom-is-loading');
        setTimeout(() => {
            $html.addClass('dom-is-animated');
        }, 1000)
    }
}
<commit_msg>fix browser back button TransitionManager<commit_after>/* jshint esnext: true */
import { APP_NAME, $document, $html, isDebug, $pjaxWrapper, $window } from '../utils/environment';
import { EVENT as APP_EVENT } from '../App';

//List here all of your transitions
import * as transitions from './transitions';

const MODULE_NAME = 'Transition';
const EVENT_NAMESPACE = `${APP_NAME}.${MODULE_NAME}`;

const EVENT = {
    CLICK: `click.${EVENT_NAMESPACE}`,
    READYTOREMOVE: `readyToRemove.${EVENT_NAMESPACE}`,
    READYTODESTROY: `readyToDestroy.${EVENT_NAMESPACE}`
};

/*

@todo :

- ✅ get data-transition on clicked link -> launch() and add switch(){}
- ❌ add goto listener
- ❌ add newPageReady functon with google analytics send (maybe pjax do that?)
- ✅ add overrideClass system for all transitions
- ✅ add base class manager like old DefaultTransition (dom-is-loaded, dom-is-loading etc..)

======= SCHEMA =======

[] : listener
* : trigger event

[pjax:send] -> (transition) launch()

[pjax:switch] (= new view is loaded) -> (transition) hideView()-> hide animations & *readyToRemove

[readyToRemove] -> remove() -> delete modules
                            -> remove oldView from the DOM, and innerHTMl newView
                            -> display()

display() -> (transition) displayView() -> display animations & *readyToDestroy
          -> init new modules

[readyToRemove] -> reinit()

*/

export default class {
    constructor() {

        // jQuery ondomready
        $window.on('load',() => {
            this.load();
        });

        this.transition = new transitions['BaseTransition']({
            wrapper: this.wrapper
        });

        /*
        ===== PJAX CONFIGURATION =====
        */

        this.containerClass = '.js-pjax-container';
        this.wrapperId = 'js-pjax-wrapper';
        this.noPjaxRequestClass = 'no-transition';
        this.wrapper = document.getElementById(this.wrapperId);

        this.options = {
            debug: false,
            cacheBust: false,
            elements: [`a:not(.${this.noPjaxRequestClass})`,'form[action]'],
            selectors: ['title',`${this.containerClass}`],
            switches: {}
        };
        this.options.switches[this.containerClass] = (oldEl, newEl, options) => this.switch(oldEl, newEl, options)
        this.pjax = new Pjax(this.options);

        /*
        ===== LISTENERS =====
        */

        document.addEventListener('pjax:send',(e) => this.send(e));

        $document.on(EVENT.READYTOREMOVE,(event) => {
            this.remove(event.oldView, event.newView);
        });
        $document.on(EVENT.READYTODESTROY,(event) => {
            this.reinit();
        });
    }

    /**
     * (PJAX) Launch when pjax receive a request
     * get & manage data-transition,init and launch it
     * @param  {event}
     * @return void
     */
    send(e) {
        if(isDebug) {
            console.log("---- Launch request 🙌 -----");
        }

        let el,transition;

        if(e.triggerElement != undefined) {

            el = e.triggerElement;

            transition = el.getAttribute('data-transition') ? el.getAttribute('data-transition') : 'BaseTransition';
            $html.attr('data-transition',transition);

        } else {
            transition = 'BaseTransition';
            el = document;
        }

        // options available : wrapper, overrideClass
        this.transition = new transitions[transition]({
            wrapper: this.wrapper,
            clickedLink: el
        });

        this.transition.launch();

    }

    /**
     * (PJAX) Launch when new page is loaded
     * @param  {js dom element},
     * @param  {js dom element}
     * @param  {options : pjax options}
     * @return void
     */
    switch(oldView, newView, options) {
        if(isDebug) {
            console.log('---- Next view loaded 👌 -----');
        }
        this.transition.hideView(oldView, newView);
    }

    /**
     * Launch when you trigger EVENT.READYTOREMOVE in your transition -> hideView(), at the end
     * after oldView hidden, delete modules and launch this.display()
     * @param  {js dom element},
     * @param  {js dom element}
     * @return void
     */
    remove(oldView, newView) {

        $document.triggerHandler({
            type: APP_EVENT.DELETE_SCOPED_MODULES,
            $scope: $pjaxWrapper
        });

        oldView.remove();

        this.display(newView);
    }

    /**
     * launch after this.remove()
     * @param  {js dom element},
     * @return void
     */
    display(view) {
        this.wrapper.innerHTML = view.outerHTML;

        // Fetch any inline script elements.
        const scripts = view.querySelectorAll('script.js-inline');

        if (scripts instanceof window.NodeList) {
            let i = 0;
            let len = scripts.length;
            for (; i < len; i++) {
                eval(scripts[i].innerHTML);
            }
        }

        $document.triggerHandler({
            type: APP_EVENT.INIT_SCOPED_MODULES,
            isPjax: true
        });

        this.pjax.onSwitch();

        this.transition.displayView(view);

    }

    /**
     * Launch when you trigger EVENT.READYTODESTROY in your transition -> displayView(), at the end
     * @return void
     */
    reinit() {
        this.transition.destroy();
        $html.attr('data-transition','');
        this.transition = new transitions['BaseTransition']({
            wrapper: this.wrapper
        });
    }

    /**
     * DOM is loaded
     *
     * @return {void}
     */
    load() {
        $html.addClass('dom-is-loaded');
        $html.removeClass('dom-is-loading');
        setTimeout(() => {
            $html.addClass('dom-is-animated');
        }, 1000)
    }
}
<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * Switcher : inner class that hold bunch of templates associated with a value.
 * DOM only.
 * It allows to switch between templates (rendered and mounted as Container) somewhere in DOM.
 */

var utils = require('../../utils'),
	interpolable = require('../../interpolable').interpolable;

var Switcher = function(context, node, parentContainer, items, defaultTemplate, destructOnSwitch) {
	this.witness = document.createComment('switcher');
	node.appendChild(this.witness); // dummy dom position marker
	this.node = node;
	this.context = context;
	this.items = items;
	this.parentContainer = parentContainer;
	this.defaultTemplate = defaultTemplate;
	this.destructOnSwitch = destructOnSwitch;
};

Switcher.prototype = {
	destroy: function() {
		// console.log('switcher destroy');
		this.interpolableInstance.destroy();
		this.interpolableInstance = null;
		var item;
		for (var i in this.items) {
			item = this.items[i];
			if (item.container)
				item.container.destroy();
			if (item.witness.parentNode)
				item.witness.parentNode.removeChild(item.witness);
		}
		this.node = null;
		this.context = null;
		this.witness = null;
		this.items = null;
		this.parentContainer = null;
		this.defaultItem = null;
	},
	expression: function(expression) {
		expression = interpolable(expression);
		if (expression.__interpolable__) {
			this.node.binds = this.node.binds || [];
			var self = this;
			expression.subscribeTo(this.context, function(value) {
				self.switch(value);
			}, this.node.binds);
			this.switch(expression.output(this.context));
		} else if (typeof expression === 'function')
			this.switch(expression(this.context));
		else
			this.switch(expression);
	},
	switch: function(value) {
		var self = this,
			ok = this.items.some(function(item) {
				if (item.value == value) {
					if (!item.container)
						item.container = item.template.toContainer(self.context, self.parentContainer);
					self._mount(item.container);
					return true;
				}
			});
		if (!ok) {
			if (this.defaultTemplate) {
				if (!this.defaultContainer)
					this.defaultContainer = this.defaultTemplate.toContainer(this.context, this.parentContainer);
				self._mount(this.defaultContainer);
			} else
				self._unmountCurrent();
		}
	},
	_unmountCurrent: function() {
		if (this.currentContainer) {
			var cur = this.currentContainer,
				self = this;
			cur.unmount(false, function() {
				if (self.node.__yContainer__)
					self.node.removeChild(cur);
				if (self.destructOnSwitch) {
					cur.context = null;
					cur.destroy();
				}
			});
			this.currentContainer = null;
		}
	},
	_mount: function(container) {
		if (this.currentContainer === container)
			return;
		this._unmountCurrent();
		this.currentContainer = container;

		if (this.node.__yContainer__ && !this.node.parentNode) { // node is not mounted
			utils.array.insertAfter(this.node.childNodes, this.witness, container);
			return;
		}
		var nextSibling = this.witness.nextSibling;
		if (nextSibling)
			container.insertBeforeNode(nextSibling);
		else
			container.appendTo(this.witness.parentNode);
	}
};

module.exports = Switcher;
<commit_msg>switcher constructor : work on sequenceSwitch and witness + remove default template from args<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * Switcher : inner class that hold bunch of templates associated with a value.
 * DOM only.
 * It allows to switch between templates (rendered and mounted as Container) somewhere in DOM.
 */

var utils = require('../../utils'),
	interpolable = require('../../interpolable').interpolable;

var Switcher = function(context, node, parentContainer, items, destructOnSwitch, sequencedSwitch) {
	this.node = node;
	this.context = context;
	this.items = items;
	this.sequencedSwitch = sequencedSwitch;
	this.parentContainer = parentContainer;
	this.destructOnSwitch = destructOnSwitch;
	var self = this;
	node.binds = node.binds ||  [];
	node.binds.push(function() {
		self.destroy();
	});
	items.forEach(function(item) {
		var witness = document.createComment('switcher : ' + item.value);
		node.appendChild(witness); // dummy dom position marker
		item.witness = witness;
		if (item.value === 'default')
			self.defaultItem = item;
	});
};

Switcher.prototype = {
	destroy: function() {
		// console.log('switcher destroy');
		this.interpolableInstance.destroy();
		this.interpolableInstance = null;
		var item;
		for (var i in this.items) {
			item = this.items[i];
			if (item.container)
				item.container.destroy();
			if (item.witness.parentNode)
				item.witness.parentNode.removeChild(item.witness);
		}
		this.node = null;
		this.context = null;
		this.witness = null;
		this.items = null;
		this.parentContainer = null;
		this.defaultItem = null;
	},
	expression: function(expression) {
		expression = interpolable(expression);
		if (expression.__interpolable__) {
			this.node.binds = this.node.binds || [];
			var self = this;
			expression.subscribeTo(this.context, function(value) {
				self.switch(value);
			}, this.node.binds);
			this.switch(expression.output(this.context));
		} else if (typeof expression === 'function')
			this.switch(expression(this.context));
		else
			this.switch(expression);
	},
	switch: function(value) {
		var self = this,
			ok = this.items.some(function(item) {
				if (item.value == value) {
					if (!item.container)
						item.container = item.template.toContainer(self.context, self.parentContainer);
					self._mount(item.container);
					return true;
				}
			});
		if (!ok) {
			if (this.defaultTemplate) {
				if (!this.defaultContainer)
					this.defaultContainer = this.defaultTemplate.toContainer(this.context, this.parentContainer);
				self._mount(this.defaultContainer);
			} else
				self._unmountCurrent();
		}
	},
	_unmountCurrent: function() {
		if (this.currentContainer) {
			var cur = this.currentContainer,
				self = this;
			cur.unmount(false, function() {
				if (self.node.__yContainer__)
					self.node.removeChild(cur);
				if (self.destructOnSwitch) {
					cur.context = null;
					cur.destroy();
				}
			});
			this.currentContainer = null;
		}
	},
	_mount: function(container) {
		if (this.currentContainer === container)
			return;
		this._unmountCurrent();
		this.currentContainer = container;

		if (this.node.__yContainer__ && !this.node.parentNode) { // node is not mounted
			utils.array.insertAfter(this.node.childNodes, this.witness, container);
			return;
		}
		var nextSibling = this.witness.nextSibling;
		if (nextSibling)
			container.insertBeforeNode(nextSibling);
		else
			container.appendTo(this.witness.parentNode);
	}
};

module.exports = Switcher;
<|endoftext|>


<commit_before>var ccxt = require('ccxt')
const coinUtils = require('../../../coin-utils')
const _ = require('lodash/fp')
const common = require('../../common/ccxt')

function trade (side, account, cryptoAtoms, fiatCode, cryptoCode, exchangeName) {
  try {
    const exchange = setUpExchange(account, exchangeName)
    const symbol = common.verifyCurrencies(exchangeName, fiatCode, cryptoCode)
    const amount = coinUtils.toUnit(cryptoAtoms, cryptoCode).toFixed(8)
    if (exchangeName === 'itbit') {
      return exchange.fetchOrderBook(symbol)
        .then(orderBook => {
          return exchange.createOrder(symbol, 'limit', side, amount, calculatePrice(side, amount, orderBook), { walletId: account.walletId })
        })
    }
    return exchange.createOrder(symbol, 'market', side, amount)
  } catch (e) {
    return Promise.reject(e)
  }
}

function setUpExchange (account, exchangeName) {
  // map given credentials to cctx properties
  if (!_.includes(exchangeName, ccxt.exchanges)) {
    throw new Error(`Exchange ${exchangeName} not supported by ccxt.`)
  }

  switch (exchangeName) {
    case 'itbit':
      if (!account.clientKey || !account.clientSecret || !account.userId || !account.walletId)
        throw new Error('Must provide user ID, wallet ID, client key, and client secret')
      return new ccxt[exchangeName](_.mapKeys((key) => { return key === 'clientKey' ? 'apiKey' : key === 'clientSecret' ? 'secret' : key === 'userId' ? 'uid' : key }, _.omit(['walletId'], account)))
    case 'kraken':
      if (!account.apiKey || !account.privateKey)
        throw new Error('Must provide key and private key')
      return new ccxt[exchangeName](_.mapKeys((key) => { return key === 'privateKey' ? 'secret' : key }, account))
    case 'bitstamp':
      if (!account.key || !account.secret || !account.clientId)
        throw new Error('Must provide key, secret and client ID')
      return new ccxt[exchangeName](_.mapKeys((key) => { return key === 'key' ? 'apiKey' : key === 'clientId' ? 'uid' : key }, account))
    default:
      throw new Error(`Exchange ${exchangeName} not supported.`)
  }
}

function calculatePrice (side, amount, orderBook) {
  const book = side === 'buy' ? 'asks' : 'bids'
  let collected = 0.0
  for (const entry of orderBook[book]) {
    collected += parseFloat(entry[1])
    if (collected >= amount) return parseFloat(entry[0])
  }
  throw new Error('Insufficient market depth')
}

module.exports = { trade }
<commit_msg>Restructured long lines of code<commit_after>var ccxt = require('ccxt')
const coinUtils = require('../../../coin-utils')
const _ = require('lodash/fp')
const common = require('../../common/ccxt')

function trade (side, account, cryptoAtoms, fiatCode, cryptoCode, exchangeName) {
  try {
    const exchange = setUpExchange(account, exchangeName)
    const symbol = common.verifyCurrencies(exchangeName, fiatCode, cryptoCode)
    const amount = coinUtils.toUnit(cryptoAtoms, cryptoCode).toFixed(8)
    if (exchangeName === 'itbit') {
      return exchange.fetchOrderBook(symbol)
        .then(orderBook => {
          const price = calculatePrice(side, amount, orderBook)
          return exchange.createOrder(symbol, 'limit', side, amount, price, { walletId: account.walletId })
        })
    }
    return exchange.createOrder(symbol, 'market', side, amount)
  } catch (e) {
    return Promise.reject(e)
  }
}

function setUpExchange (account, exchangeName) {
  // map given credentials to cctx properties
  if (!_.includes(exchangeName, ccxt.exchanges)) {
    throw new Error(`Exchange ${exchangeName} not supported by ccxt.`)
  }

  switch (exchangeName) {
    case 'itbit':
      if (!account.clientKey || !account.clientSecret || !account.userId || !account.walletId) {
        throw new Error('Must provide user ID, wallet ID, client key, and client secret')
      }
      return new ccxt[exchangeName](_.mapKeys((key) => {
        if (key === 'clientKey') return 'apiKey'
        if (key === 'clientSecret') return 'secret'
        if (key === 'userId') return 'uid'
        return key
      }, _.omit(['walletId'], account)))
    case 'kraken':
      if (!account.apiKey || !account.privateKey) {
        throw new Error('Must provide key and private key')
      }
      return new ccxt[exchangeName](_.mapKeys((key) => {
        if (key === 'privateKey') return 'secret'
        return key
      }, account))
    case 'bitstamp':
      if (!account.key || !account.secret || !account.clientId) {
        throw new Error('Must provide key, secret and client ID')
      }
      return new ccxt[exchangeName](_.mapKeys((key) => {
        if (key === 'key') return 'apiKey'
        if (key === 'clientId') return 'uid'
        return key
      }, account))
    default:
      throw new Error(`Exchange ${exchangeName} not supported.`)
  }
}

function calculatePrice (side, amount, orderBook) {
  const book = side === 'buy' ? 'asks' : 'bids'
  let collected = 0.0
  for (const entry of orderBook[book]) {
    collected += parseFloat(entry[1])
    if (collected >= amount) return parseFloat(entry[0])
  }
  throw new Error('Insufficient market depth')
}

module.exports = { trade }
<|endoftext|>


<commit_before><commit_msg>Delete compiled ProcessPuzzleUI.js<commit_after><|endoftext|>


<commit_before>// Copyright 2014, Renasar Technologies Inc.
/* jshint: node:true */

'use strict';

var di = require('di');

module.exports = taskGraphRunnerProtocolFactory;

di.annotate(taskGraphRunnerProtocolFactory, new di.Provide('Protocol.TaskGraphRunner'));
di.annotate(taskGraphRunnerProtocolFactory,
    new di.Inject(
        'Services.Messenger',
        'Constants',
        'Assert',
        '_'
    )
);

function taskGraphRunnerProtocolFactory (messenger, Constants, assert, _) {
    function TaskGraphRunnerProtocol() {
    }

    TaskGraphRunnerProtocol.prototype.getTaskGraphLibrary = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskGraphLibrary',
            { filter: filter }
        );
    };

    TaskGraphRunnerProtocol.prototype.getTaskLibrary = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskLibrary',
            { filter: filter }
        );
    };

    TaskGraphRunnerProtocol.prototype.getActiveTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraph',
            { filter: filter }
        );
    };

    TaskGraphRunnerProtocol.prototype.getActiveTaskGraphs = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraphs',
            { filter: filter }
        );
    };

    TaskGraphRunnerProtocol.prototype.defineTaskGraph = function (definition) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTaskGraph',
            { definition: definition }
        );
    };

    TaskGraphRunnerProtocol.prototype.defineTask = function (definition) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTask',
            { definition: definition }
        );
    };

    TaskGraphRunnerProtocol.prototype.runTaskGraph = function (name, options, target) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.runTaskGraph',
            { name: name, options: options, target: target }
        );
    };

    TaskGraphRunnerProtocol.prototype.cancelTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.cancelTaskGraph',
            filter
        );
    };

    TaskGraphRunnerProtocol.prototype.pauseTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.pauseTaskGraph',
            filter
        );
    };

    TaskGraphRunnerProtocol.prototype.resumeTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.resumeTaskGraph',
            filter
        );
    };

    TaskGraphRunnerProtocol.prototype.getTaskGraphProperties = function (instance) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskGraphProperties',
            { instance: instance }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetTaskGraphLibrary = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskGraphLibrary',
            function(data, message) {
                message.promise(
                    callback(data.filter)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetTaskLibrary = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskLibrary',
            function(data, message) {
                message.promise(
                    callback(data.filter)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeDefineTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTaskGraph',
            function(data, message) {
                message.promise(
                    callback(data.definition)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeDefineTask = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTask',
            function (data, message) {
                message.promise(
                    callback(data.definition)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetActiveTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraph',
            function (data, message) {
                message.promise(
                    callback(data.filter)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetActiveTaskGraphs = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraphs',
            function (data, message) {
                message.promise(
                    callback(data.filter)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeRunTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.runTaskGraph',
            function (data, message) {
                message.promise(
                    callback(data.name, data.options, data.target)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeCancelTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.cancelTaskGraph',
            function (data, message) {
                message.promise(
                    callback(data)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribePauseTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.pauseTaskGraph',
            function (data, message) {
                message.promise(
                    callback(data)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeResumeTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.resumeTaskGraph',
            function (data, message) {
                message.promise(
                    callback(data)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetTaskGraphProperties = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.TaskGraphRunner.Exchange.Name,
            'methods.subscribeGetTaskGraphProperties',
            function (data, message) {
                message.promise(
                    callback(data.instance)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeRequestTasks = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.TaskGraphRunner.Exchange.Name,
            'methods.subscribeRequestTasks',
            function (data, message) {
                message.promise(
                    callback(data.instance)
                );
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribePublishTasks = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.TaskGraphRunner.Exchange.Name,
            'methods.subscribePublishTasks',
            function (data, message) {
                message.promise(
                    callback(data.instance)
                );
            }
        );
    };

    return new TaskGraphRunnerProtocol();
}
<commit_msg>add result object to tgr protocol<commit_after>// Copyright 2014, Renasar Technologies Inc.
/* jshint: node:true */

'use strict';

var di = require('di');

module.exports = taskGraphRunnerProtocolFactory;

di.annotate(taskGraphRunnerProtocolFactory, new di.Provide('Protocol.TaskGraphRunner'));
di.annotate(taskGraphRunnerProtocolFactory,
    new di.Inject(
        'Q',
        'Services.Messenger',
        'Constants',
        'Assert',
        '_',
        'Result'
    )
);

function taskGraphRunnerProtocolFactory (
    Q,
    messenger,
    Constants,
    assert,
    _,
    Result
) {
    function TaskGraphRunnerProtocol() {
    }

    TaskGraphRunnerProtocol.prototype.getTaskGraphLibrary = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskGraphLibrary',
            { filter: filter }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.getTaskLibrary = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskLibrary',
            { filter: filter }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.getActiveTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraph',
            { filter: filter }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.getActiveTaskGraphs = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraphs',
            { filter: filter }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.defineTaskGraph = function (definition) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTaskGraph',
            { definition: definition }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.defineTask = function (definition) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTask',
            { definition: definition }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.runTaskGraph = function (name, options, target) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.runTaskGraph',
            { name: name, options: options, target: target }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.cancelTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.cancelTaskGraph',
            filter
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.pauseTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.pauseTaskGraph',
            filter
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.resumeTaskGraph = function (filter) {
        assert.object(filter);

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.resumeTaskGraph',
            filter
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.getTaskGraphProperties = function (instance) {
        // TODO: BBP what asserts to we need here?

        return messenger.request(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskGraphProperties',
            { instance: instance }
        ).then(function (data) {
            return data.value;
        });
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetTaskGraphLibrary = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskGraphLibrary',
            function(data, message) {
                Q.resolve(
                    callback(data.filter)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetTaskLibrary = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getTaskLibrary',
            function(data, message) {
                Q.resolve(
                    callback(data.filter)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeDefineTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTaskGraph',
            function(data, message) {
                Q.resolve(
                    callback(data.definition)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeDefineTask = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.defineTask',
            function (data, message) {
                Q.resolve(
                    callback(data.definition)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetActiveTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraph',
            function (data, message) {
                Q.resolve(
                    callback(data.filter)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetActiveTaskGraphs = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.getActiveTaskGraphs',
            function (data, message) {
                Q.resolve(
                    callback(data.filter)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeRunTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.runTaskGraph',
            function (data, message) {
                Q.resolve(
                    callback(data.name, data.options, data.target)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeCancelTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.cancelTaskGraph',
            function (data, message) {
                Q.resolve(
                    callback(data)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribePauseTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.pauseTaskGraph',
            function (data, message) {
                Q.resolve(
                    callback(data)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeResumeTaskGraph = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.Exchanges.TaskGraphRunner.Name,
            'methods.resumeTaskGraph',
            function (data, message) {
                Q.resolve(
                    callback(data)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeGetTaskGraphProperties = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.TaskGraphRunner.Exchange.Name,
            'methods.subscribeGetTaskGraphProperties',
            function (data, message) {
                Q.resolve(
                    callback(data.instance)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribeRequestTasks = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.TaskGraphRunner.Exchange.Name,
            'methods.subscribeRequestTasks',
            function (data, message) {
                Q.resolve(
                    callback(data.instance)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    TaskGraphRunnerProtocol.prototype.subscribePublishTasks = function (callback) {
        assert.func(callback);

        return messenger.subscribe(
            Constants.Protocol.TaskGraphRunner.Exchange.Name,
            'methods.subscribePublishTasks',
            function (data, message) {
                Q.resolve(
                    callback(data.instance)
                ).then(function (result) {
                    message.resolve(
                        new Result({ value: result })
                    );
                }).catch(function (error) {
                    message.reject(error);
                });
            }
        );
    };

    return new TaskGraphRunnerProtocol();
}
<|endoftext|>


<commit_before>import moment from 'moment';
import _ from 'lodash';
import airService from './AirService';
import { AirRuntimeError } from './AirErrors';

module.exports = (settings) => {
  const service = airService(settings);
  return {
    shop(options) {
      return service.searchLowFares(options);
    },

    toQueue(options) {
      return service.gdsQueue(options);
    },

    book(options) {
      return service.airPricePricingSolutionXML(options).then((data) => {
        const bookingParams = Object.assign({}, {
          passengers: options.passengers,
          rule: options.rule,
          ticketDate: moment().add(3, 'hours').format(),
          ActionStatusType: 'TAU',
        }, data);
        return service.createReservation(bookingParams).catch((err) => {
          if (err instanceof AirRuntimeError.SegmentBookingFailed
              || err instanceof AirRuntimeError.NoValidFare) {
            const code = err.data['universal:UniversalRecord'].LocatorCode;
            return service.cancelUR({
              LocatorCode: code,
            }).then(() => {
              throw err;
            }).catch(() => {
              if (settings.debug > 0) {
                console.log('Cant cancel booking with UR', code);
              }
              throw err;
            });
          }
          throw err;
        });
      });
    },

    importPNR(options) {
      return service.importPNR(options);
    },

    ticket(options) {
      return service.importPNR(options).then((data) => {
        const ticketParams = Object.assign({}, options, {
          ReservationLocator: data[0].uapi_reservation_locator,
        });
        return service.ticket(ticketParams)
          .then(result => result, (err) => {
            if (err instanceof AirRuntimeError.TicketingFoidRequired) {
              return service.importPNR(options)
                .then(booking => service.foid(booking[0]))
                .then(() => service.ticket(ticketParams));
            }
            return Promise.reject(err);
          });
      });
    },

    flightInfo(options) {
      const parameters = {
        flightInfoCriteria: _.isArray(options) ? options : [options],
      };
      return service.flightInfo(parameters)
        .then(data => data)
        .catch((err) => {
          if (settings.debug > 0) {
            console.log('Cant get flightInfo', err);
          }
          Promise.reject(err);
        });
    },

    getTicket(options) {
      return service.getTicket(options);
    },
  };
};
<commit_msg>getTickets method added<commit_after>import moment from 'moment';
import _ from 'lodash';
import airService from './AirService';
import { AirRuntimeError } from './AirErrors';

module.exports = (settings) => {
  const service = airService(settings);
  return {
    shop(options) {
      return service.searchLowFares(options);
    },

    toQueue(options) {
      return service.gdsQueue(options);
    },

    book(options) {
      return service.airPricePricingSolutionXML(options).then((data) => {
        const bookingParams = Object.assign({}, {
          passengers: options.passengers,
          rule: options.rule,
          ticketDate: moment().add(3, 'hours').format(),
          ActionStatusType: 'TAU',
        }, data);
        return service.createReservation(bookingParams).catch((err) => {
          if (err instanceof AirRuntimeError.SegmentBookingFailed
              || err instanceof AirRuntimeError.NoValidFare) {
            const code = err.data['universal:UniversalRecord'].LocatorCode;
            return service.cancelUR({
              LocatorCode: code,
            }).then(() => {
              throw err;
            }).catch(() => {
              if (settings.debug > 0) {
                console.log('Cant cancel booking with UR', code);
              }
              throw err;
            });
          }
          throw err;
        });
      });
    },

    importPNR(options) {
      return service.importPNR(options);
    },

    ticket(options) {
      return service.importPNR(options).then((data) => {
        const ticketParams = Object.assign({}, options, {
          ReservationLocator: data[0].uapi_reservation_locator,
        });
        return service.ticket(ticketParams)
          .then(result => result, (err) => {
            if (err instanceof AirRuntimeError.TicketingFoidRequired) {
              return service.importPNR(options)
                .then(booking => service.foid(booking[0]))
                .then(() => service.ticket(ticketParams));
            }
            return Promise.reject(err);
          });
      });
    },

    flightInfo(options) {
      const parameters = {
        flightInfoCriteria: _.isArray(options) ? options : [options],
      };
      return service.flightInfo(parameters)
        .then(data => data)
        .catch((err) => {
          if (settings.debug > 0) {
            console.log('Cant get flightInfo', err);
          }
          Promise.reject(err);
        });
    },

    getTicket(options) {
      return service.getTicket(options);
    },

    getTickets(options) {
      return service.importPNR(options)
        .then(
           pnrData => Promise.all(
             pnrData[0].tickets.map(
               ticket => service.getTicket({ ticketNumber: ticket.number })
             )
           )
        );
    },
  };
};
<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2017-2018 Digital Bazaar, Inc. All rights reserved.
 */
'use strict';

const constants = require('../constants');
const jsonld = require('jsonld');
const util = require('../util');
const {sha256digest} = require('../sha256digest');
const LinkedDataProof = require('./LinkedDataProof');

module.exports = class LinkedDataSignature extends LinkedDataProof {
  /**
   * @param type {string} Provided by subclass.
   *
   * @param [verificationMethod] {string} A key id URL to the paired public key.
   *
   * Advanced optional parameters and overrides:
   *
   * @param [proof] {object} a JSON-LD document with options to use for
   *   the `proof` node (e.g. any other custom fields can be provided here
   *   using a context different from security-v2).
   * @typedef {Object} LDKeyPair
   * @param {LDKeyPair} LDKeyClass - The crypto-ld key type that this suite
   *   will use to sign/verify signatures.
   * @param [date] {string|Date} signing date to use if not passed.
   * @param {function} [signer] - Signer function.
   * @param [useNativeCanonize] {boolean} true to use a native canonize
   *   algorithm.
   */
  constructor({
    type, verificationMethod, proof, LDKeyClass, date, signer, useNativeCanonize
  } = {}) {
    // validate common options
    if(verificationMethod !== undefined &&
      typeof verificationMethod !== 'string') {
      throw new TypeError('"verificationMethod" must be a URL string.');
    }
    super({type});
    this.verificationMethod = verificationMethod;
    this.LDKeyClass = LDKeyClass;
    this.signer = signer;
    this.proof = proof;
    if(date !== undefined) {
      this.date = new Date(date);
      if(isNaN(this.date)) {
        throw TypeError(`"date" "${date}" is not a valid date.`);
      }
    }
    this.useNativeCanonize = useNativeCanonize;
  }

  /**
   * @param document {object} to be signed.
   * @param purpose {ProofPurpose}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<object>} Resolves with the created proof object.
   */
  async createProof(
    {document, purpose, documentLoader, expansionMap}) {
    // build proof (currently known as `signature options` in spec)
    let proof;
    if(this.proof) {
      // shallow copy
      proof = {...this.proof};
    } else {
      // create proof JSON-LD document
      proof = {};
    }

    // ensure proof type is set
    proof.type = this.type;

    // set default `now` date if not given in `proof` or `options`
    let date = this.date;
    if(proof.created === undefined && date === undefined) {
      date = new Date();
    }

    // ensure date is in string format
    if(date && typeof date !== 'string') {
      date = util.w3cDate(date);
    }

    // add API overrides
    if(date) {
      proof.created = date;
    }

    proof.verificationMethod = this.verificationMethod;

    // add any extensions to proof (mostly for legacy support)
    proof = await this.updateProof({
      document, proof, purpose, documentLoader, expansionMap
    });

    // allow purpose to update the proof; the `proof` is in the
    // SECURITY_CONTEXT_URL `@context` -- therefore the `purpose` must
    // ensure any added fields are also represented in that same `@context`
    proof = await purpose.update(
      proof, {document, suite: this, documentLoader, expansionMap});

    // create data to sign
    const verifyData = await this.createVerifyData({
      document, proof, documentLoader, expansionMap
    });

    // sign data
    proof = await this.sign(
      {verifyData, document, proof, documentLoader, expansionMap});

    return proof;
  }

  /**
   * @param document {object} to be signed.
   * @param purpose {ProofPurpose}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<object>} Resolves with the created proof object.
   */
  async updateProof({proof}) {
    // extending classes may do more
    return proof;
  }

  /**
   * @param proof {object} the proof to be verified.
   * @param document {object} the document the proof applies to.
   * @param purpose {ProofPurpose}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<{object}>} Resolves with the verification result.
   */
  async verifyProof({
    proof, document, purpose, documentLoader, expansionMap,
  }) {
    try {
      // create data to verify
      const verifyData = await this.createVerifyData(
        {document, proof, documentLoader, expansionMap});

      // fetch verification method
      const verificationMethod = await this.getVerificationMethod(
        {proof, document, documentLoader, expansionMap});

      // verify signature on data
      const verified = await this.verifySignature({
        verifyData, verificationMethod, document, proof,
        documentLoader, expansionMap});
      if(!verified) {
        throw new Error('Invalid signature.');
      }

      // ensure proof was performed for a valid purpose
      const purposeResult = await purpose.validate(
        proof, {document, suite: this, verificationMethod,
          documentLoader, expansionMap});
      if(!purposeResult.valid) {
        throw purposeResult.error;
      }

      return {verified: true, purposeResult};
    } catch(error) {
      return {verified: false, error};
    }
  }

  async canonize(input, {documentLoader, expansionMap, skipExpansion}) {
    return jsonld.canonize(input, {
      algorithm: 'URDNA2015',
      format: 'application/n-quads',
      documentLoader,
      expansionMap,
      skipExpansion,
      useNative: this.useNativeCanonize
    });
  }

  async canonizeProof(proof, {document, documentLoader, expansionMap}) {
    // `jws`,`signatureValue`,`proofValue` must not be included in the proof
    // options
    proof = {
      '@context': document['@context'] || constants.SECURITY_CONTEXT_URL,
      ...proof
    };
    delete proof.jws;
    delete proof.signatureValue;
    delete proof.proofValue;
    return this.canonize(proof, {
      documentLoader,
      expansionMap,
      skipExpansion: false
    });
  }

  /**
   * @param document {object} to be signed/verified.
   * @param proof {object}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<{Uint8Array}>}.
   */
  async createVerifyData({
    document, proof, documentLoader, expansionMap}) {
    // concatenate hash of c14n proof options and hash of c14n document
    const c14nProofOptions = await this.canonizeProof(
      proof, {document, documentLoader, expansionMap});
    const c14nDocument = await this.canonize(document, {
      documentLoader,
      expansionMap
    });
    return util.concat(
      await sha256digest({string: c14nProofOptions}),
      await sha256digest({string: c14nDocument}));
  }

  /**
   * @param document {object} to be signed.
   * @param proof {object}
   * @param documentLoader {function}
   */
  async getVerificationMethod({proof, documentLoader}) {
    let {verificationMethod} = proof;

    if(typeof verificationMethod === 'object') {
      verificationMethod = verificationMethod.id;
    }

    if(!verificationMethod) {
      throw new Error('No "verificationMethod" found in proof.');
    }

    // Note: `expansionMap` is intentionally not passed; we can safely drop
    // properties here and must allow for it
    const framed = await jsonld.frame(verificationMethod, {
      '@context': constants.SECURITY_CONTEXT_URL,
      '@embed': '@always',
      id: verificationMethod
    }, {documentLoader, compactToRelative: false});
    if(!framed) {
      throw new Error(`Verification method ${verificationMethod} not found.`);
    }

    // ensure verification method has not been revoked
    if(framed.revoked !== undefined) {
      throw new Error('The verification method has been revoked.');
    }

    return framed;
  }

  /**
   * @param verifyData {Uint8Array}.
   * @param document {object} to be signed.
   * @param proof {object}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<{object}>} the proof containing the signature value.
   */
  async sign() {
    throw new Error('Must be implemented by a derived class.');
  }

  /**
   * @param verifyData {Uint8Array}.
   * @param verificationMethod {object}.
   * @param document {object} to be signed.
   * @param proof {object}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<boolean>}
   */
  async verifySignature() {
    throw new Error('Must be implemented by a derived class.');
  }
};
<commit_msg>Add additional validation for verificationMethod, signer and verifier.<commit_after>/*!
 * Copyright (c) 2017-2018 Digital Bazaar, Inc. All rights reserved.
 */
'use strict';

const constants = require('../constants');
const jsonld = require('jsonld');
const util = require('../util');
const {sha256digest} = require('../sha256digest');
const LinkedDataProof = require('./LinkedDataProof');

module.exports = class LinkedDataSignature extends LinkedDataProof {
  /**
   * @param {object} options - Options hashmap.
   * @param {string} options.type - Suite name, provided by subclass.
   * @typedef LDKeyPair
   * @param {LDKeyPair} LDKeyClass - The crypto-ld key class that this suite
   *   will use to sign/verify signatures. Provided by subclass. Used
   *   during the `verifySignature` operation, to create an instance (containing
   *   a `verifier()` property) of a public key fetched via a `documentLoader`.
   *
   * Either a `key` OR at least one of `signer`/`verifier` is required:
   *
   * @param {object} [options.key] - An optional key object (containing an
   *   `id` property, and either `signer` or `verifier`, depending on the
   *   intended operation. Useful for when the application is managing keys
   *   itself (when using a KMS, you never have access to the private key,
   *   and so should use the `signer` param instead).
   * @param {Function} [options.signer] - Signer function that returns an
   *   object with an async sign() method. This is useful when interfacing
   *   with a KMS (since you don't get access to the private key and its
   *   `signer()`, the KMS client gives you only the signer function to use).
   * @param {Function} [options.verifier] - Verifier function that returns
   *   an object with an async `verify()` method. Useful when working with a
   *   KMS-provided verifier function.
   *
   * Advanced optional parameters and overrides:
   *
   * @param {string} [options.verificationMethod]  A key id URL of the paired
   *   public key. If not provided, this is set from key.id, signer.id or
   *   verifier.id.
   * @param {object} [options.proof] - A JSON-LD document with options to use
   *   for the `proof` node (e.g. any other custom fields can be provided here
   *   using a context different from security-v2). If not provided, this is
   *   constructed during signing.
   * @param {string|Date} [options.date] - Signing date to use if not passed.
   * @param {boolean} [options.useNativeCanonize] - Whether to use a native
   *   canonize algorithm.
   */
  constructor({
    type, verificationMethod, proof, LDKeyClass, date, key, signer, verifier,
    useNativeCanonize
  } = {}) {
    super({type});
    this.LDKeyClass = LDKeyClass;
    this.proof = proof;
    const vm = this._validateVerificationMethod({
      verificationMethod, key, signer, verifier
    });
    this.verificationMethod = vm.verificationMethod;
    this.key = vm.key;
    this.signer = vm.signer;
    this.verifier = vm.verifier;
    if(date) {
      this.date = new Date(date);
      if(isNaN(this.date)) {
        throw TypeError(`"date" "${date}" is not a valid date.`);
      }
    }
    this.useNativeCanonize = useNativeCanonize;
  }

  /**
   * See constructor docstring for param details.
   *
   * @returns {{verificationMethod: string, key: LDKeyPair, signer: Function,
   *   verifier: Function}} - Validated and initialized key-related parameters.
   */
  _validateVerificationMethod({verificationMethod, key, signer, verifier}) {
    if(!(key || signer || verifier)) {
      // eslint-disable-next-line max-len
      throw new TypeError('Either a "key" or at least one of "signer"/"verifier" parameters is required');
    }
    if((key && signer) || (key && verifier)) {
      // eslint-disable-next-line max-len
      throw new TypeError('Either a "key" or at least one of "signer"/"verifier" parameters is required, but not both.');
    }

    const vm = {};
    if(key) {
      vm.key = key;
      vm.verificationMethod = verificationMethod || key.id;
      if(typeof key.signer === 'function') {
        vm.signer = key.signer;
      }
      if(typeof key.verifier === 'function') {
        vm.verifier = key.verifier;
      }
      if(!(vm.signer || vm.verifier)) {
        // eslint-disable-next-line max-len
        throw new TypeError('The "key" parameter must contain a "signer" or "verifier" method.');
      }
    } else {
      vm.verificationMethod = verificationMethod ||
        signer && signer.id ||
        verifier && verifier.id;
      vm.signer = signer;
      vm.verifier = verifier;
    }

    if(!(vm.verificationMethod && typeof verificationMethod !== 'string')) {
      // This means that verificationMethod was not passed in directly,
      // AND that neither key.id or signer.id/verifier.id exists.
      throw new TypeError('"verificationMethod" must be a URL string.');
    }

    return vm;
  }

  /**
   * @param document {object} to be signed.
   * @param purpose {ProofPurpose}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<object>} Resolves with the created proof object.
   */
  async createProof(
    {document, purpose, documentLoader, expansionMap}) {
    // build proof (currently known as `signature options` in spec)
    let proof;
    if(this.proof) {
      // shallow copy
      proof = {...this.proof};
    } else {
      // create proof JSON-LD document
      proof = {};
    }

    // ensure proof type is set
    proof.type = this.type;

    // set default `now` date if not given in `proof` or `options`
    let date = this.date;
    if(proof.created === undefined && date === undefined) {
      date = new Date();
    }

    // ensure date is in string format
    if(date && typeof date !== 'string') {
      date = util.w3cDate(date);
    }

    // add API overrides
    if(date) {
      proof.created = date;
    }

    proof.verificationMethod = this.verificationMethod;

    // add any extensions to proof (mostly for legacy support)
    proof = await this.updateProof({
      document, proof, purpose, documentLoader, expansionMap
    });

    // allow purpose to update the proof; the `proof` is in the
    // SECURITY_CONTEXT_URL `@context` -- therefore the `purpose` must
    // ensure any added fields are also represented in that same `@context`
    proof = await purpose.update(
      proof, {document, suite: this, documentLoader, expansionMap});

    // create data to sign
    const verifyData = await this.createVerifyData({
      document, proof, documentLoader, expansionMap
    });

    // sign data
    proof = await this.sign(
      {verifyData, document, proof, documentLoader, expansionMap});

    return proof;
  }

  /**
   * @param document {object} to be signed.
   * @param purpose {ProofPurpose}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<object>} Resolves with the created proof object.
   */
  async updateProof({proof}) {
    // extending classes may do more
    return proof;
  }

  /**
   * @param proof {object} the proof to be verified.
   * @param document {object} the document the proof applies to.
   * @param purpose {ProofPurpose}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<{object}>} Resolves with the verification result.
   */
  async verifyProof({
    proof, document, purpose, documentLoader, expansionMap,
  }) {
    try {
      // create data to verify
      const verifyData = await this.createVerifyData(
        {document, proof, documentLoader, expansionMap});

      // fetch verification method
      const verificationMethod = await this.getVerificationMethod(
        {proof, document, documentLoader, expansionMap});

      // verify signature on data
      const verified = await this.verifySignature({
        verifyData, verificationMethod, document, proof,
        documentLoader, expansionMap});
      if(!verified) {
        throw new Error('Invalid signature.');
      }

      // ensure proof was performed for a valid purpose
      const purposeResult = await purpose.validate(
        proof, {document, suite: this, verificationMethod,
          documentLoader, expansionMap});
      if(!purposeResult.valid) {
        throw purposeResult.error;
      }

      return {verified: true, purposeResult};
    } catch(error) {
      return {verified: false, error};
    }
  }

  async canonize(input, {documentLoader, expansionMap, skipExpansion}) {
    return jsonld.canonize(input, {
      algorithm: 'URDNA2015',
      format: 'application/n-quads',
      documentLoader,
      expansionMap,
      skipExpansion,
      useNative: this.useNativeCanonize
    });
  }

  async canonizeProof(proof, {document, documentLoader, expansionMap}) {
    // `jws`,`signatureValue`,`proofValue` must not be included in the proof
    // options
    proof = {
      '@context': document['@context'] || constants.SECURITY_CONTEXT_URL,
      ...proof
    };
    delete proof.jws;
    delete proof.signatureValue;
    delete proof.proofValue;
    return this.canonize(proof, {
      documentLoader,
      expansionMap,
      skipExpansion: false
    });
  }

  /**
   * @param document {object} to be signed/verified.
   * @param proof {object}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<{Uint8Array}>}.
   */
  async createVerifyData({
    document, proof, documentLoader, expansionMap}) {
    // concatenate hash of c14n proof options and hash of c14n document
    const c14nProofOptions = await this.canonizeProof(
      proof, {document, documentLoader, expansionMap});
    const c14nDocument = await this.canonize(document, {
      documentLoader,
      expansionMap
    });
    return util.concat(
      await sha256digest({string: c14nProofOptions}),
      await sha256digest({string: c14nDocument}));
  }

  /**
   * @param document {object} to be signed.
   * @param proof {object}
   * @param documentLoader {function}
   */
  async getVerificationMethod({proof, documentLoader}) {
    let {verificationMethod} = proof;

    if(typeof verificationMethod === 'object') {
      verificationMethod = verificationMethod.id;
    }

    if(!verificationMethod) {
      throw new Error('No "verificationMethod" found in proof.');
    }

    // Note: `expansionMap` is intentionally not passed; we can safely drop
    // properties here and must allow for it
    const framed = await jsonld.frame(verificationMethod, {
      '@context': constants.SECURITY_CONTEXT_URL,
      '@embed': '@always',
      id: verificationMethod
    }, {documentLoader, compactToRelative: false});
    if(!framed) {
      throw new Error(`Verification method ${verificationMethod} not found.`);
    }

    // ensure verification method has not been revoked
    if(framed.revoked !== undefined) {
      throw new Error('The verification method has been revoked.');
    }

    return framed;
  }

  /**
   * @param verifyData {Uint8Array}.
   * @param document {object} to be signed.
   * @param proof {object}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<{object}>} the proof containing the signature value.
   */
  async sign() {
    throw new Error('Must be implemented by a derived class.');
  }

  /**
   * @param verifyData {Uint8Array}.
   * @param verificationMethod {object}.
   * @param document {object} to be signed.
   * @param proof {object}
   * @param documentLoader {function}
   * @param expansionMap {function}
   *
   * @returns {Promise<boolean>}
   */
  async verifySignature() {
    throw new Error('Must be implemented by a derived class.');
  }
};
<|endoftext|>


<commit_before>var PickerView = Backbone.View.extend({

    template: WFP.Templates.Picker,

    initialize: function() {

        // Options
        this.hideAfter = 2500;  // How long to wait (in milliseconds) before the picker is hidden.
        this.visibleLimit = 15; // How much (in px) of the element is visible horizontally when hidden to the side.

        // Constructing an element from the template
        var element = elementFromHTML(this.template());
        this.setElement(element);

        // Caching selectors
        this.$list = this.$('#font-picker-list');
        this.$add  = this.$('.add-style');

        // Attaching events
        this.listenTo(Styles, 'add', this.add);
        this.listenTo(Styles, 'remove', this._onModelRemove);
        this.attachEvents();
        this.populate();
    },

    attachEvents: function() {

        var picker = this;

        this.$el.on({
            mouseenter: function() {
                picker.mouseOver = true;
                picker.$el.off('blur', picker.hide, true);
                picker.show();
            },
            mouseleave: function() {
                picker.mouseOver = false;
                if (!document.activeElement || !jQuery.contains(picker.el, document.activeElement)) {
                    picker.hide();
                }
            },
            focusin: function() {
                picker.show();
            },
            focusout: function() {
                if (!picker.mouseOver) picker.hide();
            }
        });

        this.$add.on('click', Styles.addNew);
    },

    populate: function() {
        var picker = this;
        Styles.forEach(function(model) {
            picker.add(model);
        });
    },

    // Creates a new view with the model passed and appends it to the list.
    add: function(model) {
        var view = new StyleView({ model: model });
        this.$list.append(view.el);

        _.defer(function() {
            view.$selector.focus();
        });
    },

    // Slides the picker out horizontally.
    // `px` (Number) is the distance (in pixels) from the edge of the element to the edge of the window.
    slideOut: function(px) {
        var x = (!isNaN(px)) ? this.el.offsetWidth - px : 0;
        this.$el.css('transform', 'translate3d(' + x + 'px, 0, 0)');
    },

    // Hides the picker after the specified waiting time.
    hide: function() {
        var picker = this;
        if (!this.hideTimeout) {
            this.hideTimeout = setTimeout(function() {
                picker.slideOut(picker.visibleLimit);
            }, this.hideAfter);
        }
    },

    // Shows the picker instantly.
    show: function() {
        clearTimeout(this.hideTimeout);
        this.hideTimeout = null;
        this.slideOut();
    }

});
<commit_msg>Added some options<commit_after>var PickerView = Backbone.View.extend({

    template: WFP.Templates.Picker,

    initialize: function() {

        // Options
        this.hideable = true;   // Whether the picker is hideable.
        this.hideAfter = 1500;  // How long to wait (in milliseconds) before the picker is hidden.
        this.stickOut = 15;     // How much (in px) of the element is visible when hidden to the side.
        this.mouseOver = false; // Whether the cursor is over the picker.

        // Constructing an element from the template
        var element = elementFromHTML(this.template());
        this.setElement(element);

        // Caching selectors
        this.$list = this.$('#font-picker-list');
        this.$add  = this.$('.add-style');

        // Attaching events
        this.listenTo(Styles, 'add', this.add);
        this.listenTo(Styles, 'remove', this._onModelRemove);
        this.attachEvents();
        this.populate();
    },

    attachEvents: function() {

        var picker = this;

        this.$el.on({
            mouseenter: function() {
                picker.mouseOver = true;
                picker.show();
            },
            mouseleave: function() {
                picker.mouseOver = false;
                if (!document.activeElement || !jQuery.contains(picker.el, document.activeElement)) {
                    picker.hide();
                }
            },
            focusin: function() {
                picker.show();
            },
            focusout: function() {
                if (!picker.mouseOver) picker.hide();
            }
        });

        this.$add.on('click', Styles.addNew);
    },

    populate: function() {
        var picker = this;
        Styles.forEach(function(model) {
            picker.add(model);
        });
    },

    // Creates a new view with the model passed and appends it to the list.
    add: function(model) {
        var view = new StyleView({ model: model });
        this.$list.append(view.el);

        _.defer(function() {
            view.$selector.focus();
        });
    },

    // Slides the picker out horizontally.
    // `px` (Number) is the distance (in pixels) from the left edge of the element to the edge of the window.
    slideOut: function(px) {
        var x = (!isNaN(px)) ? this.el.offsetWidth - px : 0;
        this.$el.css('transform', 'translate3d(' + x + 'px, 0, 0)');
    },

    // Hides the picker after the specified waiting time.
    hide: function() {
        var picker = this;
        if (this.hideable && !this.hideTimeout) {
            this.hideTimeout = setTimeout(function() {
                picker.slideOut(picker.stickOut);
            }, this.hideAfter);
        }
    },

    // Shows the picker instantly.
    show: function() {
        clearTimeout(this.hideTimeout);
        this.hideTimeout = null;
        this.slideOut();
    }

});
<|endoftext|>