<commit_before>/*jslint browser: true */
/*globals Backbone, $, tangelo, vg, _, d3 */

var visfiles;

var app = {};

// Tables of Backbone objects.
app.models = {};
app.collections = {};
app.views = {};

// A model describing a file that contains a Lyra-edited visualization.
app.models.Vis = Backbone.Model.extend({
    initialize: function (options) {
        "use strict";

        options = options || {};
        this.girderApi = options.girderApi;
        this.folderId = options.folderId;
    },

    idAttribute: "_id",

    _upload: function () {
        "use strict";

        var data = JSON.stringify(this.get("lyra")),
            uploadChunks;

        var d = {
                "parentType": "folder",
                "parentId": this.folderId,
                "name": this.get("name"),
                "size": data.length
            };

        console.log(d);

        uploadChunks = _.bind(function (upload) {
            var uploadChunk = _.bind(function (start, maxChunkSize) {
                var end,
                    blob,
                    form;

                end = Math.min(start + maxChunkSize, data.length);

                blob = new window.Blob([data.slice(start, end)]);

                form = new window.FormData();
                form.append("offset", start);
                form.append("uploadId", upload._id);
                form.append("chunk", blob);

                Backbone.ajax({
                    url: this.girderApi + "/file/chunk",
                    type: "POST",
                    data: form,
                    contentType: false,
                    processData: false,
                    success: function () {
                        if (end < data.length) {
                            uploadChunk(end, maxChunkSize);
                        }
                    }
                });
            }, this);

            uploadChunk(0, 64 * 1024 * 1024);
        }, this);

        Backbone.ajax({
            url: this.girderApi + "/file",
            type: "POST",
            data: d,
            success: uploadChunks
        });
    },

    save: function () {
        "use strict";

        if (!this.isNew()) {
            // Delete the file from the server, before reuploading the current
            // spec.
            Backbone.ajax({
                url: this.girderApi + "/item/" + this.id,
                method: "DELETE",
                success: _.bind(this._upload, this)
            });
        } else {
            this._upload();
        }
    },

    fetch: function (options) {
        "use strict";

        var url = this.girderApi + "/item/" + this.id + "/download",
            success = options.success || $.noop,
            error = options.error || $.noop;

        Backbone.ajax({
            url: url,
            dataType: "json",
            success: _.bind(function (lyra) {
                this.set("lyra", lyra);
                success(this, lyra, options);
            }, this),
            error: _.bind(function (jqxhr) {
                error(this, jqxhr, options);
            }, this)
        });
    },
});

app.models.Data = Backbone.Model.extend({
    initialize: function (options) {
        "use strict";

        options = options || {};
        this.girderApi = options.girderApi;
    },

    idAttribute: "_id",

    url: function () {
        "use strict";

        return this.girderApi + "/item/" + this.get("_id") + "/download";
    },

    parse: function (response) {
        "use strict";

        return {
            data: response
        };
    }
});

// A collection describing all the Lyra vis files in a Girder instance.
app.collections.Folder = Backbone.Collection.extend({
    model: app.models.Vis,

    initialize: function (models, options) {
        "use strict";

        options = options || {};
        this.folderId = options.folderId;

        this.url = options.girderApi + "/item?folderId=" + options.folderId;
        this.fetch({
            success: function (models) {
                models.forEach(function (m) {
                    m.girderApi = options.girderApi;
                });
            }
        });
    }
});

// A view that renders a Vega visualization.
app.views.Vega = Backbone.View.extend({
    initialize: function (options) {
        "use strict";

        options = options || {};
        this.girderApi = options.girderApi;

        Backbone.on("select:vis", this.loadVis, this);
    },

    loadVis: function (file) {
        "use strict";

        var render = _.bind(function () {
            this.render();
        }, this);

        this.model = file;

        if (file.get("lyra")) {
            render();
        } else {
            file.fetch({
                success: render
            });
        }
    },

    render: function () {
        "use strict";

        vg.parse.spec(this.model.get("lyra").vega, _.bind(function (chart) {
            chart({
                el: this.el,
                renderer: "svg"
            }).update();
        }, this));
    }
});

// A view to "render" a dataset (using a read-only ACE editor instance).
app.views.Data = Backbone.View.extend({
    initialize: function (options) {
        "use strict";

        this.model = new app.models.Data({
            girderApi: options.girderApi
        });

        Backbone.on("select:data", this.loadData, this);
    },

    loadData: function (file) {
        "use strict";

        this.model.set("_id", file.get("_id"));
        this.model.fetch({
            success: _.bind(function () {
                this.render();
            }, this)
        });
    },

    render: function () {
        "use strict";

        console.log(this.model);
    },

    getData: function () {
        "use strict";

        return this.model.get("data");
    }
});

// A collection describing all the data files in a Girder instance.
app.collections.Data = Backbone.Collection.extend({
});

// A view that renders a single file as a list item.
app.views.File = Backbone.View.extend({
    initialize: function (options) {
        "use strict";

        this.selectedEvent = options.selectedEvent;
    },

    tagName: "li",

    events: {
        click: "selected"
    },

    render: function () {
        "use strict";

        d3.select(this.el)
            .append("a")
            .attr("href", "#")
            .html(this.model.get("name"));

        return this;
    },

    selected: function () {
        "use strict";

        if (this.selectedEvent) {
            Backbone.trigger(this.selectedEvent, this.model);
        }
    }
});

// A view that renders a list of files.
app.views.FileMenu = Backbone.View.extend({
    tagName: "div",

    initialize: function (options) {
        "use strict";

        var template;

        options = options || {};
        this.selectedEvent = options.selectedEvent;

        template = _.template($("#vis-files-view-template").html(), {});
        this.$el.html(template);

        // When the collection gains an item, add it to the dropdown menu.
        this.collection.on("add", this.addItem, this);

        // When a visualization is selected, change the dropdown menu text.
        Backbone.on(this.selectedEvent, this.setSelected, this);
    },

    addItem: function (file) {
        "use strict";

        var newitem = new app.views.File({
            className: "file",
            model: file,
            selectedEvent: this.selectedEvent
        });

        this.$el.find("ul")
            .append(newitem.render().el);
    },

    setSelected: function (f) {
        "use strict";

        this.selectedModel = f;

        var label = f.get("name");

        if (f.unsaved) {
            label = "" + label + "";
        }

        label += " ";

        this.$el.find("button")
            .html(label);
    },

    getSelected: function () {
        "use strict";

        return this.selectedModel;
    }
});

