<commit_before>/*
 * @requires FaultedEarth.js
 */

FaultedEarth.TraceForm = Ext.extend(gxp.plugins.Tool, {

    ptype: "app_traceform",

    /** api: config[featureManager]
     *  ``String`` id of the FeatureManager to add uploaded features to
     */

    /** api: config[featureEditor]
     *  ``String`` id of the FeatureEditor to modify uploaded features
     */

    /** api: config[temporaryWorkspace]
     *  ``String`` temporary GeoServer workspace for shapefile uploads.
     *  Default is "temp".
     */
    temporaryWorkspace: "temp",

    /** api: config[temporaryWorkspaceNamespaceUri]
     *  ``String`` namespace uri of the temporary GeoServer workspace for
     *  shapefile uploads. Default is "http://geonode.org/temporary".
     */
    temporaryWorkspaceNamespaceUri: "http://geonode.org/temporary",

    /** private: property[sessionFids]
     *  ``Array`` fids of features added/modified in this session
     */
    sessionFids: null,

    autoActivate: false,

    init: function(target) {
        FaultedEarth.TraceForm.superclass.init.apply(this, arguments);

        this.sessionFids = [];
        var featureManager = target.tools[this.featureManager];
        featureManager.featureLayer.events.on({
            "featureselected": function(e) {
                if (!e.feature.fid) {
                    return;
                }
                if (featureManager.layerRecord.get("name") == "geonode:trace") {
                    this.target.summaryId = e.feature.fid;

                    this.current_trace_url = "/traces/join/" + e.feature.fid.split(".").pop() +
                        "/trace_id/" + this.target.summaryId.split(".").pop();

                } else if (this.target.summaryId) {
                    this.output[0].ownerCt.enable();
                    this.current_trace_url = "/traces/new/trace_id/" + this.target.summaryId.split(".").pop()
                }
                this.sessionFids.push(this.target.summaryId);
            },
            "featureunselected": function(e) {
                if (this.active && featureManager.layerRecord.get("name") == "geonode:trace") {
                    this.sessionFids = [];
                    this.target.summaryId = null;
                }
            },
            scope: this
        });
    },

    addOutput: function(config) {
        return FaultedEarth.TraceForm.superclass.addOutput.call(this, {
            xtype: "form",
            labelWidth: 110,
            defaults: {
                anchor: "100%"
            },
            items: [{
                xtype: "container",
                layout: "hbox",
                cls: "composite-wrap",
                fieldLabel: "Create or edit a trace",
                items: [{
                    id: this.id + "_tooltarget",
                    xtype: "container",
                    cls: "toolbar-spaced",
                    layout: "toolbar"
                }]
            }, {
                xtype: "container",
                layout: "hbox",
                cls: "composite-wrap",
                fieldLabel: "Upload a trace",
                items: [{
                    xtype: "button",
                    text: "Import",
                    iconCls: "icon-import",
                    handler: function() {
                        var featureManager = this.target.tools[this.featureManager];
                        featureManager.loadFeatures()
                        if (this.output[0].newFeaturesOnly.getValue()) {
                            featureManager.on("clearfeatures", this.showUploadWindow, this, {single: true});
                            featureManager.clearFeatures();
                        } else {
                            this.showUploadWindow();
                        }
                    },
                    scope: this
                }]
            }, {
                xtype: "box",
                autoEl: {
                    tag: "p",
                    cls: "x-form-item"
                },
                html: "To create a Fault Section, select traces in the grid or on the map hold down ctl or shift to select multiple traces. Then click join. Filter the grid with the options below."
            }, {
                xtype: "container",
                layout: "hbox",
                fieldLabel: "Join traces",
                items: [{
                    xtype: "button",
                    text: "Join",
                    iconCls: "icon-layer-switcher",
                    handler: function() {
                        var featureManager = this.target.tools[this.featureManager];
                        alert(this.sessionFids);

                    },
                    scope: this
                    }]
             }, {
                xtype: "textfield",
                ref: "nameContains",
                fieldLabel: "Search for name",
                validationDelay: 500,
                listeners: {
                        "valid": this.updateFilter,
                        scope: this
                }
             }, {
                xtype: "checkbox",
                ref: "newFeaturesOnly",
                hideLabel: true,
                disabled: true,
                boxLabel: "Only show grid rows from this session",
                handler: this.updateFilter,
                scope: this
            }],
            listeners: {
                "added": function(cmp, ct) {
                    ct.on({
                        "expand": function() { this.activate(); },
                        "collapse": function() { this.deactivate(); },
                        scope: this
                    });
                },
                scope: this
            }
        });
    },

    activate: function() {
        if (FaultedEarth.TraceForm.superclass.activate.apply(this, arguments)) {
            var featureManager = this.target.tools[this.featureManager];
            featureManager.setLayer();
            if (!this.layerRecord) {
                this.target.createLayerRecord({
                    name: "geonode:trace",
                    source: "local"
                }, function(record) {
                    this.layerRecord = record;
                    featureManager.setLayer(record);
                }, this);
            } else {
                featureManager.setLayer(this.layerRecord);
            }
            this.output[0].newFeaturesOnly.setValue(false);
            this.output[0].nameContains.setValue("");
            featureManager.on("layerchange", function(mgr, rec) {
                mgr.featureStore.on({
                    "save": function(store, batch, data) {
                        var fid;
                        for (var action in data) {
                            for (var i=data[action].length-1; i>=0; --i) {
                                fid = data[action][i].feature.fid;
                                this.sessionFids.remove(fid);
                                if (action != "destroy") {
                                    this.sessionFids.push(fid);
                                }
                                this.output[0].newFeaturesOnly.setDisabled(!this.sessionFids.length);
                            }
                        }
                    },
                    "load": function() {
                        this.target.summaryId && window.setTimeout((function() {
                            var feature = mgr.featureLayer.getFeatureByFid(this.target.summaryId);
                            if (feature && feature.layer.selectedFeatures.indexOf(feature) == -1) {
                                feature.layer.selectedFeatures.push(feature);
                                feature.layer.events.triggerEvent("featureselected", {feature: feature});
                            }
                        }).createDelegate(this), 0);
                    },
                    scope: this
                });
            }, this, {single: true});
        }
    },

    deactivate: function() {
        if (FaultedEarth.TraceForm.superclass.deactivate.apply(this, arguments)) {
            this.target.tools[this.featureManager].featureStore.un("save", this.monitorSave, this);
        }
    },

    updateFilter: function() {
        var form = this.output[0];
        var filters = [];
        form.newFeaturesOnly.getValue() && filters.push(
            new OpenLayers.Filter.FeatureId({fids: this.sessionFids})
        );
        form.nameContains.getValue() && filters.push(
            new OpenLayers.Filter.Comparison({
                type: OpenLayers.Filter.Comparison.LIKE,
                property: "name",
                value: "*" + form.nameContains.getValue() + "*",
                matchCase: false
            })
        );
        var filter;
        if (filters.length > 0) {
            filter = filters.length == 1 ? filters[0] :
                new OpenLayers.Filter.Logical({
                    type: OpenLayers.Filter.Logical.AND,
                    filters: filters
                });
        }
        this.target.tools[this.featureManager].loadFeatures(filter);
    },
    showUploadWindow: function() {
        var uploadWindow = new Ext.Window({
            title: "Import Faults",
            width: 250,
            autoHeight: true,
            modal: true,
            items: [{
                xtype: "form",
                ref: "form",
                padding: 10,
                border: false,
                autoHeight: true,
                labelWidth: 40,
                defaults: {
                    anchor: "100%"
                },
                items: [{
                    xtype: "box",
                    autoEl: {
                        tag: "p",
                        cls: "x-form-item"
                    },
                    html: "Select a zipped shapefile for uploading. The shapefile needs to have a line geometry."
                }, {
                    xtype: "fileuploadfield",
                    ref: "fileField",
                    fieldLabel: "File",
                    allowBlank: false,
                    listeners: {
                        "fileselected": function(field, file) {
                            field.ownerCt.uploadButton.enable();
                        }
                    }
                }],
                buttonAlign: "center",
                buttons: [{
                    text: "Upload",
                    ref: "../uploadButton",
                    disabled: true,
                    handler: function() {
                        var file = uploadWindow.form.fileField.fileInput.dom.files[0];
                        Ext.Ajax.request({
                            method: "PUT",
                            url: this.target.localGeoServerUrl + "rest/workspaces/" +
                                this.temporaryWorkspace + "/datastores/" +
                                file.fileName + "/file.shp?update=overwrite",
                            xmlData: file,
                            headers: {
                                "Content-Type": file.fileName.split(".").pop().toLowerCase() == "zip" ?
                                    "application/zip" : file.type
                            },
                            success: this.handleUpload.createDelegate(this,
                                [file.fileName, uploadWindow], true),
                            scope: this
                        });
                    },
                    scope: this
                }]
            }]
        });
        uploadWindow.show();
    },

    handleUpload: function(response, options, fileName, uploadWindow) {
        uploadWindow.close();
        var fileParts = fileName.split(".");
        fileParts.pop();
        var layerName = fileParts.join("");
        new OpenLayers.Protocol.WFS({
            version: "1.1.0",
            srsName: this.target.mapPanel.map.getProjectionObject().getCode(),
            url: this.target.localGeoServerUrl + "wfs",
            featureType: layerName,
            featureNS: this.temporaryWorkspaceNamespaceUri,
            outputFormat: "GML2"
        }).read({
            callback: function(response) {
                var extent = new OpenLayers.Bounds();
                var features = response.features, feature, date;
                for (var i=features.length-1; i>=0; --i) {
                    feature = features[i];
                    extent.extend(feature.geometry.getBounds());
                    feature.fid = null;
                    feature.state = OpenLayers.State.INSERT;
                    // convert dates
                    for (var a in feature.attributes) {
                        date = Date.parseDate(feature.attributes[a], "Y/m/d");
                        if (date) {
                            feature.attributes[a] = date.format("c");
                        }
                    }
                }
                var featureManager = this.target.tools[this.featureManager];
                featureManager.featureLayer.addFeatures(features);
                featureManager.featureStore.save();

                var featureEditor = this.target.tools[this.featureEditor];
                featureEditor.actions[1].control.activate();
                this.target.mapPanel.map.zoomToExtent(extent);
            },
            scope: this
        });
        //TODO remove uploaded layer/store/style or call GeoNode updatelayers
    }

});

Ext.preg(FaultedEarth.TraceForm.prototype.ptype, FaultedEarth.TraceForm);
<commit_msg>Client implementation for Join Traces<commit_after>/*
 * @requires FaultedEarth.js
 */

