<commit_before>/*
 *
 * Author: Vova Zaytsev <zaytsev@usc.edu>
 *
 */

function StoryGraph(data) {
    /*
     *
     *
     */

    this.data = data;
    this.gfx = {};
    this.distr = null;

};

//
StoryGraph.prototype.getNode = function(nodeId) {
    /*
     *
     *
     */

    return this.data.nodes[nodeId];

}

//
StoryGraph.prototype.getNodes = function() {
    /*
     *
     *
     */

    return d3.values(this.data.nodes);

}

//
StoryGraph.prototype.getCentralNode = function() {
    /*
     *
     *
     */

     var centralNodeId = this.data.meta.centralNode;

     return this.getNode(centralNodeId);

}

//
StoryGraph.prototype.computeDistribution = function() {

    this.distr = new StoryDistribution(this);

}

//
StoryGraph.prototype.drawDistribution = function(placeId, width, height) {

    if (!this.distr)
        this.computeDistribution();

    var sg = this;
    var radius = 10;
    var ticks = 7;
    var data = [];
    var dates = this.distr.getDateRange();
    var l = this.distr.str2Date(this.distr.lD);
    var f = this.distr.str2Date(this.distr.fD);

    for (var i in dates)
        data.push({
            "key": this.distr.str2Date(dates[i]),
            "value": this.distr.getDistrValue(dates[i])
        });

    var margin = {top: 20, right: 20, bottom: 64, left: 60},
        width =  width - margin.left - margin.right,
        height = height - margin.top - margin.bottom;

    this.gfx.xScale = d3.time.scale().domain([f, l]).range([0, width]);
    this.gfx.yScale = d3.scale.linear().range([height, 0]);
    var xScale = this.gfx.xScale, yScale = this.gfx.yScale;
    yScale.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Interpolate counts
    var line = d3.svg.line()
        .interpolate("basis")
        .x(function(d) { return xScale(d.key); })
        .y(function(d) { return yScale(d.value); });

    // Generate axises
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom")
        .ticks(ticks)
        .tickFormat(d3.time.format("%Y.%m.%d"));
    var yAxis = d3.svg.axis().scale(yScale).orient("left");

    var svg = d3.select("#" + placeId).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.selectAll("line.verticalGrid").data(xScale.ticks(ticks)).enter()
        .append("line")
        .attr({
            "class":"verticalGrid",
            "y1": 0,
            "y2": height,
            "x1": function(d){ return xScale(d);},
            "x2": function(d){ return xScale(d);},
            "fill": "none",
            "shape-rendering": "crispEdges",
            "stroke" : "#EEE",
            "stroke-width": "1px"
        });

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
        .selectAll("text")
        .attr("dy", ".25em")
        .attr("dx", "-2em")
        .attr("transform", "rotate(-45)");

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("class", "label")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Daily News Volume");

    svg.append("path")
        .datum(data)
        .attr("class", "line")
        .attr("d", line)
        .attr("id", "VolumeDistribution")

    svg.append("g")
        .datum(data)
        .attr("class", "line")
        .attr("d", line);

    this.gfx.SetDistributionSelection = function(referencesList) {

        var dates = [];
        for (var i in referencesList) {
            var refId = referencesList[i];
            var node = sg.getNode(refId);
            if (node.pubDate) {
                var start = sg.distr.str2Date(node.pubDate);
                var end = sg.distr.addDays(start, 2);
                start = sg.distr.addDays(start, -2);
                dates.push({
                    "start": start,
                    "end": end
                });
            }
        }

        svg.selectAll("rect.DistrSelectionBar").remove();
        svg.selectAll("rect.DistrSelectionBar")
            .data(dates).enter()
            .insert("rect", "#VolumeDistribution")
            .attr("class", "DistrSelectionBar")
            .attr("x", function(dRange) {
                return xScale(dRange.start)-4;
            })
            .attr("y", 0)
            .attr("height", height)
            .attr("width", function(dRange) {
                return 8;
            });

    };

}

//
StoryGraph.prototype.drawNetwork = function(placeId, width, height, config) {

    if (!config) {
        config = {
            "gravity": 0.08,
            "linkDistance": 40,
            "charge": -200,
            "radius": 6
        }
    }

    if (!this.distr)
        this.computeDistribution();

    var sg = this;

    var svg = d3.select("#"+placeId).append("svg")
        .attr("width", width)
        .attr("height", height);

    svg.append("rect")
        .attr("width", width)
        .attr("height", height);

    var force = d3.layout.force()
        .gravity(config.gravity)
        .linkDistance(config.linkDistance)
        .charge(config.charge)
        .size([width, height])
        .nodes([])
        .links([]);

    var nwNodes = force.nodes();
    var nwLinks = force.links();

    var linkSelector = svg.selectAll(".link");
    var nodeSelector = svg.selectAll(".node");

    force.on("tick", function() {

        nodeSelector.each(function(d) {

          if (d.isFixed) {
              d.x = d.px = Math.min(d.boxX + 50, Math.max(d.boxX - 50, d.px));
              d.y = d.py = Math.min(d.boxY + 75, Math.max(d.boxY - 75, d.py));
          }

        });

        linkSelector.attr("x1", function(d) { return d.source.x; })
            .attr("y1", function(d) { return d.source.y; })
            .attr("x2", function(d) { return d.target.x; })
            .attr("y2", function(d) { return d.target.y; });

        nodeSelector.attr("transform", function(d) {
            var x = Math.max(config.radius, Math.min(width - config.radius, d.x));
            var y = Math.max(config.radius, Math.min(height - config.radius, d.y));
            return "translate(" + x + "," + y + ")";
        });

    });

    this.gfx.SetNetworkSelection = function(referencesList) {

        nwNodes.splice(0, nwNodes.length);
        nwLinks.splice(0, nwLinks.length);

        var nwNodesI = {};

        if (!referencesList || referencesList.length == 0) {

            for (var i in sg.data.nodes) {
                var node = new StoryNode(sg.data.nodes[i], sg, config, height, width);
                nwNodes.push(node);
                nwNodesI[node.data.refId] = node;
            }

            for (var i in sg.data.edges) {
                var edge = sg.data.edges[i];
                var sourceRefId = edge[0];
                var targetRefId = edge[1];
                var sourceNode = nwNodesI[sourceRefId];
                var targetNode = nwNodesI[targetRefId];
                var newLink = {"source": sourceNode, "target": targetNode};
                nwLinks.push(newLink);
            }

        } else {

            for (var i in referencesList) {
                var k = referencesList[i];
                var node = new StoryNode(sg.data.nodes[k], sg, config, height, width);
                nwNodes.push(node);
                nwNodesI[node.data.refId] = node;
            }

            for (var i in sg.data.edges) {
                var edge = sg.data.edges[i];
                var sourceRefId = edge[0];
                var targetRefId = edge[1];
                if (nwNodesI[sourceRefId] && nwNodesI[targetRefId]) {
                    var sourceNode = nwNodesI[sourceRefId];
                    var targetNode = nwNodesI[targetRefId];
                    var newLink = {"source": sourceNode, "target": targetNode};
                    nwLinks.push(newLink);
                }
            }
        }

        linkSelector = linkSelector.data(nwLinks);
        linkSelector.enter()
            .append("line")
            .attr("class", "link");

        nodeSelector = nodeSelector.data(nwNodes);
        nodeGSelector = nodeSelector.enter()
            .append("g")
            .attr("class", "node")
            .call(force.drag);
        nodeGSelector.append("circle")
            .attr("cx", 0)
            .attr("cy", 0)
            .attr("class", "nodecircle")
            .attr("r", function(d) { return d.radius; });
        nodeGSelector.append("text")
            .attr("dx", 12)
            .attr("dy", ".35em")
            .attr("class", "nodetext")
            .text(function(d) { return d.data.title; });

        linkSelector.exit().remove();
        nodeSelector.exit().remove();
        force.start();

    };

    this.gfx.SetNetworkSelection();

};

//
function StoryNode(node, sg, config, height, width) {
    this.boxX = node.pubDate? sg.gfx.xScale(sg.distr.str2Date(node.pubDate)) : width / 2;
    this.boxY = height / 2;
    this.index = node.refId;
    this.radius = config.radius;
    this.data = node;
    this.isFixed = false;//node.pubDate && sg.distr.referenceTop[node.pubDate].node.refId == node.refId;
    this.fixed = false;

    if (sg.distr.topKIndeces.indexOf(this.data.refId) > -1) {
        this.isFixed = true;
        this.y = this.boxY;
        this.x = this.boxX;
    }
};

//
function StoryDistribution(storyGraph, dateMargins, topK) {

    if (!topK)
        topK = 6;

    this.sg = storyGraph;
    this.str2Date = d3.time.format("%Y.%m.%d").parse;
    this.date2Str = d3.time.format("%Y.%m.%d")

    this.dates = [];
    this.dateNodes = [];
    this.average = 0.0;

    for (var i in this.sg.data.nodes) {
        var node = this.sg.data.nodes[i];
        var pd = node.pubDate;
        if (pd) {
            this.dates.push(pd);
            if (this.dateNodes[pd]) this.dateNodes[pd].push(node)
            else this.dateNodes[pd] = [node];
        }
    }

    var datesNumber = 0;
    for (var d in this.dateNodes) {
        this.average += this.dateNodes[d].length;
        datesNumber += 1;
    }
    this.average /= datesNumber;

    this.firstDate = d3.min(this.dates);
    this.lastDate = d3.max(this.dates);

    if(!dateMargins) {
        var first = this.str2Date(this.firstDate);
        var last = this.str2Date(this.lastDate);
        dateMargins = this.daysDiff(first, last) / 10;
    }

    this.fD = this.date2Str(this.addDays(this.str2Date(this.firstDate), -dateMargins));
    this.lD = this.date2Str(this.addDays(this.str2Date(this.lastDate), +dateMargins));

    this.referenceTop = {};
    for (var i in this.sg.data.nodes) {
        var node = this.sg.data.nodes[i];
        var pd = node.pubDate;
        var rc = node.referenceCount;
        if (pd && !this.referenceTop[pd] || (this.referenceTop[pd] && this.referenceTop[pd].rc < rc)) {
            this.referenceTop[pd] = {"rc": rc, "pd": pd, "node": node};
        }
    }

    this.topK = {};
    var topNodes = [];
    for (var pd in this.referenceTop)
        topNodes.push(this.referenceTop[pd]);

    topNodes.sort(function(a, b) {
        if(a.rc > b.rc) return -1;
        if(a.rc < b.rc) return 1;
        return 0;
    });

    this.topK = topNodes.slice(0, topK);
    this.topKIndeces = [];
    for (var i in this.topK)
        this.topKIndeces.push(this.topK[i].node.refId);

    this.dateDistr = [];
    for (var i in this.dates) {
        var date = this.dates[i];
        var nodes = this.dateNodes[date];
        if (node) {

            var selection = [];
            for (var j in nodes)
                selection.push(nodes[j].refId);

            this.dateDistr.push({
                "selected": false,
                "date": date,
                "nodes": nodes,
                "selection": selection,
                "documentsCount": this.dateNodes[date].length
            })
        }
    }
};