$(function () {
    "use strict";

    tangelo.config("config.json", function (config) {
        var main;

        // Issue ajax calls to get the Lyra collection in girder, and then both
        // the visualization and data folders therein.
        $.ajax({
            url: config.girderApi + "/collection",
            type: "GET",
            dataType: "json",
            data: {
                text: config.collection
            },
            success: function (lyraCollection) {
                // Now find the visualizations folder.
                $.ajax({
                    url: config.girderApi + "/folder",
                    type: "GET",
                    dataType: "json",
                    data: {
                        parentType: "collection",
                        parentId: lyraCollection._id,
                        text: config.visFolder
                    },
                    success: function (visFolder) {
                        // Make sure there is a result.
                        if (visFolder.length === 0) {
                            console.warn("No folder '" + config.visFolder + "' found in collection '" + config.collection + "'");
                        }

                        // Find the data folder.
                        $.ajax({
                            url: config.girderApi + "/folder",
                            type: "GET",
                            dataType: "json",
                            data: {
                                parentType: "collection",
                                parentId: lyraCollection._id,
                                text: config.dataFolder
                            },
                            success: function (dataFolder) {
                                // Make sure there is a result.
                                if (dataFolder.length === 0) {
                                    console.warn("No folder '" + config.dataFolder + "' found in collection '" + config.collection + "'");
                                }

                                // Run the actual application.
                                main(config, visFolder[0]._id, dataFolder[0]._id);
                            }
                        });
                    }
                });
            }

        });

        // The main application.
        main = function (config, visFolderId, dataFolderId) {
            var //visfiles,
                visMenu,
                vis,
                datafiles,
                dataMenu,
                data,
                f;

            f = {};

            // A function that launches a Lyra editor window.
            f.launchLyra = function (qargs) {
                var lyra = window.open("/lyra/editor.html?editor=true", "_blank");
                lyra.onload = function () {
                    lyra.postMessage(qargs, window.location.origin);
                };
            };

            f.createNew = function () {
                f.launchLyra({
                    new: true,
                    timeline: null,
                    data: encodeURIComponent(JSON.stringify(data.getData()))
                });
            };

            f.edit = function () {
                var model = vis.model;

                f.launchLyra({
                    new: false,
                    name: model.get("name"),
                    timeline: encodeURIComponent(JSON.stringify(model.get("timeline"))),
                    data: encodeURIComponent(JSON.stringify(model.get("lyra").vega.data[0].values))
                });
            };

            f.save = function () {
                vis.model.save();
            };

            f.receiveMessage = function (e) {
                var model,
                    name;

                if (e.data.new) {
                    name = "Unsaved " + _.uniqueId();

                    // Construct a new Vis model to represent the newly created
                    // Vega visualization.
                    model = new app.models.Vis({
                        girderApi: config.girderApi,
                        folderId: visFolderId,
                        name: name,
                        visName: name,
                        lyra: {
                            timeline: e.data.timeline,
                            vega: e.data.vega
                        }
                    });

                    // Add the model to the vis files list, and simulate its
                    // selection (so that the menu will show it as active, and
                    // it will be rendered to the Vega view).
                    visfiles.add(model);
                    Backbone.trigger("select:vis", model);
                } else {
                    vis.model.set({
                        lyra: {
                            timeline: e.data.timeline,
                            vega: e.data.vega
                        }
                    });
                }
            };

            // The "New" button.
            d3.select("#create")
                .on("click", f.createNew);

            d3.select("#edit")
                .on("click", f.edit);

            d3.select("#save")
                .on("click", f.save);

            // Set up to receive messages.
            window.addEventListener("message", f.receiveMessage, false);

            // A collection of visualization files residing on Girder, and a
            // dropdown menu to select them.
            visfiles = new app.collections.Folder([], {
                girderApi: config.girderApi,
                folderId: visFolderId
            });

            visMenu = new app.views.FileMenu({
                el: "#vis-files-view",
                collection: visfiles,
                selectedEvent: "select:vis"
            });

            // The same, but for the data files.
            datafiles = new app.collections.Folder([], {
                girderApi: config.girderApi,
                folderId: dataFolderId
            });

            dataMenu = new app.views.FileMenu({
                el: "#data-files-view",
                collection: datafiles,
                selectedEvent: "select:data"
            });

            // A Vega view.
            vis = new app.views.Vega({
                el: "#vega",
                girderApi: config.girderApi
            });

            // A data view.
            data = new app.views.Data({
                el: "#edit-area",
                girderApi: config.girderApi
            });
        };
    });
});
<commit_msg>Got rid of superfluous "visName" property<commit_after>/*jslint browser: true */
/*globals Backbone, $, tangelo, vg, _, d3 */

var visfiles;

var app = {};

// Tables of Backbone objects.
app.models = {};
app.collections = {};
app.views = {};

// A model describing a file that contains a Lyra-edited visualization.
app.models.Vis = Backbone.Model.extend({
    initialize: function (options) {
        "use strict";

        options = options || {};
        this.girderApi = options.girderApi;
        this.folderId = options.folderId;
    },

    idAttribute: "_id",

    _upload: function () {
        "use strict";

        var data = JSON.stringify(this.get("lyra")),
            uploadChunks;

        var d = {
                "parentType": "folder",
                "parentId": this.folderId,
                "name": this.get("name"),
                "size": data.length
            };

        console.log(d);

        uploadChunks = _.bind(function (upload) {
            var uploadChunk = _.bind(function (start, maxChunkSize) {
                var end,
                    blob,
                    form;

                end = Math.min(start + maxChunkSize, data.length);

                blob = new window.Blob([data.slice(start, end)]);

                form = new window.FormData();
                form.append("offset", start);
                form.append("uploadId", upload._id);
                form.append("chunk", blob);

                Backbone.ajax({
                    url: this.girderApi + "/file/chunk",
                    type: "POST",
                    data: form,
                    contentType: false,
                    processData: false,
                    success: function () {
                        if (end < data.length) {
                            uploadChunk(end, maxChunkSize);
                        }
                    }
                });
            }, this);

            uploadChunk(0, 64 * 1024 * 1024);
        }, this);

        Backbone.ajax({
            url: this.girderApi + "/file",
            type: "POST",
            data: d,
            success: uploadChunks
        });
    },

    save: function () {
        "use strict";

        if (!this.isNew()) {
            // Delete the file from the server, before reuploading the current
            // spec.
            Backbone.ajax({
                url: this.girderApi + "/item/" + this.id,
                method: "DELETE",
                success: _.bind(this._upload, this)
            });
        } else {
            this._upload();
        }
    },

    fetch: function (options) {
        "use strict";

        var url = this.girderApi + "/item/" + this.id + "/download",
            success = options.success || $.noop,
            error = options.error || $.noop;

        Backbone.ajax({
            url: url,
            dataType: "json",
            success: _.bind(function (lyra) {
                this.set("lyra", lyra);
                success(this, lyra, options);
            }, this),
            error: _.bind(function (jqxhr) {
                error(this, jqxhr, options);
            }, this)
        });
    },
});

