<commit_before>/**
* Created by Mauriel on 5/19/2019.
*/
let subjKeywordsApp = new Vue({
    el: '#app-keyword',
    delimiters: ['${', '}'],
    components: {
        VueBootstrapTypeahead
    },
    data: {
        newKeyword: '',
        resMode: RESOURCE_MODE,
        resKeywords: RES_KEYWORDS, // global constant defined in parent template of subject template
        showIsDuplicate: false,
        error: '',
    },
    mounted() {
        // Until Django / VueJS cleaned up across RLP wait for VueJS state to finalize before trying to display dynamic elements
        document.getElementById('subj-inline-error').style.display = "block";
        document.getElementById('lst-tags').style.display = "block";
    },
    methods: {
        addKeyword: function (resIdShort) {
            this.showIsDuplicate = false;  // Reset

            // Remove any empty keywords from the list
            let newKeywords = this.newKeyword.split(",");
            newKeywords = newKeywords.filter(function(a) {
               return a.trim() !== "";
            });

            // Update to cleaned up string
            this.newKeyword = newKeywords.join(",").trim();

            if (this.newKeyword.trim() === "") {
                return; // Empty string detected
            }else if (this.newKeyword.length > 500) {
                this.error = "Your keyword is too long. Ensure it has at most 500 characters.";
                return;
            }

            let newVal =  (this.resKeywords.join(",").length ? this.resKeywords.join(",") + ",": "") + this.newKeyword;
            this.error = "";
            let vue = this;
            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/", {value: newVal}, function (resp) {
                if (resp.status === "success") {
                    // Append new keywords to our data array
                    let newKeywordsArray = this.newKeyword.trim().split(",");

                    for (let i = 0; i < newKeywordsArray.length; i++) {
                        if ($.inArray(newKeywordsArray[i].trim(), this.resKeywords) >= 0) {
                            this.showIsDuplicate = true;
                        }
                        else {
                            this.resKeywords.push(newKeywordsArray[i].trim());
                            this.$refs.newKeyword.inputValue = "";  // open source bug https://github.com/alexurquhart/vue-bootstrap-typeahead/issues/19
                            this.$data.newKeyword = ""
                        }
                    }
                }
                else {
                    vue.error = resp.message.slice(0, -1);
                }
                showCompletedMessage(resp);
            }.bind(this), "json");
        },
        removeKeyword: function (resIdShort, keywordName) {
            let newVal = this.resKeywords.slice(); // Get a copy
            newVal.splice($.inArray(keywordName, this.resKeywords), 1);   // Remove the keyword

            let vue = this;
            vue.error = "";

            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/",
                {value: newVal.join(",")}, function (resp) {
                    if (resp.status === "success") {
                        vue.resKeywords = newVal;
                        if (!newVal.length) {
                            // If no keywords, the metadata is no longer sufficient to make the resource public
                            manageAccessApp.onMetadataInsufficient();
                        }
                    }
                    else {
                        if (vue.resKeywords.length){
                            // vue.error = resp.message;
                            // Response message is not very user-friendly so:
                            vue.error = "There was a problem removing your keyword.";
                        }
                    }
                }.bind(this), "json");
        },
        safeJS: function (input) {
            input.replace("\\", "\\\\")
            return encodeURIComponent(input)
        }
    }
});
<commit_msg>100 char limit #3053<commit_after>/**
* Created by Mauriel on 5/19/2019.
*/
let subjKeywordsApp = new Vue({
    el: '#app-keyword',
    delimiters: ['${', '}'],
    components: {
        VueBootstrapTypeahead
    },
    data: {
        newKeyword: '',
        resMode: RESOURCE_MODE,
        resKeywords: RES_KEYWORDS, // global constant defined in parent template of subject template
        showIsDuplicate: false,
        error: '',
    },
    mounted() {
        // Until Django / VueJS cleaned up across RLP wait for VueJS state to finalize before trying to display dynamic elements
        document.getElementById('subj-inline-error').style.display = "block";
        document.getElementById('lst-tags').style.display = "block";
    },
    methods: {
        addKeyword: function (resIdShort) {
            this.showIsDuplicate = false;  // Reset

            // Remove any empty keywords from the list
            let newKeywords = this.newKeyword.split(",");
            newKeywords = newKeywords.filter(function(a) {
               return a.trim() !== "";
            });

            // Update to cleaned up string
            this.newKeyword = newKeywords.join(",").trim();

            if (this.newKeyword.trim() === "") {
                return; // Empty string detected
            }else if (this.newKeyword.length > 100) {
                this.error = "Your keyword is too long. Ensure it has at most 100 characters.";
                return;
            }

            let newVal =  (this.resKeywords.join(",").length ? this.resKeywords.join(",") + ",": "") + this.newKeyword;
            this.error = "";
            let vue = this;
            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/", {value: newVal}, function (resp) {
                if (resp.status === "success") {
                    // Append new keywords to our data array
                    let newKeywordsArray = this.newKeyword.trim().split(",");

                    for (let i = 0; i < newKeywordsArray.length; i++) {
                        if ($.inArray(newKeywordsArray[i].trim(), this.resKeywords) >= 0) {
                            this.showIsDuplicate = true;
                        }
                        else {
                            this.resKeywords.push(newKeywordsArray[i].trim());
                            this.$refs.newKeyword.inputValue = "";  // open source bug https://github.com/alexurquhart/vue-bootstrap-typeahead/issues/19
                            this.$data.newKeyword = ""
                        }
                    }
                }
                else {
                    vue.error = resp.message.slice(0, -1);
                }
                showCompletedMessage(resp);
            }.bind(this), "json");
        },
        removeKeyword: function (resIdShort, keywordName) {
            let newVal = this.resKeywords.slice(); // Get a copy
            newVal.splice($.inArray(keywordName, this.resKeywords), 1);   // Remove the keyword

            let vue = this;
            vue.error = "";

            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/",
                {value: newVal.join(",")}, function (resp) {
                    if (resp.status === "success") {
                        vue.resKeywords = newVal;
                        if (!newVal.length) {
                            // If no keywords, the metadata is no longer sufficient to make the resource public
                            manageAccessApp.onMetadataInsufficient();
                        }
                    }
                    else {
                        if (vue.resKeywords.length){
                            // vue.error = resp.message;
                            // Response message is not very user-friendly so:
                            vue.error = "There was a problem removing your keyword.";
                        }
                    }
                }.bind(this), "json");
        },
        safeJS: function (input) {
            input.replace("\\", "\\\\")
            return encodeURIComponent(input)
        }
    }
});
<|endoftext|>


<commit_before>const math = require('./math.js');
const GraphBufferGeometry = require('./GraphBufferGeometry.js');

const plotTexture = new THREE.TextureLoader().load('../../grid_64.png');
plotTexture.wrapS = plotTexture.wrapT = THREE.RepeatWrapping;

/* global AFRAME */

if (typeof AFRAME === 'undefined') {
  throw new Error('"Plot" component attempted to register before AFRAME was available.');
}

/**
 * Plot component for A-Frame.
 */
AFRAME.registerComponent('plot', {

    schema: {
        'function': {'type': 'string', 'default': '0'},
        'order': {'type': 'number', 'default': 32},
        'label_text': {'type': 'string', 'default': ''},
        'show_formula': {'type': 'boolean', 'default': false},
        'show_axes': {'type': 'boolean', 'default': true},
        'bounds': {'type': 'string', 'default': '-1 1 -1 1 -1 1'},
        'show_zero_planes': {'type': 'boolean', 'default': false},
        'show_bounding_box': {'type': 'boolean', 'default': false},
        'show_grid': {'type': 'boolean', 'default': true}, // TODO
        'grix_x_scale': {'type': 'number', 'default': 0.1}, // TODO
        'grid_z_scale': {'type': 'number', 'default': 0.1}, // TODO
        'color': {'type': 'string', 'default': '#AAA'},
        'animate': {'type': 'boolean', 'default': false}
    },

    /**
    * Set if component needs multiple instancing.
    */
    multiple: false,

    /**
    * Called once when component is attached. Generally for initial setup.
    */
    init: function() {
        var code = math.compile(this.data.function);
        var scope = {t: 0.0};
        this.scope = scope;
        this.F = function(i, j) {
            scope.x = i;
            scope.y = j;
            return code.eval(scope);
        };

        console.log(this.data);

        var root = new THREE.Object3D();
        this.root = root;

        // TODO: make this more robust with format checking
        // [-x, +x, -y, +y, -z, +z]
        this.bounds = this.data.bounds.split(' ').map(function(x) {
            return parseFloat(x);
        });

        // TODO: make custom axes that extend to the bounds
        if (this.data.axes_enabled === true) {
            var axes = makeAxes();
            root.add(axes);
        }

        if (this.data.show_zero_planes === true) {
            var zeroPlanes = makeZeroPlanes(this.bounds);
            root.add(zeroPlanes);
        }

        if (this.data.show_bounding_box === true) {
            var boundingBox = makeBoundingBox(this.bounds);
            root.add(boundingBox);
        }

        this.graphObject = null;
        this.createPlot();
        this.el.setObject3D('mesh', root);
    },

    createPlot: function() {
        if (this.graphObject !== null) {
            this.root.remove(this.graphObject);
        }

        this.graphObject = createGraphObject(this.F, this.data.order, this.bounds,
                this.data.color, this.data.grid_x_scale, this.data.grid_y_scale,
                this.data.show_grid);
        this.root.add(this.graphObject);
    },

    /**
    * Called when component is attached and when component data changes.
    * Generally modifies the entity based on the data.
    */
    //update: function (oldData) { },

    /**
    * Called when a component is removed (e.g., via removeAttribute).
    * Generally undoes all modifications to the entity.
    */
    //remove: function () { },

    /**
    * Called on each scene tick.
    */
    tick: function (t) {
        if (this.data.animate) {
            this.scope.t = (t % 1000) / 1000;
            this.createPlot();
        }
    },

    /**
    * Called when entity pauses.
    * Use to stop or remove any dynamic or background behavior such as events.
    */
    //pause: function () { },

    /**
    * Called when entity resumes.
    * Use to continue or add any dynamic or background behavior such as events.
    */
    //play: function () { }
});

function makeAxes(bounds) {
    var axes = new THREE.AxisHelper();
    return axes;
}

function makeZeroPlanes(bounds) {
    var zeroPlaneMaterial = new THREE.MeshLambertMaterial();
    zeroPlaneMaterial.side = THREE.DoubleSide;
    zeroPlaneMaterial.transparent = true;
    zeroPlaneMaterial.opacity = 1 / 8;
    zeroPlaneMaterial.color = new THREE.Color(0x2244BB);

    var zeroPlanes = new THREE.Object3D();

    var xRange = bounds[1] - bounds[0];
    var yRange = bounds[3] - bounds[2];
    var zRange = bounds[5] - bounds[4];

    var zeroZGeometry = new THREE.PlaneGeometry(xRange, yRange);
    var zeroZ = new THREE.Mesh(zeroZGeometry, zeroPlaneMaterial);
    zeroZ.position.set(bounds[0] + xRange / 2, bounds[2] + yRange / 2, 0.0);
    zeroPlanes.add(zeroZ);

    var zeroYGeometry = new THREE.PlaneGeometry(xRange, zRange);
    var zeroY = new THREE.Mesh(zeroYGeometry, zeroPlaneMaterial);
    zeroY.position.set(bounds[0] + xRange / 2, 0.0, bounds[4] + zRange / 2);
    zeroY.rotation.set(Math.PI / 2, 0.0, 0.0);
    zeroPlanes.add(zeroY);

    var zeroXGeometry = new THREE.PlaneGeometry(zRange, yRange);
    var zeroX = new THREE.Mesh(zeroXGeometry, zeroPlaneMaterial);
    zeroX.position.set(0.0, bounds[2] + yRange / 2, bounds[4] + zRange / 2);
    zeroX.rotation.set(0.0, Math.PI / 2, 0.0);
    zeroPlanes.add(zeroX);

    return zeroPlanes;
}