//
StoryDistribution.prototype.SelectTopFrom = function(sgNodeSubset, k) {

    k = Math.min(k, sgNodeSubset.length);
    if (k == 0)
        return [];

    this.nodeArray = [];

};

//
StoryDistribution.prototype.addDays = function(date, deltaDays) {
    var dat = new Date(date.valueOf());
    dat.setDate(dat.getDate() + deltaDays);
    return dat;
};

//
StoryDistribution.prototype.dateRange = function(start, end) {
    var dateArray = [];
    var currentDate = start;
    while (currentDate <= end) {
        dateArray.push(this.date2Str(new Date(currentDate)));
        currentDate = this.addDays(currentDate, 1);
    }
    return dateArray;
};

//
StoryDistribution.prototype.getDistrValue = function(date) {
    if (this.dateNodes[date])
        return this.dateNodes[date].length;
    return 0;
};

//
StoryDistribution.prototype.getDateRange = function() {
    return this.dateRange(this.str2Date(this.fD), this.str2Date(this.lD));
};

//
StoryDistribution.prototype.daysDiff = function(first, second) {
    return (second-first)/(1000*60*60*24);
};<commit_msg>update contrib data<commit_after>/*
 *
 * Author: Vova Zaytsev <zaytsev@usc.edu>
 *
 */

function StoryGraph(data) {
    /*
     *
     *
     */

    this.data = data;
    this.gfx = {};
    this.distr = null;

};

//
StoryGraph.prototype.getNode = function(nodeId) {
    /*
     *
     *
     */

    return this.data.nodes[nodeId];

}

//
StoryGraph.prototype.getNodes = function() {
    /*
     *
     *
     */

    return d3.values(this.data.nodes);

}

//
StoryGraph.prototype.getCentralNode = function() {
    /*
     *
     *
     */

     var centralNodeId = this.data.meta.centralNode;

     return this.getNode(centralNodeId);

}

//
StoryGraph.prototype.computeDistribution = function() {

    this.distr = new StoryDistribution(this);

}

//
StoryGraph.prototype.drawDistribution = function(placeId, width, height) {

    if (!this.distr)
        this.computeDistribution();

    var sg = this;
    var radius = 10;
    var ticks = 7;
    var data = [];
    var dates = this.distr.getDateRange();
    var l = this.distr.str2Date(this.distr.lD);
    var f = this.distr.str2Date(this.distr.fD);

    for (var i in dates)
        data.push({
            "key": this.distr.str2Date(dates[i]),
            "value": this.distr.getDistrValue(dates[i])
        });

    var margin = {top: 20, right: 20, bottom: 64, left: 60},
        width =  width - margin.left - margin.right,
        height = height - margin.top - margin.bottom;

    this.gfx.xScale = d3.time.scale().domain([f, l]).range([0, width]);
    this.gfx.yScale = d3.scale.linear().range([height, 0]);
    var xScale = this.gfx.xScale, yScale = this.gfx.yScale;
    yScale.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Interpolate counts
    var line = d3.svg.line()
        .interpolate("basis")
        .x(function(d) { return xScale(d.key); })
        .y(function(d) { return yScale(d.value); });

    // Generate axises
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom")
        .ticks(ticks)
        .tickFormat(d3.time.format("%Y.%m.%d"));
    var yAxis = d3.svg.axis().scale(yScale).orient("left");

    var svg = d3.select("#" + placeId).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.selectAll("line.verticalGrid").data(xScale.ticks(ticks)).enter()
        .append("line")
        .attr({
            "class":"verticalGrid",
            "y1": 0,
            "y2": height,
            "x1": function(d){ return xScale(d);},
            "x2": function(d){ return xScale(d);},
            "fill": "none",
            "shape-rendering": "crispEdges",
            "stroke" : "#EEE",
            "stroke-width": "1px"
        });

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
        .selectAll("text")
        .attr("dy", ".25em")
        .attr("dx", "-2em")
        .attr("transform", "rotate(-45)");

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("class", "label")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Daily News Volume");

    svg.append("path")
        .datum(data)
        .attr("class", "line")
        .attr("d", line)
        .attr("id", "VolumeDistribution")

    svg.append("g")
        .datum(data)
        .attr("class", "line")
        .attr("d", line);

    this.gfx.SetDistributionSelection = function(referencesList) {

        var dates = [];
        for (var i in referencesList) {
            var refId = referencesList[i];
            var node = sg.getNode(refId);
            if (node.pubDate) {
                var start = sg.distr.str2Date(node.pubDate);
                var end = sg.distr.addDays(start, 2);
                start = sg.distr.addDays(start, -2);
                dates.push({
                    "start": start,
                    "end": end
                });
            }
        }

        svg.selectAll("rect.DistrSelectionBar").remove();
        svg.selectAll("rect.DistrSelectionBar")
            .data(dates).enter()
            .insert("rect", "#VolumeDistribution")
            .attr("class", "DistrSelectionBar")
            .attr("x", function(dRange) {
                return xScale(dRange.start)-4;
            })
            .attr("y", 0)
            .attr("height", height)
            .attr("width", function(dRange) {
                return 8;
            });

    };

}

//
StoryGraph.prototype.drawNetwork = function(placeId, width, height, config) {

    if (!config) {
        config = {
            "gravity": 0.08,
            "linkDistance": 40,
            "charge": -200,
            "radius": 6
        }
    }

    if (!this.distr)
        this.computeDistribution();

    var sg = this;

    var svg = d3.select("#"+placeId).append("svg")
        .attr("width", width)
        .attr("height", height);

    svg.append("rect")
        .attr("width", width)
        .attr("height", height);

    var force = d3.layout.force()
        .gravity(config.gravity)
        .linkDistance(config.linkDistance)
        .charge(config.charge)
        .size([width, height])
        .nodes([])
        .links([]);

    var nwNodes = force.nodes();
    var nwLinks = force.links();

    var linkSelector = svg.selectAll(".link");
    var nodeSelector = svg.selectAll(".node");

    nodeSelector.on("click", function(data) {

        console.log(["data", data]);

        console.log(["this", d3.select(this)]);

    });

    force.on("tick", function() {

        nodeSelector.each(function(d) {

          if (d.isFixed) {
              d.x = d.px = Math.min(d.boxX + 50, Math.max(d.boxX - 50, d.px));
              d.y = d.py = Math.min(d.boxY + 75, Math.max(d.boxY - 75, d.py));
          }

        });

        linkSelector.attr("x1", function(d) { return d.source.x; })
            .attr("y1", function(d) { return d.source.y; })
            .attr("x2", function(d) { return d.target.x; })
            .attr("y2", function(d) { return d.target.y; });

        nodeSelector.attr("transform", function(d) {
            var x = Math.max(config.radius, Math.min(width - config.radius, d.x));
            var y = Math.max(config.radius, Math.min(height - config.radius, d.y));
            return "translate(" + x + "," + y + ")";
        });

    });

    this.gfx.SetNetworkSelection = function(referencesList) {

        nwNodes.splice(0, nwNodes.length);
        nwLinks.splice(0, nwLinks.length);

        var nwNodesI = {};

        if (!referencesList || referencesList.length == 0) {

            for (var i in sg.data.nodes) {
                var node = new StoryNode(sg.data.nodes[i], sg, config, height, width);
                nwNodes.push(node);
                nwNodesI[node.data.refId] = node;
            }

            for (var i in sg.data.edges) {
                var edge = sg.data.edges[i];
                var sourceRefId = edge[0];
                var targetRefId = edge[1];
                var sourceNode = nwNodesI[sourceRefId];
                var targetNode = nwNodesI[targetRefId];
                var newLink = {"source": sourceNode, "target": targetNode};
                nwLinks.push(newLink);
            }

        } else {

            for (var i in referencesList) {
                var k = referencesList[i];
                var node = new StoryNode(sg.data.nodes[k], sg, config, height, width);
                nwNodes.push(node);
                nwNodesI[node.data.refId] = node;
            }

            for (var i in sg.data.edges) {
                var edge = sg.data.edges[i];
                var sourceRefId = edge[0];
                var targetRefId = edge[1];
                if (nwNodesI[sourceRefId] && nwNodesI[targetRefId]) {
                    var sourceNode = nwNodesI[sourceRefId];
                    var targetNode = nwNodesI[targetRefId];
                    var newLink = {"source": sourceNode, "target": targetNode};
                    nwLinks.push(newLink);
                }
            }
        }

        linkSelector = linkSelector.data(nwLinks);
        linkSelector.enter()
            .append("line")
            .attr("class", "link");

        nodeSelector = nodeSelector.data(nwNodes);
        nodeGSelector = nodeSelector.enter()
            .append("g")
            .attr("class", "node")
            .call(force.drag);
        nodeGSelector.append("circle")
            .attr("cx", 0)
            .attr("cy", 0)
            .attr("class", "nodecircle")
            .attr("r", function(d) { return d.radius; });
        nodeGSelector.append("text")
            .attr("dx", 12)
            .attr("dy", ".35em")
            .attr("class", "nodetext")
            .text(function(d) { return d.data.title; });

        linkSelector.exit().remove();
        nodeSelector.exit().remove();
        force.start();

    };

    this.gfx.SetNetworkSelection();

};

//
function StoryNode(node, sg, config, height, width) {
    this.boxX = node.pubDate? sg.gfx.xScale(sg.distr.str2Date(node.pubDate)) : width / 2;
    this.boxY = height / 2;
    this.index = node.refId;
    this.radius = config.radius;
    this.data = node;
    this.isFixed = false;//node.pubDate && sg.distr.referenceTop[node.pubDate].node.refId == node.refId;
    this.fixed = false;

    if (sg.distr.topKIndeces.indexOf(this.data.refId) > -1) {
        this.isFixed = true;
        this.y = this.boxY;
        this.x = this.boxX;
    }
};

//
function StoryDistribution(storyGraph, dateMargins, topK) {

    if (!topK)
        topK = 6;

    this.sg = storyGraph;
    this.str2Date = d3.time.format("%Y.%m.%d").parse;
    this.date2Str = d3.time.format("%Y.%m.%d")

    this.dates = [];
    this.dateNodes = [];
    this.average = 0.0;

    for (var i in this.sg.data.nodes) {
        var node = this.sg.data.nodes[i];
        var pd = node.pubDate;
        if (pd) {
            this.dates.push(pd);
            if (this.dateNodes[pd]) this.dateNodes[pd].push(node)
            else this.dateNodes[pd] = [node];
        }
    }

    var datesNumber = 0;
    for (var d in this.dateNodes) {
        this.average += this.dateNodes[d].length;
        datesNumber += 1;
    }
    this.average /= datesNumber;

    this.firstDate = d3.min(this.dates);
    this.lastDate = d3.max(this.dates);

    if(!dateMargins) {
        var first = this.str2Date(this.firstDate);
        var last = this.str2Date(this.lastDate);
        dateMargins = this.daysDiff(first, last) / 10;
    }

    this.fD = this.date2Str(this.addDays(this.str2Date(this.firstDate), -dateMargins));
    this.lD = this.date2Str(this.addDays(this.str2Date(this.lastDate), +dateMargins));

    this.referenceTop = {};
    for (var i in this.sg.data.nodes) {
        var node = this.sg.data.nodes[i];
        var pd = node.pubDate;
        var rc = node.referenceCount;
        if (pd && !this.referenceTop[pd] || (this.referenceTop[pd] && this.referenceTop[pd].rc < rc)) {
            this.referenceTop[pd] = {"rc": rc, "pd": pd, "node": node};
        }
    }

    this.topK = {};
    var topNodes = [];
    for (var pd in this.referenceTop)
        topNodes.push(this.referenceTop[pd]);

    topNodes.sort(function(a, b) {
        if(a.rc > b.rc) return -1;
        if(a.rc < b.rc) return 1;
        return 0;
    });

    this.topK = topNodes.slice(0, topK);
    this.topKIndeces = [];
    for (var i in this.topK)
        this.topKIndeces.push(this.topK[i].node.refId);

    this.dateDistr = [];
    for (var i in this.dates) {

        var date = this.dates[i];
        var nodes = this.dateNodes[date];

        if (node) {

            var selection = [];
            for (var j in nodes)
                selection.push(nodes[j].refId);

            this.dateDistr.push({
                "date": date,
                "nodes": nodes,
                "selected": false,
                "selection": selection,
                "documentsCount": this.dateNodes[date].length
            })

        }
    }
};