app.models.Data = Backbone.Model.extend({
    initialize: function (options) {
        "use strict";

        options = options || {};
        this.girderApi = options.girderApi;
    },

    idAttribute: "_id",

    url: function () {
        "use strict";

        return this.girderApi + "/item/" + this.get("_id") + "/download";
    },

    parse: function (response) {
        "use strict";

        return {
            data: response
        };
    }
});

// A collection describing all the Lyra vis files in a Girder instance.
app.collections.Folder = Backbone.Collection.extend({
    model: app.models.Vis,

    initialize: function (models, options) {
        "use strict";

        options = options || {};
        this.folderId = options.folderId;

        this.url = options.girderApi + "/item?folderId=" + options.folderId;
        this.fetch({
            success: function (models) {
                models.forEach(function (m) {
                    m.girderApi = options.girderApi;
                });
            }
        });
    }
});

// A view that renders a Vega visualization.
app.views.Vega = Backbone.View.extend({
    initialize: function (options) {
        "use strict";

        options = options || {};
        this.girderApi = options.girderApi;

        Backbone.on("select:vis", this.loadVis, this);
    },

    loadVis: function (file) {
        "use strict";

        var render = _.bind(function () {
            this.render();
        }, this);

        this.model = file;

        if (file.get("lyra")) {
            render();
        } else {
            file.fetch({
                success: render
            });
        }
    },

    render: function () {
        "use strict";

        vg.parse.spec(this.model.get("lyra").vega, _.bind(function (chart) {
            chart({
                el: this.el,
                renderer: "svg"
            }).update();
        }, this));
    }
});

// A view to "render" a dataset (using a read-only ACE editor instance).
app.views.Data = Backbone.View.extend({
    initialize: function (options) {
        "use strict";

        this.model = new app.models.Data({
            girderApi: options.girderApi
        });

        Backbone.on("select:data", this.loadData, this);
    },

    loadData: function (file) {
        "use strict";

        this.model.set("_id", file.get("_id"));
        this.model.fetch({
            success: _.bind(function () {
                this.render();
            }, this)
        });
    },

    render: function () {
        "use strict";

        console.log(this.model);
    },

    getData: function () {
        "use strict";

        return this.model.get("data");
    }
});

// A collection describing all the data files in a Girder instance.
app.collections.Data = Backbone.Collection.extend({
});

// A view that renders a single file as a list item.
app.views.File = Backbone.View.extend({
    initialize: function (options) {
        "use strict";

        this.selectedEvent = options.selectedEvent;
    },

    tagName: "li",

    events: {
        click: "selected"
    },

    render: function () {
        "use strict";

        d3.select(this.el)
            .append("a")
            .attr("href", "#")
            .html(this.model.get("name"));

        return this;
    },

    selected: function () {
        "use strict";

        if (this.selectedEvent) {
            Backbone.trigger(this.selectedEvent, this.model);
        }
    }
});

// A view that renders a list of files.
app.views.FileMenu = Backbone.View.extend({
    tagName: "div",

    initialize: function (options) {
        "use strict";

        var template;

        options = options || {};
        this.selectedEvent = options.selectedEvent;

        template = _.template($("#vis-files-view-template").html(), {});
        this.$el.html(template);

        // When the collection gains an item, add it to the dropdown menu.
        this.collection.on("add", this.addItem, this);

        // When a visualization is selected, change the dropdown menu text.
        Backbone.on(this.selectedEvent, this.setSelected, this);
    },

    addItem: function (file) {
        "use strict";

        var newitem = new app.views.File({
            className: "file",
            model: file,
            selectedEvent: this.selectedEvent
        });

        this.$el.find("ul")
            .append(newitem.render().el);
    },

    setSelected: function (f) {
        "use strict";

        this.selectedModel = f;

        var label = f.get("name");

        if (f.unsaved) {
            label = "" + label + "";
        }

        label += " ";

        this.$el.find("button")
            .html(label);
    },

    getSelected: function () {
        "use strict";

        return this.selectedModel;
    }
});