function makeBoundingBox(bounds) {
    var xRange = bounds[1] - bounds[0];
    var yRange = bounds[3] - bounds[2];
    var zRange = bounds[5] - bounds[4];

    var xGeometry = new THREE.PlaneGeometry(zRange, yRange);
    var yGeometry = new THREE.PlaneGeometry(xRange, zRange);
    var zGeometry = new THREE.PlaneGeometry(xRange, yRange);

    var boundingMaterial = new THREE.MeshLambertMaterial();
    boundingMaterial.side = THREE.DoubleSide;
    boundingMaterial.color = new THREE.Color(0xDDDDDD);
    boundingMaterial.transparent = true;
    boundingMaterial.opacity = 1 / 8;

    var lowX = new THREE.Mesh(xGeometry, boundingMaterial);
    lowX.position.set(bounds[0], bounds[2] + yRange / 2, bounds[4] + zRange / 2);
    lowX.rotation.set(0.0, Math.PI / 2, 0.0);
    var highX = new THREE.Mesh(xGeometry, boundingMaterial);
    highX.position.set(bounds[1], bounds[2] + yRange / 2, bounds[4] + zRange / 2);
    highX.rotation.set(0.0, Math.PI / 2, 0.0);

    var lowY = new THREE.Mesh(yGeometry, boundingMaterial);
    lowY.position.set(bounds[0] + xRange / 2, bounds[2], bounds[4] + zRange / 2);
    lowY.rotation.set(Math.PI / 2, 0.0, 0.0);
    var highY = new THREE.Mesh(yGeometry, boundingMaterial);
    highY.position.set(bounds[0] + xRange / 2, bounds[3], bounds[4] + zRange / 2);
    highY.rotation.set(Math.PI / 2, 0.0, 0.0);

    var lowZ = new THREE.Mesh(zGeometry, boundingMaterial);
    lowZ.position.set(bounds[0] + xRange / 2, bounds[2] + yRange / 2, bounds[4]);
    var highZ = new THREE.Mesh(zGeometry, boundingMaterial);
    highZ.position.set(bounds[0] + xRange / 2, bounds[2] + yRange / 2, bounds[5]);

    var boundingBox = new THREE.Object3D();
    boundingBox.add(lowX, highX, lowY, highY, lowZ, highZ);

    return boundingBox;
}

function createGraphObject(valueFunction, order, bounds, color, gridXScale, gridZScale, showGrid) {

    var values = [];

    const iRange = bounds[1] - bounds[0];
    const jRange = bounds[5] - bounds[4];

    for (var i = 0; i < order; ++i) {
        var iCoordinate = bounds[0] + i * iRange / (order - 1);
        var valueRow = [];
        for (var j = 0; j < order; ++j) {
            var jCoordinate = bounds[4] + j * jRange / (order - 1);
            var value = valueFunction(iCoordinate, jCoordinate);
            valueRow.push(value);
        }
        values.push(valueRow);
    }

    var geometry = new GraphBufferGeometry(order, bounds, values, gridXScale, gridZScale);

    const materialProperties = {color: new THREE.Color(color)};
    //if (showGrid) {
    //    materialProperties.map = plotTexture;
    //}
    var material = new THREE.MeshLambertMaterial(materialProperties);

    material.side = THREE.DoubleSide;
    var result = new THREE.Mesh(geometry, material);
    return result;

}
<commit_msg>Create graph in 'update' rather than 'init'.<commit_after>const math = require('./math.js');
const GraphBufferGeometry = require('./GraphBufferGeometry.js');

/* global AFRAME */

if (typeof AFRAME === 'undefined') {
  throw new Error('"Plot" component attempted to register before AFRAME was available.');
}

/**
 * Plot component for A-Frame.
 */
AFRAME.registerComponent('plot', {

    schema: {
        'function': {'type': 'string', 'default': '0'},
        'order': {'type': 'number', 'default': 32},
        'label_text': {'type': 'string', 'default': ''},
        'show_formula': {'type': 'boolean', 'default': false},
        'show_axes': {'type': 'boolean', 'default': true},
        'bounds': {'type': 'string', 'default': '-1 1 -1 1 -1 1'},
        'show_zero_planes': {'type': 'boolean', 'default': false},
        'show_bounding_box': {'type': 'boolean', 'default': false},
        'show_grid': {'type': 'boolean', 'default': true}, // TODO
        'grix_x_scale': {'type': 'number', 'default': 0.1}, // TODO
        'grid_z_scale': {'type': 'number', 'default': 0.1}, // TODO
        'color': {'type': 'string', 'default': '#AAA'},
        'animate': {'type': 'boolean', 'default': false}
    },

    /**
    * Set if component needs multiple instancing.
    */
    multiple: false,

    /**
    * Called once when component is attached. Generally for initial setup.
    */
    init: function() {

    },

    createPlot: function() {
        if (this.graphObject !== null) {
            this.root.remove(this.graphObject);
        }

        this.graphObject = createGraphObject(this.F, this.data.order, this.bounds,
                this.data.color, this.data.grid_x_scale, this.data.grid_y_scale,
                this.data.show_grid);
        this.root.add(this.graphObject);
    },

    /**
    * Called when component is attached and when component data changes.
    * Generally modifies the entity based on the data.
    */
    update: function (oldData) {
        var code = math.compile(this.data.function);
        var scope = {t: 0.0};
        this.scope = scope;
        this.F = function(i, j) {
            scope.x = i;
            scope.y = j;
            return code.eval(scope);
        };

        console.log(this.data);

        var root = new THREE.Object3D();
        this.root = root;

        // TODO: make this more robust with format checking
        // [-x, +x, -y, +y, -z, +z]
        this.bounds = this.data.bounds.split(' ').map(function(x) {
            return parseFloat(x);
        });

        // TODO: make custom axes that extend to the bounds
        if (this.data.axes_enabled === true) {
            var axes = makeAxes();
            root.add(axes);
        }

        if (this.data.show_zero_planes === true) {
            var zeroPlanes = makeZeroPlanes(this.bounds);
            root.add(zeroPlanes);
        }

        if (this.data.show_bounding_box === true) {
            var boundingBox = makeBoundingBox(this.bounds);
            root.add(boundingBox);
        }

        this.graphObject = null;
        this.createPlot();
        this.el.setObject3D('mesh', root);

        console.log(root);
    },

    /**
    * Called when a component is removed (e.g., via removeAttribute).
    * Generally undoes all modifications to the entity.
    */
    //remove: function () { },

    /**
    * Called on each scene tick.
    */
    tick: function (t) {
        if (this.data.animate) {
            this.scope.t = (t % 1000) / 1000;
            this.createPlot();
        }
    },

    /**
    * Called when entity pauses.
    * Use to stop or remove any dynamic or background behavior such as events.
    */
    //pause: function () { },

    /**
    * Called when entity resumes.
    * Use to continue or add any dynamic or background behavior such as events.
    */
    //play: function () { }
});

function makeAxes(bounds) {
    var axes = new THREE.AxisHelper();
    return axes;
}

function makeZeroPlanes(bounds) {
    var zeroPlaneMaterial = new THREE.MeshLambertMaterial();
    zeroPlaneMaterial.side = THREE.DoubleSide;
    zeroPlaneMaterial.transparent = true;
    zeroPlaneMaterial.opacity = 1 / 8;
    zeroPlaneMaterial.color = new THREE.Color(0x2244BB);

    var zeroPlanes = new THREE.Object3D();

    var xRange = bounds[1] - bounds[0];
    var yRange = bounds[3] - bounds[2];
    var zRange = bounds[5] - bounds[4];

    var zeroZGeometry = new THREE.PlaneGeometry(xRange, yRange);
    var zeroZ = new THREE.Mesh(zeroZGeometry, zeroPlaneMaterial);
    zeroZ.position.set(bounds[0] + xRange / 2, bounds[2] + yRange / 2, 0.0);
    zeroPlanes.add(zeroZ);

    var zeroYGeometry = new THREE.PlaneGeometry(xRange, zRange);
    var zeroY = new THREE.Mesh(zeroYGeometry, zeroPlaneMaterial);
    zeroY.position.set(bounds[0] + xRange / 2, 0.0, bounds[4] + zRange / 2);
    zeroY.rotation.set(Math.PI / 2, 0.0, 0.0);
    zeroPlanes.add(zeroY);

    var zeroXGeometry = new THREE.PlaneGeometry(zRange, yRange);
    var zeroX = new THREE.Mesh(zeroXGeometry, zeroPlaneMaterial);
    zeroX.position.set(0.0, bounds[2] + yRange / 2, bounds[4] + zRange / 2);
    zeroX.rotation.set(0.0, Math.PI / 2, 0.0);
    zeroPlanes.add(zeroX);

    return zeroPlanes;
}

function makeBoundingBox(bounds) {
    var xRange = bounds[1] - bounds[0];
    var yRange = bounds[3] - bounds[2];
    var zRange = bounds[5] - bounds[4];

    var xGeometry = new THREE.PlaneGeometry(zRange, yRange);
    var yGeometry = new THREE.PlaneGeometry(xRange, zRange);
    var zGeometry = new THREE.PlaneGeometry(xRange, yRange);

    var boundingMaterial = new THREE.MeshLambertMaterial();
    boundingMaterial.side = THREE.DoubleSide;
    boundingMaterial.color = new THREE.Color(0xDDDDDD);
    boundingMaterial.transparent = true;
    boundingMaterial.opacity = 1 / 8;

    var lowX = new THREE.Mesh(xGeometry, boundingMaterial);
    lowX.position.set(bounds[0], bounds[2] + yRange / 2, bounds[4] + zRange / 2);
    lowX.rotation.set(0.0, Math.PI / 2, 0.0);
    var highX = new THREE.Mesh(xGeometry, boundingMaterial);
    highX.position.set(bounds[1], bounds[2] + yRange / 2, bounds[4] + zRange / 2);
    highX.rotation.set(0.0, Math.PI / 2, 0.0);

    var lowY = new THREE.Mesh(yGeometry, boundingMaterial);
    lowY.position.set(bounds[0] + xRange / 2, bounds[2], bounds[4] + zRange / 2);
    lowY.rotation.set(Math.PI / 2, 0.0, 0.0);
    var highY = new THREE.Mesh(yGeometry, boundingMaterial);
    highY.position.set(bounds[0] + xRange / 2, bounds[3], bounds[4] + zRange / 2);
    highY.rotation.set(Math.PI / 2, 0.0, 0.0);

    var lowZ = new THREE.Mesh(zGeometry, boundingMaterial);
    lowZ.position.set(bounds[0] + xRange / 2, bounds[2] + yRange / 2, bounds[4]);
    var highZ = new THREE.Mesh(zGeometry, boundingMaterial);
    highZ.position.set(bounds[0] + xRange / 2, bounds[2] + yRange / 2, bounds[5]);

    var boundingBox = new THREE.Object3D();
    boundingBox.add(lowX, highX, lowY, highY, lowZ, highZ);

    return boundingBox;
}