FaultedEarth.TraceForm = Ext.extend(gxp.plugins.Tool, {

    ptype: "app_traceform",

    /** api: config[featureManager]
     *  ``String`` id of the FeatureManager to add uploaded features to
     */

    /** api: config[featureEditor]
     *  ``String`` id of the FeatureEditor to modify uploaded features
     */

    /** api: config[temporaryWorkspace]
     *  ``String`` temporary GeoServer workspace for shapefile uploads.
     *  Default is "temp".
     */
    temporaryWorkspace: "temp",

    /** api: config[temporaryWorkspaceNamespaceUri]
     *  ``String`` namespace uri of the temporary GeoServer workspace for
     *  shapefile uploads. Default is "http://geonode.org/temporary".
     */
    temporaryWorkspaceNamespaceUri: "http://geonode.org/temporary",

    /** private: property[sessionFids]
     *  ``Array`` fids of features added/modified in this session
     */
    sessionFids: null,

    autoActivate: false,

    init: function(target) {
        FaultedEarth.TraceForm.superclass.init.apply(this, arguments);

        this.sessionFids = [];
        var featureManager = target.tools[this.featureManager];
        featureManager.featureLayer.events.on({
            "featureselected": function(e) {
                if (!e.feature.fid) {
                    return;
                }
                if (featureManager.layerRecord.get("name") == "geonode:observations_trace") {
                    this.target.summaryId = e.feature.fid;

                    this.current_trace_url = "/observations/traces/join" /*+ e.feature.fid.split(".").pop() +
                        "/trace_id/" + this.target.summaryId.split(".").pop();*/

                } else if (this.target.summaryId) {
                    this.output[0].ownerCt.enable();
                    this.current_trace_url = "/traces/new/trace_id/" + this.target.summaryId.split(".").pop()
                }
                this.sessionFids.push(this.target.summaryId);
            },
            "featureunselected": function(e) {
                if (this.active && featureManager.layerRecord.get("name") == "geonode:observations_trace") {
                    this.sessionFids = [];
                    this.target.summaryId = null;
                }
            },
            scope: this
        });
    },

    addOutput: function(config) {
        return FaultedEarth.TraceForm.superclass.addOutput.call(this, {
            xtype: "form",
            labelWidth: 110,
            defaults: {
                anchor: "100%"
            },
            items: [{
                xtype: "container",
                layout: "hbox",
                cls: "composite-wrap",
                fieldLabel: "Create or edit a trace",
                items: [{
                    id: this.id + "_tooltarget",
                    xtype: "container",
                    cls: "toolbar-spaced",
                    layout: "toolbar"
                }]
            }, {
                xtype: "container",
                layout: "hbox",
                cls: "composite-wrap",
                fieldLabel: "Upload a trace",
                items: [{
                    xtype: "button",
                    text: "Import",
                    iconCls: "icon-import",
                    handler: function() {
                        var featureManager = this.target.tools[this.featureManager];
                        featureManager.loadFeatures()
                        if (this.output[0].newFeaturesOnly.getValue()) {
                            featureManager.on("clearfeatures", this.showUploadWindow, this, {single: true});
                            featureManager.clearFeatures();
                        } else {
                            this.showUploadWindow();
                        }
                    },
                    scope: this
                }]
            }, {
                xtype: "box",
                autoEl: {
                    tag: "p",
                    cls: "x-form-item"
                },
                html: "To create a Fault Section, select traces in the grid or on the map hold down ctl or shift to select multiple traces. Then click join. Filter the grid with the options below."
            }, {
                xtype: "container",
                layout: "hbox",
                fieldLabel: "Join traces",
                items: [{
                    xtype: "button",
                    text: "Join",
                    iconCls: "icon-layer-switcher",
                    handler: function() {
                        var featureManager = this.target.tools[this.featureManager];
                        Ext.Ajax.request({
                            method: "PUT",
                            url: 'http://localhost' + this.current_trace_url,
                            params: Ext.encode(this.sessionFids),
                            success: function(response, opts) {
                                alert('Fault Section created');
                            },
                            failure: function(response, opts){
                                alert('Failed to create the Fault Section');
                            },

                            scope: this
                        });

                    },
                    scope: this
                    }]
             }, {
                xtype: "textfield",
                ref: "nameContains",
                fieldLabel: "Search for name",
                validationDelay: 500,
                listeners: {
                        "valid": this.updateFilter,
                        scope: this
                }
             }, {
                xtype: "checkbox",
                ref: "newFeaturesOnly",
                hideLabel: true,
                disabled: true,
                boxLabel: "Only show grid rows from this session",
                handler: this.updateFilter,
                scope: this
            }],
            listeners: {
                "added": function(cmp, ct) {
                    ct.on({
                        "expand": function() { this.activate(); },
                        "collapse": function() { this.deactivate(); },
                        scope: this
                    });
                },
                scope: this
            }
        });
    },

    activate: function() {
        if (FaultedEarth.TraceForm.superclass.activate.apply(this, arguments)) {
            var featureManager = this.target.tools[this.featureManager];
            featureManager.setLayer();
            if (!this.layerRecord) {
                this.target.createLayerRecord({
                    name: "geonode:observations_trace",
                    source: "local"
                }, function(record) {
                    this.layerRecord = record;
                    featureManager.setLayer(record);
                }, this);
            } else {
                featureManager.setLayer(this.layerRecord);
            }
            this.output[0].newFeaturesOnly.setValue(false);
            this.output[0].nameContains.setValue("");
            featureManager.on("layerchange", function(mgr, layer, attr) {
                mgr.featureStore.on({
                    "save": function(store, batch, data) {
                        var fid;
                        for (var action in data) {
                            for (var i=data[action].length-1; i>=0; --i) {
                                fid = data[action][i].feature.fid;
                                this.sessionFids.remove(fid);
                                if (action != "destroy") {
                                    this.sessionFids.push(fid);
                                }
                                this.output[0].newFeaturesOnly.setDisabled(!this.sessionFids.length);
                            }
                        }
                    },
                    "load": function() {
                        this.target.summaryId && window.setTimeout((function() {
                            var feature = mgr.featureLayer.getFeatureByFid(this.target.summaryId);
                            if (feature && feature.layer.selectedFeatures.indexOf(feature) == -1) {
                                feature.layer.selectedFeatures.push(feature);
                                feature.layer.events.triggerEvent("featureselected", {feature: feature});
                            }
                        }).createDelegate(this), 0);
                    },
                    scope: this
                });
            }, this, {single: true});
        }
    },

    deactivate: function() {
        if (FaultedEarth.TraceForm.superclass.deactivate.apply(this, arguments)) {
            this.target.tools[this.featureManager].featureStore.un("save", this.monitorSave, this);
        }
    },

    updateFilter: function() {
        var form = this.output[0];
        var filters = [];
        form.newFeaturesOnly.getValue() && filters.push(
            new OpenLayers.Filter.FeatureId({fids: this.sessionFids})
        );
        form.nameContains.getValue() && filters.push(
            new OpenLayers.Filter.Comparison({
                type: OpenLayers.Filter.Comparison.LIKE,
                property: "name",
                value: "*" + form.nameContains.getValue() + "*",
                matchCase: false
            })
        );
        var filter;
        if (filters.length > 0) {
            filter = filters.length == 1 ? filters[0] :
                new OpenLayers.Filter.Logical({
                    type: OpenLayers.Filter.Logical.AND,
                    filters: filters
                });
        }
        this.target.tools[this.featureManager].loadFeatures(filter);
    },
    showUploadWindow: function() {
        var uploadWindow = new Ext.Window({
            title: "Import Faults",
            width: 250,
            autoHeight: true,
            modal: true,
            items: [{
                xtype: "form",
                ref: "form",
                padding: 10,
                border: false,
                autoHeight: true,
                labelWidth: 40,
                defaults: {
                    anchor: "100%"
                },
                items: [{
                    xtype: "box",
                    autoEl: {
                        tag: "p",
                        cls: "x-form-item"
                    },
                    html: "Select a zipped shapefile for uploading. The shapefile needs to have a line geometry."
                }, {
                    xtype: "fileuploadfield",
                    ref: "fileField",
                    fieldLabel: "File",
                    allowBlank: false,
                    listeners: {
                        "fileselected": function(field, file) {
                            field.ownerCt.uploadButton.enable();
                        }
                    }
                }],
                buttonAlign: "center",
                buttons: [{
                    text: "Upload",
                    ref: "../uploadButton",
                    disabled: true,
                    handler: function() {
                        var file = uploadWindow.form.fileField.fileInput.dom.files[0];
                        Ext.Ajax.request({
                            method: "PUT",
                            url: this.target.localGeoServerUrl + "rest/workspaces/" +
                                this.temporaryWorkspace + "/datastores/" +
                                file.fileName + "/file.shp?update=overwrite",
                            xmlData: file,
                            headers: {
                                "Content-Type": file.name.split(".").pop().toLowerCase() == "zip" ?
                                    "application/zip" : file.type
                            },
                            success: this.handleUpload.createDelegate(this,
                                [file.name, uploadWindow], true),
                            scope: this
                        });
                    },
                    scope: this
                }]
            }]
        });
        uploadWindow.show();
    },

    handleUpload: function(response, options, fileName, uploadWindow) {
        uploadWindow.close();
        var fileParts = fileName.split(".");
        fileParts.pop();
        var layerName = fileParts.join("");
        new OpenLayers.Protocol.WFS({
            version: "1.1.0",
            srsName: this.target.mapPanel.map.getProjectionObject().getCode(),
            url: this.target.localGeoServerUrl + "wfs",
            featureType: layerName,
            featureNS: this.temporaryWorkspaceNamespaceUri,
            outputFormat: "GML2"
        }).read({
            callback: function(response) {
                var extent = new OpenLayers.Bounds();
                var features = response.features, feature, date;
                for (var i=features.length-1; i>=0; --i) {
                    feature = features[i];
                    extent.extend(feature.geometry.getBounds());
                    feature.fid = null;
                    feature.state = OpenLayers.State.INSERT;
                    // convert dates
                    for (var a in feature.attributes) {
                        date = Date.parseDate(feature.attributes[a], "Y/m/d");
                        if (date) {
                            feature.attributes[a] = date.format("c");
                        }
                    }
                }
                var featureManager = this.target.tools[this.featureManager];
                featureManager.featureLayer.addFeatures(features);
                featureManager.featureStore.save();

                var featureEditor = this.target.tools[this.featureEditor];
                featureEditor.actions[1].control.activate();
                this.target.mapPanel.map.zoomToExtent(extent);
            },
            scope: this
        });
        //TODO remove uploaded layer/store/style or call GeoNode updatelayers
    }

});

Ext.preg(FaultedEarth.TraceForm.prototype.ptype, FaultedEarth.TraceForm);
<|endoftext|>


<commit_before>var Entity = {
	x: null,
	y: null,
	width: null,
	height: null,
	draw: function() {
	},
	update: function() {
	},
	collideWith: function() {
	}
};
<commit_msg>Unique Prototype Entity framework<commit_after>var Entity = function(x, y, width, height) {
	this.x = x;
	this.y = y;
	this.width = width;
	this.height = height;
};
Entity.prototype.draw = function() {
};
Entity.prototype.update = function() {
};
Entity.prototype.collideWith = function() {
};
<|endoftext|>