//
StoryDistribution.prototype.SelectTopFrom = function(sgNodeSubset, k) {

    k = Math.min(k, sgNodeSubset.length);
    if (k == 0)
        return [];

    this.nodeArray = [];

};

//
StoryDistribution.prototype.addDays = function(date, deltaDays) {
    var dat = new Date(date.valueOf());
    dat.setDate(dat.getDate() + deltaDays);
    return dat;
};

//
StoryDistribution.prototype.dateRange = function(start, end) {
    var dateArray = [];
    var currentDate = start;
    while (currentDate <= end) {
        dateArray.push(this.date2Str(new Date(currentDate)));
        currentDate = this.addDays(currentDate, 1);
    }
    return dateArray;
};

//
StoryDistribution.prototype.getDistrValue = function(date) {
    if (this.dateNodes[date])
        return this.dateNodes[date].length;
    return 0;
};

//
StoryDistribution.prototype.getDateRange = function() {
    return this.dateRange(this.str2Date(this.fD), this.str2Date(this.lD));
};

//
StoryDistribution.prototype.daysDiff = function(first, second) {
    return (second-first)/(1000*60*60*24);
};<|endoftext|>


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

  // default layout options
  var defaults = {
    animate: true, // whether to show the layout as it's running
    refresh: 1, // number of ticks per frame; higher is faster but more jerky
    maxSimulationTime: 4000, // max length in ms to run the layout
    ungrabifyWhileSimulating: false, // so you can't drag nodes during layout
    fit: true, // on every layout reposition of nodes, fit the viewport
    padding: 30, // padding around the simulation
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }

    // layout event callbacks
    ready: function(){}, // on layoutready
    stop: function(){}, // on layoutstop

    // positioning options
    randomize: false, // use random node positions at beginning of layout
    avoidOverlap: true, // if true, prevents overlap of node bounding boxes
    handleDisconnected: true, // if true, avoids disconnected components from overlapping
    nodeSpacing: function( node ){ return 10; }, // extra spacing around nodes
    flow: undefined, // use DAG/tree flow layout if specified, e.g. { axis: 'y', minSeparation: 30 }
    alignment: undefined, // relative alignment constraints on nodes, e.g. function( node ){ return { x: 0, y: 1 } }

    // different methods of specifying edge length
    // each can be a constant numerical value or a function like `function( edge ){ return 2; }`
    edgeLength: undefined, // sets edge length directly in simulation
    edgeSymDiffLength: undefined, // symmetric diff edge length in simulation
    edgeJaccardLength: undefined, // jaccard edge length in simulation

    // iterations of cola algorithm; uses default values on undefined
    unconstrIter: undefined, // unconstrained initial layout iterations
    userConstIter: undefined, // initial layout iterations with user-specified constraints
    allConstIter: undefined, // initial layout iterations with all constraints including non-overlap

    // infinite layout options
    infinite: false // overrides all other options for a forces-all-the-time mode
  };

  // constructor
  // options : object containing layout options
  function ColaLayout( options ){
    this.options = $$.util.extend(true, {}, defaults, options);
  }

  // runs the layout
  ColaLayout.prototype.run = function(){
    var layout = this;
    var options = this.options;

    layout.manuallyStopped = false;

    $$.util.require('cola', function(cola){

      var cy = options.cy; // cy is automatically populated for us in the constructor
      var eles = options.eles;
      var nodes = eles.nodes();
      var edges = eles.edges();
      var ready = false;

      var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
        x1: 0, y1: 0, w: cy.width(), h: cy.height()
      } );

      var getOptVal = function( val, ele ){
        if( $$.is.fn(val) ){
          var fn = val;
          return fn.apply( ele, [ ele ] );
        } else {
          return val;
        }
      };

      var updateNodePositions = function(){
        var x = { min: Infinity, max: -Infinity };
        var y = { min: Infinity, max: -Infinity };

        for( var i = 0; i < nodes.length; i++ ){
          var node = nodes[i];
          var scratch = node._private.scratch.cola;

          x.min = Math.min( x.min, scratch.x || 0 );
          x.max = Math.max( x.max, scratch.x || 0 );

          y.min = Math.min( y.min, scratch.y || 0 );
          y.max = Math.max( y.max, scratch.y || 0 );
        }

        nodes.positions(function(i, node){
          var scratch = node._private.scratch.cola;
          var retPos;

          if( !node.grabbed() && !node.isParent() ){
            retPos = {
              x: bb.x1 + scratch.x - x.min,
              y: bb.y1 + scratch.y - y.min
            };

            if( !$$.is.number(retPos.x) || !$$.is.number(retPos.y) ){
              retPos = undefined;
            }
          }

          return retPos;
        });

        nodes.updateCompoundBounds(); // because the way this layout sets positions is buggy for some reason; ref #878

        if( !ready ){
          onReady();
          ready = true;
        }

        if( options.fit ){
          cy.fit( options.padding );
        }
      };

      var onDone = function(){
        if( options.ungrabifyWhileSimulating ){
          grabbableNodes.grabify();
        }

        nodes.off('grab free position', grabHandler);
        nodes.off('lock unlock', lockHandler);

        // trigger layoutstop when the layout stops (e.g. finishes)
        layout.one('layoutstop', options.stop);
        layout.trigger({ type: 'layoutstop', layout: layout });
      };

      var onReady = function(){
        // trigger layoutready when each node has had its position set at least once
        layout.one('layoutready', options.ready);
        layout.trigger({ type: 'layoutready', layout: layout });
      };

      var ticksPerFrame = options.refresh;
      var tickSkip = 1; // frames until a tick; used to slow down sim for debugging

      if( options.refresh < 0 ){
        tickSkip = Math.abs( options.refresh );
        ticksPerFrame = 1;
      } else {
        ticksPerFrame = Math.max( 1, ticksPerFrame ); // at least 1
      }

      var adaptor = layout.adaptor = cola.adaptor({
        trigger: function( e ){ // on sim event
          switch( e.type ){
            case 'tick':
              if( options.animate ){
                updateNodePositions();
              }
              break;

            case 'end':
              updateNodePositions();
              if( !options.infinite ){ onDone(); }
              break;
          }
        },

        kick: function( tick ){ // kick off the simulation
          var skip = 0;

          var inftick = function(){
            if( layout.manuallyStopped ){
              onDone();

              return true;
            }

            var ret = tick();

            if( ret && options.infinite ){ // resume layout if done
              adaptor.resume(); // resume => new kick
            }

            return ret; // allow regular finish b/c of new kick
          };

          var multitick = function(){ // multiple ticks in a row
            var ret;

            // skip ticks to slow down layout for debugging
            // var thisSkip = skip;
            // skip = (skip + 1) % tickSkip;
            // if( thisSkip !== 0 ){
            //   return false;
            // }

            for( var i = 0; i < ticksPerFrame && !ret; i++ ){
              ret = ret || inftick(); // pick up true ret vals => sim done
            }

            return ret;
          };

          if( options.animate ){
            var frame = function(){
              if( multitick() ){ return; }

              $$.util.requestAnimationFrame( frame );
            };

            $$.util.requestAnimationFrame( frame );
          } else {
            while( !inftick() ){}
          }
        },

        on: function( type, listener ){}, // dummy; not needed

        drag: function(){} // not needed for our case
      });
      layout.adaptor = adaptor;

      // if set no grabbing during layout
      var grabbableNodes = nodes.filter(':grabbable');
      if( options.ungrabifyWhileSimulating ){
        grabbableNodes.ungrabify();
      }

      // handle node dragging
      var grabHandler;
      nodes.on('grab free position', grabHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;
        var pos = node._private.position;

        if( node.grabbed() ){
          scrCola.x = pos.x - bb.x1;
          scrCola.y = pos.y - bb.y1;

          adaptor.dragstart( scrCola );
        } else if( $$.is.number(scrCola.x) && $$.is.number(scrCola.y) ){
          pos.x = scrCola.x + bb.x1;
          pos.y = scrCola.y + bb.y1;
        }

        switch( e.type ){
          case 'grab':
            adaptor.dragstart( scrCola );
            adaptor.resume();
            break;
          case 'free':
            adaptor.dragend( scrCola );
            break;
        }

      });

      var lockHandler;
      nodes.on('lock unlock', lockHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;

        if( node.locked() ){
          adaptor.dragstart( scrCola );
        } else {
          adaptor.dragend( scrCola );
        }
      });

      var nonparentNodes = nodes.stdFilter(function( node ){
        return !node.isParent();
      });

      // add nodes to cola
      adaptor.nodes( nonparentNodes.map(function( node, i ){
        var padding = getOptVal( options.nodeSpacing, node );
        var pos = node.position();

        var struct = node._private.scratch.cola = {
          x: options.randomize ? Math.round( Math.random() * bb.w ) : pos.x,
          y: options.randomize ? Math.round( Math.random() * bb.h ) : pos.y,
          width: node.outerWidth() + 2*padding,
          height: node.outerHeight() + 2*padding,
          index: i
        };

        return struct;
      }) );

      if( options.alignment ){ // then set alignment constraints

        var offsetsX = [];
        var offsetsY = [];

        nonparentNodes.forEach(function( node ){
          var align = getOptVal( options.alignment, node );
          var scrCola = node._private.scratch.cola;
          var index = scrCola.index;

          if( !align ){ return; }

          if( align.x != null ){
            offsetsX.push({
              node: index,
              offset: align.x
            });
          }

          if( align.y != null ){
            offsetsY.push({
              node: index,
              offset: align.y
            });
          }
        });

        // add alignment constraints on nodes
        var constraints = [];

        if( offsetsX.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'x',
            offsets: offsetsX
          });
        }

        if( offsetsY.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'y',
            offsets: offsetsY
          });
        }

        adaptor.constraints( constraints );

      }

      // add compound nodes to cola
      adaptor.groups( nodes.stdFilter(function( node ){
        return node.isParent();
      }).map(function( node, i ){ // add basic group incl leaf nodes
        node._private.scratch.cola = {
          index: i,

          leaves: node.descendants().stdFilter(function( child ){
            return !child.isParent();
          }).map(function( child ){
            return child[0]._private.scratch.cola.index;
          })
        };

        return node;
      }).map(function( node ){ // add subgroups
        node._private.scratch.cola.groups = node.descendants().stdFilter(function( child ){
          return child.isParent();
        }).map(function( child ){
          return child._private.scratch.cola.index;
        });

        return node._private.scratch.cola;
      }) );

      // get the edge length setting mechanism
      var length;
      var lengthFnName;
      if( options.edgeLength != null ){
        length = options.edgeLength;
        lengthFnName = 'linkDistance';
      } else if( options.edgeSymDiffLength != null ){
        length = options.edgeSymDiffLength;
        lengthFnName = 'symmetricDiffLinkLengths';
      } else if( options.edgeJaccardLength != null ){
        length = options.edgeJaccardLength;
        lengthFnName = 'jaccardLinkLengths';
      } else {
        length = 100;
        lengthFnName = 'linkDistance';
      }

      var lengthGetter = function( link ){
        return link.calcLength;
      };

      // add the edges to cola
      adaptor.links( edges.stdFilter(function( edge ){
        return !edge.source().isParent() && !edge.target().isParent();
      }).map(function( edge, i ){
        var c = edge._private.scratch.cola = {
          source: edge.source()[0]._private.scratch.cola.index,
          target: edge.target()[0]._private.scratch.cola.index
        };

        if( length != null ){
          c.calcLength = getOptVal( length, edge );
        }

        return c;
      }) );

      adaptor.size([ bb.w, bb.h ]);

      if( length != null ){
        adaptor[ lengthFnName ]( lengthGetter );
      }

      // set the flow of cola
      if( options.flow ){
        var flow;
        var defAxis = 'y';
        var defMinSep = 50;

        if( $$.is.string(options.flow) ){
          flow = {
            axis: options.flow,
            minSeparation: defMinSep
          };
        } else if( $$.is.number(options.flow) ){
          flow = {
            axis: defAxis,
            minSeparation: options.flow
          };
        } else if( $$.is.plainObject(options.flow) ){
          flow = options.flow;

          flow.axis = flow.axis || defAxis;
          flow.minSeparation = flow.minSeparation != null ? flow.minSeparation : defMinSep;
        } else { // e.g. options.flow: true
          flow = {
            axis: defAxis,
            minSeparation: defMinSep
          };
        }

        adaptor.flowLayout( flow.axis , flow.minSeparation );
      }

      layout.trigger({ type: 'layoutstart', layout: layout });

      adaptor
        .avoidOverlaps( options.avoidOverlap )
        .handleDisconnected( options.handleDisconnected )
        .start( options.unconstrIter, options.userConstIter, options.allConstIter)
      ;

      if( !options.infinite ){
        setTimeout(function(){
          if( !layout.manuallyStopped ){
            adaptor.stop();
          }
        }, options.maxSimulationTime);
      }

    }); // require

    return this; // chaining
  };

  // called on continuous layouts to stop them before they finish
  ColaLayout.prototype.stop = function(){
    if( this.adaptor ){
      this.manuallyStopped = true;
      this.adaptor.stop();
    }

    return this; // chaining
  };

  // register the layout
  $$('layout', 'cola', ColaLayout);

})(cytoscape);
<commit_msg> Patch for future versions of Cola #1000<commit_after>;(function($$){ 'use strict';

  // default layout options
  var defaults = {
    animate: true, // whether to show the layout as it's running
    refresh: 1, // number of ticks per frame; higher is faster but more jerky
    maxSimulationTime: 4000, // max length in ms to run the layout
    ungrabifyWhileSimulating: false, // so you can't drag nodes during layout
    fit: true, // on every layout reposition of nodes, fit the viewport
    padding: 30, // padding around the simulation
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }

    // layout event callbacks
    ready: function(){}, // on layoutready
    stop: function(){}, // on layoutstop

    // positioning options
    randomize: false, // use random node positions at beginning of layout
    avoidOverlap: true, // if true, prevents overlap of node bounding boxes
    handleDisconnected: true, // if true, avoids disconnected components from overlapping
    nodeSpacing: function( node ){ return 10; }, // extra spacing around nodes
    flow: undefined, // use DAG/tree flow layout if specified, e.g. { axis: 'y', minSeparation: 30 }
    alignment: undefined, // relative alignment constraints on nodes, e.g. function( node ){ return { x: 0, y: 1 } }

    // different methods of specifying edge length
    // each can be a constant numerical value or a function like `function( edge ){ return 2; }`
    edgeLength: undefined, // sets edge length directly in simulation
    edgeSymDiffLength: undefined, // symmetric diff edge length in simulation
    edgeJaccardLength: undefined, // jaccard edge length in simulation

    // iterations of cola algorithm; uses default values on undefined
    unconstrIter: undefined, // unconstrained initial layout iterations
    userConstIter: undefined, // initial layout iterations with user-specified constraints
    allConstIter: undefined, // initial layout iterations with all constraints including non-overlap

    // infinite layout options
    infinite: false // overrides all other options for a forces-all-the-time mode
  };

  // constructor
  // options : object containing layout options
  function ColaLayout( options ){
    this.options = $$.util.extend(true, {}, defaults, options);
  }

  // runs the layout
  ColaLayout.prototype.run = function(){
    var layout = this;
    var options = this.options;

    layout.manuallyStopped = false;

    $$.util.require('cola', function(cola){

      var cy = options.cy; // cy is automatically populated for us in the constructor
      var eles = options.eles;
      var nodes = eles.nodes();
      var edges = eles.edges();
      var ready = false;

      var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
        x1: 0, y1: 0, w: cy.width(), h: cy.height()
      } );

      var getOptVal = function( val, ele ){
        if( $$.is.fn(val) ){
          var fn = val;
          return fn.apply( ele, [ ele ] );
        } else {
          return val;
        }
      };

      var updateNodePositions = function(){
        var x = { min: Infinity, max: -Infinity };
        var y = { min: Infinity, max: -Infinity };

        for( var i = 0; i < nodes.length; i++ ){
          var node = nodes[i];
          var scratch = node._private.scratch.cola;

          x.min = Math.min( x.min, scratch.x || 0 );
          x.max = Math.max( x.max, scratch.x || 0 );

          y.min = Math.min( y.min, scratch.y || 0 );
          y.max = Math.max( y.max, scratch.y || 0 );
        }

        nodes.positions(function(i, node){
          var scratch = node._private.scratch.cola;
          var retPos;

          if( !node.grabbed() && !node.isParent() ){
            retPos = {
              x: bb.x1 + scratch.x - x.min,
              y: bb.y1 + scratch.y - y.min
            };

            if( !$$.is.number(retPos.x) || !$$.is.number(retPos.y) ){
              retPos = undefined;
            }
          }

          return retPos;
        });

        nodes.updateCompoundBounds(); // because the way this layout sets positions is buggy for some reason; ref #878

        if( !ready ){
          onReady();
          ready = true;
        }

        if( options.fit ){
          cy.fit( options.padding );
        }
      };

      var onDone = function(){
        if( options.ungrabifyWhileSimulating ){
          grabbableNodes.grabify();
        }

        nodes.off('grab free position', grabHandler);
        nodes.off('lock unlock', lockHandler);

        // trigger layoutstop when the layout stops (e.g. finishes)
        layout.one('layoutstop', options.stop);
        layout.trigger({ type: 'layoutstop', layout: layout });
      };

      var onReady = function(){
        // trigger layoutready when each node has had its position set at least once
        layout.one('layoutready', options.ready);
        layout.trigger({ type: 'layoutready', layout: layout });
      };

      var ticksPerFrame = options.refresh;
      var tickSkip = 1; // frames until a tick; used to slow down sim for debugging

      if( options.refresh < 0 ){
        tickSkip = Math.abs( options.refresh );
        ticksPerFrame = 1;
      } else {
        ticksPerFrame = Math.max( 1, ticksPerFrame ); // at least 1
      }

      var adaptor = layout.adaptor = cola.adaptor({
        trigger: function( e ){ // on sim event
          var TICK = cola.EventType ? cola.EventType.tick : null;
          var END = cola.EventType ? cola.EventType.end : null;

          switch( e.type ){
            case 'tick':
            case TICK:
              if( options.animate ){
                updateNodePositions();
              }
              break;

            case 'end':
            case END:
              updateNodePositions();
              if( !options.infinite ){ onDone(); }
              break;
          }
        },

        kick: function(){ // kick off the simulation
          var skip = 0;

          var inftick = function(){
            if( layout.manuallyStopped ){
              onDone();

              return true;
            }

            var ret = adaptor.tick();

            if( ret && options.infinite ){ // resume layout if done
              adaptor.resume(); // resume => new kick
            }

            return ret; // allow regular finish b/c of new kick
          };

          var multitick = function(){ // multiple ticks in a row
            var ret;

            // skip ticks to slow down layout for debugging
            // var thisSkip = skip;
            // skip = (skip + 1) % tickSkip;
            // if( thisSkip !== 0 ){
            //   return false;
            // }

            for( var i = 0; i < ticksPerFrame && !ret; i++ ){
              ret = ret || inftick(); // pick up true ret vals => sim done
            }

            return ret;
          };

          if( options.animate ){
            var frame = function(){
              if( multitick() ){ return; }

              $$.util.requestAnimationFrame( frame );
            };

            $$.util.requestAnimationFrame( frame );
          } else {
            while( !inftick() ){}
          }
        },

        on: function( type, listener ){}, // dummy; not needed

        drag: function(){} // not needed for our case
      });
      layout.adaptor = adaptor;

      // if set no grabbing during layout
      var grabbableNodes = nodes.filter(':grabbable');
      if( options.ungrabifyWhileSimulating ){
        grabbableNodes.ungrabify();
      }

      // handle node dragging
      var grabHandler;
      nodes.on('grab free position', grabHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;
        var pos = node._private.position;

        if( node.grabbed() ){
          scrCola.x = pos.x - bb.x1;
          scrCola.y = pos.y - bb.y1;

          adaptor.dragstart( scrCola );
        } else if( $$.is.number(scrCola.x) && $$.is.number(scrCola.y) ){
          pos.x = scrCola.x + bb.x1;
          pos.y = scrCola.y + bb.y1;
        }

        switch( e.type ){
          case 'grab':
            adaptor.dragstart( scrCola );
            adaptor.resume();
            break;
          case 'free':
            adaptor.dragend( scrCola );
            break;
        }

      });

      var lockHandler;
      nodes.on('lock unlock', lockHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;

        if( node.locked() ){
          adaptor.dragstart( scrCola );
        } else {
          adaptor.dragend( scrCola );
        }
      });

      var nonparentNodes = nodes.stdFilter(function( node ){
        return !node.isParent();
      });

      // add nodes to cola
      adaptor.nodes( nonparentNodes.map(function( node, i ){
        var padding = getOptVal( options.nodeSpacing, node );
        var pos = node.position();

        var struct = node._private.scratch.cola = {
          x: options.randomize ? Math.round( Math.random() * bb.w ) : pos.x,
          y: options.randomize ? Math.round( Math.random() * bb.h ) : pos.y,
          width: node.outerWidth() + 2*padding,
          height: node.outerHeight() + 2*padding,
          index: i
        };

        return struct;
      }) );

      if( options.alignment ){ // then set alignment constraints

        var offsetsX = [];
        var offsetsY = [];

        nonparentNodes.forEach(function( node ){
          var align = getOptVal( options.alignment, node );
          var scrCola = node._private.scratch.cola;
          var index = scrCola.index;

          if( !align ){ return; }

          if( align.x != null ){
            offsetsX.push({
              node: index,
              offset: align.x
            });
          }

          if( align.y != null ){
            offsetsY.push({
              node: index,
              offset: align.y
            });
          }
        });

        // add alignment constraints on nodes
        var constraints = [];

        if( offsetsX.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'x',
            offsets: offsetsX
          });
        }

        if( offsetsY.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'y',
            offsets: offsetsY
          });
        }

        adaptor.constraints( constraints );

      }

      // add compound nodes to cola
      adaptor.groups( nodes.stdFilter(function( node ){
        return node.isParent();
      }).map(function( node, i ){ // add basic group incl leaf nodes
        node._private.scratch.cola = {
          index: i,

          leaves: node.descendants().stdFilter(function( child ){
            return !child.isParent();
          }).map(function( child ){
            return child[0]._private.scratch.cola.index;
          })
        };

        return node;
      }).map(function( node ){ // add subgroups
        node._private.scratch.cola.groups = node.descendants().stdFilter(function( child ){
          return child.isParent();
        }).map(function( child ){
          return child._private.scratch.cola.index;
        });

        return node._private.scratch.cola;
      }) );

      // get the edge length setting mechanism
      var length;
      var lengthFnName;
      if( options.edgeLength != null ){
        length = options.edgeLength;
        lengthFnName = 'linkDistance';
      } else if( options.edgeSymDiffLength != null ){
        length = options.edgeSymDiffLength;
        lengthFnName = 'symmetricDiffLinkLengths';
      } else if( options.edgeJaccardLength != null ){
        length = options.edgeJaccardLength;
        lengthFnName = 'jaccardLinkLengths';
      } else {
        length = 100;
        lengthFnName = 'linkDistance';
      }

      var lengthGetter = function( link ){
        return link.calcLength;
      };

      // add the edges to cola
      adaptor.links( edges.stdFilter(function( edge ){
        return !edge.source().isParent() && !edge.target().isParent();
      }).map(function( edge, i ){
        var c = edge._private.scratch.cola = {
          source: edge.source()[0]._private.scratch.cola.index,
          target: edge.target()[0]._private.scratch.cola.index
        };

        if( length != null ){
          c.calcLength = getOptVal( length, edge );
        }

        return c;
      }) );

      adaptor.size([ bb.w, bb.h ]);

      if( length != null ){
        adaptor[ lengthFnName ]( lengthGetter );
      }

      // set the flow of cola
      if( options.flow ){
        var flow;
        var defAxis = 'y';
        var defMinSep = 50;

        if( $$.is.string(options.flow) ){
          flow = {
            axis: options.flow,
            minSeparation: defMinSep
          };
        } else if( $$.is.number(options.flow) ){
          flow = {
            axis: defAxis,
            minSeparation: options.flow
          };
        } else if( $$.is.plainObject(options.flow) ){
          flow = options.flow;

          flow.axis = flow.axis || defAxis;
          flow.minSeparation = flow.minSeparation != null ? flow.minSeparation : defMinSep;
        } else { // e.g. options.flow: true
          flow = {
            axis: defAxis,
            minSeparation: defMinSep
          };
        }

        adaptor.flowLayout( flow.axis , flow.minSeparation );
      }

      layout.trigger({ type: 'layoutstart', layout: layout });

      adaptor
        .avoidOverlaps( options.avoidOverlap )
        .handleDisconnected( options.handleDisconnected )
        .start( options.unconstrIter, options.userConstIter, options.allConstIter)
      ;

      if( !options.infinite ){
        setTimeout(function(){
          if( !layout.manuallyStopped ){
            adaptor.stop();
          }
        }, options.maxSimulationTime);
      }

    }); // require

    return this; // chaining
  };

  // called on continuous layouts to stop them before they finish
  ColaLayout.prototype.stop = function(){
    if( this.adaptor ){
      this.manuallyStopped = true;
      this.adaptor.stop();
    }

    return this; // chaining
  };

  // register the layout
  $$('layout', 'cola', ColaLayout);

})(cytoscape);
<|endoftext|>