$(function () {
    "use strict";

    tangelo.config("config.json", function (config) {
        var main;

        // Issue ajax calls to get the Lyra collection in girder, and then both
        // the visualization and data folders therein.
        $.ajax({
            url: config.girderApi + "/collection",
            type: "GET",
            dataType: "json",
            data: {
                text: config.collection
            },
            success: function (lyraCollection) {
                // Now find the visualizations folder.
                $.ajax({
                    url: config.girderApi + "/folder",
                    type: "GET",
                    dataType: "json",
                    data: {
                        parentType: "collection",
                        parentId: lyraCollection._id,
                        text: config.visFolder
                    },
                    success: function (visFolder) {
                        // Make sure there is a result.
                        if (visFolder.length === 0) {
                            console.warn("No folder '" + config.visFolder + "' found in collection '" + config.collection + "'");
                        }

                        // Find the data folder.
                        $.ajax({
                            url: config.girderApi + "/folder",
                            type: "GET",
                            dataType: "json",
                            data: {
                                parentType: "collection",
                                parentId: lyraCollection._id,
                                text: config.dataFolder
                            },
                            success: function (dataFolder) {
                                // Make sure there is a result.
                                if (dataFolder.length === 0) {
                                    console.warn("No folder '" + config.dataFolder + "' found in collection '" + config.collection + "'");
                                }

                                // Run the actual application.
                                main(config, visFolder[0]._id, dataFolder[0]._id);
                            }
                        });
                    }
                });
            }

        });

        // The main application.
        main = function (config, visFolderId, dataFolderId) {
            var //visfiles,
                visMenu,
                vis,
                datafiles,
                dataMenu,
                data,
                f;

            f = {};

            // A function that launches a Lyra editor window.
            f.launchLyra = function (qargs) {
                var lyra = window.open("/lyra/editor.html?editor=true", "_blank");
                lyra.onload = function () {
                    lyra.postMessage(qargs, window.location.origin);
                };
            };

            f.createNew = function () {
                f.launchLyra({
                    new: true,
                    timeline: null,
                    data: encodeURIComponent(JSON.stringify(data.getData()))
                });
            };

            f.edit = function () {
                var model = vis.model;

                f.launchLyra({
                    new: false,
                    name: model.get("name"),
                    timeline: encodeURIComponent(JSON.stringify(model.get("timeline"))),
                    data: encodeURIComponent(JSON.stringify(model.get("lyra").vega.data[0].values))
                });
            };

            f.save = function () {
                vis.model.save();
            };

            f.receiveMessage = function (e) {
                var model,
                    name;

                if (e.data.new) {
                    name = "Unsaved " + _.uniqueId();

                    // Construct a new Vis model to represent the newly created
                    // Vega visualization.
                    model = new app.models.Vis({
                        girderApi: config.girderApi,
                        folderId: visFolderId,
                        name: name,
                        lyra: {
                            timeline: e.data.timeline,
                            vega: e.data.vega
                        }
                    });

                    // Add the model to the vis files list, and simulate its
                    // selection (so that the menu will show it as active, and
                    // it will be rendered to the Vega view).
                    visfiles.add(model);
                    Backbone.trigger("select:vis", model);
                } else {
                    vis.model.set({
                        lyra: {
                            timeline: e.data.timeline,
                            vega: e.data.vega
                        }
                    });
                }
            };

            // The "New" button.
            d3.select("#create")
                .on("click", f.createNew);

            d3.select("#edit")
                .on("click", f.edit);

            d3.select("#save")
                .on("click", f.save);

            // Set up to receive messages.
            window.addEventListener("message", f.receiveMessage, false);

            // A collection of visualization files residing on Girder, and a
            // dropdown menu to select them.
            visfiles = new app.collections.Folder([], {
                girderApi: config.girderApi,
                folderId: visFolderId
            });

            visMenu = new app.views.FileMenu({
                el: "#vis-files-view",
                collection: visfiles,
                selectedEvent: "select:vis"
            });

            // The same, but for the data files.
            datafiles = new app.collections.Folder([], {
                girderApi: config.girderApi,
                folderId: dataFolderId
            });

            dataMenu = new app.views.FileMenu({
                el: "#data-files-view",
                collection: datafiles,
                selectedEvent: "select:data"
            });

            // A Vega view.
            vis = new app.views.Vega({
                el: "#vega",
                girderApi: config.girderApi
            });

            // A data view.
            data = new app.views.Data({
                el: "#edit-area",
                girderApi: config.girderApi
            });
        };
    });
});
<|endoftext|>


<commit_before>var
  where = 'client' // Adds files only to the client
;

Package.describe({
  name    : 'semantic:ui-css',
  summary : 'Semantic UI - CSS Release of Semantic UI',
  version : '{version}',
  git     : 'git://github.com/Semantic-Org/Semantic-UI-CSS.git',
});

Package.onUse(function(api) {

  api.versionsFrom('1.0');

  api.use('jquery', 'client');

  api.addAssets
    // icons
    'themes/default/assets/fonts/icons.eot',
    'themes/default/assets/fonts/icons.svg',
    'themes/default/assets/fonts/icons.ttf',
    'themes/default/assets/fonts/icons.woff',
    'themes/default/assets/fonts/icons.woff2',

    // flags
    'themes/default/assets/images/flags.png'
  ], 'client');

  api.addFiles([
    // release
    'semantic.css',
    'semantic.js'
  ], 'client');

});
<commit_msg>Fix parenthesis<commit_after>var
  where = 'client' // Adds files only to the client
;

Package.describe({
  name    : 'semantic:ui-css',
  summary : 'Semantic UI - CSS Release of Semantic UI',
  version : '{version}',
  git     : 'git://github.com/Semantic-Org/Semantic-UI-CSS.git',
});

Package.onUse(function(api) {

  api.versionsFrom('1.0');

  api.use('jquery', 'client');

  api.addAssets([
    // icons
    'themes/default/assets/fonts/icons.eot',
    'themes/default/assets/fonts/icons.svg',
    'themes/default/assets/fonts/icons.ttf',
    'themes/default/assets/fonts/icons.woff',
    'themes/default/assets/fonts/icons.woff2',

    // flags
    'themes/default/assets/images/flags.png'
  ], 'client');

  api.addFiles([
    // release
    'semantic.css',
    'semantic.js'
  ], 'client');

});
<|endoftext|>