<commit_before>/**
 * 图(Graph)
 *
 * 图(Graph)是一种比线性表和树更为复杂的数据结构。
 *
 * 线性结构：是研究数据元素之间的一对一关系。在这种结构中，除第一个和最后一个元素外，任何一个元素都有唯一的一个直接前驱和直接后继。
 *
 * 树结构：是研究数据元素之间的一对多的关系。在这种结构中，每个元素对下(层)可以有0个或多个元素相联系，对上(层)只有唯一的一个元素相关，数据元素之间有明显的层次关系。
 *
 * 图结构：是研究数据元素之间的多对多的关系。在这种结构中，任意两个元素之间可能存在关系。即结点之间的关系可以是任意的，图中任意元素之间都可能相关。
 *
 * 图的应用极为广泛，已渗入到诸如语言学、逻辑学、物理、化学、电讯、计算机科学以及数学的其它分支。
 *
 * 图的基本概念
 *
 * 一个图(G)定义为一个偶对(V,E) ，记为G=(V,E) 。其中： V是顶点(Vertex)的非空有限集合，记为V(G)；E是无序集V&V的一个子集，记为E(G) ，其元素是图的弧(Arc)。
 * 将顶点集合为空的图称为空图。其形式化定义为：
     G=(V ，E)
     V={v|v∈data object}
     E={<v,w>| v,w∈V∧p(v,w)}
     P(v,w)表示从顶点v到顶点w有一条直接通路。
 *
 * 弧(Arc) ：表示两个顶点v和w之间存在一个关系，用顶点偶对<v,w>表示。通常根据图的顶点偶对将图分为有向图和无向图。
 * 有向图(Digraph)： 若图G的关系集合E(G)中，顶点偶对<v,w>的v和w之间是有序的，称图G是有向图。
 *   在有向图中，若 <v,w>∈E(G) ，表示从顶点v到顶点w有一条弧。 其中：v称为弧尾(tail)或始点(initial node)，w称为弧头(head)或终点(terminal node) 。
 * 无向图(Undigraph)： 若图G的关系集合E(G)中，顶点偶对<v,w>的v和w之间是无序的，称图G是无向图。
 *   在无向图中，若<v,w>∈E(G) ，有<w,v>∈E(G) ，即E(G)是对称，则用无序对(v,w) 表示v和w之间的一条边(Edge)，因此(v,w) 和(w,v)代表的是同一条边。
 *
 * 例1：设有有向图G1和无向图G2，形式化定义分别是：
         G1=(V1 ，E1)
         V1={a,b,c,d,e}
         E1={<a,b>,<a,c>, <a,e>,<c,d>,<c,e> ,<d,a>,<d,b>,<e,d>}
         G2=(V2 ，E2)
         V2={a,b,c,d}
         E2={(a,b), (a,c), (a,d), (b,d), (b,c), (c,d)}
 *
 * 完全无向图：对于无向图，若图中顶点数为n ，用e表示边的数目，则e ∈[0，n(n-1)/2] 。具有n(n-1)/2条边的无向图称为完全无向图。
 完全无向图另外的定义是：
 * 对于无向图G=(V，E)，若vi，vj ∈V ，当vi≠vj时，有(vi ,vj)∈E，即图中任意两个不同的顶点间都有一条无向边，这样的无向图称为完全无向图。
 *
 * 完全有向图：对于有向图，若图中顶点数为n ，用e表示弧的数目，则e∈[0，n(n-1)] 。具有n(n-1)条边的有向图称为完全有向图。
 完全有向图另外的定义是：
 * 对于有向图G=(V，E)，若vi，vj∈V ，当vi ≠vj时，有<vi ,vj>∈E∧<vj , vi >∈E ，即图中任意两个不同的顶点间都有一条弧，这样的有向图称为完全有向图。
 *
 * 有很少边或弧的图（e<n㏒n）的图称为稀疏图，反之称为稠密图。
 * 权(Weight)：与图的边和弧相关的数。权可以表示从一个顶点到另一个顶点的距离或耗费。
 *
 * 子图和生成子图：设有图G=(V，E)和G’=(V’，E’)，若V’∈V且E’∈E ，则称图G’是G的子图；若V’=V且E’∈E，则称图G’是G的一个生成子图。
 * 顶点的邻接(Adjacent)：对于无向图G=(V，E)，若边(v,w)∈E，则称顶点v和w 互为邻接点，即v和w相邻接。边(v,w)依附(incident)与顶点v和w 。
 * 对于有向图G=(V ，E)，若有向弧<v,w>∈E，则称顶点v “邻接到”顶点w，顶点w “邻接自”顶点v ，弧<v,w> 与顶点v和w “相关联” 。
 *
 * 顶点的度、入度、出度：对于无向图G=(V，E)， vi∈V，图G中依附于vi的边的数目称为顶点vi的度(degree)，记为TD(vi)。
 显然，在无向图中，所有顶点度的和是图中边的2倍。 即   ∑TD(vi)=2e      i=1, 2, …, n ，e为图的边数。
 对有向图G=(V，E)，若vi ∈V ，图G中以vi作为起点的有向边(弧)的数目称为顶点vi的出度(Outdegree)，记为OD(vi) ；以vi作为终点的有向边(弧)的数目称为顶点vi的入度(Indegree)，记为ID(vi) 。顶点vi的出度与入度之和称为vi的度，记为TD(vi) 。即
 TD(vi)=OD(vi)+ID(vi)
 *
 * 路径(Path)、路径长度、回路(Cycle) ：对无向图G=(V，E)，若从顶点vi经过若干条边能到达vj，称顶点vi和vj是连通的，又称顶点vi到vj有路径。
 对有向图G=(V，E)，从顶点vi到vj有有向路径，指的是从顶点vi经过若干条有向边(弧)能到达vj。
 或路径是图G中连接两顶点之间所经过的顶点序列。即
     Path=vi0vi1…vim ，vij∈V且(vij-1, vij)∈E   j=1,2, …,m
     或
     Path=vi0vi1 …vim ，vij∈V且<vij-1, vij>∈E  j=1,2, …,m
 路径上边或有向边(弧)的数目称为该路径的长度。
 在一条路径中，若没有重复相同的顶点，该路径称为简单路径；第一个顶点和最后一个顶点相同的路径称为回路(环)；在一个回路中，若除第一个与最后一个顶点外，其余顶点不重复出现的回路称为简单回路(简单环)。
 *
 * 连通图、图的连通分量：对无向图G=(V，E)，若vi ，vj ∈V，vi和vj都是连通的，则称图G是连通图，否则称为非连通图。若G是非连通图，则极大的连通子图称为G的连通分量。
 对有向图G=(V，E)，若vi ，vj ∈V，都有以vi为起点， vj 为终点以及以vj为起点，vi为终点的有向路径，称图G是强连通图，否则称为非强连通图。若G是非强连通图，则极大的强连通子图称为G的强连通分量。
 “极大”的含义：指的是对子图再增加图G中的其它顶点，子图就不再连通。
 生成树、生成森林：一个连通图(无向图)的生成树是一个极小连通子图，它含有图中全部n个顶点和只有足以构成一棵树的n-1条边，称为图的生成树。
 关于无向图的生成树的几个结论：
 ◆ 一棵有n个顶点的生成树有且仅有n-1条边；
 ◆ 如果一个图有n个顶点和小于n-1条边，则是非连通图；
 ◆ 如果多于n-1条边，则一定有环；
 ◆ 有n-1条边的图不一定是生成树。

 有向图的生成森林是这样一个子图，由若干棵有向树组成，含有图中全部顶点。
 有向树是只有一个顶点的入度为0 ，其余顶点的入度均为1的有向图。

 *
 * 网：每个边(或弧)都附加一个权值的图，称为带权图。带权的连通图(包括弱连通的有向图)称为网或网络。网络是工程上常用的一个概念，用来表示一个工程或某种流程
 */

/**
 * 图的存储结构
 *
    图的存储结构比较复杂，其复杂性主要表现在：
    ◆ 任意顶点之间可能存在联系，无法以数据元素在存储区中的物理位置来表示元素之间的关系。
    ◆ 图中顶点的度不一样，有的可能相差很大，若按度数最大的顶点设计结构，则会浪费很多存储单元，反之按每个顶点自己的度设计不同的结构，又会影响操作。
    图的常用的存储结构有：邻接矩阵、邻接链表、十字链表、邻接多重表和边表。
 */

/*
邻接矩阵(数组)表示法

基本思想：对于有n个顶点的图，用一维数组vexs[n]存储顶点信息，用二维数组A[n][n]存储顶点之间关系的信息。该二维数组称为邻接矩阵。在邻接矩阵中，以顶点在vexs数组中的下标代表顶点，邻接矩阵中的元素A[i][j]存放的是顶点i到顶点j之间关系的信息。

1  无向图的数组表示

(1)  无权图的邻接矩阵
无向无权图G=(V，E)有n(n≧1)个顶点，其邻接矩阵是n阶对称方阵。其元素的定义如下：
                -- 1   若(vi , vj)∈E，即vi , vj邻接
    A[i][j]=
                -- 0   若(vi , vj)∉E，即vi , vj不邻接

(2)  带权图的邻接矩阵
无向带权图G=(V，E) 的邻接矩阵。其元素的定义如下：
                -- Wij    若(vi , vj)∈E，即vi , vj邻接，权值为wij
    A[i][j]=

                -- ∞   若(vi , vj)∉E，即vi , vj不邻接时

(3)  无向图邻接矩阵的特性
◆ 邻接矩阵是对称方阵
◆ 对于顶点vi，其度数是第i行的非0元素的个数；
◆ 无向图的边数是上(或下)三角形矩阵中非0元素个数。

2  有向图的数组表示

(1)  无权图的邻接矩阵
若有向无权图G=(V，E)有n(n≧1)个顶点，则其邻接矩阵是n阶对称方阵。元素定义如下：
                -- 1   若<vi, vj>∈E，从vi到vj有弧
    A[i][j]=
                -- 0   若<vi , vj>∉E  从vi到vj 没有弧

(2)  带权图的邻接矩阵
有向带权图G=(V，E)的邻接矩阵。其元素的定义如下：
                -- wij    若<vi,vj>∈E，即vi , vj邻接，权值为wij
    A[i][j]=
                ∞   若<vi,vj>∉E，即vi , vj不邻接时

⑶ 有向图邻接矩阵的特性
◆ 对于顶点vi，第i行的非0元素的个数是其出度OD(vi)；第i列的非0元素的个数是其入度ID(vi) 。
◆ 邻接矩阵中非0元素的个数就是图的弧的数目。

 */<commit_msg>modified<commit_after>/**
 * 图(Graph)
 *
 * 图(Graph)是一种比线性表和树更为复杂的数据结构。
 *
 * 线性结构：是研究数据元素之间的一对一关系。在这种结构中，除第一个和最后一个元素外，任何一个元素都有唯一的一个直接前驱和直接后继。
 *
 * 树结构：是研究数据元素之间的一对多的关系。在这种结构中，每个元素对下(层)可以有0个或多个元素相联系，对上(层)只有唯一的一个元素相关，数据元素之间有明显的层次关系。
 *
 * 图结构：是研究数据元素之间的多对多的关系。在这种结构中，任意两个元素之间可能存在关系。即结点之间的关系可以是任意的，图中任意元素之间都可能相关。
 *
 * 图的应用极为广泛，已渗入到诸如语言学、逻辑学、物理、化学、电讯、计算机科学以及数学的其它分支。
 *
 * 图的基本概念
 *
 * 一个图(G)定义为一个偶对(V,E) ，记为G=(V,E) 。其中： V是顶点(Vertex)的非空有限集合，记为V(G)；E是无序集V&V的一个子集，记为E(G) ，其元素是图的弧(Arc)。
 * 将顶点集合为空的图称为空图。其形式化定义为：
 G=(V ，E)
 V={v|v∈data object}
 E={<v,w>| v,w∈V∧p(v,w)}
 P(v,w)表示从顶点v到顶点w有一条直接通路。
 *
 * 弧(Arc) ：表示两个顶点v和w之间存在一个关系，用顶点偶对<v,w>表示。通常根据图的顶点偶对将图分为有向图和无向图。
 * 有向图(Digraph)： 若图G的关系集合E(G)中，顶点偶对<v,w>的v和w之间是有序的，称图G是有向图。
 *   在有向图中，若 <v,w>∈E(G) ，表示从顶点v到顶点w有一条弧。 其中：v称为弧尾(tail)或始点(initial node)，w称为弧头(head)或终点(terminal node) 。
 * 无向图(Undigraph)： 若图G的关系集合E(G)中，顶点偶对<v,w>的v和w之间是无序的，称图G是无向图。
 *   在无向图中，若<v,w>∈E(G) ，有<w,v>∈E(G) ，即E(G)是对称，则用无序对(v,w) 表示v和w之间的一条边(Edge)，因此(v,w) 和(w,v)代表的是同一条边。
 *
 * 例1：设有有向图G1和无向图G2，形式化定义分别是：
 G1=(V1 ，E1)
 V1={a,b,c,d,e}
 E1={<a,b>,<a,c>, <a,e>,<c,d>,<c,e> ,<d,a>,<d,b>,<e,d>}
 G2=(V2 ，E2)
 V2={a,b,c,d}
 E2={(a,b), (a,c), (a,d), (b,d), (b,c), (c,d)}
 *
 * 完全无向图：对于无向图，若图中顶点数为n ，用e表示边的数目，则e ∈[0，n(n-1)/2] 。具有n(n-1)/2条边的无向图称为完全无向图。
 完全无向图另外的定义是：
 * 对于无向图G=(V，E)，若vi，vj ∈V ，当vi≠vj时，有(vi ,vj)∈E，即图中任意两个不同的顶点间都有一条无向边，这样的无向图称为完全无向图。
 *
 * 完全有向图：对于有向图，若图中顶点数为n ，用e表示弧的数目，则e∈[0，n(n-1)] 。具有n(n-1)条边的有向图称为完全有向图。
 完全有向图另外的定义是：
 * 对于有向图G=(V，E)，若vi，vj∈V ，当vi ≠vj时，有<vi ,vj>∈E∧<vj , vi >∈E ，即图中任意两个不同的顶点间都有一条弧，这样的有向图称为完全有向图。
 *
 * 有很少边或弧的图（e<n㏒n）的图称为稀疏图，反之称为稠密图。
 * 权(Weight)：与图的边和弧相关的数。权可以表示从一个顶点到另一个顶点的距离或耗费。
 *
 * 子图和生成子图：设有图G=(V，E)和G’=(V’，E’)，若V’∈V且E’∈E ，则称图G’是G的子图；若V’=V且E’∈E，则称图G’是G的一个生成子图。
 * 顶点的邻接(Adjacent)：对于无向图G=(V，E)，若边(v,w)∈E，则称顶点v和w 互为邻接点，即v和w相邻接。边(v,w)依附(incident)与顶点v和w 。
 * 对于有向图G=(V ，E)，若有向弧<v,w>∈E，则称顶点v “邻接到”顶点w，顶点w “邻接自”顶点v ，弧<v,w> 与顶点v和w “相关联” 。
 *
 * 顶点的度、入度、出度：对于无向图G=(V，E)， vi∈V，图G中依附于vi的边的数目称为顶点vi的度(degree)，记为TD(vi)。
 显然，在无向图中，所有顶点度的和是图中边的2倍。 即   ∑TD(vi)=2e      i=1, 2, …, n ，e为图的边数。
 对有向图G=(V，E)，若vi ∈V ，图G中以vi作为起点的有向边(弧)的数目称为顶点vi的出度(Outdegree)，记为OD(vi) ；以vi作为终点的有向边(弧)的数目称为顶点vi的入度(Indegree)，记为ID(vi) 。顶点vi的出度与入度之和称为vi的度，记为TD(vi) 。即
 TD(vi)=OD(vi)+ID(vi)
 *
 * 路径(Path)、路径长度、回路(Cycle) ：对无向图G=(V，E)，若从顶点vi经过若干条边能到达vj，称顶点vi和vj是连通的，又称顶点vi到vj有路径。
 对有向图G=(V，E)，从顶点vi到vj有有向路径，指的是从顶点vi经过若干条有向边(弧)能到达vj。
 或路径是图G中连接两顶点之间所经过的顶点序列。即
 Path=vi0vi1…vim ，vij∈V且(vij-1, vij)∈E   j=1,2, …,m
 或
 Path=vi0vi1 …vim ，vij∈V且<vij-1, vij>∈E  j=1,2, …,m
 路径上边或有向边(弧)的数目称为该路径的长度。
 在一条路径中，若没有重复相同的顶点，该路径称为简单路径；第一个顶点和最后一个顶点相同的路径称为回路(环)；在一个回路中，若除第一个与最后一个顶点外，其余顶点不重复出现的回路称为简单回路(简单环)。
 *
 * 连通图、图的连通分量：对无向图G=(V，E)，若vi ，vj ∈V，vi和vj都是连通的，则称图G是连通图，否则称为非连通图。若G是非连通图，则极大的连通子图称为G的连通分量。
 对有向图G=(V，E)，若vi ，vj ∈V，都有以vi为起点， vj 为终点以及以vj为起点，vi为终点的有向路径，称图G是强连通图，否则称为非强连通图。若G是非强连通图，则极大的强连通子图称为G的强连通分量。
 “极大”的含义：指的是对子图再增加图G中的其它顶点，子图就不再连通。
 生成树、生成森林：一个连通图(无向图)的生成树是一个极小连通子图，它含有图中全部n个顶点和只有足以构成一棵树的n-1条边，称为图的生成树。
 关于无向图的生成树的几个结论：
 ◆ 一棵有n个顶点的生成树有且仅有n-1条边；
 ◆ 如果一个图有n个顶点和小于n-1条边，则是非连通图；
 ◆ 如果多于n-1条边，则一定有环；
 ◆ 有n-1条边的图不一定是生成树。

 有向图的生成森林是这样一个子图，由若干棵有向树组成，含有图中全部顶点。
 有向树是只有一个顶点的入度为0 ，其余顶点的入度均为1的有向图。

 *
 * 网：每个边(或弧)都附加一个权值的图，称为带权图。带权的连通图(包括弱连通的有向图)称为网或网络。网络是工程上常用的一个概念，用来表示一个工程或某种流程
 */