function createGraphObject(valueFunction, order, bounds, color, gridXScale, gridZScale, showGrid) {

    var values = [];

    const iRange = bounds[1] - bounds[0];
    const jRange = bounds[5] - bounds[4];

    for (var i = 0; i < order; ++i) {
        var iCoordinate = bounds[0] + i * iRange / (order - 1);
        var valueRow = [];
        for (var j = 0; j < order; ++j) {
            var jCoordinate = bounds[4] + j * jRange / (order - 1);
            var value = valueFunction(iCoordinate, jCoordinate);
            valueRow.push(value);
        }
        values.push(valueRow);
    }

    var geometry = new GraphBufferGeometry(order, bounds, values, gridXScale, gridZScale);

    const materialProperties = {color: new THREE.Color(color)};
    //if (showGrid) {
    //    materialProperties.map = plotTexture;
    //}
    var material = new THREE.MeshPhongMaterial(materialProperties);
    material.side = THREE.DoubleSide;
    var result = new THREE.Mesh(geometry, material);
    return result;

}
<|endoftext|>


<commit_before>import warning from 'warning'
import { pipe, isStr } from './utils'
import { parseHref, env } from './utils-path'
import { createPopstate, push, replace, go } from './history'
import { makeVisit, recalibrate } from './visit'

function dispatcher(actions, msg) {
  let resolved = actions.some(fn => fn(msg))
  warning(resolved, 'Could not resolve location: %s', msg.href)
  return resolved
}

function getDispatcher(matchers) {
  let actions = matchers.map(matcher => pipe(matcher.match, matcher.resolve))
  return recordVisit.bind(null, dispatcher.bind(null, actions))
}

export function recordVisit(dispatch, msg) {
  let { ultra, state } = msg
  let { visited, newState } = makeVisit(ultra, state)
  ultra.visited = visited
  if (newState) {
    msg = Object.assign({}, msg, { state: newState })
    return replace(dispatch, msg)
  }
  return dispatch(msg)
}

function guardDispatch(ultra, dispatch, loc) {
  let [len, pausedHref, confirm] = ultra.pauseRecord, { href } = loc
  let msg = Object.assign({}, loc, { ultra })
  let ok = () => {
    ultra.resume()
    return dispatch(msg)
  }
  let cancel = pipe(recalibrate, go).bind(null, msg)
  if (confirm && len === env.history.length) {
    if (href !== pausedHref) return confirm(ok, cancel, msg)
  } else return ok()
}

function navigate(ultra, dispatch, navAction, loc) {
  loc = isStr(loc) ? parseHref(loc) : loc
  return guardDispatch(ultra, navAction.bind(null, dispatch), loc)
}

function run(matchers, popstate) {
  let _pauseRecord = [], dispatch = getDispatcher(matchers)
  let ultra = {
    get pauseRecord() {
      return _pauseRecord
    },
    resume() {
      return (_pauseRecord = [])
    },
    pause(cb) {
      return (_pauseRecord = [env.history.length, env.href, cb])
    },
    stop: popstate.add(loc => guardDispatch(ultra, dispatch, loc)),
    nav: (action, loc) => navigate(ultra, dispatch, action, loc),
    push: loc => ultra.nav(push, loc),
    replace: loc => ultra.nav(replace, loc),
    visited: null,
    popstate,
    matchers
  }
  return ultra
}

function initialize(matchers, ultraOptions = {}) {
  let { stop, matchers: currentMatchers, popstate, visited } = ultraOptions
  if (currentMatchers) matchers = currentMatchers.concat(matchers)
  if (!popstate) popstate = createPopstate()
  if (stop) stop.call(ultraOptions)
  let ultra = run(matchers, popstate)
  if (!visited) ultra.nav((cb, msg) => cb(msg), env.href)
  return ultra
}

export function container(...matchers) {
  return initialize.bind(null, matchers)
}
<commit_msg>simplify container, make matchers, popstate getters on ultra<commit_after>import warning from 'warning'
import { pipe, isStr } from './utils'
import { parseHref, env } from './utils-path'
import { createPopstate, push, replace, go } from './history'
import { makeVisit, recalibrate } from './visit'

function dispatcher(actions, msg) {
  let resolved = actions.some(fn => fn(msg))
  warning(resolved, 'Could not resolve location: %s', msg.href)
  return resolved
}

function getDispatcher(matchers) {
  let actions = matchers.map(matcher => pipe(matcher.match, matcher.resolve))
  return recordVisit.bind(null, dispatcher.bind(null, actions))
}

export function recordVisit(dispatch, msg) {
  let { ultra, state } = msg
  let { visited, newState } = makeVisit(ultra, state)
  ultra.visited = visited
  if (newState) {
    msg = Object.assign({}, msg, { state: newState })
    return replace(dispatch, msg)
  }
  return dispatch(msg)
}

function guardDispatch(ultra, dispatch, loc) {
  let [len, pausedHref, confirm] = ultra.pauseRecord, { href } = loc
  let msg = Object.assign({}, loc, { ultra })
  let ok = () => {
    ultra.resume()
    return dispatch(msg)
  }
  let cancel = pipe(recalibrate, go).bind(null, msg)
  if (confirm && len === env.history.length) {
    if (href !== pausedHref) return confirm(ok, cancel, msg)
  } else return ok()
}

function navigate(ultra, dispatch, navAction, loc) {
  loc = isStr(loc) ? parseHref(loc) : loc
  return guardDispatch(ultra, navAction.bind(null, dispatch), loc)
}

function run(_matchers, _popstate) {
  let _pauseRecord = [], dispatch = getDispatcher(_matchers)
  let ultra = {
    visited: null,
    get popstate() {
      return _popstate
    },
    get matchers() {
      return _matchers
    },
    get pauseRecord() {
      return _pauseRecord
    },
    resume() {
      return (_pauseRecord = [])
    },
    pause(cb) {
      return (_pauseRecord = [env.history.length, env.href, cb])
    },
    stop: _popstate.add(loc => guardDispatch(ultra, dispatch, loc)),
    nav: (action, loc) => navigate(ultra, dispatch, action, loc),
    push: loc => ultra.nav(push, loc),
    replace: loc => ultra.nav(replace, loc)
  }
  return ultra
}

export function container(matchers, instance = {}) {
  let { stop, popstate, visited } = instance
  if (!popstate) popstate = createPopstate()
  let ultra = run(matchers, popstate)
  if (stop) stop.call(instance)
  if (!visited) ultra.nav((cb, msg) => cb(msg), env.href)
  return ultra
}
<|endoftext|>


<commit_before>/**
* Created by Mauriel on 5/19/2019.
*/
let subjKeywordsApp = new Vue({
    el: '#app-keyword',
    delimiters: ['${', '}'],
    components: {
        VueBootstrapTypeahead
    },
    data: {
        newKeyword: '',
        resMode: RESOURCE_MODE,
        resKeywords: RES_KEYWORDS, // global constant defined in parent template of subject template
        showIsDuplicate: false,
        error: '',
    },
    mounted() {
        // Until Django / VueJS cleaned up across RLP wait for VueJS state to finalize before trying to display dynamic elements
        document.getElementById('subj-inline-error').style.display = "block";
        document.getElementById('lst-tags').style.display = "block";
    },
    methods: {
        addKeyword: function (resIdShort) {
            this.showIsDuplicate = false;  // Reset

            // Remove any empty keywords from the list
            let newKeywords = this.newKeyword.split(",");
            newKeywords = newKeywords.filter(function(a) {
               return a.trim() !== "";
            });

            // Update to cleaned up string
            this.newKeyword = newKeywords.join(",").trim();

            if (this.newKeyword.trim() === "") {
                this.error = "Your keyword was empty. Please try again";
                return; // Empty string detected
            }

            let newVal =  (this.resKeywords.join(",").length ? this.resKeywords.join(",") + ",": "") + this.newKeyword;
            this.error = "";
            let vue = this;
            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/", {value: newVal}, function (resp) {
                if (resp.status === "success") {
                    // Append new keywords to our data array
                    let newKeywordsArray = this.newKeyword.trim().split(",");

                    for (let i = 0; i < newKeywordsArray.length; i++) {
                        if ($.inArray(newKeywordsArray[i].trim(), this.resKeywords) >= 0) {
                            this.showIsDuplicate = true;
                        }
                        else {
                            this.resKeywords.push(newKeywordsArray[i].trim());
                            this.$refs.newKeyword.inputValue = "";  // open source bug https://github.com/alexurquhart/vue-bootstrap-typeahead/issues/19
                            this.$data.newKeyword = ""
                        }
                    }
                }
                else {
                    vue.error = resp.message.slice(0, -1);
                }
                showCompletedMessage(resp);
            }.bind(this), "json");
        },
        removeKeyword: function (resIdShort, keywordName) {
            let newVal = this.resKeywords.slice(); // Get a copy
            newVal.splice($.inArray(keywordName, this.resKeywords), 1);   // Remove the keyword

            this.error = "";
            let vue = this;

            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/",
                {value: newVal.join(",")}, function (resp) {
                    if (resp.status === "success") {
                        vue.resKeywords = newVal;
                        if (!newVal.length) {
                            // If no keywords, the metadata is no longer sufficient to make the resource public
                            manageAccessApp.onMetadataInsufficient();
                        }
                    }
                    else {
                        if (vue.resKeywords.length){
                            vue.error = resp.message;
                        }
                    }
                }.bind(this), "json");
        },
        safeJS: function (input) {
            input.replace("\\", "\\\\")
            return encodeURIComponent(input)
        }
    }
});
<commit_msg>keywords no error on empty #3053<commit_after>/**
* Created by Mauriel on 5/19/2019.
*/
let subjKeywordsApp = new Vue({
    el: '#app-keyword',
    delimiters: ['${', '}'],
    components: {
        VueBootstrapTypeahead
    },
    data: {
        newKeyword: '',
        resMode: RESOURCE_MODE,
        resKeywords: RES_KEYWORDS, // global constant defined in parent template of subject template
        showIsDuplicate: false,
        error: '',
    },
    mounted() {
        // Until Django / VueJS cleaned up across RLP wait for VueJS state to finalize before trying to display dynamic elements
        document.getElementById('subj-inline-error').style.display = "block";
        document.getElementById('lst-tags').style.display = "block";
    },
    methods: {
        addKeyword: function (resIdShort) {
            this.showIsDuplicate = false;  // Reset

            // Remove any empty keywords from the list
            let newKeywords = this.newKeyword.split(",");
            newKeywords = newKeywords.filter(function(a) {
               return a.trim() !== "";
            });

            // Update to cleaned up string
            this.newKeyword = newKeywords.join(",").trim();

            if (this.newKeyword.trim() === "") {
                return; // Empty string detected
            }

            let newVal =  (this.resKeywords.join(",").length ? this.resKeywords.join(",") + ",": "") + this.newKeyword;
            this.error = "";
            let vue = this;
            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/", {value: newVal}, function (resp) {
                if (resp.status === "success") {
                    // Append new keywords to our data array
                    let newKeywordsArray = this.newKeyword.trim().split(",");

                    for (let i = 0; i < newKeywordsArray.length; i++) {
                        if ($.inArray(newKeywordsArray[i].trim(), this.resKeywords) >= 0) {
                            this.showIsDuplicate = true;
                        }
                        else {
                            this.resKeywords.push(newKeywordsArray[i].trim());
                            this.$refs.newKeyword.inputValue = "";  // open source bug https://github.com/alexurquhart/vue-bootstrap-typeahead/issues/19
                            this.$data.newKeyword = ""
                        }
                    }
                }
                else {
                    vue.error = resp.message.slice(0, -1);
                }
                showCompletedMessage(resp);
            }.bind(this), "json");
        },
        removeKeyword: function (resIdShort, keywordName) {
            let newVal = this.resKeywords.slice(); // Get a copy
            newVal.splice($.inArray(keywordName, this.resKeywords), 1);   // Remove the keyword

            this.error = "";
            let vue = this;

            $.post("/hsapi/_internal/" + resIdShort + "/subject/add-metadata/",
                {value: newVal.join(",")}, function (resp) {
                    if (resp.status === "success") {
                        vue.resKeywords = newVal;
                        if (!newVal.length) {
                            // If no keywords, the metadata is no longer sufficient to make the resource public
                            manageAccessApp.onMetadataInsufficient();
                        }
                    }
                    else {
                        if (vue.resKeywords.length){
                            vue.error = resp.message;
                        }
                    }
                }.bind(this), "json");
        },
        safeJS: function (input) {
            input.replace("\\", "\\\\")
            return encodeURIComponent(input)
        }
    }
});
<|endoftext|>