<commit_before>(function () {
    'use strict';

    var app = angular.module('app');

    app.directive('tmtStencil', ['common', function (common) {

        var directive = {
            link: link,
            restrict: 'E',
            scope: {
                shape: '=',
                action: '&',
                padding: '=',
                scale: '='
            }
        };

        return directive;

        function link(scope, element, attrs) {

            if (angular.isUndefined(scope.scale)) {
                scope.scale = 1.0;
            }

            if (angular.isUndefined(scope.padding)) {
                scope.padding = 0.0;
            }

            var graph = new joint.dia.Graph();
            var ShapeClass = common.utils.stringToFunction(scope.shape.className);
            var cell = new ShapeClass();
            var diagram;

            if (cell.isLink()) {
                diagram = linkStencil(cell, scope.shape.label, element, scope.scale, scope.padding, graph);
            }
            else {
                diagram = elementStencil(cell, scope.shape.label, element, scope.scale, scope.padding, graph);
            }

            diagram.on('cell:pointerclick', scope.action);
            var toolTip = 'Add a new ' + scope.shape.label + ' to the model';
            cell.attr({'.tooltip': { text: toolTip }});
            graph.addCell(cell);
        }

        function linkStencil(shape, label, element, scale, padding, graph) {

            var elementWidth = $(element).parent('div').width();
            shape.attributes.source = { x: (1.0 - scale) * elementWidth + padding, y: padding };
            shape.attributes.target = { x: scale * elementWidth - padding, y: 0.5 * scale * elementWidth - padding };
            shape.setLabel(label);

            return newDiagram(0.5 * elementWidth + 2.0 * padding, elementWidth, 1, graph, element[0], false);
        }

        function elementStencil(shape, label, element, scale, padding, graph) {

            var elementWidth = $(element).parent('div').width();
            shape.resize(shape.get('size').width * scale, shape.get('size').height * scale);
            var shapeHeight = shape.get('size').height;
            shape.translate(0.5 * (elementWidth - shape.get('size').width), padding);
            shape.attr('text/text', label);

            return newDiagram(shapeHeight + 2.0 * padding, elementWidth, 1, graph, element[0], false);
        }

    }]);

    app.directive('tmtDiagram', ['common', function (common) {

        var directive = {
            link: link,
            restrict: 'E',
            scope: {
                height: '=',
                width: '=',
                gridSize: '=',
                graph: '=',
                select: '&',
                newFlow: '&',
                initialiseGraph: '&',
                interactive: '='
            }
        };

        var selected = null;
        var selectOnScope = null;
        var getLogFn = common.logger.getLogFn;
        var log = getLogFn();

        return directive;

        function link(scope, element, attrs) {

            $(element).parent().height(scope.height);
            var diagram = newDiagram(scope.height - 10, scope.width - 10, scope.gridSize, scope.graph, element[0], scope.interactive);

            selectOnScope = scope.select;

            scope.graph.on('add', function (newCell) { newCell.translate($(element).parent().scrollLeft(), $(element).parent().scrollTop());});

            diagram.on('cell:pointerclick', function (cellView, evt, x, y) {
                if (!cellView.model.isLink()) {

                    if (cellView._action === 'linkFrom') {

                        addLinkFrom(cellView);

                    }
                    else if (cellView._action === 'removeLinkFrom') {

                        removeLinkFrom(cellView);

                    }
                    else {

                        if (selected && !selected.model.isLink() && selected.linkFrom) {

                            scope.newFlow({ source: selected.model, target: cellView.model });
                            removeLinkFrom(selected);
                        }

                        setSelected(cellView);
                    }
                }
            });

            diagram.on('blank:pointerclick', function (evt, x, y) {

                if (selected && !selected.model.isLink()) {
                    removeLinkFrom(selected);
                }

                setSelected(null);
            });

            diagram.on('link:options', function (evt, cellView, x, y) {

                if (selected && !selected.model.isLink()) {
                    removeLinkFrom(selected);
                }

                setSelected(cellView);
                });

                diagram.on('cell:pointermove', function (cellView, evt, x, y) {

                    var bbox = cellView.getBBox();
                    var constrained = false;
                    var constrainedX = x;
                    var constrainedY = y;

                    //minimum x
                    if (bbox.x <= 0) {
                        constrainedX = x + scope.gridSize;
                        constrained = true;
                    }

                    //expand the diagram right
                    if (bbox.x + bbox.width >= diagram.options.width) {
                        diagram.setDimensions(bbox.x + bbox.width, diagram.options.height);
                        $(element).parent().scrollLeft(diagram.options.width - scope.width);
                    }

                    //scroll the diagram left
                    if (bbox.x <= $(element).parent().scrollLeft()) {
                        $(element).parent().scrollLeft(bbox.x);
                    }

                    //scroll the diagram right
                    if (bbox.x + bbox.width - $(element).parent().scrollLeft() >= $(element).parent().width() && bbox.x + bbox.width < diagram.options.width) {
                        $(element).parent().scrollLeft(bbox.x + bbox.width - $(element).parent().width());
                    }

                    //minimum y
                    if (bbox.y <= 0) {
                        constrainedY = y + scope.gridSize;
                        constrained = true;
                    }

                    //expand the diagram down
                    if (bbox.y + bbox.height >= diagram.options.height) {
                        diagram.setDimensions(diagram.options.width, bbox.y + bbox.height);
                        $(element).parent().scrollTop(diagram.options.height - scope.height);
                    }

                    //scroll the diagram up
                    if (bbox.y <= $(element).parent().scrollTop()) {
                        $(element).parent().scrollTop(bbox.y);
                    }

                    //scroll the diagram up
                    if (bbox.y <= $(element).parent().scrollTop()) {
                        $(element).parent().scrollTop(bbox.y);
                    }

                    //scroll the diagram down
                    if (bbox.y + bbox.height - $(element).parent().scrollTop() >= $(element).parent().height() && bbox.y + bbox.height < diagram.options.height) {
                        $(element).parent().scrollTop(bbox.y + bbox.height - $(element).parent().height());
                    }

                    if (constrained)
                    {
                        cellView.pointermove(evt, constrainedX, constrainedY);
                    }
            });

                diagram.setSelected = function (cell) {

                    if (selected) {
                        selected.setUnselected();
                    }

                    if (cell) {
                        var cellView = diagram.findViewByModel(cell);

                        if (cellView) {
                            cellView.setSelected();
                            selected = cellView;
                        }
                    }
                    else {
                        selected = null;
                    }
                };

            scope.initialiseGraph({ diagram: diagram });
        }

        function addLinkFrom(cellView) {
            cellView.linkFrom = true;
            (new V(cellView.$el.find('.element-tool-link')[0])).addClass("linking");
            log('Select another model element to add a data flow');
        }

        function removeLinkFrom(cellView) {
            cellView.linkFrom = false;
            (new V(cellView.$el.find('.element-tool-link')[0])).removeClass("linking");
        }

        function setSelected(cellView)
        {
            var element = null;

            if (cellView)
            {
                element = cellView.model;
            }

            selectOnScope({ element: element });
        }

    }]);

    function newDiagram(height, width, gridSize, graph, target, interactive) {

        var paper = new joint.dia.Paper({
            el: target,
            width: width,
            height: height,
            gridSize: gridSize,
            model: graph,
            interactive: interactive
        });

        return paper;
    }

})();