/**
 * 图的存储结构
 *
 图的存储结构比较复杂，其复杂性主要表现在：
 ◆ 任意顶点之间可能存在联系，无法以数据元素在存储区中的物理位置来表示元素之间的关系。
 ◆ 图中顶点的度不一样，有的可能相差很大，若按度数最大的顶点设计结构，则会浪费很多存储单元，反之按每个顶点自己的度设计不同的结构，又会影响操作。
 图的常用的存储结构有：邻接矩阵、邻接链表、十字链表、邻接多重表和边表。
 */

/*
邻接矩阵(数组)表示法

基本思想：对于有n个顶点的图，用一维数组vexs[n]存储顶点信息，用二维数组A[n][n]存储顶点之间关系的信息。该二维数组称为邻接矩阵。在邻接矩阵中，以顶点在vexs数组中的下标代表顶点，邻接矩阵中的元素A[i][j]存放的是顶点i到顶点j之间关系的信息。

1  无向图的数组表示

(1)  无权图的邻接矩阵
无向无权图G=(V，E)有n(n≧1)个顶点，其邻接矩阵是n阶对称方阵。其元素的定义如下：
                -- 1   若(vi , vj)∈E，即vi , vj邻接
    A[i][j]=
                -- 0   若(vi , vj)∉E，即vi , vj不邻接

(2)  带权图的邻接矩阵
无向带权图G=(V，E) 的邻接矩阵。其元素的定义如下：
                -- Wij    若(vi , vj)∈E，即vi , vj邻接，权值为wij
    A[i][j]=

                -- ∞   若(vi , vj)∉E，即vi , vj不邻接时

(3)  无向图邻接矩阵的特性
◆ 邻接矩阵是对称方阵
◆ 对于顶点vi，其度数是第i行的非0元素的个数；
◆ 无向图的边数是上(或下)三角形矩阵中非0元素个数。

2  有向图的数组表示

(1)  无权图的邻接矩阵
若有向无权图G=(V，E)有n(n≧1)个顶点，则其邻接矩阵是n阶对称方阵。元素定义如下：
                -- 1   若<vi, vj>∈E，从vi到vj有弧
    A[i][j]=
                -- 0   若<vi , vj>∉E  从vi到vj 没有弧

(2)  带权图的邻接矩阵
有向带权图G=(V，E)的邻接矩阵。其元素的定义如下：
                -- wij    若<vi,vj>∈E，即vi , vj邻接，权值为wij
    A[i][j]=
                ∞   若<vi,vj>∉E，即vi , vj不邻接时

⑶ 有向图邻接矩阵的特性
◆ 对于顶点vi，第i行的非0元素的个数是其出度OD(vi)；第i列的非0元素的个数是其入度ID(vi) 。
◆ 邻接矩阵中非0元素的个数就是图的弧的数目。

3  图的邻接矩阵的操作

图的邻接矩阵的实现比较容易，定义两个数组分别存储顶点信息(数据元素)和边或弧的信息(数据元素之间的关系) 。

 */

// 图的数组（邻接矩阵）存储表示
var DG = 1;     // 有向图
var DN = 2;     // 有向网
var UDG = 3;    // 无向图
var UDN = 4;    // 无向网

function ArcCell(adj, info) {
    // 顶点类型。对于无权图，用1或0表示相邻否；对带权图，则为权值类型
    this.adj = adj || Infinity;
    // 该弧相关信息
    this.info = info || null;
}

function MGraph(vexs, arcs, vexnum, arcnum, kind) {
    // 顶点向量
    this.vexs = vexs || [];
    // 邻接矩阵
    this.arcs = arcs || [];
    // 图的当前顶点数
    this.vexnum = vexnum || 0;
    // 图的当前弧数
    this.arcnum = arcnum || 0;
    // 图的种类标志
    this.kind = kind || DG;
}

MGraph.prototype = {
    createGraph: function(){
        switch(this.kind){
            case DG: return createDG(this);     // 构造有向图
            case DN: return createDN(this);     // 构造有向网
            case UDG: return createUDG(this);   // 构造无向图
            case UDN: return createUDN(this);   // 构造无向网
            default: throw new Error('非有效的图类型');
        }
    }
};

function createUDN(MGraph){
    MGraph.vexnum = parseInt(prompt('vexnum: '), 10);
    MGraph.arcnum = parseInt(prompt('arcnum: '), 10);
    // incInfo为0则各弧不含其他信息
    var incInfo = parseInt(prompt('incInfo: '), 10);

    // 构造顶点向量
    var i , j;
    for(i = 0; i < MGraph.vexnum; i++) MGraph.vexs[i] = prompt('vex: ');

    // 初始化邻接矩阵
    for(i = 0; i < MGraph.vexnum; i++){
        for(j = 0; j < MGraph.vexnum; j++) {
            MGraph.arcs[i] = MGraph.arcs[i] || [];
            MGraph.arcs[i][j] = new ArcCell(Infinity, null);
        }
    }

    // 构造邻接矩阵
    for(var k = 0; k < MGraph.arcnum; k++){
        // 输入一条边依附的顶点及权值
        var v1 = prompt('v1: ');
        var v2 = prompt('v2: ');
        var w = prompt('weight: ');

        // 确定v1，v2在G中的位置
        i = this.locateVex(v1);
        j = this.locateVex(v2);

        // 弧<v1, v2>的权值
        MGraph.arcs[i][j].adj = w;
        if(incInfo) MGraph.arcs[i][j].info = prompt('info: ');
        MGraph.arcs[j][i] = MGraph.arcs[i][j];
    }
}<|endoftext|>


<commit_before>'use strict';
const path = require('path');
const startInstance = require('./common.js').startInstance;
const createEndpoint = require('./common.js').createEndpoint;
const tmp = require('tmp');
const rmRf = require('rimraf-promise');
const mkdirp = require('mkdirp-promise/lib/node5');

class LocalRunner {
  constructor (basePath) {
    this.rootDir = tmp.dirSync({'prefix': 'arango-resilience'}).name;
    this.basePath = basePath;
  }

  createEndpoint () {
    return createEndpoint();
  }

  firstStart (instance) {
    let dir = path.join(this.rootDir, instance.name);
    let dataDir = path.join(dir, 'data');
    let appsDir = path.join(dir, 'apps');

    instance.args.unshift('--configuration=none');
    instance.args.push('--javascript.startup-directory=' + path.join(this.basePath, 'js'));
    instance.args.push('--javascript.app-path=' + appsDir);
    instance.args.push('--server.endpoint=' + instance.endpoint);
    instance.args.push(dataDir);

    let arangod = path.join(this.basePath, 'build', 'bin', 'arangod');
    if (process.env.RESILIENCE_ARANGO_WRAPPER) {
      let wrapper = process.env.RESILIENCE_ARANGO_WRAPPER.split(' ');
      instance.binary = wrapper.shift();
      instance.args = wrapper.concat(arangod, instance.args);
    } else {
      instance.binary = arangod;
    }

    return Promise.all([
      mkdirp(dataDir),
      mkdirp(appsDir)
    ])
    .then(() => {
      return startInstance(instance);
    });
  }

  restart (instance) {
    return startInstance(instance);
  }

  cleanup () {
    return rmRf(this.rootDir);
  }
}

module.exports = LocalRunner;
<commit_msg>Nuke existing instance dir before first start<commit_after>'use strict';
const path = require('path');
const startInstance = require('./common.js').startInstance;
const createEndpoint = require('./common.js').createEndpoint;
const tmp = require('tmp');
const rmRf = require('rimraf-promise');
const mkdirp = require('mkdirp-promise/lib/node5');

class LocalRunner {
  constructor (basePath) {
    this.rootDir = tmp.dirSync({'prefix': 'arango-resilience'}).name;
    this.basePath = basePath;
  }

  createEndpoint () {
    return createEndpoint();
  }

  firstStart (instance) {
    let dir = path.join(this.rootDir, instance.name);
    let dataDir = path.join(dir, 'data');
    let appsDir = path.join(dir, 'apps');

    instance.args.unshift('--configuration=none');
    instance.args.push('--javascript.startup-directory=' + path.join(this.basePath, 'js'));
    instance.args.push('--javascript.app-path=' + appsDir);
    instance.args.push('--server.endpoint=' + instance.endpoint);
    instance.args.push(dataDir);

    let arangod = path.join(this.basePath, 'build', 'bin', 'arangod');
    if (process.env.RESILIENCE_ARANGO_WRAPPER) {
      let wrapper = process.env.RESILIENCE_ARANGO_WRAPPER.split(' ');
      instance.binary = wrapper.shift();
      instance.args = wrapper.concat(arangod, instance.args);
    } else {
      instance.binary = arangod;
    }

    return rmRf(dir)
    .then(() => Promise.all([
      mkdirp(dataDir),
      mkdirp(appsDir)
    ]))
    .then(() => {
      return startInstance(instance);
    });
  }

  restart (instance) {
    return startInstance(instance);
  }

  cleanup () {
    return rmRf(this.rootDir);
  }
}

module.exports = LocalRunner;
<|endoftext|>