<commit_before>var xhr = new XMLHttpRequest();
xhr.open("GET", "cdeye/beans");
xhr.setRequestHeader("Accept", "application/json");
xhr.onreadystatechange = function(event) {
    if(xhr.readyState === 4)
        if (xhr.status === 200)
            display();
        else
            alert("CDEye not accessible!");
};
xhr.send();

function display() {
    var beans = JSON.parse(xhr.responseText);

    var nodes = [];
    var links = [];
    var producerGroups = [];

    var i, j;

    for (i = 0; i < beans.bean.length; i++) {
        var bean = beans.bean[i];
        if (!nodes[i])
            nodes[i] = {name: bean.classSimpleName, width: 200, height: 40};
        if (bean.injectionPoints) {
            var injectionPoints = bean.injectionPoints.injectionPoint;
            for (j = 0; j < injectionPoints.length; j++)
                links.push({source: parseInt(injectionPoints[j].bean), target: i});
        }
        if (bean.producers) {
            var producers = bean.producers.producer;
            var producerGroup = [];
            for (j = 0; j < producers.length; j++) {
                var producer = parseInt(producers[j].bean);
                producerGroup.push(producer);
                // Override the node with the producer member name
                nodes[producer] = {name: producers[j].name, width: 200, height: 40};
            }
            // TODO: find a way to have the declaring bean at the top of the group
            producerGroup.push(i);
            producerGroups.push(producerGroup);
        }
    }

    var d3cola = cola.d3adaptor()
        .linkDistance(100)
        .avoidOverlaps(true)
        .handleDisconnected(true)
        .convergenceThreshold(0.001)
        //.symmetricDiffLinkLengths(1)
        //.jaccardLinkLengths(10, 0.5)
        .size([window.innerWidth, window.innerHeight]);

    var svg = d3.select("body").append("svg")
        .attr("width", "100%")
        .attr("height", "100%")
        .attr("preserveAspectRatio", "xMidYMid");

    // define arrow markers for graph links
    svg.append("svg:defs")
        .append("svg:marker")
        .attr("id", "end-arrow")
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 5)
        .attr("markerWidth", 3)
        .attr("markerHeight", 3)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("d", "M0,-5L10,0L0,5L2,0")
        .attr("stroke-width", "0px")
        .attr("fill", "#555");

    var container = svg.append("g");

    var updateViewBox = true;
    svg.call(d3.behavior.zoom().on("zoom", function() {
        updateViewBox = false;
        container.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
    }));
    svg.call(d3.behavior.drag().on("dragstart", function() {
        updateViewBox = false;
    }));

    var color = d3.scale.category20();

    var powerGraph = null;
    d3cola.nodes(nodes)
        .links(links)
        //.groups(groups)
        .powerGraphGroups(function (d) {
            powerGraph = d;
            d.groups.forEach(function (v) {
                return v.padding = 10;
            });
        });

    function addGroup(id, nodeIds) {
        var idx;
        var parents = {};
        var leaves = [], offsets = [], groups = [];
        for (var k = 0; k < nodeIds.length; k++) {
            var node = nodes[nodeIds[k]];
            if (node.parent) {
                // TODO: handle second level group nesting
                parents[node.parent.id] = node.parent;
            } else {
                leaves.push(node);
                idx = d3cola.rootGroup().leaves.indexOf(node);
                d3cola.rootGroup().leaves.splice(idx, 1);
            }
            offsets.push({node: nodeIds[k], offset: 0});
        }

        var grp = {id: id, padding: 10, leaves: leaves, groups: groups};
        grp.leaves.forEach(function (v) {
            if (!v.parent)
                v.parent = grp;
        });

        for (var groupId in parents) {
            groups.push(parents[groupId]);
            idx = d3cola.rootGroup().groups.indexOf(parents[groupId]);
            d3cola.rootGroup().groups.splice(idx, 1);
        }

        d3cola.groups().push(grp);
        d3cola.rootGroup().groups.push(grp);

        d3cola.constraints().push({type: "alignment", axis: "x", offsets: offsets});
    }

    // Add groups for the producers and their declaring bean
    var rid = d3cola.rootGroup().groups.length - 1;
    for (i = 0; i < producerGroups.length; i++)
        addGroup(rid, producerGroups[i]);

    var group = container.selectAll(".group")
        .data(d3cola.groups())
        //.data(powerGraph.groups)
        .enter().append("rect")
        .attr("rx", 8).attr("ry", 8)
        .attr("class", "group")
        .style("fill", function (d, i) { return color(i); });

    var link = container.selectAll(".link")
        .data(powerGraph.powerEdges)
        .enter().append("path")
        .attr("class", "link");

    var margin = 10, pad = 12;

    var node = container.selectAll(".node")
        .data(nodes)
        .enter().append("rect")
        .attr("class", "node")
        .attr("width", function (d) { return d.width + 2 * margin; })
        .attr("height", function (d) { return d.height + 2 * margin; })
        .attr("rx", 5).attr("ry", 5)
        .call(d3cola.drag)
        // override the dragstart listener to stop the viewBox update and the drag event propagation
        .call(d3cola.drag().on("dragstart.d3adaptor", function(d) {
            updateViewBox = false;
            d3.event.sourceEvent.stopPropagation();
            d3cola.dragstart(d);
        }));

    var label = container.selectAll(".label")
        .data(nodes)
        .enter().append("text")
        .attr("class", "label")
        .text(function (d) { return d.name; })
        .call(d3cola.drag)
        // override the dragstart listener to stop the viewBox update and the drag event propagation
        .call(d3cola.drag().on("dragstart.d3adaptor", function(d) {
            updateViewBox = false;
            d3.event.sourceEvent.stopPropagation();
            d3cola.dragstart(d);
        }))
        .each(function (d) {
            var b = this.getBBox();
            var extra = 2 * margin + 2 * pad;
            d.width = b.width + extra;
            d.height = b.height + extra;
        });

    d3cola.on("tick", function () {
        update();
        if (updateViewBox)
            viewBox();
    }).on("end", function () {
        routeEdges();
        d3cola.on("tick", update);
        d3cola.on("end", routeEdges);
    });

    function routeEdges() {
        d3cola.prepareEdgeRouting(20);
        link.attr("d", function (d) {
            return lineFunction(d3cola.routeEdge(d));
        });
    }

    var lineFunction = d3.svg.line()
        .x(function (d) { return d.x; })
        .y(function (d) { return d.y; })
        .interpolate("linear");

    d3cola.start();

    function update() {
        node.each(function (d) { d.innerBounds = d.bounds.inflate(-margin); })
            .attr("x", function (d) { return d.innerBounds.x; })
            .attr("y", function (d) { return d.innerBounds.y; })
            .attr("width", function (d) { return d.innerBounds.width(); })
            .attr("height", function (d) { return d.innerBounds.height(); });

        group.each(function (d) { d.innerBounds = d.bounds.inflate(-margin); })
            .attr("x", function (d) { return d.innerBounds.x; })
            .attr("y", function (d) { return d.innerBounds.y; })
            .attr("width", function (d) { return d.innerBounds.width(); })
            .attr("height", function (d) { return d.innerBounds.height(); });

        link.attr("d", function (d) {
            cola.vpsc.makeEdgeBetween(d, d.source.innerBounds, d.target.innerBounds, 5);
            return lineFunction([{ x: d.sourceIntersection.x, y: d.sourceIntersection.y }, { x: d.arrowStart.x, y: d.arrowStart.y }]);
        });

        label.attr("x", function (d) { return d.x; })
            .attr("y", function (d) { return d.y + this.getBBox().height / 3.5; });
    }

    function viewBox() {
        var b = cola.vpsc.Rectangle.empty();
        container.selectAll("rect").each(function (d) {
            var bb = this.getBBox();
            b = b.union(new cola.vpsc.Rectangle(bb.x, bb.x + bb.width, bb.y, bb.y + bb.height));
        });
        svg.attr("viewBox", b.x + " " + b.y + " " + (b.width()) + " " + (b.height()));
    }
}<commit_msg>B-spline shortest-path edge routing (to be fixed for power graph groups)<commit_after>var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:8080/cdeye/beans");
xhr.setRequestHeader("Accept", "application/json");
xhr.onreadystatechange = function(event) {
    if(xhr.readyState === 4)
        if (xhr.status === 200)
            display();
        else
            alert("CDEye not accessible!");
};
xhr.send();