<commit_msg>Code climate issues<commit_after>(function () {
    'use strict';

    var app = angular.module('app');

    app.directive('tmtStencil', ['common', function (common) {

        var directive = {
            link: link,
            restrict: 'E',
            scope: {
                shape: '=',
                action: '&',
                padding: '=',
                scale: '='
            }
        };

        return directive;

        function link(scope, element) {

            if (angular.isUndefined(scope.scale)) {
                scope.scale = 1.0;
            }

            if (angular.isUndefined(scope.padding)) {
                scope.padding = 0.0;
            }

            var graph = new joint.dia.Graph();
            var ShapeClass = common.utils.stringToFunction(scope.shape.className);
            var cell = new ShapeClass();
            var diagram;

            if (cell.isLink()) {
                diagram = linkStencil(cell, scope.shape.label, element, scope.scale, scope.padding, graph);
            }
            else {
                diagram = elementStencil(cell, scope.shape.label, element, scope.scale, scope.padding, graph);
            }

            diagram.on('cell:pointerclick', scope.action);
            var toolTip = 'Add a new ' + scope.shape.label + ' to the model';
            cell.attr({'.tooltip': { text: toolTip }});
            graph.addCell(cell);
        }

        function linkStencil(shape, label, element, scale, padding, graph) {

            var elementWidth = $(element).parent('div').width();
            shape.attributes.source = { x: (1.0 - scale) * elementWidth + padding, y: padding };
            shape.attributes.target = { x: scale * elementWidth - padding, y: 0.5 * scale * elementWidth - padding };
            shape.setLabel(label);

            return newDiagram(0.5 * elementWidth + 2.0 * padding, elementWidth, 1, graph, element[0], false);
        }

        function elementStencil(shape, label, element, scale, padding, graph) {

            var elementWidth = $(element).parent('div').width();
            shape.resize(shape.get('size').width * scale, shape.get('size').height * scale);
            var shapeHeight = shape.get('size').height;
            shape.translate(0.5 * (elementWidth - shape.get('size').width), padding);
            shape.attr('text/text', label);

            return newDiagram(shapeHeight + 2.0 * padding, elementWidth, 1, graph, element[0], false);
        }

    }]);

    app.directive('tmtDiagram', ['common', function (common) {

        var directive = {
            link: link,
            restrict: 'E',
            scope: {
                height: '=',
                width: '=',
                gridSize: '=',
                graph: '=',
                select: '&',
                newFlow: '&',
                initialiseGraph: '&',
                interactive: '='
            }
        };

        var selected = null;
        var selectOnScope = null;
        var getLogFn = common.logger.getLogFn;
        var log = getLogFn();

        return directive;

        function link(scope, element) {

            $(element).parent().height(scope.height);
            var diagram = newDiagram(scope.height - 10, scope.width - 10, scope.gridSize, scope.graph, element[0], scope.interactive);

            selectOnScope = scope.select;

            scope.graph.on('add', function (newCell) { newCell.translate($(element).parent().scrollLeft(), $(element).parent().scrollTop());});

            diagram.on('cell:pointerclick', function (cellView) {
                if (!cellView.model.isLink()) {

                    if (cellView._action === 'linkFrom') {

                        addLinkFrom(cellView);

                    }
                    else if (cellView._action === 'removeLinkFrom') {

                        removeLinkFrom(cellView);

                    }
                    else {

                        if (selected && !selected.model.isLink() && selected.linkFrom) {

                            scope.newFlow({ source: selected.model, target: cellView.model });
                            removeLinkFrom(selected);
                        }

                        setSelected(cellView);
                    }
                }
            });

            diagram.on('blank:pointerclick', function () {

                if (selected && !selected.model.isLink()) {
                    removeLinkFrom(selected);
                }

                setSelected(null);
            });

            diagram.on('link:options', function (evt, cellView) {

                if (selected && !selected.model.isLink()) {
                    removeLinkFrom(selected);
                }

                setSelected(cellView);
                });

                diagram.on('cell:pointermove', function (cellView, evt, x, y) {

                    var bbox = cellView.getBBox();
                    var constrained = false;
                    var constrainedX = x;
                    var constrainedY = y;

                    //minimum x
                    if (bbox.x <= 0) {
                        constrainedX = x + scope.gridSize;
                        constrained = true;
                    }

                    //expand the diagram right
                    if (bbox.x + bbox.width >= diagram.options.width) {
                        diagram.setDimensions(bbox.x + bbox.width, diagram.options.height);
                        $(element).parent().scrollLeft(diagram.options.width - scope.width);
                    }

                    //scroll the diagram left
                    if (bbox.x <= $(element).parent().scrollLeft()) {
                        $(element).parent().scrollLeft(bbox.x);
                    }

                    //scroll the diagram right
                    if (bbox.x + bbox.width - $(element).parent().scrollLeft() >= $(element).parent().width() && bbox.x + bbox.width < diagram.options.width) {
                        $(element).parent().scrollLeft(bbox.x + bbox.width - $(element).parent().width());
                    }

                    //minimum y
                    if (bbox.y <= 0) {
                        constrainedY = y + scope.gridSize;
                        constrained = true;
                    }

                    //expand the diagram down
                    if (bbox.y + bbox.height >= diagram.options.height) {
                        diagram.setDimensions(diagram.options.width, bbox.y + bbox.height);
                        $(element).parent().scrollTop(diagram.options.height - scope.height);
                    }

                    //scroll the diagram up
                    if (bbox.y <= $(element).parent().scrollTop()) {
                        $(element).parent().scrollTop(bbox.y);
                    }

                    //scroll the diagram up
                    if (bbox.y <= $(element).parent().scrollTop()) {
                        $(element).parent().scrollTop(bbox.y);
                    }

                    //scroll the diagram down
                    if (bbox.y + bbox.height - $(element).parent().scrollTop() >= $(element).parent().height() && bbox.y + bbox.height < diagram.options.height) {
                        $(element).parent().scrollTop(bbox.y + bbox.height - $(element).parent().height());
                    }

                    if (constrained)
                    {
                        cellView.pointermove(evt, constrainedX, constrainedY);
                    }
            });

                diagram.setSelected = function (cell) {

                    if (selected) {
                        selected.setUnselected();
                    }

                    if (cell) {
                        var cellView = diagram.findViewByModel(cell);

                        if (cellView) {
                            cellView.setSelected();
                            selected = cellView;
                        }
                    }
                    else {
                        selected = null;
                    }
                };

            scope.initialiseGraph({ diagram: diagram });
        }

        function addLinkFrom(cellView) {
            cellView.linkFrom = true;
            (new V(cellView.$el.find('.element-tool-link')[0])).addClass("linking");
            log('Select another model element to add a data flow');
        }

        function removeLinkFrom(cellView) {
            cellView.linkFrom = false;
            (new V(cellView.$el.find('.element-tool-link')[0])).removeClass("linking");
        }

        function setSelected(cellView)
        {
            var element = null;

            if (cellView)
            {
                element = cellView.model;
            }

            selectOnScope({ element: element });
        }

    }]);

    function newDiagram(height, width, gridSize, graph, target, interactive) {

        var paper = new joint.dia.Paper({
            el: target,
            width: width,
            height: height,
            gridSize: gridSize,
            model: graph,
            interactive: interactive
        });

        return paper;
    }

})();

<|endoftext|>