<commit_before>class DashboardController {
    constructor () {
        this.defaultWeekDuration = 7;
        this.defaultWeekStartDate = moment().startOf('week');

        this.handlers = {
            shopListLoadingDataHandlers: [],
            weekMealsLoadingDataHandlers: [],
            datePickerHandlers: []
        };
    }

    setDatePickerHandlers(handler) {
        this.handlers.datePickerHandlers.push(handler);
    };

    setShopListHandlers(handler) {
        this.handlers.shopListLoadingDataHandlers.push(handler);
    };

    setWeekMealDataHandlers(handler) {
        this.handlers.weekMealsLoadingDataHandlers.push(handler);
    };

    runDatePickerHandlers(startDate, endDate) {
        this.handlers.datePickerHandlers.forEach(function (handler) {
            handler(startDate, endDate);
        })
    };

    runShopListHandlers(date, duration) {
        this.handlers.shopListLoadingDataHandlers.forEach(function (handler) {
            handler(date, duration);
        })
    };

    runWeekMealsHandlers(startDate) {
        this.handlers.weekMealsLoadingDataHandlers.forEach(function (handler) {
            handler(startDate);
        })
    };
}

Mealpler.controller('DashboardCtrl', DashboardController);<commit_msg>MP-34: edited functions as arrow functions<commit_after>class DashboardController {
    constructor () {
        this.defaultWeekDuration = 7;
        this.defaultWeekStartDate = moment().startOf('week');

        this.handlers = {
            shopListLoadingDataHandlers: [],
            weekMealsLoadingDataHandlers: [],
            datePickerHandlers: []
        };
    }

    setDatePickerHandlers(handler) {
        this.handlers.datePickerHandlers.push(handler);
    };

    setShopListHandlers(handler) {
        this.handlers.shopListLoadingDataHandlers.push(handler);
    };

    setWeekMealDataHandlers(handler) {
        this.handlers.weekMealsLoadingDataHandlers.push(handler);
    };

    runDatePickerHandlers(startDate, endDate) {
        this.handlers.datePickerHandlers.forEach((handler) => handler(startDate, endDate));
    };

    runShopListHandlers(date, duration) {
        this.handlers.shopListLoadingDataHandlers.forEach((handler) => handler(date, duration));
    };

    runWeekMealsHandlers(startDate) {
        this.handlers.weekMealsLoadingDataHandlers.forEach((handler) => handler(startDate));
    };
}

Mealpler.controller('DashboardCtrl', DashboardController);<|endoftext|>


<commit_before>/* eslint-disable import/no-unresolved, import/extensions */
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, View, Text } from 'react-native';
import { ViewPropTypes } from '../utils';
/* eslint-enable import/no-unresolved, import/extensions */
import withTheme from '../styles/withTheme';

import RippleFeedback from '../RippleFeedback';
import Icon from '../Icon';

const propTypes = {
  testID: PropTypes.string,
  /**
   * Will be rendered above the label as a content of the action.
   * If string, result will be <Icon name={icon} ...rest />
   * If ReactElement, will be used as is
   */
  icon: PropTypes.oneOfType([PropTypes.element, PropTypes.string]).isRequired,
  /**
   * Name of Icon set that should be use. From react-native-vector-icons
   */
  iconSet: PropTypes.string,
  /**
   * Will be rendered under the icon as a content of the action.
   */
  label: PropTypes.string,
  /**
   * True if the action is active (for now it'll be highlight by primary color)
   */
  active: PropTypes.bool,
  /**
   * Callback for on press event.
   */
  onPress: PropTypes.func,
  /**
   * Inline style of bottom navigation
   */
  style: PropTypes.shape({
    container: ViewPropTypes.style,
    active: Text.propTypes.style, // eslint-disable-line
    disabled: Text.propTypes.style, // eslint-disable-line
  }),
  disabled: PropTypes.bool,
};
const defaultProps = {
  testID: null,
  label: null,
  onPress: null,
  iconSet: null,
  active: false,
  disabled: false,
  style: {},
};

function getStyles(props) {
  const { bottomNavigationAction } = props.theme;

  const local = {};

  if (props.active) {
    local.container = bottomNavigationAction.containerActive;
    local.icon = bottomNavigationAction.iconActive;
    local.label = bottomNavigationAction.labelActive;
  }

  if (!props.label) {
    local.container = { paddingTop: 16, paddingBottom: 16 };
  }

  return {
    container: [
      bottomNavigationAction.container,
      local.container,
      props.style.container,
    ],
    icon: [bottomNavigationAction.icon, local.icon, props.style.icon],
    label: [bottomNavigationAction.label, local.label, props.style.label],
  };
}

class BottomNavigationAction extends PureComponent {
  renderIcon(styles) {
    const { icon } = this.props;
    const { color } = StyleSheet.flatten(styles.icon);

    let element;
    if (React.isValidElement(icon)) {
      // we need icon to change color after it's selected, so we send the color and style to
      // custom element
      element = React.cloneElement(icon, { style: styles.icon, color });
    } else {
      element = <Icon name={icon} style={styles.icon} color={color} />;
    }
    return element;
  }

  renderLabel(styles) {
    const { label } = this.props;

    if (!label) {
      return null;
    }

    return <Text style={styles.label}>{label}</Text>;
  }

  render() {
    const { onPress, testID, disabled } = this.props;

    const styles = getStyles(this.props, this.context);

    return (
      <RippleFeedback disabled={disabled} testID={testID} onPress={onPress}>
        <View style={styles.container} pointerEvents="box-only">
          {this.renderIcon(styles)}
          {this.renderLabel(styles)}
        </View>
      </RippleFeedback>
    );
  }
}

BottomNavigationAction.propTypes = propTypes;
BottomNavigationAction.defaultProps = defaultProps;

export default withTheme(BottomNavigationAction);
<commit_msg>BottomNavigationAction: pass iconSet to Icon component. (#398)<commit_after>/* eslint-disable import/no-unresolved, import/extensions */
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, View, Text } from 'react-native';
import { ViewPropTypes } from '../utils';
/* eslint-enable import/no-unresolved, import/extensions */
import withTheme from '../styles/withTheme';

import RippleFeedback from '../RippleFeedback';
import Icon from '../Icon';

const propTypes = {
  testID: PropTypes.string,
  /**
   * Will be rendered above the label as a content of the action.
   * If string, result will be <Icon name={icon} ...rest />
   * If ReactElement, will be used as is
   */
  icon: PropTypes.oneOfType([PropTypes.element, PropTypes.string]).isRequired,
  /**
   * Name of Icon set that should be use. From react-native-vector-icons
   */
  iconSet: PropTypes.string,
  /**
   * Will be rendered under the icon as a content of the action.
   */
  label: PropTypes.string,
  /**
   * True if the action is active (for now it'll be highlight by primary color)
   */
  active: PropTypes.bool,
  /**
   * Callback for on press event.
   */
  onPress: PropTypes.func,
  /**
   * Inline style of bottom navigation
   */
  style: PropTypes.shape({
    container: ViewPropTypes.style,
    active: Text.propTypes.style, // eslint-disable-line
    disabled: Text.propTypes.style, // eslint-disable-line
  }),
  disabled: PropTypes.bool,
};
const defaultProps = {
  testID: null,
  label: null,
  onPress: null,
  iconSet: null,
  active: false,
  disabled: false,
  style: {},
};

function getStyles(props) {
  const { bottomNavigationAction } = props.theme;

  const local = {};

  if (props.active) {
    local.container = bottomNavigationAction.containerActive;
    local.icon = bottomNavigationAction.iconActive;
    local.label = bottomNavigationAction.labelActive;
  }

  if (!props.label) {
    local.container = { paddingTop: 16, paddingBottom: 16 };
  }

  return {
    container: [
      bottomNavigationAction.container,
      local.container,
      props.style.container,
    ],
    icon: [bottomNavigationAction.icon, local.icon, props.style.icon],
    label: [bottomNavigationAction.label, local.label, props.style.label],
  };
}

class BottomNavigationAction extends PureComponent {
  renderIcon(styles) {
    const { icon, iconSet } = this.props;
    const { color } = StyleSheet.flatten(styles.icon);

    let element;
    if (React.isValidElement(icon)) {
      // we need icon to change color after it's selected, so we send the color and style to
      // custom element
      element = React.cloneElement(icon, { style: styles.icon, color });
    } else {
      element = (
        <Icon name={icon} style={styles.icon} color={color} iconSet={iconSet} />
      );
    }
    return element;
  }

  renderLabel(styles) {
    const { label } = this.props;

    if (!label) {
      return null;
    }

    return <Text style={styles.label}>{label}</Text>;
  }

  render() {
    const { onPress, testID, disabled } = this.props;

    const styles = getStyles(this.props, this.context);

    return (
      <RippleFeedback disabled={disabled} testID={testID} onPress={onPress}>
        <View style={styles.container} pointerEvents="box-only">
          {this.renderIcon(styles)}
          {this.renderLabel(styles)}
        </View>
      </RippleFeedback>
    );
  }
}

BottomNavigationAction.propTypes = propTypes;
BottomNavigationAction.defaultProps = defaultProps;

export default withTheme(BottomNavigationAction);
<|endoftext|>


<commit_before>angular.module('orderCloud')
    .directive('ocIfRoles', OrderCloudIfRoles);

/**
 * @ngdoc directive
 * @name ocIfRoles
 *
 * @description
 * Shows/hides elements based on user's roles and provided required roles.
 *
 *
 * @examples
 * 1) If only one role is required, provide that role as the directive attribute's value
 *

 *
 * 2) If multiple roles are required, provide an array with all roles listed as directive attribute's value
 *

 *
 * 3) If only one of numerous roles are required, provide a || delimited list of roles as directive attribute's value
 *

 *
 * 4) RoleGroup alias can be configured ahead of time using the ocRolesProvider -- RoleGroups can be configured to compare for ANY or ALL provided roles
 *

 */

function OrderCloudIfRoles(ocRoles, $ocRoles) {
    var directive = {
        scope: {
            ocIfRoles: '@'
        },
        multiElement: true,
        restrict: 'A',
        priority: 599, //ngIf has priority 600 and terminal: true -- therefore, this directive is ignored if ngIf removes element
        link: link
    };

    function link(scope, element, attr) {
        var roleGroups = $ocRoles.GetRoleGroups();
        var ocIfRolesObj = scope.$eval(scope.ocIfRoles);
        if (typeof ocIfRolesObj == 'object') {
            analyzeRoles(ocIfRolesObj.Items, ocIfRolesObj.Any);
        } else if (scope.ocIfRoles && !/[^a-z]/i.test(scope.ocIfRoles)) {
            if (roleGroups[scope.ocIfRoles]) {
                //single string role group
                var roleGroup = roleGroups[scope.ocIfRoles];
                analyzeRoles(roleGroup.Roles, roleGroup.Type === 'Any');
            } else {
                //single string role
                analyzeRoles([scope.ocIfRoles]);
            }
        } else if (scope.ocIfRoles.split(' || ').length > 1) {
            //pipe delimited string values
            analyzeRoles(scope.ocIfRoles.split(' || '), true);
        } else {
            scope.$watch('ocIfRoles', function ocIfWatchAction(value) {
                if (angular.isArray(value) && value.length && (typeof value[0] == 'string')) {
                    //interpolated array value
                    analyzeRoles(value);
                }
            });
        }

        function analyzeRoles(requiredRoles, any) {
            if (!ocRoles.UserIsAuthorized(requiredRoles, any)) {
                removeElement();
            }
        }

        function removeElement() {
            element.before('');
            element.remove();
        }
    }

    return directive;
}<commit_msg>oc-if-roles directive: - Remove isolated scope to avoid multiple attribute conflict errors - Add object notation example<commit_after>angular.module('orderCloud')
    .directive('ocIfRoles', OrderCloudIfRoles);

/**
 * @ngdoc directive
 * @name ocIfRoles
 *
 * @description
 * Shows/hides elements based on user's roles and provided required roles.
 *
 *
 * @examples
 * 1) If only one role is required, provide that role as the directive attribute's value
 *

 *
 * 2) If multiple roles are required, provide an array with all roles listed as directive attribute's value
 *

 *
 * 3) If only one of numerous roles are required, provide a || delimited list of roles as directive attribute's value
 *

 *
 * 4) RoleGroup alias can be configured ahead of time using the ocRolesProvider -- RoleGroups can be configured to compare for ANY or ALL provided roles
 *

 *
 * 5) Object notation similar to that used in ocNavItems can also be used. This can include multiple Roles and/or RoleGroups
 *

 */