<commit_before>/**
 * Created by tusharmathur on 5/15/15.
 */
"use strict";
var _ = require('lodash');
var request = require('request');
var fs = require('fs');
var event = require('common-js-pub-sub');
var MAX_BUFFER = 1000;
var utils = function (params, ev) {
    var u = {
        //DIRTY METHODS
        onError: function (err) {
            if (err instanceof Error) {
                throw err;
            } else {
                throw Error(err);
            }
        },

        setProperty: function (obj, key, val) {
            obj[key] = val;
        },

        extractAndSetProperty: function (obj, key, func, val) {
            u.setProperty(obj, key, func(val));
        },

        getContentLength: function (res) {
            return parseInt(res.headers['content-length'], 10);
        },

        addParamPosition: function (val) {
            return params.position + val;
        },

        stripFirstParamAsError: function (func) {
            return function (err, res) {
                if (err instanceof Error) {
                    u.onError(err);
                }
                func(res);
            };
        },

        getItemLength: function (item) {
            return item.length;
        },

        writeBufferAtPosition: function (buffer) {
            fs.write(params.fd, buffer, 0, u.getItemLength(buffer), params.position, u.DATA_SAVE);
        },

        makeRequest: function () {
            request(params.uri, params.headers)
                .on('data', u.DATA_RECEIVE)
                .on('response', u.DATA_START)
                .on('error', u.ERROR)
                .on('complete', u.DATA_COMPLETE)
        },
        updateAndSetPositionOnParams: function (buffer) {
            params.position += buffer.length;
        },
        createTriggerFor: function (eventName) {
            return _.partial(ev.publish, eventName);
        },
        saveDownloadedBytes: function () {
            var buf = new Buffer(MAX_BUFFER);
            buf.write(JSON.stringify(params));
            fs.write(params.fd, buf, 0, buf.length, params.totalFileSize, u.METADATA_SAVE)
        },
        truncate: function () {
            fs.truncate(params.fd, params.totalFileSize, u.FILE_TRUNCATE);
        },
        rename: function () {
            fs.rename(params.path, params.path.replace('.mtd', ''), u.FILE_RENAME);
        },
        checkForCompletion: function () {
            if (params.position === params.totalFileSize) {
                u.FILE_COMPLETE();
            }
        }

    };
    //THUNKS (PRETTY METHODS!)
    u.stripErrorParamAndCreateTrigger = _.flow(u.createTriggerFor, u.stripFirstParamAsError);

    //EVENTS
    u.FILE_OPEN = u.stripErrorParamAndCreateTrigger('FILE_OPEN');
    u.METADATA_SAVE = u.stripErrorParamAndCreateTrigger('METADATA_SAVE');
    u.FILE_TRUNCATE = u.stripErrorParamAndCreateTrigger('FILE_TRUNCATE');
    u.DATA_SAVE = u.stripErrorParamAndCreateTrigger('DATA_SAVE');
    u.FILE_RENAME = u.stripErrorParamAndCreateTrigger('FILE_RENAME');

    u.DATA_RECEIVE = u.createTriggerFor('DATA_RECEIVE');
    u.DATA_COMPLETE = u.createTriggerFor('DATA_COMPLETE');
    u.DATA_START = u.createTriggerFor('DATA_START');
    u.FILE_COMPLETE = _.once(u.createTriggerFor('FILE_COMPLETE'));
    u.ERROR = _.partial(ev.publish, 'ERROR');

    u.createFileDescriptor = _.partial(_.ary(fs.open, 3), params.path, 'w+', u.FILE_OPEN);
    u.setFileDescriptorOnParams = _.partial(u.setProperty, params, 'fd');
    u.extractAndSetContentLengthOnParams = _.partial(u.extractAndSetProperty, params, 'totalFileSize', u.getContentLength);
    u.setDownloadedBytesOnParams = _.partial(u.setProperty, params, 'downloadedBytes');

    return u;
};

var defaultOptions = {
    headers: {}
};
function download(options) {
    options = _.assign(options, defaultOptions);
    return {
        start: function (cb) {
            var params = {
                position: 0, path: options.path + '.mtd', uri: options.uri
            }, ev = event();
            var u = utils(params, ev);

            //Thunks
            //TODO: Public to test
            ev.subscribe('FILE_RENAME', cb);
            ev.subscribe('FILE_TRUNCATE', u.rename);
            ev.subscribe('FILE_COMPLETE', u.truncate);
            ev.subscribe('ERROR', u.onError);

            ev.subscribe('INIT', u.createFileDescriptor);

            ev.subscribe('FILE_OPEN', u.makeRequest);
            ev.subscribe('FILE_OPEN', u.setFileDescriptorOnParams);

            ev.subscribe('DATA_START', u.extractAndSetContentLengthOnParams);

            ev.subscribe('DATA_RECEIVE', u.writeBufferAtPosition);
            ev.subscribe('DATA_RECEIVE', u.updateAndSetPositionOnParams);

            ev.subscribe('DATA_SAVE', u.setDownloadedBytesOnParams);
            ev.subscribe('DATA_SAVE', u.saveDownloadedBytes);

            ev.subscribe('METADATA_SAVE', u.checkForCompletion);

            //START
            ev.publish('INIT', null);

        }
    }
}

exports.utils = utils;
exports.download = download;<commit_msg>update start api<commit_after>/**
 * Created by tusharmathur on 5/15/15.
 */
"use strict";
var _ = require('lodash');
var request = require('request');
var fs = require('fs');
var event = require('common-js-pub-sub');
var MAX_BUFFER = 1000;
var utils = function (params, ev) {
    var u = {
        //DIRTY METHODS
        onError: function (err) {
            if (err instanceof Error) {
                throw err;
            } else {
                throw Error(err);
            }
        },

        setProperty: function (obj, key, val) {
            obj[key] = val;
        },

        extractAndSetProperty: function (obj, key, func, val) {
            u.setProperty(obj, key, func(val));
        },

        getContentLength: function (res) {
            return parseInt(res.headers['content-length'], 10);
        },

        addParamPosition: function (val) {
            return params.position + val;
        },

        stripFirstParamAsError: function (func) {
            return function (err, res) {
                if (err instanceof Error) {
                    u.onError(err);
                }
                func(res);
            };
        },

        getItemLength: function (item) {
            return item.length;
        },

        writeBufferAtPosition: function (buffer) {
            fs.write(params.fd, buffer, 0, u.getItemLength(buffer), params.position, u.DATA_SAVE);
        },

        makeRequest: function () {
            request(params.uri, params.headers)
                .on('data', u.DATA_RECEIVE)
                .on('response', u.DATA_START)
                .on('error', u.ERROR)
                .on('complete', u.DATA_COMPLETE)
        },
        updateAndSetPositionOnParams: function (buffer) {
            params.position += buffer.length;
        },
        createTriggerFor: function (eventName) {
            return _.partial(ev.publish, eventName);
        },
        saveDownloadedBytes: function () {
            var buf = new Buffer(MAX_BUFFER);
            buf.write(JSON.stringify(params));
            fs.write(params.fd, buf, 0, buf.length, params.totalFileSize, u.METADATA_SAVE)
        },
        truncate: function () {
            fs.truncate(params.fd, params.totalFileSize, u.FILE_TRUNCATE);
        },
        rename: function () {
            fs.rename(params.path, params.path.replace('.mtd', ''), u.FILE_RENAME);
        },
        checkForCompletion: function () {
            if (params.position === params.totalFileSize) {
                u.FILE_COMPLETE();
            }
        }

    };
    //THUNKS (PRETTY METHODS!)
    u.stripErrorParamAndCreateTrigger = _.flow(u.createTriggerFor, u.stripFirstParamAsError);

    //EVENTS
    u.FILE_OPEN = u.stripErrorParamAndCreateTrigger('FILE_OPEN');
    u.METADATA_SAVE = u.stripErrorParamAndCreateTrigger('METADATA_SAVE');
    u.FILE_TRUNCATE = u.stripErrorParamAndCreateTrigger('FILE_TRUNCATE');
    u.DATA_SAVE = u.stripErrorParamAndCreateTrigger('DATA_SAVE');
    u.FILE_RENAME = u.stripErrorParamAndCreateTrigger('FILE_RENAME');

    u.DATA_RECEIVE = u.createTriggerFor('DATA_RECEIVE');
    u.DATA_COMPLETE = u.createTriggerFor('DATA_COMPLETE');
    u.DATA_START = u.createTriggerFor('DATA_START');
    u.FILE_COMPLETE = _.once(u.createTriggerFor('FILE_COMPLETE'));
    u.ERROR = _.partial(ev.publish, 'ERROR');

    u.createFileDescriptor = _.partial(_.ary(fs.open, 3), params.path, 'w+', u.FILE_OPEN);
    u.setFileDescriptorOnParams = _.partial(u.setProperty, params, 'fd');
    u.extractAndSetContentLengthOnParams = _.partial(u.extractAndSetProperty, params, 'totalFileSize', u.getContentLength);
    u.setDownloadedBytesOnParams = _.partial(u.setProperty, params, 'downloadedBytes');

    return u;
};