<commit_before>/**
 * modules
 * @type {*[]}
 */
let polyfills = [
    [Object, 'assign', 'node_modules/core-js/library/fn/object/assign'],
    [Object, 'values', 'node_modules/core-js/library/fn/object/values'],
    [Object, 'entries', 'node_modules/core-js/library/fn/object/entries'],
    [HTMLElement.prototype, 'attachShadow', 'node_modules/@webcomponents/shadydom/shadydom.min.js', true],
    [document, 'registerElement', 'node_modules/webcomponents.js/webcomponents-lite', true],
    [window, 'Reflect', 'node_modules/core-js/library/fn/reflect'],
    [window, 'WeakMap', 'node_modules/core-js/library/fn/weak-map'],
    [window, 'Map', 'node_modules/core-js/library/fn/map'],
];

export {
    polyfills,
}<commit_msg>disable shadowDom polyfill<commit_after>/**
 * modules
 * @type {*[]}
 */
let polyfills = [
    [Object, 'assign', 'node_modules/core-js/library/fn/object/assign'],
    [Object, 'values', 'node_modules/core-js/library/fn/object/values'],
    [Object, 'entries', 'node_modules/core-js/library/fn/object/entries'],
    //[HTMLElement.prototype, 'attachShadow', 'node_modules/shadowdom/shadydom/shadydom.min.js', true],
    [document, 'registerElement', 'node_modules/webcomponents.js/webcomponents-lite', true],
    [window, 'Reflect', 'node_modules/core-js/library/fn/reflect'],
    [window, 'WeakMap', 'node_modules/core-js/library/fn/weak-map'],
    [window, 'Map', 'node_modules/core-js/library/fn/map'],
];

export {
    polyfills,
}<|endoftext|>


<commit_before>// Subscribe to the `meteor_autoupdate_clientVersions` collection,
// which contains the set of acceptable client versions.
//
// A "hard code push" occurs when the running client version is not in
// the set of acceptable client versions (or the server updates the
// collection, there is a published client version marked `current` and
// the running client version is no longer in the set).
//
// When the `reload` package is loaded, a hard code push causes
// the browser to reload, so that it will load the latest client
// version from the server.
//
// A "soft code push" represents the situation when the running client
// version is in the set of acceptable versions, but there is a newer
// version available on the server.
//
// `Autoupdate.newClientAvailable` is a reactive data source which
// becomes `true` if there is a new version of the client is available on
// the server.
//
// This package doesn't implement a soft code reload process itself,
// but `newClientAvailable` could be used for example to display a
// "click to reload" link to the user.

// The client version of the client code currently running in the
// browser.
var autoupdateVersion = __meteor_runtime_config__.autoupdateVersion || "unknown";
var autoupdateVersionRefreshable =
  __meteor_runtime_config__.autoupdateVersionRefreshable || "unknown";

// The collection of acceptable client versions.
ClientVersions = new Meteor.Collection("meteor_autoupdate_clientVersions");

Autoupdate = {};

Autoupdate.newClientAvailable = function () {
  return !! ClientVersions.findOne({
               _id: "version",
               version: {$ne: autoupdateVersion} }) ||
         !! ClientVersions.findOne({
               _id: "version-refreshable",
               version: {$ne: autoupdateVersionRefreshable} });
};

var knownToSupportCssOnLoad = false;

var retry = new Retry({
  // Unlike the stream reconnect use of Retry, which we want to be instant
  // in normal operation, this is a wacky failure. We don't want to retry
  // right away, we can start slowly.
  //
  // A better way than timeconstants here might be to use the knowledge
  // of when we reconnect to help trigger these retries. Typically, the
  // server fixing code will result in a restart and reconnect, but
  // potentially the subscription could have a transient error.
  minCount: 0, // don't do any immediate retries
  baseTimeout: 30*1000 // start with 30s
});
var failures = 0;

Autoupdate._retrySubscription = function () {
  Meteor.subscribe("meteor_autoupdate_clientVersions", {
    onError: function (error) {
      Meteor._debug("autoupdate subscription failed:", error);
      failures++;
      retry.retryLater(failures, function () {
        // Just retry making the subscription, don't reload the whole
        // page. While reloading would catch more cases (for example,
        // the server went back a version and is now doing old-style hot
        // code push), it would also be more prone to reload loops,
        // which look really bad to the user. Just retrying the
        // subscription over DDP means it is at least possible to fix by
        // updating the server.
        Autoupdate._retrySubscription();
      });
    },
    onReady: function () {
      if (Package.reload) {
        var checkNewVersionDocument = function (doc) {
          var self = this;
          if (doc._id === 'version-refreshable' &&
              doc.version !== autoupdateVersionRefreshable) {
            autoupdateVersionRefreshable = doc.version;
            // Switch out old css links for the new css links. Inspired by:
            // https://github.com/guard/guard-livereload/blob/master/js/livereload.js#L710
            var newCss = (doc.assets && doc.assets.allCss) || [];
            var oldLinks = [];
            _.each(document.getElementsByTagName('link'), function (link) {
              if (link.className === '__meteor-css__') {
                oldLinks.push(link);
              }
            });

            var waitUntilCssLoads = function  (link, callback) {
              var executeCallback = _.once(callback);
              link.onload = function () {
                knownToSupportCssOnLoad = true;
                executeCallback();
              };
              if (! knownToSupportCssOnLoad) {
                var id = Meteor.setInterval(function () {
                  if (link.sheet) {
                    executeCallback();
                    Meteor.clearInterval(id);
                  }
                }, 50);
              }
            };

            var attachStylesheetLink = function (newLink) {
              var removeOldLinks = _.after(newCss.length, function () {
                _.each(oldLinks, function (oldLink) {
                  oldLink.parentNode.removeChild(oldLink);
                });
              });

              document.getElementsByTagName("head").item(0).appendChild(newLink);

              waitUntilCssLoads(newLink, function () {
                Meteor.setTimeout(removeOldLinks, 200);
              });
            };

            _.each(newCss, function (css) {
              var newLink = document.createElement("link");
              newLink.setAttribute("rel", "stylesheet");
              newLink.setAttribute("type", "text/css");
              newLink.setAttribute("class", "__meteor-css__");
              newLink.setAttribute("href", css.url);
              attachStylesheetLink(newLink);
            });
          }
          else if (doc._id === 'version' &&
                   doc.version !== autoupdateVersion && handle) {
            handle.stop();
            Package.reload.Reload._reload();
          }
        };

        var handle = ClientVersions.find().observe({
          added: checkNewVersionDocument,
          changed: checkNewVersionDocument
        });
      }
    }
  });
};
Autoupdate._retrySubscription();
<commit_msg>Fix for autoupdate refresh not firing on initial document<commit_after>// Subscribe to the `meteor_autoupdate_clientVersions` collection,
// which contains the set of acceptable client versions.
//
// A "hard code push" occurs when the running client version is not in
// the set of acceptable client versions (or the server updates the
// collection, there is a published client version marked `current` and
// the running client version is no longer in the set).
//
// When the `reload` package is loaded, a hard code push causes
// the browser to reload, so that it will load the latest client
// version from the server.
//
// A "soft code push" represents the situation when the running client
// version is in the set of acceptable versions, but there is a newer
// version available on the server.
//
// `Autoupdate.newClientAvailable` is a reactive data source which
// becomes `true` if there is a new version of the client is available on
// the server.
//
// This package doesn't implement a soft code reload process itself,
// but `newClientAvailable` could be used for example to display a
// "click to reload" link to the user.