function OrderCloudIfRoles(ocRoles, $ocRoles) {
    var directive = {
        multiElement: true,
        restrict: 'A',
        priority: 599, //ngIf has priority 600 and terminal: true -- therefore, this directive is ignored if ngIf removes element
        link: link
    };

    function link(scope, element, attr) {
        //Use attr.ocIfRoles to avoid need for isolated scope
        var attrValue = attr.ocIfRoles;
        var roleGroups = $ocRoles.GetRoleGroups();
        var ocIfRolesObj = scope.$eval(attrValue);
        if (typeof ocIfRolesObj == 'object') {
            analyzeRoles(ocIfRolesObj.Items, ocIfRolesObj.Any);
        } else if (attrValue && !/[^a-z]/i.test(attrValue)) {
            if (roleGroups[attrValue]) {
                //single string role group
                var roleGroup = roleGroups[attrValue];
                analyzeRoles(roleGroup.Roles, roleGroup.Type === 'Any');
            } else {
                //single string role
                analyzeRoles([attrValue]);
            }
        } else if (attrValue.split(' || ').length > 1) {
            //pipe delimited string values
            analyzeRoles(attrValue.split(' || '), true);
        } else {
            scope.$watch('ocIfRoles', function ocIfWatchAction(value) {
                if (angular.isArray(value) && value.length && (typeof value[0] == 'string')) {
                    //interpolated array value
                    analyzeRoles(value);
                }
            });
        }

        function analyzeRoles(requiredRoles, any) {
            if (!ocRoles.UserIsAuthorized(requiredRoles, any)) {
                removeElement();
            }
        }

        function removeElement() {
            element.before('');
            element.remove();
        }
    }

    return directive;
}<|endoftext|>


<commit_before>define([
	"Ember",
	"config",
	"components/list/ListItemComponent",
	"Moment",
	"hbs!templates/components/list/SubscriptionItemComponent"
], function(
	Ember,
	config,
	ListItemComponent,
	Moment,
	layout
) {

	var get = Ember.get;
	var getOwner = Ember.getOwner;
	var alias = Ember.computed.alias;

	var subscriptionEditUrl   = config.twitch[ "subscription" ][ "edit-url" ];
	var subscriptionCancelUrl = config.twitch[ "subscription" ][ "cancel-url" ];

	return ListItemComponent.extend({
		layout: layout,
		classNames: [ "subscription-item-component" ],
		attributeBindings: [ "style" ],

		product  : alias( "content.product" ),
		channel  : alias( "product.partner_login" ),
		emoticons: alias( "product.emoticons" ),

		style: function() {
			var banner =  get( this, "channel.profile_banner" )
			           || get( this, "channel.video_banner" )
			           || "";
			return ( "background-image:url(\"" + banner + "\")" ).htmlSafe();
		}.property( "channel.profile_banner", "channel.video_banner" ),

		hasEnded: function() {
			var access_end = get( this, "content.access_end" );
			return new Date() > access_end;
		}.property( "content.access_end" ).volatile(),

		ends: function() {
			var access_end = get( this, "content.access_end" );
			return new Moment().to( access_end );
		}.property( "content.access_end" ).volatile(),

		openBrowser: function( url ) {
			var applicationRoute = getOwner( this ).lookup( "route:application" );
			var channel = get( this, "channel.id" );
			url = url.replace( "{channel}", channel );
			applicationRoute.send( "openBrowser", url );
		},

		actions: {
			edit: function( success ) {
				this.openBrowser( subscriptionEditUrl );
				if ( success instanceof Function ) {
					success();
				}
			},

			cancel: function( success ) {
				this.openBrowser( subscriptionCancelUrl );
				if ( success instanceof Function ) {
					success();
				}
			}
		}
	});

});
<commit_msg>Rewrite SubscriptionItemComponent's browser logic<commit_after>define([
	"Ember",
	"config",
	"nwjs/openBrowser",
	"components/list/ListItemComponent",
	"Moment",
	"hbs!templates/components/list/SubscriptionItemComponent"
], function(
	Ember,
	config,
	openBrowser,
	ListItemComponent,
	Moment,
	layout
) {

	var get = Ember.get;
	var alias = Ember.computed.alias;

	var subscriptionEditUrl   = config.twitch[ "subscription" ][ "edit-url" ];
	var subscriptionCancelUrl = config.twitch[ "subscription" ][ "cancel-url" ];

	return ListItemComponent.extend({
		layout: layout,
		classNames: [ "subscription-item-component" ],
		attributeBindings: [ "style" ],

		product  : alias( "content.product" ),
		channel  : alias( "product.partner_login" ),
		emoticons: alias( "product.emoticons" ),

		style: function() {
			var banner =  get( this, "channel.profile_banner" )
			           || get( this, "channel.video_banner" )
			           || "";
			return ( "background-image:url(\"" + banner + "\")" ).htmlSafe();
		}.property( "channel.profile_banner", "channel.video_banner" ),

		hasEnded: function() {
			var access_end = get( this, "content.access_end" );
			return new Date() > access_end;
		}.property( "content.access_end" ).volatile(),

		ends: function() {
			var access_end = get( this, "content.access_end" );
			return new Moment().to( access_end );
		}.property( "content.access_end" ).volatile(),

		openBrowser: function( url ) {
			var channel = get( this, "channel.id" );
			if ( !channel ) { return Promise.reject(); }

			url = url.replace( "{channel}", channel );
			openBrowser( url );
			return Promise.resolve();
		},

		actions: {
			edit: function( success, failure ) {
				this.openBrowser( subscriptionEditUrl )
					.then( success, failure )
					.catch(function() {});
			},

			cancel: function( success, failure ) {
				this.openBrowser( subscriptionCancelUrl )
					.then( success, failure )
					.catch(function() {});
			}
		}
	});

});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

/**
 * Controller for the "new story" modal popup.
 */
angular.module('sb.story').controller('StoryModalController',
    function ($scope, $modalInstance, params, Project, Story, Task) {
        'use strict';

        $scope.projects = Project.browse({});
        $scope.story = new Story({title: ''});
        $scope.tasks = [new Task({
            title: '',
            project_id: params.projectId || null
        })];

        var lastTitle = '', trackingStoryTitle = true;
        $scope.$on('$destroy', $scope.$watch(
            function () {
                return $scope.story.title;
            },
            function (newTitle) {

                // Exit if we've set a custom title.
                if (!trackingStoryTitle) {
                    return;
                }

                // Get the first task in the list.
                var task = $scope.tasks[0];
                if (trackingStoryTitle && task.title === lastTitle) {
                    task.title = newTitle;
                    lastTitle = newTitle;
                } else {
                    trackingStoryTitle = false;
                }
            }
        ));

        /**
         * Saves the story, then saves all the tasks associated with that
         * story.
         */
        $scope.save = function () {
            $scope.story.$create(function (story) {

                var resolvingTasks = $scope.tasks.length;

                // Now that we've created the task, save all the tasks.
                $scope.tasks.forEach(function (task) {
                    task.story_id = story.id;
                    task.$create(function () {
                        resolvingTasks--;
                        if (resolvingTasks === 0) {
                            $modalInstance.close(story);
                        }
                    });
                });
            });
        };

        /**
         * Close this modal without saving.
         */
        $scope.close = function () {
            $modalInstance.dismiss('cancel');
        };

        /**
         * Add another task.
         */
        $scope.addTask = function () {
            // When adding a new modal, grab the project ID from the last
            // item in the list.

            var lastTask = $scope.tasks[$scope.tasks.length - 1];
            $scope.tasks.push(new Task({
                project_id: lastTask.project_id
            }));
        };

        /**
         * Remove a task from the task list, but only if we have
         * more than one task.
         */
        $scope.removeTask = function (task) {
            if ($scope.tasks.length < 2) {
                return;
            }
            var idx = $scope.tasks.indexOf(task);
            $scope.tasks.splice(idx, 1);
        };

        /**
         * Project typeahead search method.
         */
        $scope.searchProjects = function (value) {
            return Project.browse({name: value, limit: 10}).$promise;
        };

        /**
         * Formats the project name.
         */
        $scope.formatProjectName = function (model) {
            if (!!model) {
                return model.name;
            }
            return '';
        };

        /**
         * Select a new project.
         */
        $scope.selectNewProject = function (model, task) {
            task.project_id = model.id;
        };
    })
;
<commit_msg>Story project is defaulted to the current project if available<commit_after>/*
 * Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

/**
 * Controller for the "new story" modal popup.
 */
angular.module('sb.story').controller('StoryModalController',
    function ($scope, $modalInstance, params, Project, Story, Task) {
        'use strict';

        $scope.projects = Project.browse({});
        $scope.story = new Story({title: '',
            project_id: params.projectId || null});

        $scope.tasks = [new Task({
            project_id: params.projectId || null
        })];

        // Preload the project
        if (params.projectId) {
            Project.get({
                id: params.projectId
            }, function (project) {
                $scope.asyncProject = project;
            });
        }

        var lastTitle = '', trackingStoryTitle = true;
        $scope.$on('$destroy', $scope.$watch(
            function () {
                return $scope.story.title;
            },
            function (newTitle) {

                // Exit if we've set a custom title.
                if (!trackingStoryTitle) {
                    return;
                }

                // Get the first task in the list.
                var task = $scope.tasks[0];
                if (trackingStoryTitle && task.title === lastTitle) {
                    task.title = newTitle;
                    lastTitle = newTitle;
                } else {
                    trackingStoryTitle = false;
                }
            }
        ));

        /**
         * Saves the story, then saves all the tasks associated with that
         * story.
         */
        $scope.save = function () {
            $scope.story.$create(function (story) {

                var resolvingTasks = $scope.tasks.length;

                // Now that we've created the task, save all the tasks.
                $scope.tasks.forEach(function (task) {
                    task.story_id = story.id;
                    task.$create(function () {
                        resolvingTasks--;
                        if (resolvingTasks === 0) {
                            $modalInstance.close(story);
                        }
                    });
                });
            });
        };

        /**
         * Close this modal without saving.
         */
        $scope.close = function () {
            $modalInstance.dismiss('cancel');
        };

        /**
         * Add another task.
         */
        $scope.addTask = function () {
            // When adding a new modal, grab the project ID from the last
            // item in the list.

            var lastTask = $scope.tasks[$scope.tasks.length - 1];
            var project_id = lastTask.project_id;

            if (! project_id ) {
                // if we are in the scope of a project, grab the project ID
                // from that scope.
                project_id = params.projectId || null;
            }

            var current_task = new Task({project_id: project_id});
            if ( project_id ) {
                // Preload the project
                Project.get({
                    id: project_id
                }, function (project) {
                    $scope.asyncProject = project;
                });
            }
            $scope.tasks.push(current_task);
        };

        /**
         * Remove a task from the task list, but only if we have
         * more than one task.
         */
        $scope.removeTask = function (task) {
            if ($scope.tasks.length < 2) {
                return;
            }
            var idx = $scope.tasks.indexOf(task);
            $scope.tasks.splice(idx, 1);
        };

        /**
         * Project typeahead search method.
         */
        $scope.searchProjects = function (value) {
            return Project.browse({name: value, limit: 10}).$promise;
        };

        /**
         * Formats the project name.
         */
        $scope.formatProjectName = function (model) {
            if (!!model) {
                return model.name;
            }
            return '';
        };

        /**
         * Select a new project.
         */
        $scope.selectNewProject = function (model, task) {
            task.project_id = model.id;
        };
    })
;
<|endoftext|>