var defaultOptions = {
    headers: {}
};
function download(options) {
    options = _.assign(options, defaultOptions);
    return {
        start: function (uri, cb) {
            var params = {
                position: 0, path: options.path + '.mtd', uri: uri
            }, ev = event();
            var u = utils(params, ev);

            ev.subscribe('FILE_RENAME', cb);
            ev.subscribe('FILE_TRUNCATE', u.rename);
            ev.subscribe('FILE_COMPLETE', u.truncate);
            ev.subscribe('ERROR', u.onError);

            ev.subscribe('INIT', u.createFileDescriptor);

            ev.subscribe('FILE_OPEN', u.makeRequest);
            ev.subscribe('FILE_OPEN', u.setFileDescriptorOnParams);

            ev.subscribe('DATA_START', u.extractAndSetContentLengthOnParams);

            ev.subscribe('DATA_RECEIVE', u.writeBufferAtPosition);
            ev.subscribe('DATA_RECEIVE', u.updateAndSetPositionOnParams);

            ev.subscribe('DATA_SAVE', u.setDownloadedBytesOnParams);
            ev.subscribe('DATA_SAVE', u.saveDownloadedBytes);

            ev.subscribe('METADATA_SAVE', u.checkForCompletion);

            //START
            ev.publish('INIT', null);

        }
    }
}

exports.utils = utils;
exports.download = download;<|endoftext|>


<commit_before>import {metadata} from 'aurelia-metadata';
import {AggregateError} from 'aurelia-pal';
import {resolver, StrategyResolver, Resolver} from './resolvers';
import {Invoker} from './invokers';

function validateKey(key: any) {
  if (key === null || key === undefined) {
    throw new Error('key/value cannot be null or undefined. Are you trying to inject/register something that doesn\'t exist with DI?');
  }
}
export const _emptyParameters = Object.freeze([]);

metadata.registration = 'aurelia:registration';
metadata.invoker = 'aurelia:invoker';

let resolverDecorates = resolver.decorates;

/**
* Stores the information needed to invoke a function.
*/
export class InvocationHandler {
  /**
  * The function to be invoked by this handler.
  */
  fn: Function;

  /**
  * The invoker implementation that will be used to actually invoke the function.
  */
  invoker: Invoker;

  /**
  * The statically known dependencies of this function invocation.
  */
  dependencies: any[];

  /**
  * Instantiates an InvocationDescription.
  * @param fn The Function described by this description object.
  * @param invoker The strategy for invoking the function.
  * @param dependencies The static dependencies of the function call.
  */
  constructor(fn: Function, invoker: Invoker, dependencies: any[]) {
    this.fn = fn;
    this.invoker = invoker;
    this.dependencies = dependencies;
  }

  /**
  * Invokes the function.
  * @param container The calling container.
  * @param dynamicDependencies Additional dependencies to use during invocation.
  * @return The result of the function invocation.
  */
  invoke(container: Container, dynamicDependencies?: any[]): any {
    return dynamicDependencies !== undefined
      ? this.invoker.invokeWithDynamicDependencies(container, this.fn, this.dependencies, dynamicDependencies)
      : this.invoker.invoke(container, this.fn, this.dependencies);
  }
}

/**
* Used to configure a Container instance.
*/
export interface ContainerConfiguration {
  /**
  * An optional callback which will be called when any function needs an InvocationHandler created (called once per Function).
  */
  onHandlerCreated?: (handler: InvocationHandler) => InvocationHandler;

  handlers?: Map<any, any>;
}

function invokeWithDynamicDependencies(container, fn, staticDependencies, dynamicDependencies) {
  let i = staticDependencies.length;
  let args = new Array(i);

  while (i--) {
    args[i] = container.get(staticDependencies[i]);
  }

  if (dynamicDependencies !== undefined) {
    args = args.concat(dynamicDependencies);
  }

  return Reflect.construct(fn, args);
}

let classInvokers = {
  [0]: {
    invoke(container, Type) {
      return new Type();
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [1]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [2]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [3]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [4]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]), container.get(deps[3]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [5]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]), container.get(deps[3]), container.get(deps[4]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  fallback: {
    invoke: invokeWithDynamicDependencies,
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  }
};

function getDependencies(f) {
  if (!f.hasOwnProperty('inject')) {
    return [];
  }

  if (typeof f.inject === 'function') {
    return f.inject();
  }

  return f.inject;
}

/**
* A lightweight, extensible dependency injection container.
*/
export class Container {
  /**
  * The global root Container instance. Available if makeGlobal() has been called. Aurelia Framework calls makeGlobal().
  */
  static instance: Container;

  /**
  * The parent container in the DI hierarchy.
  */
  parent: Container;

  /**
  * The root container in the DI hierarchy.
  */
  root: Container;

  /** @internal */
  _configuration: ContainerConfiguration;

  /** @internal */
  _onHandlerCreated: (handler: InvocationHandler) => InvocationHandler;

  /** @internal */
  _handlers: Map<any, any>;

  /** @internal */
  _resolvers: Map<any, any>;

  /**
  * Creates an instance of Container.
  * @param configuration Provides some configuration for the new Container instance.
  */
  constructor(configuration?: ContainerConfiguration) {
    if (configuration === undefined) {
      configuration = {};
    }

    this._configuration = configuration;
    this._onHandlerCreated = configuration.onHandlerCreated;
    this._handlers = configuration.handlers || (configuration.handlers = new Map());
    this._resolvers = new Map();
    this.root = this;
    this.parent = null;
  }

  /**
  * Makes this container instance globally reachable through Container.instance.
  */
  makeGlobal(): Container {
    Container.instance = this;
    return this;
  }

  /**
  * Sets an invocation handler creation callback that will be called when new InvocationsHandlers are created (called once per Function).
  * @param onHandlerCreated The callback to be called when an InvocationsHandler is created.
  */
  setHandlerCreatedCallback(onHandlerCreated: (handler: InvocationHandler) => InvocationHandler) {
    this._onHandlerCreated = onHandlerCreated;
    this._configuration.onHandlerCreated = onHandlerCreated;
  }

  /**
  * Registers an existing object instance with the container.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param instance The instance that will be resolved when the key is matched. This defaults to the key value when instance is not supplied.
  * @return The resolver that was registered.
  */
  registerInstance(key: any, instance?: any): Resolver {
    return this.registerResolver(key, new StrategyResolver(0, instance === undefined ? key : instance));
  }

  /**
  * Registers a type (constructor function) such that the container always returns the same instance for each request.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param fn The constructor function to use when the dependency needs to be instantiated. This defaults to the key value when fn is not supplied.
  * @return The resolver that was registered.
  */
  registerSingleton(key: any, fn?: Function): Resolver {
    return this.registerResolver(key, new StrategyResolver(1, fn === undefined ? key : fn));
  }

  /**
  * Registers a type (constructor function) such that the container returns a new instance for each request.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param fn The constructor function to use when the dependency needs to be instantiated. This defaults to the key value when fn is not supplied.
  * @return The resolver that was registered.
  */
  registerTransient(key: any, fn?: Function): Resolver {
    return this.registerResolver(key, new StrategyResolver(2, fn === undefined ? key : fn));
  }

  /**
  * Registers a custom resolution function such that the container calls this function for each request to obtain the instance.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param handler The resolution function to use when the dependency is needed.
  * @return The resolver that was registered.
  */
  registerHandler(key: any, handler: (container?: Container, key?: any, resolver?: Resolver) => any): Resolver {
    return this.registerResolver(key, new StrategyResolver(3, handler));
  }

  /**
  * Registers an additional key that serves as an alias to the original DI key.
  * @param originalKey The key that originally identified the dependency; usually a constructor function.
  * @param aliasKey An alternate key which can also be used to resolve the same dependency  as the original.
  * @return The resolver that was registered.
  */
  registerAlias(originalKey: any, aliasKey: any): Resolver {
    return this.registerResolver(aliasKey, new StrategyResolver(5, originalKey));
  }

  /**
  * Registers a custom resolution function such that the container calls this function for each request to obtain the instance.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param resolver The resolver to use when the dependency is needed.
  * @return The resolver that was registered.
  */
  registerResolver(key: any, resolver: Resolver): Resolver {
    validateKey(key);

    let allResolvers = this._resolvers;
    let result = allResolvers.get(key);

    if (result === undefined) {
      allResolvers.set(key, resolver);
    } else if (result.strategy === 4) {
      result.state.push(resolver);
    } else {
      allResolvers.set(key, new StrategyResolver(4, [result, resolver]));
    }

    return resolver;
  }

  /**
  * Registers a type (constructor function) by inspecting its registration annotations. If none are found, then the default singleton registration is used.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param fn The constructor function to use when the dependency needs to be instantiated. This defaults to the key value when fn is not supplied.
  */
  autoRegister(key: any, fn?: Function): Resolver {
    fn = fn === undefined ? key : fn;

    if (typeof fn === 'function') {
      let registration = metadata.get(metadata.registration, fn);

      if (registration === undefined) {
        return this.registerResolver(key, new StrategyResolver(1, fn));
      }

      return registration.registerResolver(this, key, fn);
    }

    return this.registerResolver(key, new StrategyResolver(0, fn));
  }

  /**
  * Registers an array of types (constructor functions) by inspecting their registration annotations. If none are found, then the default singleton registration is used.
  * @param fns The constructor function to use when the dependency needs to be instantiated.
  */
  autoRegisterAll(fns: any[]): void {
    let i = fns.length;
    while (i--) {
      this.autoRegister(fns[i]);
    }
  }

  /**
  * Unregisters based on key.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  */
  unregister(key: any) : void {
    this._resolvers.delete(key);
  }

  /**
  * Inspects the container to determine if a particular key has been registred.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param checkParent Indicates whether or not to check the parent container hierarchy.
  * @return Returns true if the key has been registred; false otherwise.
  */
  hasResolver(key: any, checkParent: boolean = false): boolean {
    validateKey(key);

    return this._resolvers.has(key) || (checkParent && this.parent !== null && this.parent.hasResolver(key, checkParent));
  }

  /**
  * Resolves a single instance based on the provided key.
  * @param key The key that identifies the object to resolve.
  * @return Returns the resolved instance.
  */
  get(key: any): any {
    validateKey(key);

    if (key === Container) {
      return this;
    }

    if (resolverDecorates(key)) {
      return key.get(this, key);
    }

    let resolver = this._resolvers.get(key);

    if (resolver === undefined) {
      if (this.parent === null) {
        return this.autoRegister(key).get(this, key);
      }

      return this.parent._get(key);
    }

    return resolver.get(this, key);
  }

  _get(key) {
    let resolver = this._resolvers.get(key);

    if (resolver === undefined) {
      if (this.parent === null) {
        return this.autoRegister(key).get(this, key);
      }

      return this.parent._get(key);
    }

    return resolver.get(this, key);
  }

  /**
  * Resolves all instance registered under the provided key.
  * @param key The key that identifies the objects to resolve.
  * @return Returns an array of the resolved instances.
  */
  getAll(key: any): any[] {
    validateKey(key);

    let resolver = this._resolvers.get(key);

    if (resolver === undefined) {
      if (this.parent === null) {
        return _emptyParameters;
      }

      return this.parent.getAll(key);
    }

    if (resolver.strategy === 4) {
      let state = resolver.state;
      let i = state.length;
      let results = new Array(i);

      while (i--) {
        results[i] = state[i].get(this, key);
      }

      return results;
    }

    return [resolver.get(this, key)];
  }