function display() {
    var beans = JSON.parse(xhr.responseText);

    var nodes = [];
    var links = [];
    var producerGroups = [];

    var i, j;

    for (i = 0; i < beans.bean.length; i++) {
        var bean = beans.bean[i];
        if (!nodes[i])
            nodes[i] = {id: i, name: bean.classSimpleName, width: 200, height: 40};
        if (bean.injectionPoints) {
            var injectionPoints = bean.injectionPoints.injectionPoint;
            for (j = 0; j < injectionPoints.length; j++)
                links.push({source: parseInt(injectionPoints[j].bean), target: i});
        }
        if (bean.producers) {
            var producers = bean.producers.producer;
            var producerGroup = [];
            for (j = 0; j < producers.length; j++) {
                var producer = parseInt(producers[j].bean);
                producerGroup.push(producer);
                // Override the node with the producer member name
                nodes[producer] = {id: producer, name: producers[j].name, width: 200, height: 40};
            }
            // TODO: find a way to have the declaring bean at the top of the group
            producerGroup.push(i);
            producerGroups.push(producerGroup);
        }
    }

    var d3cola = cola.d3adaptor()
        .linkDistance(100)
        .avoidOverlaps(true)
        .handleDisconnected(true)
        .convergenceThreshold(0.01)
        //.symmetricDiffLinkLengths(1)
        .jaccardLinkLengths(100)
        .size([window.innerWidth, window.innerHeight]);

    var svg = d3.select("body").append("svg")
        .attr("width", "100%")
        .attr("height", "100%")
        .attr("preserveAspectRatio", "xMidYMid");

    // define arrow markers for graph links
    svg.append("svg:defs")
        .append("svg:marker")
        .attr("id", "end-arrow")
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 5)
        .attr("markerWidth", 3)
        .attr("markerHeight", 3)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("d", "M0,-5L10,0L0,5L2,0")
        .attr("stroke-width", "0px")
        .attr("fill", "#555");

    var container = svg.append("g");

    var updateViewBox = true;
    svg.call(d3.behavior.zoom().on("zoom", function() {
        updateViewBox = false;
        container.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
    }));
    svg.call(d3.behavior.drag().on("dragstart", function() {
        updateViewBox = false;
    }));

    var color = d3.scale.category20();

    var powerGraph = null;
    d3cola.nodes(nodes)
        .links(links)
        //.groups(groups)
        .powerGraphGroups(function (d) {
            powerGraph = d;
            d.groups.forEach(function (v) {
                return v.padding = 10;
            });
        });

    function addGroup(id, nodeIds) {
        var idx;
        var parents = {};
        var leaves = [], offsets = [], groups = [];
        for (var k = 0; k < nodeIds.length; k++) {
            var node = nodes[nodeIds[k]];
            if (node.parent) {
                // TODO: handle second level group nesting
                parents[node.parent.id] = node.parent;
            } else {
                leaves.push(node);
                idx = d3cola.rootGroup().leaves.indexOf(node);
                d3cola.rootGroup().leaves.splice(idx, 1);
            }
            offsets.push({node: nodeIds[k], offset: 0});
        }

        var grp = {id: id, padding: 10, leaves: leaves, groups: groups};
        grp.leaves.forEach(function (v) {
            if (!v.parent)
                v.parent = grp;
        });

        for (var groupId in parents) {
            groups.push(parents[groupId]);
            idx = d3cola.rootGroup().groups.indexOf(parents[groupId]);
            d3cola.rootGroup().groups.splice(idx, 1);
        }

        d3cola.groups().push(grp);
        d3cola.rootGroup().groups.push(grp);

        d3cola.constraints().push({type: "alignment", axis: "x", offsets: offsets});
    }

    // Add groups for the producers and their declaring bean
    var rid = d3cola.rootGroup().groups.length - 1;
    for (i = 0; i < producerGroups.length; i++)
        addGroup(rid, producerGroups[i]);

    var group = container.selectAll(".group")
        .data(d3cola.groups())
        //.data(powerGraph.groups)
        .enter().append("rect")
        .attr("rx", 8).attr("ry", 8)
        .attr("class", "group")
        .style("fill", function (d, i) { return color(i); });

    var link = container.selectAll(".link")
        .data(powerGraph.powerEdges)
        .enter().append("path")
        .attr("class", "link");

    var margin = 10, pad = 12;

    var node = container.selectAll(".node")
        .data(nodes)
        .enter().append("rect")
        .attr("class", "node")
        .attr("width", function (d) { return d.width + 2 * margin; })
        .attr("height", function (d) { return d.height + 2 * margin; })
        .attr("rx", 5).attr("ry", 5)
        .call(d3cola.drag)
        // override the dragstart listener to stop the viewBox update and the drag event propagation
        .call(d3cola.drag().on("dragstart.d3adaptor", function(d) {
            updateViewBox = false;
            d3.event.sourceEvent.stopPropagation();
            d3cola.dragstart(d);
        }));

    var label = container.selectAll(".label")
        .data(nodes)
        .enter().append("text")
        .attr("class", "label")
        .text(function (d) { return d.name; })
        .call(d3cola.drag)
        // override the dragstart listener to stop the viewBox update and the drag event propagation
        .call(d3cola.drag().on("dragstart.d3adaptor", function(d) {
            updateViewBox = false;
            d3.event.sourceEvent.stopPropagation();
            d3cola.dragstart(d);
        }))
        .each(function (d) {
            var b = this.getBBox();
            var extra = 2 * margin + 2 * pad;
            d.width = b.width + extra;
            d.height = b.height + extra;
        });

    d3cola.on("tick", function () {
        update();
        if (updateViewBox)
            viewBox();
    }).on("end", function () {
        routeEdges();
        d3cola.on("tick", update);
        d3cola.on("end", routeEdges);
    });

    function routeEdges() {
        d3cola.prepareEdgeRouting(0);
        link.attr("d", function (d) {
            // FIXME: edge routing does not work with power graph groups
            if (!d.source.name || !d.target.name)
                return lineFunction([{ x: d.sourceIntersection.x, y: d.sourceIntersection.y }, { x: d.arrowStart.x, y: d.arrowStart.y }]);
            else
                return lineFunction(d3cola.routeEdge(d));
        });
    }

    var lineFunction = d3.svg.line()
        .x(function (d) { return d.x; })
        .y(function (d) { return d.y; })
        .interpolate("basis");

    d3cola.start();

    function update() {
        node.each(function (d) { d.innerBounds = d.bounds.inflate(-margin); })
            .attr("x", function (d) { return d.innerBounds.x; })
            .attr("y", function (d) { return d.innerBounds.y; })
            .attr("width", function (d) { return d.innerBounds.width(); })
            .attr("height", function (d) { return d.innerBounds.height(); });

        group.each(function (d) { d.innerBounds = d.bounds.inflate(-margin); })
            .attr("x", function (d) { return d.innerBounds.x; })
            .attr("y", function (d) { return d.innerBounds.y; })
            .attr("width", function (d) { return d.innerBounds.width(); })
            .attr("height", function (d) { return d.innerBounds.height(); });

        link.attr("d", function (d) {
            cola.vpsc.makeEdgeBetween(d, d.source.innerBounds, d.target.innerBounds, 5);
            return lineFunction([{ x: d.sourceIntersection.x, y: d.sourceIntersection.y }, { x: d.arrowStart.x, y: d.arrowStart.y }]);
        });

        label.attr("x", function (d) { return d.x; })
            .attr("y", function (d) { return d.y + this.getBBox().height / 3.5; });
    }

    function viewBox() {
        var b = cola.vpsc.Rectangle.empty();
        container.selectAll("rect").each(function (d) {
            var bb = this.getBBox();
            b = b.union(new cola.vpsc.Rectangle(bb.x, bb.x + bb.width, bb.y, bb.y + bb.height));
        });
        svg.attr("viewBox", b.x + " " + b.y + " " + (b.width()) + " " + (b.height()));
    }
}<|endoftext|>