<commit_before>(function () {
    var Ext = window.Ext4 || window.Ext;

    Ext.define('Rally.apps.roadmapplanningboard.PlanningBoardColumn', {
        extend: 'Rally.ui.cardboard.Column',
        alias: 'widget.planningboardcolumn',

        mixins: {
            maskable: 'Rally.ui.mask.Maskable'
        },

        requires: [
            'Rally.apps.roadmapplanningboard.plugin.OrcaColumnDropController'
        ],

        config: {
            storeConfig: {
                fetch: ['Value', 'FormattedID', 'Owner','Name', 'PreliminaryEstimate', 'DisplayColor']
            },
            dropControllerConfig: {
                ptype: 'orcacolumndropcontroller'
            },
            moreItemsConfig: {
                token: '/portfolioitems'
            },
            cardConfig: {
                showIconsAndHighlightBorder: true,
                showPlusIcon: false,
                showColorIcon: true,
                showGearIcon: true,
                showReadyIcon: false,
                showBlockedIcon: false,
                showEditMenuItem: true,
                showCopyMenuItem: false,
                showSplitMenuItem: false,
                showDeleteMenuItem: true
            }
        },

        initComponent: function () {
            this.callParent(arguments);
            return this.on('beforerender', function () {
                var cls;

                cls = 'planning-column';
                this.getContentCell().addCls(cls);
                return this.getColumnHeaderCell().addCls(cls);
            }, this, {
                single: true
            });
        },

        isMatchingRecord: function () {
            return true;
        },

        _getProgressBarHtml: function () {
            return '

';
        },

        findCardInfo: function (searchCriteria, includeHiddenCards) {
            var card, index, _i, _len, _ref;

            searchCriteria = searchCriteria.get && searchCriteria.getId() ? searchCriteria.getId() : searchCriteria;
            _ref = this.getCards(includeHiddenCards);
            for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
                card = _ref[index];
                if (card.getRecord().getId() === searchCriteria || card.getEl() === searchCriteria || card.getEl() === Ext.get(searchCriteria)) {
                    return {
                        record: card.getRecord(),
                        index: index,
                        card: card
                    };
                }
            }
            return null;
        },

        destroy: function () {
            var plugin, _i, _len, _ref;

            _ref = this.plugins;
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                plugin = _ref[_i];
                if (plugin !== null) {
                    plugin.destroy();
                }
            }
            return this.callParent(arguments);
        }
    });

})();
<commit_msg>DE18968 - Remove 'More Items' link from columns for RPB<commit_after>(function () {
    var Ext = window.Ext4 || window.Ext;

    Ext.define('Rally.apps.roadmapplanningboard.PlanningBoardColumn', {
        extend: 'Rally.ui.cardboard.Column',
        alias: 'widget.planningboardcolumn',

        mixins: {
            maskable: 'Rally.ui.mask.Maskable'
        },

        requires: [
            'Rally.apps.roadmapplanningboard.plugin.OrcaColumnDropController'
        ],

        config: {
            storeConfig: {
                fetch: ['Value', 'FormattedID', 'Owner','Name', 'PreliminaryEstimate', 'DisplayColor']
            },
            dropControllerConfig: {
                ptype: 'orcacolumndropcontroller'
            },
            moreItemsConfig: {
                hidden: true,
                token: '/portfolioitems'
            },
            cardConfig: {
                showIconsAndHighlightBorder: true,
                showPlusIcon: false,
                showColorIcon: true,
                showGearIcon: true,
                showReadyIcon: false,
                showBlockedIcon: false,
                showEditMenuItem: true,
                showCopyMenuItem: false,
                showSplitMenuItem: false,
                showDeleteMenuItem: true
            }
        },

        initComponent: function () {
            this.callParent(arguments);
            return this.on('beforerender', function () {
                var cls;

                cls = 'planning-column';
                this.getContentCell().addCls(cls);
                return this.getColumnHeaderCell().addCls(cls);
            }, this, {
                single: true
            });
        },

        isMatchingRecord: function () {
            return true;
        },

        _getProgressBarHtml: function () {
            return '

';
        },

        findCardInfo: function (searchCriteria, includeHiddenCards) {
            var card, index, _i, _len, _ref;

            searchCriteria = searchCriteria.get && searchCriteria.getId() ? searchCriteria.getId() : searchCriteria;
            _ref = this.getCards(includeHiddenCards);
            for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
                card = _ref[index];
                if (card.getRecord().getId() === searchCriteria || card.getEl() === searchCriteria || card.getEl() === Ext.get(searchCriteria)) {
                    return {
                        record: card.getRecord(),
                        index: index,
                        card: card
                    };
                }
            }
            return null;
        },

        destroy: function () {
            var plugin, _i, _len, _ref;

            _ref = this.plugins;
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                plugin = _ref[_i];
                if (plugin !== null) {
                    plugin.destroy();
                }
            }
            return this.callParent(arguments);
        }
    });

})();
<|endoftext|>


<commit_before>module.exports = async function(context, commands) {
  commands.meta.setTitle('Test Grafana SPA');
  commands.meta.setDescription(
    'Test the first page, click the timepicker and then choose <b>Last 30 days</b> and measure that page.'
  );
  await commands.measure.start(
    'https://dashboard.sitespeed.io/d/000000064/drilldown?orgId=1',
    'pageTimingMetricsDefault'
  );
  await commands.click.byClassName('toolbar-button css-1t4b87h-toolbar-button');
  await commands.wait.byTime(3000);
  await commands.measure.start('pageTimingMetrics30Days');
  await commands.click.byXpathAndWait(
    '/html/body/grafana-app/div/div/react-container/div/div[1]/div[3]/div/div[1]/div/div/div[1]/div[2]/div[1]/div[2]/div[11]'
  );
  await commands.wait.byTime(5000);
  return commands.measure.stop();
};
<commit_msg>remove unused file<commit_after><|endoftext|>


<commit_before>import React, { Component, PropTypes } from "react";
import _ from "lodash";

let groups = {};
let userAddedComponents = {};

let internalSupportedComponents = {
  TextField: {
    getValueFromChangeEvent: (args)=>{
      return args[0].target.value;
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0]);
    },
    errorPropName: "errorText"
  },
  SelectField: {
    getValueFromChangeEvent: (args)=>{
      return args[1];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0], args[1], args[2]);
    },
    errorPropName: "errorText"
  },
  DateRangePicker: {
    getValueFromChangeEvent: (args)=>{
      return args[0];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0]);
    },
    errorPropName: "errorText"
  },
  DatePicker: {
    getValueFromChangeEvent: (args)=>{
      return args[1];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[1]);
    }
  },
  Select: {
    getValueFromChangeEvent: (args)=>{
      return args[0];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0]);
    }
  }
};

function getAllSupportedComponent(){
  return Object.assign({}, internalSupportedComponents, userAddedComponents);
}

let fieldValidatorCore = {
  addSupport: (name, getValueFromChangeEvent, changeCallBackCaller, errorPropName) => {
    userAddedComponents[name] = {
      getValueFromChangeEvent: getValueFromChangeEvent,
      changeCallBackCaller: changeCallBackCaller,
      errorPropName: errorPropName
    };
  },
  removeSupport: (name) => {
    if (userAddedComponents[name] !== undefined){
      delete userAddedComponents.name;
    } else {
      console.info("Field-Validator", "removeComponent: didn't find the component");
    }
  },
  getAllCurrentlySupported: ()=>{
    return getAllSupportedComponent();
  },
  checkGroup: (groupName) => {
    let valid = true;
    let validityRes = {
      isValid: true,
      validCompponents: [],
      inValidComponents: []
    };
    let allCompsInGroup = groups[groupName];
    if (allCompsInGroup === undefined) {
      valid = true;
    } else {
      allCompsInGroup.forEach((v) => {
        if (v.isValid === false){
          valid = false;
          validityRes.inValidComponents.push(v.props.children);
        } else {
          validityRes.validCompponents.push(v.props.children);
        }
      });
    }
    validityRes.isValid = valid;
    return validityRes;
  }
};

class Validation extends Component {

  constructor(props) {
    super(props);

    this.state = {
      childCompoentToRender: null,
      unControlledChild: true,
      isValid: true
    };
    this.testValidity = this.testValidity.bind(this);
  }

  get isValid() {
    return this.testValidity(this.currentChildValue);
  }

  componentWillReceiveProps(props){
    if (this.state.unsupported !== true){
      if (this.state.unControlledChild === false){
        let isDerivedValueComing = false;
        if (!(_.isEqual(this.originalVal, props.children.props[this.props.valueProp]))){
          isDerivedValueComing = true;
        }
        if (this.childModified === true || isDerivedValueComing){
          if (!(_.isEqual(this.currentChildValue, props.children.props[this.props.valueProp]))){
            this.baseProps[this.props.valueProp] = props.children.props[this.props.valueProp];
            this.testValidity(props.children.props.value);
          }
        }
      }
    }
  }

  componentWillMount() {
    this.typeOfCompnent = this.props.children.type.displayName ? this.props.children.type.displayName : this.props.children.type.name;
    if (userAddedComponents[this.typeOfCompnent] !== undefined){
      this.mountingSetup(userAddedComponents[this.typeOfCompnent].getValueFromChangeEvent, userAddedComponents[this.typeOfCompnent].changeCallBackCaller);
    } else {
      if (internalSupportedComponents[this.typeOfCompnent] !== undefined){
        this.mountingSetup(internalSupportedComponents[this.typeOfCompnent].getValueFromChangeEvent, internalSupportedComponents[this.typeOfCompnent].changeCallBackCaller);
      } else {
        console.error("Field-Validator",
          `${this.typeOfCompnent} is currently not supported by field-validator,
          Please use fieldValidatorCore.addSupport to add support for the component, For more information please refer to docs`);
        console.info("Field-Validator", `Ignoring ${this.typeOfCompnent}, and it will work as if it was not wraped with Validation tag`);
        this.mountingSetup(null, null, true);
      }
    }
  }

  componentDidMount(){
    if (this.props.group && this.state.unsupported !== true){
      if (groups[this.props.group] === undefined){
        groups[this.props.group] = [];
      }
      groups[this.props.group].push(this);
    }
  }

  mountingSetup(valueFromArgs, argsToPassToActualHandler, unsupportedFlag){
    if (unsupportedFlag === true){
      this.setState({
        childCompoentToRender: this.props.children,
        unsupported: unsupportedFlag
      });
    } else {
      this.baseProps = _.cloneDeep(this.props.children.props);
      let isUncontrolled = true;
      if (this.baseProps[this.props.valueProp] !== undefined){
        isUncontrolled = false;
        this.originalVal = this.baseProps[this.props.valueProp];
        this.currentChildValue = this.baseProps[this.props.valueProp];
      } else {
        //try with default prop
        if (this.baseProps[this.props.defaultValueProp] !== undefined){
          this.originalVal = this.baseProps[this.props.defaultValueProp];
          this.currentChildValue = this.baseProps[this.props.defaultValueProp];
        }
      }

      let oldOnChange = this.baseProps[this.props.onChangeCallback];
      this.baseProps[this.props.onChangeCallback] = (...args)=>{
        let rArgs = valueFromArgs(args);
        this.childModified = true;
        if (!this.absorbing){
          this.absorbing = true;
          this.baseProps[this.props.valueProp] = rArgs;
          this.currentChildValue = rArgs;
          this.testValidity(rArgs);
          if (oldOnChange) {
            argsToPassToActualHandler(oldOnChange, args);
          }
          this.absorbing = false;
        }
      };
      let theComponent = React.cloneElement(this.props.children, this.baseProps);
      this.setState({
        childCompoentToRender: theComponent,
        unControlledChild: isUncontrolled
      });
    }
  }

  testValidity(val){
    let res = {
      isValid: true,
      errorMessage: null
    };
    try {
      this.props.validators.every((v)=>{
        if (v.validator(val) === false){
          res.isValid = false;
          res.errorMessage = v.errorMessage;
          return false;
        } else {
          return true;
        }
      });
    } catch (err) {
      console.error(err);
    }
    if (res.isValid === false){
      if (getAllSupportedComponent()[this.typeOfCompnent].errorPropName){
        this.baseProps[getAllSupportedComponent()[this.typeOfCompnent].errorPropName] = res.errorMessage;
      }
      this.setState({
        childCompoentToRender: React.cloneElement(this.props.children, this.baseProps),
        isValid: false,
        errorText: res.errorMessage
      });
    } else {
      if (getAllSupportedComponent()[this.typeOfCompnent].errorPropName){
        this.baseProps[getAllSupportedComponent()[this.typeOfCompnent].errorPropName] = null;
      }
      this.setState({
        childCompoentToRender: React.cloneElement(this.props.children, this.baseProps),
        isValid: true,
        errorText: null
      });
    }
    return res.isValid;
  }

  render() {
    if (this.state.unsupported === true){
      return this.props.children;
    } else {
      return (

        {
          this.state.childCompoentToRender ? this.state.childCompoentToRender : ""
        }{
          (!(getAllSupportedComponent()[this.typeOfCompnent].errorPropName)) && this.state.isValid === false ?

            {
              this.state.errorText
            }

 : ""
        }

      );
    }
  }
}

Validation.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.element
  ]),
  validators: PropTypes.array.isRequired,
  onChangeCallback: PropTypes.string,
  group: PropTypes.string,
  valueProp: PropTypes.string,
  defaultValueProp: PropTypes.string,
  errorStyle: PropTypes.object
};

Validation.defaultProps = {
  onChangeCallback: "onChange",
  valueProp: "value",
  defaultValueProp: "defaultValue",
  errorStyle: {}
};