  /**
  * Creates a new dependency injection container whose parent is the current container.
  * @return Returns a new container instance parented to this.
  */
  createChild(): Container {
    let child = new Container(this._configuration);
    child.root = this.root;
    child.parent = this;
    return child;
  }

  /**
  * Invokes a function, recursively resolving its dependencies.
  * @param fn The function to invoke with the auto-resolved dependencies.
  * @param dynamicDependencies Additional function dependencies to use during invocation.
  * @return Returns the instance resulting from calling the function.
  */
  invoke(fn: Function & { name?: string }, dynamicDependencies?: any[]) {
    try {
      let handler = this._handlers.get(fn);

      if (handler === undefined) {
        handler = this._createInvocationHandler(fn);
        this._handlers.set(fn, handler);
      }

      return handler.invoke(this, dynamicDependencies);
    } catch (e) {
      throw new AggregateError(`Error invoking ${fn.name}. Check the inner error for details.`, e, true);
    }
  }

  _createInvocationHandler(fn: Function & { inject?: any }): InvocationHandler {
    let dependencies;

    if (fn.inject === undefined) {
      dependencies = metadata.getOwn(metadata.paramTypes, fn) || _emptyParameters;
    } else {
      dependencies = [];
      let ctor = fn;
      while (typeof ctor === 'function') {
        dependencies.push(...getDependencies(ctor));
        ctor = Object.getPrototypeOf(ctor);
      }
    }

    let invoker = metadata.getOwn(metadata.invoker, fn)
      || classInvokers[dependencies.length] || classInvokers.fallback;

    let handler = new InvocationHandler(fn, invoker, dependencies);
    return this._onHandlerCreated !== undefined ? this._onHandlerCreated(handler) : handler;
  }
}
<commit_msg>fix(container): check for custom registration before bubbling<commit_after>import {metadata} from 'aurelia-metadata';
import {AggregateError} from 'aurelia-pal';
import {resolver, StrategyResolver, Resolver} from './resolvers';
import {Invoker} from './invokers';

function validateKey(key: any) {
  if (key === null || key === undefined) {
    throw new Error('key/value cannot be null or undefined. Are you trying to inject/register something that doesn\'t exist with DI?');
  }
}
export const _emptyParameters = Object.freeze([]);

metadata.registration = 'aurelia:registration';
metadata.invoker = 'aurelia:invoker';

let resolverDecorates = resolver.decorates;

/**
* Stores the information needed to invoke a function.
*/
export class InvocationHandler {
  /**
  * The function to be invoked by this handler.
  */
  fn: Function;

  /**
  * The invoker implementation that will be used to actually invoke the function.
  */
  invoker: Invoker;

  /**
  * The statically known dependencies of this function invocation.
  */
  dependencies: any[];

  /**
  * Instantiates an InvocationDescription.
  * @param fn The Function described by this description object.
  * @param invoker The strategy for invoking the function.
  * @param dependencies The static dependencies of the function call.
  */
  constructor(fn: Function, invoker: Invoker, dependencies: any[]) {
    this.fn = fn;
    this.invoker = invoker;
    this.dependencies = dependencies;
  }

  /**
  * Invokes the function.
  * @param container The calling container.
  * @param dynamicDependencies Additional dependencies to use during invocation.
  * @return The result of the function invocation.
  */
  invoke(container: Container, dynamicDependencies?: any[]): any {
    return dynamicDependencies !== undefined
      ? this.invoker.invokeWithDynamicDependencies(container, this.fn, this.dependencies, dynamicDependencies)
      : this.invoker.invoke(container, this.fn, this.dependencies);
  }
}

/**
* Used to configure a Container instance.
*/
export interface ContainerConfiguration {
  /**
  * An optional callback which will be called when any function needs an InvocationHandler created (called once per Function).
  */
  onHandlerCreated?: (handler: InvocationHandler) => InvocationHandler;

  handlers?: Map<any, any>;
}

function invokeWithDynamicDependencies(container, fn, staticDependencies, dynamicDependencies) {
  let i = staticDependencies.length;
  let args = new Array(i);

  while (i--) {
    args[i] = container.get(staticDependencies[i]);
  }

  if (dynamicDependencies !== undefined) {
    args = args.concat(dynamicDependencies);
  }

  return Reflect.construct(fn, args);
}

let classInvokers = {
  [0]: {
    invoke(container, Type) {
      return new Type();
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [1]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [2]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [3]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [4]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]), container.get(deps[3]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  [5]: {
    invoke(container, Type, deps) {
      return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]), container.get(deps[3]), container.get(deps[4]));
    },
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  },
  fallback: {
    invoke: invokeWithDynamicDependencies,
    invokeWithDynamicDependencies: invokeWithDynamicDependencies
  }
};

function getDependencies(f) {
  if (!f.hasOwnProperty('inject')) {
    return [];
  }

  if (typeof f.inject === 'function') {
    return f.inject();
  }

  return f.inject;
}

/**
* A lightweight, extensible dependency injection container.
*/
export class Container {
  /**
  * The global root Container instance. Available if makeGlobal() has been called. Aurelia Framework calls makeGlobal().
  */
  static instance: Container;

  /**
  * The parent container in the DI hierarchy.
  */
  parent: Container;

  /**
  * The root container in the DI hierarchy.
  */
  root: Container;

  /** @internal */
  _configuration: ContainerConfiguration;

  /** @internal */
  _onHandlerCreated: (handler: InvocationHandler) => InvocationHandler;

  /** @internal */
  _handlers: Map<any, any>;

  /** @internal */
  _resolvers: Map<any, any>;

  /**
  * Creates an instance of Container.
  * @param configuration Provides some configuration for the new Container instance.
  */
  constructor(configuration?: ContainerConfiguration) {
    if (configuration === undefined) {
      configuration = {};
    }

    this._configuration = configuration;
    this._onHandlerCreated = configuration.onHandlerCreated;
    this._handlers = configuration.handlers || (configuration.handlers = new Map());
    this._resolvers = new Map();
    this.root = this;
    this.parent = null;
  }

  /**
  * Makes this container instance globally reachable through Container.instance.
  */
  makeGlobal(): Container {
    Container.instance = this;
    return this;
  }

  /**
  * Sets an invocation handler creation callback that will be called when new InvocationsHandlers are created (called once per Function).
  * @param onHandlerCreated The callback to be called when an InvocationsHandler is created.
  */
  setHandlerCreatedCallback(onHandlerCreated: (handler: InvocationHandler) => InvocationHandler) {
    this._onHandlerCreated = onHandlerCreated;
    this._configuration.onHandlerCreated = onHandlerCreated;
  }

  /**
  * Registers an existing object instance with the container.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param instance The instance that will be resolved when the key is matched. This defaults to the key value when instance is not supplied.
  * @return The resolver that was registered.
  */
  registerInstance(key: any, instance?: any): Resolver {
    return this.registerResolver(key, new StrategyResolver(0, instance === undefined ? key : instance));
  }

  /**
  * Registers a type (constructor function) such that the container always returns the same instance for each request.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param fn The constructor function to use when the dependency needs to be instantiated. This defaults to the key value when fn is not supplied.
  * @return The resolver that was registered.
  */
  registerSingleton(key: any, fn?: Function): Resolver {
    return this.registerResolver(key, new StrategyResolver(1, fn === undefined ? key : fn));
  }

  /**
  * Registers a type (constructor function) such that the container returns a new instance for each request.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param fn The constructor function to use when the dependency needs to be instantiated. This defaults to the key value when fn is not supplied.
  * @return The resolver that was registered.
  */
  registerTransient(key: any, fn?: Function): Resolver {
    return this.registerResolver(key, new StrategyResolver(2, fn === undefined ? key : fn));
  }

  /**
  * Registers a custom resolution function such that the container calls this function for each request to obtain the instance.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param handler The resolution function to use when the dependency is needed.
  * @return The resolver that was registered.
  */
  registerHandler(key: any, handler: (container?: Container, key?: any, resolver?: Resolver) => any): Resolver {
    return this.registerResolver(key, new StrategyResolver(3, handler));
  }

  /**
  * Registers an additional key that serves as an alias to the original DI key.
  * @param originalKey The key that originally identified the dependency; usually a constructor function.
  * @param aliasKey An alternate key which can also be used to resolve the same dependency  as the original.
  * @return The resolver that was registered.
  */
  registerAlias(originalKey: any, aliasKey: any): Resolver {
    return this.registerResolver(aliasKey, new StrategyResolver(5, originalKey));
  }

  /**
  * Registers a custom resolution function such that the container calls this function for each request to obtain the instance.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param resolver The resolver to use when the dependency is needed.
  * @return The resolver that was registered.
  */
  registerResolver(key: any, resolver: Resolver): Resolver {
    validateKey(key);

    let allResolvers = this._resolvers;
    let result = allResolvers.get(key);

    if (result === undefined) {
      allResolvers.set(key, resolver);
    } else if (result.strategy === 4) {
      result.state.push(resolver);
    } else {
      allResolvers.set(key, new StrategyResolver(4, [result, resolver]));
    }

    return resolver;
  }

  /**
  * Registers a type (constructor function) by inspecting its registration annotations. If none are found, then the default singleton registration is used.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param fn The constructor function to use when the dependency needs to be instantiated. This defaults to the key value when fn is not supplied.
  */
  autoRegister(key: any, fn?: Function): Resolver {
    fn = fn === undefined ? key : fn;

    if (typeof fn === 'function') {
      let registration = metadata.get(metadata.registration, fn);

      if (registration === undefined) {
        return this.registerResolver(key, new StrategyResolver(1, fn));
      }

      return registration.registerResolver(this, key, fn);
    }

    return this.registerResolver(key, new StrategyResolver(0, fn));
  }

  /**
  * Registers an array of types (constructor functions) by inspecting their registration annotations. If none are found, then the default singleton registration is used.
  * @param fns The constructor function to use when the dependency needs to be instantiated.
  */
  autoRegisterAll(fns: any[]): void {
    let i = fns.length;
    while (i--) {
      this.autoRegister(fns[i]);
    }
  }

  /**
  * Unregisters based on key.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  */
  unregister(key: any) : void {
    this._resolvers.delete(key);
  }

  /**
  * Inspects the container to determine if a particular key has been registred.
  * @param key The key that identifies the dependency at resolution time; usually a constructor function.
  * @param checkParent Indicates whether or not to check the parent container hierarchy.
  * @return Returns true if the key has been registred; false otherwise.
  */
  hasResolver(key: any, checkParent: boolean = false): boolean {
    validateKey(key);

    return this._resolvers.has(key) || (checkParent && this.parent !== null && this.parent.hasResolver(key, checkParent));
  }