<commit_before>(function($){
const editorkey = Symbol(); // marker

$.fn.ex = function($toolbar, $statusbar){
	return this.each( function() {
		const rng = bililiteRange(this);
		const data = rng.data;
		if (data[editorkey]) return; // only set this up once
		data[editorkey] = bililiteRange.version;
		const $element = $(this);
		const toolbar = new Toolbar ($toolbar[0], this, rng.executor(), 'extoolbar');

		[data.stdout, data.stderr] = $statusbar.statusDisplayer();
		data.autoindent = true;
		data.global = true;

		$element.on('map', evt => {
			const {command, variant, lhs, rhs} = evt.detail;
			if (variant){
				if (command == 'map'){
					let button;
					const parsedrhs = parseToolbarCommand(rhs);
					const toggle = /(?:set\s+)?([a-zA-Z]+)\s+toggle/.exec(parsedrhs.command);
					if (toggle){
						button = toolbar.toggleButton(lhs, parsedrhs.command);
						button.setAttribute('aria-pressed', data[toggle[1]] ? 'true' : 'false');
					}else{
						button = toolbar.button(lhs, parsedrhs.command);
						if (parsedrhs.observe) toolbar.observerElement(button, parsedrhs.observe);
					}
					if (parsedrhs.title) button.setAttribute('title', parsedrhs.title);
				}else if (command == 'unmap'){
					$(`button[name=${JSON.stringify(lhs)}]`, $toolbar).remove();
				}
			}else{
				// hotkey
				if (command == 'map'){
					$element.off('keydown', {keys: lhs});
					$element.on('keydown', {keys: lhs}, rng.executor({command: rhs, returnvalue: false}));
				}else if (command == 'unmap'){
					$element.off('keydown', {keys: lhs});
				}
			}
		});

		$element.on('keydown', {keys: 'ctrl-o :'}, evt => {
			$statusbar.prompt(':').then( rng.executor({defaultaddress: '.'}) ).
			 then(...$statusbar.statusDisplayer()).
			 finally(() => $element.focus());
			return false;
		});

		// A variation on VIM keys, in evim mode (starts with ctrl-o)
		const vimobjects = {
			w: 'word',
			W: 'bigword',
			s: 'sentence',
			p: 'paragraph',
			'[': 'section',
			'"': '"',
			"'": "'",
			'(': '()'
		}
		const vimverbs = {
			// [ verb, outer, bounds to set ]
			'': ['to', true, 'endbounds'],
			B: ['from', true, 'startbounds'],
			a: ['whole', true, undefined],
			b: ['from', false, 'startbounds'],
			i: ['whole', false, undefined],
			t: ['to', false, 'endbounds'],
		};

		const evim = RegExp (`ctrl-o ([${Object.keys(vimverbs).join('')}]) ([${Object.keys(vimobjects).join('')}])`);
		$element.on('keydown', {keys: evim}, evt => {
			const match = evim.exec(evt.hotkeys);
			const verb = vimverbs[match[1]];
			rng.bounds('selection').bounds(verb[0], vimobjects[match[2]], verb[1]);
			rng.bounds(verb[2]);
			rng.select().scrollIntoView();
			return false;
		});
		const evim2 = RegExp (`ctrl-o ([${Object.keys(vimobjects).join('')}])`);
		// no verb; means move to next
		$element.on('keydown', {keys: evim2}, evt => {
			const match = evim2.exec(evt.hotkeys);
			const verb = vimverbs[''];
			rng.bounds('selection').bounds(verb[0], vimobjects[match[1]], verb[1]);
			rng.bounds(verb[2]);
			rng.select().scrollIntoView();
			return false;
		});
		const evim3 = /ctrl-o ([fF]) (.)/;
		$element.on('keydown', {keys: evim3}, evt => {
			const match = evim3.exec(evt.hotkeys);
			const flags = match[1] == 'F' ? 'b' : '';
			rng.bounds('selection').bounds('find', match[2], flags);
			rng.select().scrollIntoView();
			return false;
		});

		rng.ex('%%source .exrc');

	});
};

bililiteRange.ex.createAttributeOption = function (name, states, attrname = name){
	bililiteRange.createOption(name, {monitored: true});
	bililiteRange.ex.commands[name] = function (parameter, variant){
		const el = this.element;
		if (parameter=='?'){
			data.stdout (Toolbar.getAttribute(el, attrname));
		}else if (parameter == 'toggle'){
			Toolbar.toggleAttribute (el, attrname, states);
		}else{
			Toolbar.setAttribute (el, attrname, parameter);
		}
	};
}

function parseToolbarCommand(string){
	let ret = {};
	try {
		bililiteRange.ex.splitCommands(string, ' ').forEach(function(item){
			var match = /(\w+)=(.+)/.exec(item);
			if (!match) throw new Error();
			ret[match[1]] = bililiteRange.ex.string(match[2]);
		});
	}catch (err){
		ret.command = string;
	}
	if (!ret.command) throw new Error (`map: No command in "${string}"`);
	return ret;
}

})(jQuery);<commit_msg>jquery.ex.js: bugfix<commit_after>(function($){
const editorkey = Symbol(); // marker

$.fn.ex = function($toolbar, $statusbar){
	return this.each( function() {
		const rng = bililiteRange(this);
		const data = rng.data;
		if (data[editorkey]) return; // only set this up once
		data[editorkey] = bililiteRange.version;
		const $element = $(this);
		const toolbar = new Toolbar ($toolbar[0], this, rng.executor(), 'extoolbar');

		[data.stdout, data.stderr] = $statusbar.statusDisplayer();
		data.autoindent = true;
		data.global = true;

		$element.on('map', evt => {
			const {command, variant, lhs, rhs} = evt.detail;
			if (variant){
				if (command == 'map'){
					let button;
					const parsedrhs = parseToolbarCommand(rhs);
					const toggle = /(?:set\s+)?([a-zA-Z]+)\s+toggle/.exec(parsedrhs.command);
					if (toggle){
						button = toolbar.toggleButton(lhs, parsedrhs.command);
						button.setAttribute('aria-pressed', data[toggle[1]] ? 'true' : 'false');
					}else{
						button = toolbar.button(lhs, parsedrhs.command);
						if (parsedrhs.observe) toolbar.observerElement(button, parsedrhs.observe);
					}
					if (parsedrhs.title) button.setAttribute('title', parsedrhs.title);
				}else if (command == 'unmap'){
					$(`button[name=${JSON.stringify(lhs)}]`, $toolbar).remove();
				}
			}else{
				// hotkey
				if (command == 'map'){
					$element.off('keydown', {keys: lhs});
					$element.on('keydown', {keys: lhs}, rng.executor({command: rhs, returnvalue: false}));
				}else if (command == 'unmap'){
					$element.off('keydown', {keys: lhs});
				}
			}
		});

		$element.on('keydown', {keys: 'ctrl-o :'}, evt => {
			$statusbar.prompt(':').then( rng.executor({defaultaddress: '.'}) ).
			 then(...$statusbar.statusDisplayer()).
			 finally(() => $element.focus());
			return false;
		});

		// A variation on VIM keys, in evim mode (starts with ctrl-o)
		const vimobjects = {
			w: 'word',
			W: 'bigword',
			s: 'sentence',
			p: 'paragraph',
			'[': 'section',
			'"': '"',
			"'": "'",
			'(': '()'
		}
		const vimverbs = {
			// [ verb, outer, bounds to set ]
			'': ['to', true, 'endbounds'],
			B: ['from', true, 'startbounds'],
			a: ['whole', true, undefined],
			b: ['from', false, 'startbounds'],
			i: ['whole', false, undefined],
			t: ['to', false, 'endbounds'],
		};

		const evim = RegExp (`ctrl-o ([${Object.keys(vimverbs).join('')}]) ([${Object.keys(vimobjects).join('')}])`);
		$element.on('keydown', {keys: evim}, evt => {
			const match = evim.exec(evt.hotkeys);
			const verb = vimverbs[match[1]];
			rng.bounds('selection').bounds(verb[0], vimobjects[match[2]], verb[1]);
			rng.bounds(verb[2]);
			rng.select().scrollIntoView();
			return false;
		});
		const evim2 = RegExp (`ctrl-o ([${Object.keys(vimobjects).join('')}])`);
		// no verb; means move to next
		$element.on('keydown', {keys: evim2}, evt => {
			const match = evim2.exec(evt.hotkeys);
			const verb = vimverbs[''];
			rng.bounds('selection').bounds(verb[0], vimobjects[match[1]], verb[1]);
			rng.bounds(verb[2]);
			rng.select().scrollIntoView();
			return false;
		});
		const evim3 = /ctrl-o ([fF]) (.)/;
		$element.on('keydown', {keys: evim3}, evt => {
			const match = evim3.exec(evt.hotkeys);
			const flags = match[1] == 'F' ? 'b' : '';
			rng.bounds('selection').bounds('find', match[2], flags);
			rng.select().scrollIntoView();
			return false;
		});

		rng.ex('%%source .exrc');

	});
};

bililiteRange.ex.createAttributeOption = function (name, states, attrname = name){
	bililiteRange.createOption(name, {monitored: true});
	bililiteRange.ex.commands[name] = function (parameter, variant){
		const el = this.element;
		if (parameter=='?'){
			this.data.stdout (Toolbar.getAttribute(el, attrname));
		}else if (parameter == 'toggle'){
			Toolbar.toggleAttribute (el, attrname, states);
		}else{
			Toolbar.setAttribute (el, attrname, parameter);
		}
	};
}

function parseToolbarCommand(string){
	let ret = {};
	try {
		bililiteRange.ex.splitCommands(string, ' ').forEach(function(item){
			var match = /(\w+)=(.+)/.exec(item);
			if (!match) throw new Error();
			ret[match[1]] = bililiteRange.ex.string(match[2]);
		});
	}catch (err){
		ret.command = string;
	}
	if (!ret.command) throw new Error (`map: No command in "${string}"`);
	return ret;
}

})(jQuery);<|endoftext|>