export {Validation, fieldValidatorCore};
<commit_msg>fixing minor bug while component being unmounted<commit_after>import React, { Component, PropTypes } from "react";
import _ from "lodash";

function generateUUID() {
  var basex = 16;
  var d = new Date().getTime();
  if (window.performance && typeof window.performance.now === "function"){
    d += performance.now(); //use high-precision timer if available
  }
  var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
    var r = (d + Math.random()*basex)%basex | 0;
    d = Math.floor(d/basex);
    var sr = 0x3;
    var srx = r&sr;
    var srx1 = 0x8;
    return (c==="x" ? r : (srx|srx1)).toString(basex);
  });
  return uuid;
}

let groups = {};
let userAddedComponents = {};

let internalSupportedComponents = {
  TextField: {
    getValueFromChangeEvent: (args)=>{
      return args[0].target.value;
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0]);
    },
    errorPropName: "errorText"
  },
  SelectField: {
    getValueFromChangeEvent: (args)=>{
      return args[1];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0], args[1], args[2]);
    },
    errorPropName: "errorText"
  },
  DateRangePicker: {
    getValueFromChangeEvent: (args)=>{
      return args[0];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0]);
    },
    errorPropName: "errorText"
  },
  DatePicker: {
    getValueFromChangeEvent: (args)=>{
      return args[1];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[1]);
    }
  },
  Select: {
    getValueFromChangeEvent: (args)=>{
      return args[0];
    },
    changeCallBackCaller: (callback, args)=>{
      callback(args[0]);
    }
  }
};

function getAllSupportedComponent(){
  return Object.assign({}, internalSupportedComponents, userAddedComponents);
}

let fieldValidatorCore = {
  addSupport: (name, getValueFromChangeEvent, changeCallBackCaller, errorPropName) => {
    userAddedComponents[name] = {
      getValueFromChangeEvent: getValueFromChangeEvent,
      changeCallBackCaller: changeCallBackCaller,
      errorPropName: errorPropName
    };
  },
  removeSupport: (name) => {
    if (userAddedComponents[name] !== undefined){
      delete userAddedComponents.name;
    } else {
      console.info("Field-Validator", "removeComponent: didn't find the component");
    }
  },
  getAllCurrentlySupported: ()=>{
    return getAllSupportedComponent();
  },
  checkGroup: (groupName) => {
    let valid = true;
    let validityRes = {
      isValid: true,
      validCompponents: [],
      inValidComponents: []
    };
    let allCompsInGroup = groups[groupName];
    if (allCompsInGroup === undefined) {
      valid = true;
    } else {
      allCompsInGroup.forEach((v1) => {
        let v = v1.component;
        if (v.isValid === false){
          valid = false;
          validityRes.inValidComponents.push(v.props.children);
        } else {
          validityRes.validCompponents.push(v.props.children);
        }
      });
    }
    validityRes.isValid = valid;
    return validityRes;
  }
};

class Validation extends Component {

  constructor(props) {
    super(props);

    this.state = {
      childCompoentToRender: null,
      unControlledChild: true,
      isValid: true,
      id: generateUUID()
    };
    this.testValidity = this.testValidity.bind(this);
  }

  get isValid() {
    return this.testValidity(this.currentChildValue);
  }

  componentWillReceiveProps(props){
    if (this.state.unsupported !== true){
      if (this.state.unControlledChild === false){
        let isDerivedValueComing = false;
        if (!(_.isEqual(this.originalVal, props.children.props[this.props.valueProp]))){
          isDerivedValueComing = true;
        }
        if (this.childModified === true || isDerivedValueComing){
          if (!(_.isEqual(this.currentChildValue, props.children.props[this.props.valueProp]))){
            this.baseProps[this.props.valueProp] = props.children.props[this.props.valueProp];
            this.testValidity(props.children.props.value);
          }
        }
      }
    }
  }

  componentWillMount() {
    this.typeOfCompnent = this.props.children.type.displayName ? this.props.children.type.displayName : this.props.children.type.name;
    if (userAddedComponents[this.typeOfCompnent] !== undefined){
      this.mountingSetup(userAddedComponents[this.typeOfCompnent].getValueFromChangeEvent, userAddedComponents[this.typeOfCompnent].changeCallBackCaller);
    } else {
      if (internalSupportedComponents[this.typeOfCompnent] !== undefined){
        this.mountingSetup(internalSupportedComponents[this.typeOfCompnent].getValueFromChangeEvent, internalSupportedComponents[this.typeOfCompnent].changeCallBackCaller);
      } else {
        console.error("Field-Validator",
          `${this.typeOfCompnent} is currently not supported by field-validator,
          Please use fieldValidatorCore.addSupport to add support for the component, For more information please refer to docs`);
        console.info("Field-Validator", `Ignoring ${this.typeOfCompnent}, and it will work as if it was not wraped with Validation tag`);
        this.mountingSetup(null, null, true);
      }
    }
  }

  componentDidMount(){
    if (this.props.group && this.state.unsupported !== true){
      if (groups[this.props.group] === undefined){
        groups[this.props.group] = [];
      }
      groups[this.props.group].push({
        id: this.state.id,
        component: this
      });
    }
  }

  mountingSetup(valueFromArgs, argsToPassToActualHandler, unsupportedFlag){
    if (unsupportedFlag === true){
      this.setState({
        childCompoentToRender: this.props.children,
        unsupported: unsupportedFlag
      });
    } else {
      this.baseProps = _.cloneDeep(this.props.children.props);
      let isUncontrolled = true;
      if (this.baseProps[this.props.valueProp] !== undefined){
        isUncontrolled = false;
        this.originalVal = this.baseProps[this.props.valueProp];
        this.currentChildValue = this.baseProps[this.props.valueProp];
      } else {
        //try with default prop
        if (this.baseProps[this.props.defaultValueProp] !== undefined){
          this.originalVal = this.baseProps[this.props.defaultValueProp];
          this.currentChildValue = this.baseProps[this.props.defaultValueProp];
        }
      }

      let oldOnChange = this.baseProps[this.props.onChangeCallback];
      this.baseProps[this.props.onChangeCallback] = (...args)=>{
        let rArgs = valueFromArgs(args);
        this.childModified = true;
        if (!this.absorbing){
          this.absorbing = true;
          this.baseProps[this.props.valueProp] = rArgs;
          this.currentChildValue = rArgs;
          this.testValidity(rArgs);
          if (oldOnChange) {
            argsToPassToActualHandler(oldOnChange, args);
          }
          this.absorbing = false;
        }
      };
      let theComponent = React.cloneElement(this.props.children, this.baseProps);
      this.setState({
        childCompoentToRender: theComponent,
        unControlledChild: isUncontrolled
      });
    }
  }

  testValidity(val){
    let res = {
      isValid: true,
      errorMessage: null
    };
    try {
      this.props.validators.every((v)=>{
        if (v.validator(val) === false){
          res.isValid = false;
          res.errorMessage = v.errorMessage;
          return false;
        } else {
          return true;
        }
      });
    } catch (err) {
      console.error(err);
    }
    if (res.isValid === false){
      if (getAllSupportedComponent()[this.typeOfCompnent].errorPropName){
        this.baseProps[getAllSupportedComponent()[this.typeOfCompnent].errorPropName] = res.errorMessage;
      }
      this.setState({
        childCompoentToRender: React.cloneElement(this.props.children, this.baseProps),
        isValid: false,
        errorText: res.errorMessage
      });
    } else {
      if (getAllSupportedComponent()[this.typeOfCompnent].errorPropName){
        this.baseProps[getAllSupportedComponent()[this.typeOfCompnent].errorPropName] = null;
      }
      this.setState({
        childCompoentToRender: React.cloneElement(this.props.children, this.baseProps),
        isValid: true,
        errorText: null
      });
    }
    return res.isValid;
  }

  componentWillUnmount(){
    if (this.props.group){
      _.remove(groups[this.props.group], (v)=>{
        return v.id === this.state.id;
      });
    }
  }

  render() {
    if (this.state.unsupported === true){
      return this.props.children;
    } else {
      return (

        {
          this.state.childCompoentToRender ? this.state.childCompoentToRender : ""
        }{
          (!(getAllSupportedComponent()[this.typeOfCompnent].errorPropName)) && this.state.isValid === false ?

            {
              this.state.errorText
            }

 : ""
        }

      );
    }
  }
}

Validation.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.element
  ]),
  validators: PropTypes.array.isRequired,
  onChangeCallback: PropTypes.string,
  group: PropTypes.string,
  valueProp: PropTypes.string,
  defaultValueProp: PropTypes.string,
  errorStyle: PropTypes.object
};

Validation.defaultProps = {
  onChangeCallback: "onChange",
  valueProp: "value",
  defaultValueProp: "defaultValue",
  errorStyle: {}
};

export {Validation, fieldValidatorCore};
<|endoftext|>


<commit_before>// tpl - a general purpose template cli
// (c) 2011 Paul Vorbach. Licensed under MIT.
;(function() {

module.exports.version = 'v0.1.1';

var fs = require('fs');
var path = require('path');
var confdir = require('confdir');
var append = require('append');

// default configuration
var defaultConf = {
  parsers: {
    default: 'props-markdown'
  },
  templates: {
    default: {
      file: 'default.ejs',
      engine: 'ejs',
      ext: '.txt'
    }
  }
};

function apply(file, opt, cb) {
  // look for configuration directory
  confdir(process.cwd(), 'tpl', function(err, dir) {
    try {
      if (err)
        dir = path.resolve(__dirname, '.tpl');

      // read configuration file
      var json = fs.readFileSync(path.resolve(dir, 'conf.json'), 'utf8');
      var conf = JSON.parse(json);
      // set configuration
      conf = append(defaultConf, conf);

      var ext = path.extname(file);
      var parser;
      // determine parser
      if (typeof conf.parsers[ext] != 'undefined')
        parser = conf.parser[ext];
      else
        parser = conf.parsers.default;
      // require parser
      parser = require(path.resolve(dir, 'parsers', parser + '.js'));

      // parse file
      var doc = append(opt, parser(file));
      console.log(doc);

      var tpl;
      // determine template and engine
      if (typeof doc.template != 'undefined')
        tpl = conf.templates[doc.template]
      else
        tpl = conf.templates.default;

      // resolve template file
      tpl.file = path.resolve(dir, 'templates', tpl.file);
      // require template engine
      tpl.engine = require(path.resolve(dir, 'templates', tpl.engine + '.js'));

      // render
      cb(null, tpl.engine(tpl.file, doc));
    } catch (err) {
      cb(err);
    }
  });
}

module.exports.apply = apply;

}).call(this);
<commit_msg>Stop printing parsed document<commit_after>// tpl - a general purpose template cli
// (c) 2011 Paul Vorbach. Licensed under MIT.
;(function() {

module.exports.version = 'v0.1.1';

var fs = require('fs');
var path = require('path');
var confdir = require('confdir');
var append = require('append');

// default configuration
var defaultConf = {
  parsers: {
    default: 'props-markdown'
  },
  templates: {
    default: {
      file: 'default.ejs',
      engine: 'ejs',
      ext: '.txt'
    }
  }
};

function apply(file, opt, cb) {
  // look for configuration directory
  confdir(process.cwd(), 'tpl', function(err, dir) {
    try {
      if (err)
        dir = path.resolve(__dirname, '.tpl');

      // read configuration file
      var json = fs.readFileSync(path.resolve(dir, 'conf.json'), 'utf8');
      var conf = JSON.parse(json);
      // set configuration
      conf = append(defaultConf, conf);

      var ext = path.extname(file);
      var parser;
      // determine parser
      if (typeof conf.parsers[ext] != 'undefined')
        parser = conf.parser[ext];
      else
        parser = conf.parsers.default;
      // require parser
      parser = require(path.resolve(dir, 'parsers', parser + '.js'));

      // parse file
      var doc = append(opt, parser(file));

      var tpl;
      // determine template and engine
      if (typeof doc.template != 'undefined')
        tpl = conf.templates[doc.template]
      else
        tpl = conf.templates.default;

      // resolve template file
      tpl.file = path.resolve(dir, 'templates', tpl.file);
      // require template engine
      tpl.engine = require(path.resolve(dir, 'templates', tpl.engine + '.js'));

      // render
      cb(null, tpl.engine(tpl.file, doc));
    } catch (err) {
      cb(err);
    }
  });
}

module.exports.apply = apply;

}).call(this);
<|endoftext|>