  /**
  * Resolves a single instance based on the provided key.
  * @param key The key that identifies the object to resolve.
  * @return Returns the resolved instance.
  */
  get(key: any): any {
    validateKey(key);

    if (key === Container) {
      return this;
    }

    if (resolverDecorates(key)) {
      return key.get(this, key);
    }

    let resolver = this._resolvers.get(key);

    if (resolver === undefined) {
      if (this.parent === null) {
        return this.autoRegister(key).get(this, key);
      }

      let registration = metadata.get(metadata.registration, key);

      if (registration === undefined) {
        return this.parent._get(key);
      }

      return registration.registerResolver(this, key, key).get(this, key);
    }

    return resolver.get(this, key);
  }

  _get(key) {
    let resolver = this._resolvers.get(key);

    if (resolver === undefined) {
      if (this.parent === null) {
        return this.autoRegister(key).get(this, key);
      }

      return this.parent._get(key);
    }

    return resolver.get(this, key);
  }

  /**
  * Resolves all instance registered under the provided key.
  * @param key The key that identifies the objects to resolve.
  * @return Returns an array of the resolved instances.
  */
  getAll(key: any): any[] {
    validateKey(key);

    let resolver = this._resolvers.get(key);

    if (resolver === undefined) {
      if (this.parent === null) {
        return _emptyParameters;
      }

      return this.parent.getAll(key);
    }

    if (resolver.strategy === 4) {
      let state = resolver.state;
      let i = state.length;
      let results = new Array(i);

      while (i--) {
        results[i] = state[i].get(this, key);
      }

      return results;
    }

    return [resolver.get(this, key)];
  }

  /**
  * Creates a new dependency injection container whose parent is the current container.
  * @return Returns a new container instance parented to this.
  */
  createChild(): Container {
    let child = new Container(this._configuration);
    child.root = this.root;
    child.parent = this;
    return child;
  }

  /**
  * Invokes a function, recursively resolving its dependencies.
  * @param fn The function to invoke with the auto-resolved dependencies.
  * @param dynamicDependencies Additional function dependencies to use during invocation.
  * @return Returns the instance resulting from calling the function.
  */
  invoke(fn: Function & { name?: string }, dynamicDependencies?: any[]) {
    try {
      let handler = this._handlers.get(fn);

      if (handler === undefined) {
        handler = this._createInvocationHandler(fn);
        this._handlers.set(fn, handler);
      }

      return handler.invoke(this, dynamicDependencies);
    } catch (e) {
      throw new AggregateError(`Error invoking ${fn.name}. Check the inner error for details.`, e, true);
    }
  }

  _createInvocationHandler(fn: Function & { inject?: any }): InvocationHandler {
    let dependencies;

    if (fn.inject === undefined) {
      dependencies = metadata.getOwn(metadata.paramTypes, fn) || _emptyParameters;
    } else {
      dependencies = [];
      let ctor = fn;
      while (typeof ctor === 'function') {
        dependencies.push(...getDependencies(ctor));
        ctor = Object.getPrototypeOf(ctor);
      }
    }

    let invoker = metadata.getOwn(metadata.invoker, fn)
      || classInvokers[dependencies.length] || classInvokers.fallback;

    let handler = new InvocationHandler(fn, invoker, dependencies);
    return this._onHandlerCreated !== undefined ? this._onHandlerCreated(handler) : handler;
  }
}
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var fs          = require('fs');
var merge       = require('merge');
var mergeTrees  = require('broccoli-merge-trees');
var flatiron    = require('broccoli-flatiron');
var Funnel      = require('broccoli-funnel');
var SVGOptmizer = require('./svg-optimizer');

module.exports = {
  name: 'ember-inline-svg',

  included: function(app) {
    if (app.app) {
      app = app.app;
    }
    this.app = app;
  },

  options: function() {
    return merge(true, {}, {
      paths:   ['public'],
      optimize: { /* svgo defaults */ }
    }, (this.app && this.app.options && this.app.options.svg) || {});
  },

  svgPaths: function() {
    if (this.isDevelopingAddon()) {
      return ['tests/dummy/public'];
    }
    return this.options().paths;
  },

  optimizeSVGs: function(tree) {
    var config = this.options().optimize;
    if (!config) {
      return tree;
    }

    return new SVGOptmizer([tree], {svgoConfig: config});
  },

  treeForApp: function(tree) {
    var svgs = mergeTrees(this.svgPaths().filter(function(path) {
      return fs.existsSync(path);
    }));

    svgs = new Funnel(svgs, {
      include: [new RegExp(/\.svg$/)]
    });

    svgs = this.optimizeSVGs(svgs);

    svgs = flatiron(svgs, {
      outputFile: 'svgs.js',
      trimExtensions: true
    });

    return mergeTrees([tree, svgs]);
  }
};
<commit_msg>Filter SVGs before merging and allow duplicates when merging SVG dirs<commit_after>/* jshint node: true */
'use strict';

var fs          = require('fs');
var merge       = require('merge');
var mergeTrees  = require('broccoli-merge-trees');
var flatiron    = require('broccoli-flatiron');
var Funnel      = require('broccoli-funnel');
var SVGOptmizer = require('./svg-optimizer');

module.exports = {
  name: 'ember-inline-svg',

  included: function(app) {
    if (app.app) {
      app = app.app;
    }
    this.app = app;
  },

  options: function() {
    return merge(true, {}, {
      paths:   ['public'],
      optimize: { /* svgo defaults */ }
    }, (this.app && this.app.options && this.app.options.svg) || {});
  },

  svgPaths: function() {
    if (this.isDevelopingAddon()) {
      return ['tests/dummy/public'];
    }
    return this.options().paths;
  },

  optimizeSVGs: function(tree) {
    var config = this.options().optimize;
    if (!config) {
      return tree;
    }

    return new SVGOptmizer([tree], {svgoConfig: config});
  },

  treeForApp: function(tree) {
    var existingPaths = this.svgPaths().filter(function(path) {
      return fs.existsSync(path);
    });

    var svgTrees = existingPaths.map(function(path) {
      return new Funnel(path, {
        include: [new RegExp(/\.svg$/)]
      });
    });

    var svgs = mergeTrees(svgTrees, {
      overwrite: true
    });

    var optimized = this.optimizeSVGs(svgs);

    var manifest = flatiron(optimized, {
      outputFile: 'svgs.js',
      trimExtensions: true
    });

    return mergeTrees([tree, manifest]);
  }
};
<|endoftext|>


<commit_before>"use strict";

var _ = require("underscore");
var util = require("substance-util");
var Composite = require("./composite");

var Container = function(document, view) {
  this.document = document;
  this.view = view;

  this.treeView = [];
  this.listView = [];

  this.__parents = {};
  this.__composites = {};

  this.rebuild();
};

Container.Prototype = function() {

  var _each = function(iterator, context) {
    var queue = [];
    var i;

    for (i = this.treeView.length - 1; i >= 0; i--) {
      queue.unshift({
        id: this.treeView[i],
        parent: null
      });
    }

    var item, node;
    while(queue.length > 0) {
      item = queue.shift();
      node = this.document.get(item.id);
      if (node instanceof Composite) {
        var children = node.getNodes();
        for (i = children.length - 1; i >= 0; i--) {
          queue.unshift({
            id: children[i],
            parent: node.id,
          });
        }
      }
      iterator.call(context, node, item.parent);
    }
  };

  this.rebuild = function() {

    // clear the list view
    this.treeView.splice(0, this.treeView.length);
    this.listView.splice(0, this.listView.length);

    this.treeView = _.clone(this.view.nodes);
    for (var i = 0; i < this.view.length; i++) {
      this.treeView.push(this.view[i]);
    }

    this.__parents = {};
    this.__composites = {};
    _each.call(this, function(node, parent) {
      if (node instanceof Composite) {
        this.__parents[node.id] = parent;
        this.__composites[parent] = parent;
      } else {
        this.listView.push(node.id);
        if (this.__parents[node.id]) {
          throw new Error("Nodes must be unique in one view.");
        }
        this.__parents[node.id] = parent;
        this.__composites[parent] = parent;
      }
    }, this);
  };

  this.getTopLevelNodes = function() {
    return _.map(this.treeView, function(id) {
      return this.document.get(id);
    }, this);
  };

  this.getNodes = function(idsOnly) {
    var nodeIds = this.listView;
    if (idsOnly) {
      return _.clone(nodeIds);
    }
    else {
      var result = [];
      for (var i = 0; i < nodeIds.length; i++) {
        result.push(this.document.get(nodeIds[i]));
      }
      return result;
    }
  };

  this.getPosition = function(nodeId) {
    var nodeIds = this.listView;
    return nodeIds.indexOf(nodeId);
  };

  this.getNodeFromPosition = function(pos) {
    var nodeIds = this.listView;
    var id = nodeIds[pos];
    if (id !== undefined) {
      return this.document.get(id);
    } else {
      return null;
    }
  };

  this.getParent = function(nodeId) {
    return this.__parents[nodeId];
  };

  this.update = function(op) {
    var path = op.path;
    var needRebuild = (path[0] === this.view.id ||  this.__composites[path[0]] !== undefined);
    if (needRebuild) this.rebuild();
  };

  this.getLength = function() {
    return this.listView.length;
  };

  // Returns true if there is another node after a given position.
  // --------
  //

  this.hasSuccessor = function(nodePos) {
    var l = this.getLength();
    return nodePos < l - 1;
  };

  // Returns true if given view and node pos has a predecessor
  // --------
  //

  this.hasPredecessor = function(nodePos) {
    return nodePos > 0;
  };

  // Get predecessor node for a given view and node id
  // --------
  //

  this.getPredecessor = function(id) {
    var pos = this.getPosition(id);
    if (pos <= 0) return null;
    return this.getNodeFromPosition(pos-1);
  };

  // Get successor node for a given view and node id
  // --------
  //

  this.getSuccessor = function(id) {
    var pos = this.getPosition(id);
    if (pos >= this.getLength() - 1) return null;
    return this.getNodeFromPosition(pos+1);
  };

  this.firstChild = function(node) {
    if (node instanceof Composite) {
      var first = this.document.get(node.getNodes()[0]);
      return this.firstChild(first);
    } else {
      return node;
    }
  };

  this.lastChild = function(node) {
    if (node instanceof Composite) {
      var last = this.document.get(_.last(node.getNodes()));
      return this.lastChild(last);
    } else {
      return node;
    }
  };

  // Provides a document position which addresses begin of a given node
  // --------
  //

  this.before = function(node) {
    var child = this.firstChild(node);
    var nodePos = this.getPosition(child.id);
    return [nodePos, 0];
  };

  // Provides a document position which addresses the end of a given node
  // --------
  //

  this.after = function(node) {
    var child = this.lastChild(node);
    var nodePos = this.getPosition(child.id);
    var charPos = child.getLength();
    return [nodePos, charPos];
  };

};

Container.prototype = _.extend(new Container.Prototype(), util.Events.Listener);

Object.defineProperties(Container.prototype, {
  "id": {
    get: function() { return this.view.id; }
  },
  "type": {
    get: function() { return this.view.type; }
  },
  "nodes": {
    get: function() { return this.view.nodes; },
    set: function(val) { this.view.nodes = val; }
  }
});

module.exports = Container;
<commit_msg>getRoot gets the top level parent of a given node id.<commit_after>"use strict";

var _ = require("underscore");
var util = require("substance-util");
var Composite = require("./composite");