<commit_before>//jquery utils

String.prototype.ssplit = function (char, amount) {
    if (amount === 0) return [];
    var parts = this.split(char);
    var len = parts.length - 1;
    if (amount && Math.abs(amount) < len) {
        if (amount > 0) {
            var splited = parts.splice(0, amount);
            var toJoin = parts.splice(0,len).join(char);
            parts = splited.concat(toJoin);
        }else{
            var splited = parts.splice(amount, len);
            var toJoin = parts.splice(0,len).join(char);
            parts = [].concat(toJoin, splited);
        }
    }
    return parts;
};

$.extend({
    textToHtml: function(text){
        /*
        This function will transform the given text into HTML text.
        For example:
            "this is a\nmultiline\nString" -> "this is a
multiline
String"

        More to come.
        */

        if (text !== undefined) {
            var htmlText = $('

').text(text).html();
            return htmlText.replace(/\n/g, '
');
        }

        return "";
    },
    htmlToText: function(htmlText){
        /*
        This function does the oposite of textToHtml
        */

        if (htmlText !== undefined) {

            var text = htmlText.replace(/
|<\/br>/g, '\n');
            return $('

').html(text).text();
            // return text;
        }

        return "";

    },
    sorted : function(obj, sortFunction){
        var type = $.type(obj);
        if(type === "object"){
            var keys = Object.keys(obj).sort(sortFunction);
            var sortedObj = {};
            for (var i = 0; i < keys.length; i++) {
                sortedObj[keys[i]] = obj[keys[i]];
            }
            return sortedObj;
        }

        return obj;
    },
    toLinearArray : function(){
        /*
        Merge and converts a multi dimentional array into a single dimentional array
        For instance:
            $.toLinearArray(0,1,[[[4, 5],2],3], [8], 3, null, [0]) -> [0, 1, 4, 5, 2, 3, 8, 3, null, 0]
        */

        var dest = [];
        var objToMerge = Array.prototype.slice.call(arguments, 0);

        function append(d, o){
            var len = o.length;
            for (var i = 0; i < len; i++) {
                var obj = o[i];
                if (!$.isArray(obj)){
                    d.push(obj);
                }else{
                    append(d, obj);
                }
            }
        }

        append(dest, objToMerge);

        return dest;
    },
    attribute : function(){
        function getAttrFromPath(o, p){
            var pp = p.split('.');
            var i = 0;
            while(i < pp.length && o !== undefined){
                o = o[pp[i]];
                i = i + 1;
            }
            return o;
        };
        switch(arguments.length){
            case 2:
                // console.log('path' + arguments[1]);
                return getAttrFromPath(arguments[0], arguments[1]);
            case 3:
                var res = arguments[1].split('.');
                var obj = arguments[0];
                for(var i = 0; i < res.length - 1; i++) {
                    var a = res.shift();
                    if (obj[a] === undefined) {
                        obj[a] = {};
                    }
                    obj = obj[a];
                }
                obj[res[0]] = arguments[2];
                return
            default:
                throw "$.attribute must receive 2 or 3 arguments";
        }
    },
    changeLocation : function(href, data){
        /*
        This method navigates to the href address sending data in post method
        */
        var div = $('

');
        $('body').append(div);
        var html = '<form action="'+href+'" method="post">';
        for (var k in data){
            html += '<input name="' + k + '" value="' + data[k] + '"/>';
        }
        html += '</form>';

        div.html(html);

        div.children('form').submit();

    }
});

$.fn.extend({
    relative : function(rel){
        /*
        This function returns the position of an object relative to the argument rel.
        If rel is not defined, the position is relative to the page.
        */

        var $rel = $(rel);
        var res = this.offset();

        if ($rel.size() > 0) {
            var relOffset = $rel.offset();
            return {'top': (res.top - relOffset.top), 'left':(res.left - relOffset.left)};
        }else{
            return res;
        }
    },
    humanize : function(text){
        /*
        This function sets or gets a human version of the text inside an html object
        */
        if (arguments.length === 0){
            //Get the inner html as a string
            return $.htmlToText(this.html());
        }else{
            //Set inner html to this
            this.html($.textToHtml(text));
        }
    },
    dimensions : function(rel){
        if (arguments.length === 0){
            var res = {
                'top': this[0].offsetTop,
                'left': this[0].offsetLeft,
                'width': this[0].scrollWidth,
                'height': this[0].scrollHeight
            };
            return res;
        }

        var res = this.relative(rel);
        res['width'] = this[0].scrollWidth;
        res['height'] = this[0].scrollHeight;

        return res;
    },
    formAttributes : function(){
        //This functions transforms the serializeArray's array of object result into a single object
        //  with one unique key for each element name

        var result = {};
        var fields = this.serializeArray();

        for (var i = fields.length - 1; i >= 0; i--) {
            var value = fields[i].value !== ""?fields[i].value:null;
            var attr = $.attribute(result, fields[i].name);
            if(attr === undefined){
                $.attribute(result, fields[i].name, value);
            }else{
                if (attr && attr.push){
                    attr.push(value);
                }else{
                    $.attribute(result, fields[i].name, [attr, value]);
                }
            }
        }
        return result;
    },
});

$(function(){
    //Some functions to modify html default behavior
    $(document).on('group-change', '.toggle:radio', function(e, originalTarget){
        var that = e.target;
        that.dataset['checked'] = that == originalTarget && that.dataset['checked'] !== "true";
        that.checked = that.dataset['checked'] === "true";

        //Triggering change event on each associate label
        for (var i = that.labels.length - 1; i >= 0; i--) {
            $(that.labels[i]).trigger('change', {checked:that.checked});
        };
    });

    $(document).on('click', '.toggle:radio', function(e){
        $('.toggle:radio[name="'+ e.target.name +'"]').trigger('group-change', [e.target]);
    });
});

<commit_msg>New contains function<commit_after>//jquery utils

String.prototype.ssplit = function (char, amount) {
    if (amount === 0) return [];
    var parts = this.split(char);
    var len = parts.length - 1;
    if (amount && Math.abs(amount) < len) {
        if (amount > 0) {
            var splited = parts.splice(0, amount);
            var toJoin = parts.splice(0,len).join(char);
            parts = splited.concat(toJoin);
        }else{
            var splited = parts.splice(amount, len);
            var toJoin = parts.splice(0,len).join(char);
            parts = [].concat(toJoin, splited);
        }
    }
    return parts;
};

$.extend({
    textToHtml: function(text){
        /*
        This function will transform the given text into HTML text.
        For example:
            "this is a\nmultiline\nString" -> "this is a
multiline
String"

        More to come.
        */

        if (text !== undefined) {
            var htmlText = $('

').text(text).html();
            return htmlText.replace(/\n/g, '
');
        }

        return "";
    },
    htmlToText: function(htmlText){
        /*
        This function does the oposite of textToHtml
        */

        if (htmlText !== undefined) {

            var text = htmlText.replace(/
|<\/br>/g, '\n');
            return $('

').html(text).text();
            // return text;
        }

        return "";

    },
    sorted : function(obj, sortFunction){
        var type = $.type(obj);
        if(type === "object"){
            var keys = Object.keys(obj).sort(sortFunction);
            var sortedObj = {};
            for (var i = 0; i < keys.length; i++) {
                sortedObj[keys[i]] = obj[keys[i]];
            }
            return sortedObj;
        }

        return obj;
    },
    toLinearArray : function(){
        /*
        Merge and converts a multi dimentional array into a single dimentional array
        For instance:
            $.toLinearArray(0,1,[[[4, 5],2],3], [8], 3, null, [0]) -> [0, 1, 4, 5, 2, 3, 8, 3, null, 0]
        */

        var dest = [];
        var objToMerge = Array.prototype.slice.call(arguments, 0);

        function append(d, o){
            var len = o.length;
            for (var i = 0; i < len; i++) {
                var obj = o[i];
                if (!$.isArray(obj)){
                    d.push(obj);
                }else{
                    append(d, obj);
                }
            }
        }

        append(dest, objToMerge);

        return dest;
    },
    attribute : function(){
        function getAttrFromPath(o, p){
            var pp = p.split('.');
            var i = 0;
            while(i < pp.length && o !== undefined){
                o = o[pp[i]];
                i = i + 1;
            }
            return o;
        };
        switch(arguments.length){
            case 2:
                // console.log('path' + arguments[1]);
                return getAttrFromPath(arguments[0], arguments[1]);
            case 3:
                var res = arguments[1].split('.');
                var obj = arguments[0];
                for(var i = 0; i < res.length - 1; i++) {
                    var a = res.shift();
                    if (obj[a] === undefined) {
                        obj[a] = {};
                    }
                    obj = obj[a];
                }
                obj[res[0]] = arguments[2];
                return
            default:
                throw "$.attribute must receive 2 or 3 arguments";
        }
    },
    changeLocation : function(href, data){
        /*
        This method navigates to the href address sending data in post method
        */
        var div = $('

');
        $('body').append(div);
        var html = '<form action="'+href+'" method="post">';
        for (var k in data){
            html += '<input name="' + k + '" value="' + data[k] + '"/>';
        }
        html += '</form>';

        div.html(html);

        div.children('form').submit();

    }
});

$.fn.extend({
    relative : function(rel){
        /*
        This function returns the position of an object relative to the argument rel.
        If rel is not defined, the position is relative to the page.
        */

        var $rel = $(rel);
        var res = this.offset();

        if ($rel.size() > 0) {
            var relOffset = $rel.offset();
            return {'top': (res.top - relOffset.top), 'left':(res.left - relOffset.left)};
        }else{
            return res;
        }
    },
    humanize : function(text){
        /*
        This function sets or gets a human version of the text inside an html object
        */
        if (arguments.length === 0){
            //Get the inner html as a string
            return $.htmlToText(this.html());
        }else{
            //Set inner html to this
            this.html($.textToHtml(text));
        }
    },
    dimensions : function(rel){
        if (arguments.length === 0){
            var res = {
                'top': this[0].offsetTop,
                'left': this[0].offsetLeft,
                'width': this[0].scrollWidth,
                'height': this[0].scrollHeight
            };
            return res;
        }

        var res = this.relative(rel);
        res['width'] = this[0].scrollWidth;
        res['height'] = this[0].scrollHeight;

        return res;
    },
    contains : function(rel){
        //This function returns if a jQuery object contains graphicaly another object
        var myDim = this.dimensions();
        var relDim = $(rel).dimensions();

        if (relDim.top < myDim.top ||
            relDim.left < myDim.left ||
            relDim.top + relDim.height > myDim.top + myDim.height ||
            relDim.left + relDim.width > myDim.left + myDim.width
            ){
            return false;
        }

        return true;
    },
    formAttributes : function(){
        //This functions transforms the serializeArray's array of object result into a single object
        //  with one unique key for each element name

        var result = {};
        var fields = this.serializeArray();

        for (var i = fields.length - 1; i >= 0; i--) {
            var value = fields[i].value !== ""?fields[i].value:null;
            var attr = $.attribute(result, fields[i].name);
            if(attr === undefined){
                $.attribute(result, fields[i].name, value);
            }else{
                if (attr && attr.push){
                    attr.push(value);
                }else{
                    $.attribute(result, fields[i].name, [attr, value]);
                }
            }
        }
        return result;
    },
});

$(function(){
    //Some functions to modify html default behavior
    $(document).on('group-change', '.toggle:radio', function(e, originalTarget){
        var that = e.target;
        that.dataset['checked'] = that == originalTarget && that.dataset['checked'] !== "true";
        that.checked = that.dataset['checked'] === "true";

        //Triggering change event on each associate label
        for (var i = that.labels.length - 1; i >= 0; i--) {
            $(that.labels[i]).trigger('change', {checked:that.checked});
        };
    });

    $(document).on('click', '.toggle:radio', function(e){
        $('.toggle:radio[name="'+ e.target.name +'"]').trigger('group-change', [e.target]);
    });
});

<|endoftext|>


<commit_before>import React, { Component } from 'react';

import SteamLogo from '../assets/steamlogo.jpg';
import HTBLogo from '../assets/htblogo.png';

const priceListStyle = {
  marginTop: '10px',
  padding: 0,
  listStyle: 'none'
};

const wellStyle = {
  boxShadow: 'none',
  WebkitBoxShadow: 'none'
};

const titleStyle = {
  whiteSpace: 'nowrap',
  overflow: 'hidden',
  textOverflow: 'ellipsis'
};

const emphasisStyle = {
  fontWeight: 500
};

const strikeOutStyle = Object.assign({textDecoration: 'line-through'}, emphasisStyle);

// TODO: Look into using spread operator here
const priceStyle = Object.assign({color: '#4cae4c'}, emphasisStyle);

class SearchResult extends Component {
  render() {
    const game = this.props.game;
    const priceListItem = (game.salePrice) ?

Price: {game.priceFormatted} {game.salePriceFormatted}

      :
Price: {game.priceFormatted}

    return (

{game.title}

Price per hour: {game.pricePerHourFormatted}

              { priceListItem }

Time to beat: {game.mainStoryTimeFormatted}

    );
  }
}

export default SearchResult;
<commit_msg>Convert to spread operator<commit_after>import React, { Component } from 'react';

import SteamLogo from '../assets/steamlogo.jpg';
import HTBLogo from '../assets/htblogo.png';

const priceListStyle = {
  marginTop: '10px',
  padding: 0,
  listStyle: 'none'
};

const wellStyle = {
  boxShadow: 'none',
  WebkitBoxShadow: 'none'
};

const titleStyle = {
  whiteSpace: 'nowrap',
  overflow: 'hidden',
  textOverflow: 'ellipsis'
};

const emphasisStyle = {
  fontWeight: 500
};

const strikeOutStyle = {
  ...emphasisStyle,
  textDecoration: 'line-through'
};

const priceStyle = {
  ...emphasisStyle,
  color: '#4cae4c'
};

class SearchResult extends Component {
  render() {
    const game = this.props.game;
    const priceListItem = (game.salePrice) ?

Price: {game.priceFormatted} {game.salePriceFormatted}

      :
Price: {game.priceFormatted}

    return (

{game.title}

Price per hour: {game.pricePerHourFormatted}

              { priceListItem }

Time to beat: {game.mainStoryTimeFormatted}

    );
  }
}

export default SearchResult;
<|endoftext|>