// The client version of the client code currently running in the
// browser.
var autoupdateVersion = __meteor_runtime_config__.autoupdateVersion || "unknown";
var autoupdateVersionRefreshable =
  __meteor_runtime_config__.autoupdateVersionRefreshable || "unknown";

// The collection of acceptable client versions.
ClientVersions = new Meteor.Collection("meteor_autoupdate_clientVersions");

Autoupdate = {};

Autoupdate.newClientAvailable = function () {
  return !! ClientVersions.findOne({
               _id: "version",
               version: {$ne: autoupdateVersion} }) ||
         !! ClientVersions.findOne({
               _id: "version-refreshable",
               version: {$ne: autoupdateVersionRefreshable} });
};

var knownToSupportCssOnLoad = false;

var retry = new Retry({
  // Unlike the stream reconnect use of Retry, which we want to be instant
  // in normal operation, this is a wacky failure. We don't want to retry
  // right away, we can start slowly.
  //
  // A better way than timeconstants here might be to use the knowledge
  // of when we reconnect to help trigger these retries. Typically, the
  // server fixing code will result in a restart and reconnect, but
  // potentially the subscription could have a transient error.
  minCount: 0, // don't do any immediate retries
  baseTimeout: 30*1000 // start with 30s
});
var failures = 0;

Autoupdate._retrySubscription = function () {
  Meteor.subscribe("meteor_autoupdate_clientVersions", {
    onError: function (error) {
      Meteor._debug("autoupdate subscription failed:", error);
      failures++;
      retry.retryLater(failures, function () {
        // Just retry making the subscription, don't reload the whole
        // page. While reloading would catch more cases (for example,
        // the server went back a version and is now doing old-style hot
        // code push), it would also be more prone to reload loops,
        // which look really bad to the user. Just retrying the
        // subscription over DDP means it is at least possible to fix by
        // updating the server.
        Autoupdate._retrySubscription();
      });
    },
    onReady: function () {
      if (Package.reload) {
        var checkNewVersionDocument = function (doc) {
          var self = this;
          if (doc._id === 'version-refreshable' &&
              doc.version !== autoupdateVersionRefreshable) {
            autoupdateVersionRefreshable = doc.version;
            // Switch out old css links for the new css links. Inspired by:
            // https://github.com/guard/guard-livereload/blob/master/js/livereload.js#L710
            var newCss = (doc.assets && doc.assets.allCss) || [];
            var oldLinks = [];
            _.each(document.getElementsByTagName('link'), function (link) {
              if (link.className === '__meteor-css__') {
                oldLinks.push(link);
              }
            });

            var waitUntilCssLoads = function  (link, callback) {
              var executeCallback = _.once(callback);
              link.onload = function () {
                knownToSupportCssOnLoad = true;
                executeCallback();
              };
              if (! knownToSupportCssOnLoad) {
                var id = Meteor.setInterval(function () {
                  if (link.sheet) {
                    executeCallback();
                    Meteor.clearInterval(id);
                  }
                }, 50);
              }
            };

            var attachStylesheetLink = function (newLink) {
              var removeOldLinks = _.after(newCss.length, function () {
                _.each(oldLinks, function (oldLink) {
                  oldLink.parentNode.removeChild(oldLink);
                });
              });

              document.getElementsByTagName("head").item(0).appendChild(newLink);

              waitUntilCssLoads(newLink, function () {
                Meteor.setTimeout(removeOldLinks, 200);
              });
            };

            _.each(newCss, function (css) {
              var newLink = document.createElement("link");
              newLink.setAttribute("rel", "stylesheet");
              newLink.setAttribute("type", "text/css");
              newLink.setAttribute("class", "__meteor-css__");
              newLink.setAttribute("href", css.url);
              attachStylesheetLink(newLink);
            });
          }
          else if (doc._id === 'version' && doc.version !== autoupdateVersion) {
            handle && handle.stop();
            Package.reload.Reload._reload();
          }
        };

        var handle = ClientVersions.find().observe({
          added: checkNewVersionDocument,
          changed: checkNewVersionDocument
        });
      }
    }
  });
};
Autoupdate._retrySubscription();
<|endoftext|>


<commit_before>'use strict'

import MultiTask from 'chiffchaff-multi'
import PipeTask from 'chiffchaff-pipe'

export default class ConcatTask extends MultiTask {
  constructor (sources, destination) {
    super([], {ignoreWeights: true})
    this._sources = sources
    this._destination = destination
  }

  addSource (source) {
    this._sources.push(source)
  }

  _start () {
    for (let source of this._sources) {
      this.add(new PipeTask(source, this._destination), {end: false})
    }
    return super._start()
      .then(() => this._destination.end())
  }
}
<commit_msg>Constructor defaults; adding destination setter<commit_after>'use strict'

import MultiTask from 'chiffchaff-multi'
import PipeTask from 'chiffchaff-pipe'

export default class ConcatTask extends MultiTask {
  constructor (sources = [], destination = null) {
    super([], {ignoreWeights: true})
    this._sources = sources
    this._destination = destination
  }

  addSource (source) {
    this._sources.push(source)
  }

  set destination (dest) {
    this._destination = dest
  }

  _start () {
    for (let source of this._sources) {
      this.add(new PipeTask(source, this._destination), {end: false})
    }
    return super._start()
      .then(() => this._destination.end())
  }
}
<|endoftext|>