var Container = function(document, view) {
  this.document = document;
  this.view = view;

  this.treeView = [];
  this.listView = [];

  this.__parents = {};
  this.__composites = {};

  this.rebuild();
};

Container.Prototype = function() {

  var _each = function(iterator, context) {
    var queue = [];
    var i;

    for (i = this.treeView.length - 1; i >= 0; i--) {
      queue.unshift({
        id: this.treeView[i],
        parent: null
      });
    }

    var item, node;
    while(queue.length > 0) {
      item = queue.shift();
      node = this.document.get(item.id);
      if (node instanceof Composite) {
        var children = node.getNodes();
        for (i = children.length - 1; i >= 0; i--) {
          queue.unshift({
            id: children[i],
            parent: node.id,
          });
        }
      }
      iterator.call(context, node, item.parent);
    }
  };

  this.rebuild = function() {

    // clear the list view
    this.treeView.splice(0, this.treeView.length);
    this.listView.splice(0, this.listView.length);

    this.treeView = _.clone(this.view.nodes);
    for (var i = 0; i < this.view.length; i++) {
      this.treeView.push(this.view[i]);
    }

    this.__parents = {};
    this.__composites = {};
    _each.call(this, function(node, parent) {
      if (node instanceof Composite) {
        this.__parents[node.id] = parent;
        this.__composites[parent] = parent;
      } else {
        this.listView.push(node.id);
        if (this.__parents[node.id]) {
          throw new Error("Nodes must be unique in one view.");
        }
        this.__parents[node.id] = parent;
        this.__composites[parent] = parent;
      }
    }, this);
  };

  this.getTopLevelNodes = function() {
    return _.map(this.treeView, function(id) {
      return this.document.get(id);
    }, this);
  };

  this.getNodes = function(idsOnly) {
    var nodeIds = this.listView;
    if (idsOnly) {
      return _.clone(nodeIds);
    }
    else {
      var result = [];
      for (var i = 0; i < nodeIds.length; i++) {
        result.push(this.document.get(nodeIds[i]));
      }
      return result;
    }
  };

  this.getPosition = function(nodeId) {
    var nodeIds = this.listView;
    return nodeIds.indexOf(nodeId);
  };

  this.getNodeFromPosition = function(pos) {
    var nodeIds = this.listView;
    var id = nodeIds[pos];
    if (id !== undefined) {
      return this.document.get(id);
    } else {
      return null;
    }
  };

  this.getParent = function(nodeId) {
    return this.__parents[nodeId];
  };

  // Get top level parent of given nodeId
  this.getRoot = function(nodeId) {
    var parent = nodeId;

    // Always use top level element for referenceing the node
    while (parent) {
      nodeId = parent;
      parent = this.getParent(nodeId);
    }
    return nodeId;
  };

  this.update = function(op) {
    var path = op.path;
    var needRebuild = (path[0] === this.view.id ||  this.__composites[path[0]] !== undefined);
    if (needRebuild) this.rebuild();
  };

  this.getLength = function() {
    return this.listView.length;
  };

  // Returns true if there is another node after a given position.
  // --------
  //

  this.hasSuccessor = function(nodePos) {
    var l = this.getLength();
    return nodePos < l - 1;
  };

  // Returns true if given view and node pos has a predecessor
  // --------
  //

  this.hasPredecessor = function(nodePos) {
    return nodePos > 0;
  };

  // Get predecessor node for a given view and node id
  // --------
  //

  this.getPredecessor = function(id) {
    var pos = this.getPosition(id);
    if (pos <= 0) return null;
    return this.getNodeFromPosition(pos-1);
  };

  // Get successor node for a given view and node id
  // --------
  //

  this.getSuccessor = function(id) {
    var pos = this.getPosition(id);
    if (pos >= this.getLength() - 1) return null;
    return this.getNodeFromPosition(pos+1);
  };

  this.firstChild = function(node) {
    if (node instanceof Composite) {
      var first = this.document.get(node.getNodes()[0]);
      return this.firstChild(first);
    } else {
      return node;
    }
  };

  this.lastChild = function(node) {
    if (node instanceof Composite) {
      var last = this.document.get(_.last(node.getNodes()));
      return this.lastChild(last);
    } else {
      return node;
    }
  };

  // Provides a document position which addresses begin of a given node
  // --------
  //

  this.before = function(node) {
    var child = this.firstChild(node);
    var nodePos = this.getPosition(child.id);
    return [nodePos, 0];
  };

  // Provides a document position which addresses the end of a given node
  // --------
  //

  this.after = function(node) {
    var child = this.lastChild(node);
    var nodePos = this.getPosition(child.id);
    var charPos = child.getLength();
    return [nodePos, charPos];
  };

};

Container.prototype = _.extend(new Container.Prototype(), util.Events.Listener);

Object.defineProperties(Container.prototype, {
  "id": {
    get: function() { return this.view.id; }
  },
  "type": {
    get: function() { return this.view.type; }
  },
  "nodes": {
    get: function() { return this.view.nodes; },
    set: function(val) { this.view.nodes = val; }
  }
});

module.exports = Container;
<|endoftext|>


<commit_before>'use strict';
const path = require('path');
const fs = require('fs');
const electron = require('electron');
const app = electron.app;
const appMenu = require('./menu');
const storage = require('./storage');
const tray = require('./tray');

require('electron-debug')();
require('electron-dl')();

let mainWindow;
let isQuitting = false;

const isAlreadyRunning = app.makeSingleInstance(() => {
	if (mainWindow) {
		if (mainWindow.isMinimized()) {
			mainWindow.restore();
		}

		mainWindow.show();
	}
});

if (isAlreadyRunning) {
	app.quit();
}

function createMainWindow() {
	const lastWindowState = storage.get('lastWindowState') || {width: 500, height: 600};
	const maxWindowInteger = 2147483647; // used to set max window width/height when toggling fullscreen
	const maxWidthValue = 850;

	const win = new electron.BrowserWindow({
		title: app.getName(),
		show: false,
		x: lastWindowState.x,
		y: lastWindowState.y,
		width: lastWindowState.width,
		height: lastWindowState.height,
		icon: process.platform === 'linux' && path.join(__dirname, 'static/Icon.png'),
		minWidth: 340,
		maxWidth: maxWidthValue,
		minHeight: 260,
		titleBarStyle: 'hidden-inset',
		autoHideMenuBar: true,
		backgroundColor: storage.get('darkMode') ? '#192633 ' : '#fff',
		webPreferences: {
			preload: path.join(__dirname, 'browser.js'),
			// Removed until preloads accepts more than a single file
			// Ref: https://github.com/electron/electron/issues/5400
			// nodeIntegration: false,
			webSecurity: false,
			plugins: true
		}
	});

	if (process.platform === 'darwin') {
		win.setSheetOffset(40);
	}

	win.loadURL('https://mobile.twitter.com/home');

	win.on('close', e => {
		if (!isQuitting) {
			e.preventDefault();

			if (process.platform === 'darwin') {
				app.hide();
			} else {
				win.hide();
			}
		}
	});

	win.on('page-title-updated', e => {
		e.preventDefault();
	});

	win.on('enter-full-screen', () => {
		win.setMaximumSize(maxWindowInteger, maxWindowInteger);
	});

	win.on('leave-full-screen', () => {
		win.setMaximumSize(maxWidthValue, maxWindowInteger);
	});

	return win;
}

app.on('ready', () => {
	electron.Menu.setApplicationMenu(appMenu);
	mainWindow = createMainWindow();
	tray.create(mainWindow);

	const page = mainWindow.webContents;

	page.on('dom-ready', () => {
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'browser.css'), 'utf8'));
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'dark-mode.css'), 'utf8'));
		mainWindow.show();
	});

	page.on('new-window', (e, url) => {
		e.preventDefault();
		electron.shell.openExternal(url);
	});
});

app.on('activate', () => {
	mainWindow.show();
});

app.on('before-quit', () => {
	isQuitting = true;

	if (!mainWindow.isFullScreen()) {
		storage.set('lastWindowState', mainWindow.getBounds());
	}
});
<commit_msg>set GTK+3 dark theme when in dark mode<commit_after>'use strict';
const path = require('path');
const fs = require('fs');
const electron = require('electron');
const app = electron.app;
const appMenu = require('./menu');
const storage = require('./storage');
const tray = require('./tray');

require('electron-debug')();
require('electron-dl')();

let mainWindow;
let isQuitting = false;

const isAlreadyRunning = app.makeSingleInstance(() => {
	if (mainWindow) {
		if (mainWindow.isMinimized()) {
			mainWindow.restore();
		}

		mainWindow.show();
	}
});

if (isAlreadyRunning) {
	app.quit();
}

function createMainWindow() {
	const lastWindowState = storage.get('lastWindowState') || {width: 500, height: 600};
	const isDarkMode = storage.get('darkMode');
	const maxWindowInteger = 2147483647; // used to set max window width/height when toggling fullscreen
	const maxWidthValue = 850;

	const win = new electron.BrowserWindow({
		title: app.getName(),
		show: false,
		x: lastWindowState.x,
		y: lastWindowState.y,
		width: lastWindowState.width,
		height: lastWindowState.height,
		icon: process.platform === 'linux' && path.join(__dirname, 'static/Icon.png'),
		minWidth: 340,
		maxWidth: maxWidthValue,
		minHeight: 260,
		titleBarStyle: 'hidden-inset',
		autoHideMenuBar: true,
		darkTheme: isDarkMode, // GTK+3
		backgroundColor: isDarkMode ? '#192633 ' : '#fff',
		webPreferences: {
			preload: path.join(__dirname, 'browser.js'),
			// Removed until preloads accepts more than a single file
			// Ref: https://github.com/electron/electron/issues/5400
			// nodeIntegration: false,
			webSecurity: false,
			plugins: true
		}
	});

	if (process.platform === 'darwin') {
		win.setSheetOffset(40);
	}

	win.loadURL('https://mobile.twitter.com/home');

	win.on('close', e => {
		if (!isQuitting) {
			e.preventDefault();

			if (process.platform === 'darwin') {
				app.hide();
			} else {
				win.hide();
			}
		}
	});

	win.on('page-title-updated', e => {
		e.preventDefault();
	});

	win.on('enter-full-screen', () => {
		win.setMaximumSize(maxWindowInteger, maxWindowInteger);
	});

	win.on('leave-full-screen', () => {
		win.setMaximumSize(maxWidthValue, maxWindowInteger);
	});

	return win;
}

app.on('ready', () => {
	electron.Menu.setApplicationMenu(appMenu);
	mainWindow = createMainWindow();
	tray.create(mainWindow);

	const page = mainWindow.webContents;

	page.on('dom-ready', () => {
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'browser.css'), 'utf8'));
		page.insertCSS(fs.readFileSync(path.join(__dirname, 'dark-mode.css'), 'utf8'));
		mainWindow.show();
	});

	page.on('new-window', (e, url) => {
		e.preventDefault();
		electron.shell.openExternal(url);
	});
});

app.on('activate', () => {
	mainWindow.show();
});

app.on('before-quit', () => {
	isQuitting = true;

	if (!mainWindow.isFullScreen()) {
		storage.set('lastWindowState', mainWindow.getBounds());
	}
});
<|endoftext|>