You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by ph...@apache.org on 2010/06/09 17:26:25 UTC

svn commit: r953041 [3/6] - in /hadoop/zookeeper/trunk: ./ src/contrib/loggraph/ src/contrib/loggraph/bin/ src/contrib/loggraph/src/ src/contrib/loggraph/src/java/ src/contrib/loggraph/src/java/org/ src/contrib/loggraph/src/java/org/apache/ src/contrib...

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.line.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.line.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.line.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.line.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,230 @@
+/*
+ * g.Raphael 0.4 - Charting library, based on Raphaël
+ *
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
+ */
+Raphael.fn.g.linechart = function (x, y, width, height, valuesx, valuesy, opts) {
+    function shrink(values, dim) {
+        var k = values.length / dim,
+            j = 0,
+            l = k,
+            sum = 0,
+            res = [];
+        while (j < values.length) {
+            l--;
+            if (l < 0) {
+                sum += values[j] * (1 + l);
+                res.push(sum / k);
+                sum = values[j++] * -l;
+                l += k;
+            } else {
+                sum += values[j++];
+            }
+        }
+        return res;
+    }
+    opts = opts || {};
+    if (!this.raphael.is(valuesx[0], "array")) {
+        valuesx = [valuesx];
+    }
+    if (!this.raphael.is(valuesy[0], "array")) {
+        valuesy = [valuesy];
+    }
+    var allx = Array.prototype.concat.apply([], valuesx),
+        ally = Array.prototype.concat.apply([], valuesy),
+        xdim = this.g.snapEnds(Math.min.apply(Math, allx), Math.max.apply(Math, allx), valuesx[0].length - 1),
+        minx = xdim.from,
+        maxx = xdim.to,
+        gutter = opts.gutter || 10,
+        kx = (width - gutter * 2) / (maxx - minx),
+        ydim = this.g.snapEnds(Math.min.apply(Math, ally), Math.max.apply(Math, ally), valuesy[0].length - 1),
+        miny = ydim.from,
+        maxy = ydim.to,
+        ky = (height - gutter * 2) / (maxy - miny),
+        len = Math.max(valuesx[0].length, valuesy[0].length),
+        symbol = opts.symbol || "",
+        colors = opts.colors || Raphael.fn.g.colors,
+        that = this,
+        columns = null,
+        dots = null,
+        chart = this.set(),
+        path = [];
+
+    for (var i = 0, ii = valuesy.length; i < ii; i++) {
+        len = Math.max(len, valuesy[i].length);
+    }
+    var shades = this.set();
+    for (var i = 0, ii = valuesy.length; i < ii; i++) {
+        if (opts.shade) {
+            shades.push(this.path().attr({stroke: "none", fill: colors[i], opacity: opts.nostroke ? 1 : .3}));
+        }
+        if (valuesy[i].length > width - 2 * gutter) {
+            valuesy[i] = shrink(valuesy[i], width - 2 * gutter);
+            len = width - 2 * gutter;
+        }
+        if (valuesx[i] && valuesx[i].length > width - 2 * gutter) {
+            valuesx[i] = shrink(valuesx[i], width - 2 * gutter);
+        }
+    }
+    var axis = this.set();
+    if (opts.axis) {
+        var ax = (opts.axis + "").split(/[,\s]+/);
+        +ax[0] && axis.push(this.g.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2, opts.northlabels));
+        +ax[1] && axis.push(this.g.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3, opts.eastlabels));
+        +ax[2] && axis.push(this.g.axis(x + gutter, y + height - gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0, opts.southlabels));
+        +ax[3] && axis.push(this.g.axis(x + gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1, opts.westlabels));
+    }
+    if (opts.northAxisLabel) {
+	this.g.text(x + gutter + width/2, gutter, opts.northAxisLabel);
+    }
+    if (opts.southAxisLabel) {
+	this.g.text(x + gutter + width/2, y + height + 20, opts.southAxisLabel);
+    }
+    if (opts.westAxisLabel) {
+	this.g.text(gutter, y + gutter + height/2, opts.westAxisLabel).attr({rotation: -90});
+    }
+    if (opts.eastAxisLabel) {
+	this.g.text(x + gutter + width + 20, y + gutter + height/2, opts.eastAxisLabel).attr({rotation: 90});
+    }
+
+    var lines = this.set(),
+        symbols = this.set(),
+        line;
+    for (var i = 0, ii = valuesy.length; i < ii; i++) {
+        if (!opts.nostroke) {
+            lines.push(line = this.path().attr({
+                stroke: colors[i],
+                "stroke-width": opts.width || 2,
+                "stroke-linejoin": "round",
+                "stroke-linecap": "round",
+                "stroke-dasharray": opts.dash || ""
+            }));
+        }
+        var sym = this.raphael.is(symbol, "array") ? symbol[i] : symbol,
+            symset = this.set();
+        path = [];
+        for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
+            var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx;
+            var Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
+            (Raphael.is(sym, "array") ? sym[j] : sym) && symset.push(this.g[Raphael.fn.g.markers[this.raphael.is(sym, "array") ? sym[j] : sym]](X, Y, (opts.width || 2) * 3).attr({fill: colors[i], stroke: "none"}));
+            path = path.concat([j ? "L" : "M", X, Y]);
+        }
+        symbols.push(symset);
+        if (opts.shade) {
+            shades[i].attr({path: path.concat(["L", X, y + height - gutter, "L",  x + gutter + ((valuesx[i] || valuesx[0])[0] - minx) * kx, y + height - gutter, "z"]).join(",")});
+        }
+        !opts.nostroke && line.attr({path: path.join(",")});
+    }
+    function createColumns(f) {
+        // unite Xs together
+        var Xs = [];
+        for (var i = 0, ii = valuesx.length; i < ii; i++) {
+            Xs = Xs.concat(valuesx[i]);
+        }
+        Xs.sort();
+        // remove duplicates
+        var Xs2 = [],
+            xs = [];
+        for (var i = 0, ii = Xs.length; i < ii; i++) {
+            Xs[i] != Xs[i - 1] && Xs2.push(Xs[i]) && xs.push(x + gutter + (Xs[i] - minx) * kx);
+        }
+        Xs = Xs2;
+        ii = Xs.length;
+        var cvrs = f || that.set();
+        for (var i = 0; i < ii; i++) {
+            var X = xs[i] - (xs[i] - (xs[i - 1] || x)) / 2,
+                w = ((xs[i + 1] || x + width) - xs[i]) / 2 + (xs[i] - (xs[i - 1] || x)) / 2,
+                C;
+            f ? (C = {}) : cvrs.push(C = that.rect(X - 1, y, Math.max(w + 1, 1), height).attr({stroke: "none", fill: "#000", opacity: 0}));
+            C.values = [];
+            C.symbols = that.set();
+            C.y = [];
+            C.x = xs[i];
+            C.axis = Xs[i];
+            for (var j = 0, jj = valuesy.length; j < jj; j++) {
+                Xs2 = valuesx[j] || valuesx[0];
+                for (var k = 0, kk = Xs2.length; k < kk; k++) {
+                    if (Xs2[k] == Xs[i]) {
+                        C.values.push(valuesy[j][k]);
+                        C.y.push(y + height - gutter - (valuesy[j][k] - miny) * ky);
+                        C.symbols.push(chart.symbols[j][k]);
+                    }
+                }
+            }
+            f && f.call(C);
+        }
+        !f && (columns = cvrs);
+    }
+    function createDots(f) {
+        var cvrs = f || that.set(),
+            C;
+        for (var i = 0, ii = valuesy.length; i < ii; i++) {
+            for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
+                var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,
+                    nearX = x + gutter + ((valuesx[i] || valuesx[0])[j ? j - 1 : 1] - minx) * kx,
+                    Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
+                f ? (C = {}) : cvrs.push(C = that.circle(X, Y, Math.abs(nearX - X) / 2).attr({stroke: "none", fill: "#000", opacity: 0}));
+                C.x = X;
+                C.y = Y;
+                C.value = valuesy[i][j];
+                C.line = chart.lines[i];
+                C.shade = chart.shades[i];
+                C.symbol = chart.symbols[i][j];
+                C.symbols = chart.symbols[i];
+                C.axis = (valuesx[i] || valuesx[0])[j];
+                f && f.call(C);
+            }
+        }
+        !f && (dots = cvrs);
+    }
+    chart.push(lines, shades, symbols, axis, columns, dots);
+    chart.lines = lines;
+    chart.shades = shades;
+    chart.symbols = symbols;
+    chart.axis = axis;
+    chart.hoverColumn = function (fin, fout) {
+        !columns && createColumns();
+        columns.mouseover(fin).mouseout(fout);
+        return this;
+    };
+    chart.clickColumn = function (f) {
+        !columns && createColumns();
+        columns.click(f);
+        return this;
+    };
+    chart.hrefColumn = function (cols) {
+        var hrefs = that.raphael.is(arguments[0], "array") ? arguments[0] : arguments;
+        if (!(arguments.length - 1) && typeof cols == "object") {
+            for (var x in cols) {
+                for (var i = 0, ii = columns.length; i < ii; i++) if (columns[i].axis == x) {
+                    columns[i].attr("href", cols[x]);
+                }
+            }
+        }
+        !columns && createColumns();
+        for (var i = 0, ii = hrefs.length; i < ii; i++) {
+            columns[i] && columns[i].attr("href", hrefs[i]);
+        }
+        return this;
+    };
+    chart.hover = function (fin, fout) {
+        !dots && createDots();
+        dots.mouseover(fin).mouseout(fout);
+        return this;
+    };
+    chart.click = function (f) {
+        !dots && createDots();
+        dots.click(f);
+        return this;
+    };
+    chart.each = function (f) {
+        createDots(f);
+        return this;
+    };
+    chart.eachColumn = function (f) {
+        createColumns(f);
+        return this;
+    };
+    return chart;
+};

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.pie.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.pie.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.pie.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.pie.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,205 @@
+/*
+ * g.Raphael 0.4 - Charting library, based on Raphaël
+ *
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
+ */
+Raphael.fn.g.piechart = function (cx, cy, r, values, opts) {
+    opts = opts || {};
+    var paper = this,
+        sectors = [],
+        covers = this.set(),
+        chart = this.set(),
+        series = this.set(),
+        order = [],
+        len = values.length,
+        angle = 0,
+        total = 0,
+        others = 0,
+        cut = 9,
+        defcut = true;
+    chart.covers = covers;
+    if (len == 1) {
+        series.push(this.circle(cx, cy, r).attr({fill: this.g.colors[0], stroke: opt.stroke || "#fff", "stroke-width": opts.strokewidth == null ? 1 : opts.strokewidth}));
+        covers.push(this.circle(cx, cy, r).attr(this.g.shim));
+        total = values[0];
+        values[0] = {value: values[0], order: 0, valueOf: function () { return this.value; }};
+        series[0].middle = {x: cx, y: cy};
+        series[0].mangle = 180;
+    } else {
+        function sector(cx, cy, r, startAngle, endAngle, fill) {
+            var rad = Math.PI / 180,
+                x1 = cx + r * Math.cos(-startAngle * rad),
+                x2 = cx + r * Math.cos(-endAngle * rad),
+                xm = cx + r / 2 * Math.cos(-(startAngle + (endAngle - startAngle) / 2) * rad),
+                y1 = cy + r * Math.sin(-startAngle * rad),
+                y2 = cy + r * Math.sin(-endAngle * rad),
+                ym = cy + r / 2 * Math.sin(-(startAngle + (endAngle - startAngle) / 2) * rad),
+                res = ["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2, "z"];
+            res.middle = {x: xm, y: ym};
+            return res;
+        }
+        for (var i = 0; i < len; i++) {
+            total += values[i];
+            values[i] = {value: values[i], order: i, valueOf: function () { return this.value; }};
+        }
+        values.sort(function (a, b) {
+            return b.value - a.value;
+        });
+        for (var i = 0; i < len; i++) {
+            if (defcut && values[i] * 360 / total <= 1.5) {
+                cut = i;
+                defcut = false;
+            }
+            if (i > cut) {
+                defcut = false;
+                values[cut].value += values[i];
+                values[cut].others = true;
+                others = values[cut].value;
+            }
+        }
+        len = Math.min(cut + 1, values.length);
+        others && values.splice(len) && (values[cut].others = true);
+        for (var i = 0; i < len; i++) {
+            var mangle = angle - 360 * values[i] / total / 2;
+            if (!i) {
+                angle = 90 - mangle;
+                mangle = angle - 360 * values[i] / total / 2;
+            }
+            if (opts.init) {
+                var ipath = sector(cx, cy, 1, angle, angle - 360 * values[i] / total).join(",");
+            }
+            var path = sector(cx, cy, r, angle, angle -= 360 * values[i] / total);
+            var p = this.path(opts.init ? ipath : path).attr({fill: opts.colors && opts.colors[i] || this.g.colors[i] || "#666", stroke: opts.stroke || "#fff", "stroke-width": (opts.strokewidth == null ? 1 : opts.strokewidth), "stroke-linejoin": "round"});
+            p.value = values[i];
+            p.middle = path.middle;
+            p.mangle = mangle;
+            sectors.push(p);
+            series.push(p);
+            opts.init && p.animate({path: path.join(",")}, (+opts.init - 1) || 1000, ">");
+        }
+        for (var i = 0; i < len; i++) {
+            var p = paper.path(sectors[i].attr("path")).attr(this.g.shim);
+            opts.href && opts.href[i] && p.attr({href: opts.href[i]});
+            p.attr = function () {};
+            covers.push(p);
+            series.push(p);
+        }
+    }
+
+    chart.hover = function (fin, fout) {
+        fout = fout || function () {};
+        var that = this;
+        for (var i = 0; i < len; i++) {
+            (function (sector, cover, j) {
+                var o = {
+                    sector: sector,
+                    cover: cover,
+                    cx: cx,
+                    cy: cy,
+                    mx: sector.middle.x,
+                    my: sector.middle.y,
+                    mangle: sector.mangle,
+                    r: r,
+                    value: values[j],
+                    total: total,
+                    label: that.labels && that.labels[j]
+                };
+                cover.mouseover(function () {
+                    fin.call(o);
+                }).mouseout(function () {
+                    fout.call(o);
+                });
+            })(series[i], covers[i], i);
+        }
+        return this;
+    };
+    // x: where label could be put
+    // y: where label could be put
+    // value: value to show
+    // total: total number to count %
+    chart.each = function (f) {
+        var that = this;
+        for (var i = 0; i < len; i++) {
+            (function (sector, cover, j) {
+                var o = {
+                    sector: sector,
+                    cover: cover,
+                    cx: cx,
+                    cy: cy,
+                    x: sector.middle.x,
+                    y: sector.middle.y,
+                    mangle: sector.mangle,
+                    r: r,
+                    value: values[j],
+                    total: total,
+                    label: that.labels && that.labels[j]
+                };
+                f.call(o);
+            })(series[i], covers[i], i);
+        }
+        return this;
+    };
+    chart.click = function (f) {
+        var that = this;
+        for (var i = 0; i < len; i++) {
+            (function (sector, cover, j) {
+                var o = {
+                    sector: sector,
+                    cover: cover,
+                    cx: cx,
+                    cy: cy,
+                    mx: sector.middle.x,
+                    my: sector.middle.y,
+                    mangle: sector.mangle,
+                    r: r,
+                    value: values[j],
+                    total: total,
+                    label: that.labels && that.labels[j]
+                };
+                cover.click(function () { f.call(o); });
+            })(series[i], covers[i], i);
+        }
+        return this;
+    };
+    chart.inject = function (element) {
+        element.insertBefore(covers[0]);
+    };
+    var legend = function (labels, otherslabel, mark, dir) {
+        var x = cx + r + r / 5,
+            y = cy,
+            h = y + 10;
+        labels = labels || [];
+        dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "east";
+        mark = paper.g.markers[mark && mark.toLowerCase()] || "disc";
+        chart.labels = paper.set();
+        for (var i = 0; i < len; i++) {
+            var clr = series[i].attr("fill"),
+                j = values[i].order,
+                txt;
+            values[i].others && (labels[j] = otherslabel || "Others");
+            labels[j] = paper.g.labelise(labels[j], values[i], total);
+            chart.labels.push(paper.set());
+            chart.labels[i].push(paper.g[mark](x + 5, h, 5).attr({fill: clr, stroke: "none"}));
+            chart.labels[i].push(txt = paper.text(x + 20, h, labels[j] || values[j]).attr(paper.g.txtattr).attr({fill: opts.legendcolor || "#000", "text-anchor": "start"}));
+            covers[i].label = chart.labels[i];
+            h += txt.getBBox().height * 1.2;
+        }
+        var bb = chart.labels.getBBox(),
+            tr = {
+                east: [0, -bb.height / 2],
+                west: [-bb.width - 2 * r - 20, -bb.height / 2],
+                north: [-r - bb.width / 2, -r - bb.height - 10],
+                south: [-r - bb.width / 2, r + 10]
+            }[dir];
+        chart.labels.translate.apply(chart.labels, tr);
+        chart.push(chart.labels);
+    };
+    if (opts.legend) {
+        legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);
+    }
+    chart.push(series, covers);
+    chart.series = series;
+    chart.covers = covers;
+    return chart;
+};

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.raphael.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.raphael.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.raphael.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/g.raphael.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,481 @@
+/*
+ * g.Raphael 0.4 - Charting library, based on Raphaël
+ *
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
+ */
+ 
+ 
+(function () {
+    Raphael.fn.g = Raphael.fn.g || {};
+    Raphael.fn.g.markers = {
+        disc: "disc",
+        o: "disc",
+        flower: "flower",
+        f: "flower",
+        diamond: "diamond",
+        d: "diamond",
+        square: "square",
+        s: "square",
+        triangle: "triangle",
+        t: "triangle",
+        star: "star",
+        "*": "star",
+        cross: "cross",
+        x: "cross",
+        plus: "plus",
+        "+": "plus",
+        arrow: "arrow",
+        "->": "arrow"
+    };
+    Raphael.fn.g.shim = {stroke: "none", fill: "#000", "fill-opacity": 0};
+    Raphael.fn.g.txtattr = {font: "12px Arial, sans-serif"};
+    Raphael.fn.g.colors = [];
+    var hues = [.6, .2, .05, .1333, .75, 0];
+    for (var i = 0; i < 10; i++) {
+        if (i < hues.length) {
+            Raphael.fn.g.colors.push("hsb(" + hues[i] + ", .75, .75)");
+        } else {
+            Raphael.fn.g.colors.push("hsb(" + hues[i - hues.length] + ", 1, .5)");
+        }
+    }
+    Raphael.fn.g.text = function (x, y, text) {
+        return this.text(x, y, text).attr(this.g.txtattr);
+    };
+    Raphael.fn.g.labelise = function (label, val, total) {
+        if (label) {
+            return (label + "").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g, function (all, value, percent) {
+                if (value) {
+                    return (+val).toFixed(value.replace(/^#+\.?/g, "").length);
+                }
+                if (percent) {
+                    return (val * 100 / total).toFixed(percent.replace(/^%+\.?/g, "").length) + "%";
+                }
+            });
+        } else {
+            return (+val).toFixed(0);
+        }
+    };
+
+    Raphael.fn.g.finger = function (x, y, width, height, dir, ending, isPath) {
+        // dir 0 for horisontal and 1 for vertical
+        if ((dir && !height) || (!dir && !width)) {
+            return isPath ? "" : this.path();
+        }
+        ending = {square: "square", sharp: "sharp", soft: "soft"}[ending] || "round";
+        var path;
+        height = Math.round(height);
+        width = Math.round(width);
+        x = Math.round(x);
+        y = Math.round(y);
+        switch (ending) {
+            case "round":
+            if (!dir) {
+                var r = Math.floor(height / 2);
+                if (width < r) {
+                    r = width;
+                    path = ["M", x + .5, y + .5 - Math.floor(height / 2), "l", 0, 0, "a", r, Math.floor(height / 2), 0, 0, 1, 0, height, "l", 0, 0, "z"];
+                } else {
+                    path = ["M", x + .5, y + .5 - r, "l", width - r, 0, "a", r, r, 0, 1, 1, 0, height, "l", r - width, 0, "z"];
+                }
+            } else {
+                var r = Math.floor(width / 2);
+                if (height < r) {
+                    r = height;
+                    path = ["M", x - Math.floor(width / 2), y, "l", 0, 0, "a", Math.floor(width / 2), r, 0, 0, 1, width, 0, "l", 0, 0, "z"];
+                } else {
+                    path = ["M", x - r, y, "l", 0, r - height, "a", r, r, 0, 1, 1, width, 0, "l", 0, height - r, "z"];
+                }
+            }
+            break;
+            case "sharp":
+            if (!dir) {
+                var half = Math.floor(height / 2);
+                path = ["M", x, y + half, "l", 0, -height, Math.max(width - half, 0), 0, Math.min(half, width), half, -Math.min(half, width), half + (half * 2 < height), "z"];
+            } else {
+                var half = Math.floor(width / 2);
+                path = ["M", x + half, y, "l", -width, 0, 0, -Math.max(height - half, 0), half, -Math.min(half, height), half, Math.min(half, height), half, "z"];
+            }
+            break;
+            case "square":
+            if (!dir) {
+                path = ["M", x, y + Math.floor(height / 2), "l", 0, -height, width, 0, 0, height, "z"];
+            } else {
+                path = ["M", x + Math.floor(width / 2), y, "l", 1 - width, 0, 0, -height, width - 1, 0, "z"];
+            }
+            break;
+            case "soft":
+            var r;
+            if (!dir) {
+                r = Math.min(width, Math.round(height / 5));
+                path = ["M", x + .5, y + .5 - Math.floor(height / 2), "l", width - r, 0, "a", r, r, 0, 0, 1, r, r, "l", 0, height - r * 2, "a", r, r, 0, 0, 1, -r, r, "l", r - width, 0, "z"];
+            } else {
+                r = Math.min(Math.round(width / 5), height);
+                path = ["M", x - Math.floor(width / 2), y, "l", 0, r - height, "a", r, r, 0, 0, 1, r, -r, "l", width - 2 * r, 0, "a", r, r, 0, 0, 1, r, r, "l", 0, height - r, "z"];
+            }
+        }
+        if (isPath) {
+            return path.join(",");
+        } else {
+            return this.path(path);
+        }
+    };
+
+    // Symbols
+    Raphael.fn.g.disc = function (cx, cy, r) {
+        return this.circle(cx, cy, r);
+    };
+    Raphael.fn.g.line = function (cx, cy, r) {
+        return this.rect(cx - r, cy - r / 5, 2 * r, 2 * r / 5);
+    };
+    Raphael.fn.g.square = function (cx, cy, r) {
+        r = r * .7;
+        return this.rect(cx - r, cy - r, 2 * r, 2 * r);
+    };
+    Raphael.fn.g.triangle = function (cx, cy, r) {
+        r *= 1.75;
+        return this.path("M".concat(cx, ",", cy, "m0-", r * .58, "l", r * .5, ",", r * .87, "-", r, ",0z"));
+    };
+    Raphael.fn.g.diamond = function (cx, cy, r) {
+        return this.path(["M", cx, cy - r, "l", r, r, -r, r, -r, -r, r, -r, "z"]);
+    };
+    Raphael.fn.g.flower = function (cx, cy, r, n) {
+        r = r * 1.25;
+        var rout = r,
+            rin = rout * .5;
+        n = +n < 3 || !n ? 5 : n;
+        var points = ["M", cx, cy + rin, "Q"],
+            R;
+        for (var i = 1; i < n * 2 + 1; i++) {
+            R = i % 2 ? rout : rin;
+            points = points.concat([+(cx + R * Math.sin(i * Math.PI / n)).toFixed(3), +(cy + R * Math.cos(i * Math.PI / n)).toFixed(3)]);
+        }
+        points.push("z");
+        return this.path(points.join(","));
+    };
+    Raphael.fn.g.star = function (cx, cy, r, r2) {
+        r2 = r2 || r * .5;
+        var points = ["M", cx, cy + r2, "L"],
+            R;
+        for (var i = 1; i < 10; i++) {
+            R = i % 2 ? r : r2;
+            points = points.concat([(cx + R * Math.sin(i * Math.PI * .2)).toFixed(3), (cy + R * Math.cos(i * Math.PI * .2)).toFixed(3)]);
+        }
+        points.push("z");
+        return this.path(points.join(","));
+    };
+    Raphael.fn.g.cross = function (cx, cy, r) {
+        r = r / 2.5;
+        return this.path("M".concat(cx - r, ",", cy, "l", [-r, -r, r, -r, r, r, r, -r, r, r, -r, r, r, r, -r, r, -r, -r, -r, r, -r, -r, "z"]));
+    };
+    Raphael.fn.g.plus = function (cx, cy, r) {
+        r = r / 2;
+        return this.path("M".concat(cx - r / 2, ",", cy - r / 2, "l", [0, -r, r, 0, 0, r, r, 0, 0, r, -r, 0, 0, r, -r, 0, 0, -r, -r, 0, 0, -r, "z"]));
+    };
+    Raphael.fn.g.arrow = function (cx, cy, r) {
+        return this.path("M".concat(cx - r * .7, ",", cy - r * .4, "l", [r * .6, 0, 0, -r * .4, r, r * .8, -r, r * .8, 0, -r * .4, -r * .6, 0], "z"));
+    };
+
+    // Tooltips
+    Raphael.fn.g.tag = function (x, y, text, angle, r) {
+        angle = angle || 0;
+        r = r == null ? 5 : r;
+        text = text == null ? "$9.99" : text;
+        var R = .5522 * r,
+            res = this.set(),
+            d = 3;
+        res.push(this.path().attr({fill: "#000", stroke: "none"}));
+        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"}));
+        res.update = function () {
+            this.rotate(0, x, y);
+            var bb = this[1].getBBox();
+            if (bb.height >= r * 2) {
+                this[0].attr({path: ["M", x, y + r, "a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2, "m", 0, -r * 2 -d, "a", r + d, r + d, 0, 1, 0, 0, (r + d) * 2, "L", x + r + d, y + bb.height / 2 + d, "l", bb.width + 2 * d, 0, 0, -bb.height - 2 * d, -bb.width - 2 * d, 0, "L", x, y - r - d].join(",")});
+            } else {
+                var dx = Math.sqrt(Math.pow(r + d, 2) - Math.pow(bb.height / 2 + d, 2));
+                // ["c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r]
+                // "a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2,
+                this[0].attr({path: ["M", x, y + r, "c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r, "M", x + dx, y - bb.height / 2 - d, "a", r + d, r + d, 0, 1, 0, 0, bb.height + 2 * d, "l", r + d - dx + bb.width + 2 * d, 0, 0, -bb.height - 2 * d, "L", x + dx, y - bb.height / 2 - d].join(",")});
+            }
+            this[1].attr({x: x + r + d + bb.width / 2, y: y});
+            angle = (360 - angle) % 360;
+            this.rotate(angle, x, y);
+            angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]});
+            return this;
+        };
+        res.update();
+        return res;
+    };
+    Raphael.fn.g.popupit = function (x, y, set, dir, size) {
+        dir = dir == null ? 2 : dir;
+        size = size || 5;
+        x = Math.round(x) + .5;
+        y = Math.round(y) + .5;
+        var bb = set.getBBox(),
+            w = Math.round(bb.width / 2),
+            h = Math.round(bb.height / 2),
+            dx = [0, w + size * 2, 0, -w - size * 2],
+            dy = [-h * 2 - size * 3, -h - size, 0, -h - size],
+            p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size,
+                "l", 0, -Math.max(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -Math.max(h - size, 0), "a", size, size, 0, 0, 1, size, -size,
+                "l", Math.max(w - size, 0), 0, size, !dir * -size, size, !dir * size, Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size,
+                "l", 0, Math.max(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, Math.max(h - size, 0), "a", size, size, 0, 0, 1, -size, size,
+                "l", -Math.max(w - size, 0), 0, "z"].join(","),
+            xy = [{x: x, y: y + size * 2 + h}, {x: x - size * 2 - w, y: y}, {x: x, y: y - size * 2 - h}, {x: x + size * 2 + w, y: y}][dir];
+        set.translate(xy.x - w - bb.x, xy.y - h - bb.y);
+        return this.path(p).attr({fill: "#000", stroke: "none"}).insertBefore(set.node ? set : set[0]);
+    };
+    Raphael.fn.g.popup = function (x, y, text, dir, size) {
+        dir = dir == null ? 2 : dir;
+        size = size || 5;
+        text = text || "$9.99";
+        var res = this.set(),
+            d = 3;
+        res.push(this.path().attr({fill: "#000", stroke: "none"}));
+        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"}));
+        res.update = function (X, Y, withAnimation) {
+            X = X || x;
+            Y = Y || y;
+            var bb = this[1].getBBox(),
+                w = bb.width / 2,
+                h = bb.height / 2,
+                dx = [0, w + size * 2, 0, -w - size * 2],
+                dy = [-h * 2 - size * 3, -h - size, 0, -h - size],
+                p = ["M", X - dx[dir], Y - dy[dir], "l", -size, (dir == 2) * -size, -Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size,
+                    "l", 0, -Math.max(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -Math.max(h - size, 0), "a", size, size, 0, 0, 1, size, -size,
+                    "l", Math.max(w - size, 0), 0, size, !dir * -size, size, !dir * size, Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size,
+                    "l", 0, Math.max(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, Math.max(h - size, 0), "a", size, size, 0, 0, 1, -size, size,
+                    "l", -Math.max(w - size, 0), 0, "z"].join(","),
+                xy = [{x: X, y: Y + size * 2 + h}, {x: X - size * 2 - w, y: Y}, {x: X, y: Y - size * 2 - h}, {x: X + size * 2 + w, y: Y}][dir];
+            if (withAnimation) {
+                this[0].animate({path: p}, 500, ">");
+                this[1].animate(xy, 500, ">");
+            } else {
+                this[0].attr({path: p});
+                this[1].attr(xy);
+            }
+            return this;
+        };
+        return res.update(x, y);
+    };
+    Raphael.fn.g.flag = function (x, y, text, angle) {
+        angle = angle || 0;
+        text = text || "$9.99";
+        var res = this.set(),
+            d = 3;
+        res.push(this.path().attr({fill: "#000", stroke: "none"}));
+        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"}));
+        res.update = function (x, y) {
+            this.rotate(0, x, y);
+            var bb = this[1].getBBox(),
+                h = bb.height / 2;
+            this[0].attr({path: ["M", x, y, "l", h + d, -h - d, bb.width + 2 * d, 0, 0, bb.height + 2 * d, -bb.width - 2 * d, 0, "z"].join(",")});
+            this[1].attr({x: x + h + d + bb.width / 2, y: y});
+            angle = 360 - angle;
+            this.rotate(angle, x, y);
+            angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]});
+            return this;
+        };
+        return res.update(x, y);
+    };
+    Raphael.fn.g.label = function (x, y, text) {
+        var res = this.set();
+        res.push(this.rect(x, y, 10, 10).attr({stroke: "none", fill: "#000"}));
+        res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"}));
+        res.update = function () {
+            var bb = this[1].getBBox(),
+                r = Math.min(bb.width + 10, bb.height + 10) / 2;
+            this[0].attr({x: bb.x - r / 2, y: bb.y - r / 2, width: bb.width + r, height: bb.height + r, r: r});
+        };
+        res.update();
+        return res;
+    };
+    Raphael.fn.g.labelit = function (set) {
+        var bb = set.getBBox(),
+            r = Math.min(20, bb.width + 10, bb.height + 10) / 2;
+        return this.rect(bb.x - r / 2, bb.y - r / 2, bb.width + r, bb.height + r, r).attr({stroke: "none", fill: "#000"}).insertBefore(set[0]);
+    };
+    Raphael.fn.g.drop = function (x, y, text, size, angle) {
+        size = size || 30;
+        angle = angle || 0;
+        var res = this.set();
+        res.push(this.path(["M", x, y, "l", size, 0, "A", size * .4, size * .4, 0, 1, 0, x + size * .7, y - size * .7, "z"]).attr({fill: "#000", stroke: "none", rotation: [22.5 - angle, x, y]}));
+        angle = (angle + 90) * Math.PI / 180;
+        res.push(this.text(x + size * Math.sin(angle), y + size * Math.cos(angle), text).attr(this.g.txtattr).attr({"font-size": size * 12 / 30, fill: "#fff"}));
+        res.drop = res[0];
+        res.text = res[1];
+        return res;
+    };
+    Raphael.fn.g.blob = function (x, y, text, angle, size) {
+        angle = (+angle + 1 ? angle : 45) + 90;
+        size = size || 12;
+        var rad = Math.PI / 180,
+            fontSize = size * 12 / 12;
+        var res = this.set();
+        res.push(this.path().attr({fill: "#000", stroke: "none"}));
+        res.push(this.text(x + size * Math.sin((angle) * rad), y + size * Math.cos((angle) * rad) - fontSize / 2, text).attr(this.g.txtattr).attr({"font-size": fontSize, fill: "#fff"}));
+        res.update = function (X, Y, withAnimation) {
+            X = X || x;
+            Y = Y || y;
+            var bb = this[1].getBBox(),
+                w = Math.max(bb.width + fontSize, size * 25 / 12),
+                h = Math.max(bb.height + fontSize, size * 25 / 12),
+                x2 = X + size * Math.sin((angle - 22.5) * rad),
+                y2 = Y + size * Math.cos((angle - 22.5) * rad),
+                x1 = X + size * Math.sin((angle + 22.5) * rad),
+                y1 = Y + size * Math.cos((angle + 22.5) * rad),
+                dx = (x1 - x2) / 2,
+                dy = (y1 - y2) / 2,
+                rx = w / 2,
+                ry = h / 2,
+                k = -Math.sqrt(Math.abs(rx * rx * ry * ry - rx * rx * dy * dy - ry * ry * dx * dx) / (rx * rx * dy * dy + ry * ry * dx * dx)),
+                cx = k * rx * dy / ry + (x1 + x2) / 2,
+                cy = k * -ry * dx / rx + (y1 + y2) / 2;
+            if (withAnimation) {
+                this.animate({x: cx, y: cy, path: ["M", x, y, "L", x1, y1, "A", rx, ry, 0, 1, 1, x2, y2, "z"].join(",")}, 500, ">");
+            } else {
+                this.attr({x: cx, y: cy, path: ["M", x, y, "L", x1, y1, "A", rx, ry, 0, 1, 1, x2, y2, "z"].join(",")});
+            }
+            return this;
+        };
+        res.update(x, y);
+        return res;
+    };
+
+    Raphael.fn.g.colorValue = function (value, total, s, b) {
+        return "hsb(" + [Math.min((1 - value / total) * .4, 1), s || .75, b || .75] + ")";
+    };
+
+    Raphael.fn.g.snapEnds = function (from, to, steps) {
+        var f = from,
+            t = to;
+        if (f == t) {
+            return {from: f, to: t, power: 0};
+        }
+        function round(a) {
+            return Math.abs(a - .5) < .25 ? Math.floor(a) + .5 : Math.round(a);
+        }
+        var d = (t - f) / steps,
+            r = Math.floor(d),
+            R = r,
+            i = 0;
+        if (r) {
+            while (R) {
+                i--;
+                R = Math.floor(d * Math.pow(10, i)) / Math.pow(10, i);
+            }
+            i ++;
+        } else {
+            while (!r) {
+                i = i || 1;
+                r = Math.floor(d * Math.pow(10, i)) / Math.pow(10, i);
+                i++;
+            }
+            i && i--;
+        }
+        var t = round(to * Math.pow(10, i)) / Math.pow(10, i);
+        if (t < to) {
+            t = round((to + .5) * Math.pow(10, i)) / Math.pow(10, i);
+        }
+        var f = round((from - (i > 0 ? 0 : .5)) * Math.pow(10, i)) / Math.pow(10, i);
+        return {from: f, to: t, power: i};
+    };
+    Raphael.fn.g.axis = function (x, y, length, from, to, steps, orientation, labels, type, dashsize) {
+        dashsize = dashsize == null ? 3 : dashsize;
+        type = type || "t";
+        steps = steps || 10;
+        var path = type == "|" || type == " " ? ["M", x + .5, y, "l", 0, .001] : orientation == 1 || orientation == 3 ? ["M", x + .5, y, "l", 0, -length] : ["M", x, y + .5, "l", length, 0],
+            ends = this.g.snapEnds(from, to, steps),
+            f = ends.from,
+            t = ends.to,
+            i = ends.power,
+            j = 0,
+            text = this.set();
+        d = (t - f) / steps;
+        var label = f,
+            rnd = i > 0 ? i : 0;
+            dx = length / steps;
+        if (+orientation == 1 || +orientation == 3) {
+            var Y = y,
+                addon = (orientation - 1 ? 1 : -1) * (dashsize + 3 + !!(orientation - 1));
+            while (Y >= y - length) {
+                type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), Y + .5, "l", dashsize * 2 + 1, 0]));
+                text.push(this.text(x + addon, Y, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({"text-anchor": orientation - 1 ? "start" : "end"}));
+                label += d;
+                Y -= dx;
+            }
+            if (Math.round(Y + dx - (y - length))) {
+                type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), y - length + .5, "l", dashsize * 2 + 1, 0]));
+                text.push(this.text(x + addon, y - length, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({"text-anchor": orientation - 1 ? "start" : "end"}));
+            }
+        } else {
+            var X = x,
+                label = f,
+                rnd = i > 0 ? i : 0,
+                addon = (orientation ? -1 : 1) * (dashsize + 9 + !orientation),
+                dx = length / steps,
+                txt = 0,
+                prev = 0;
+            while (X <= x + length) {
+
+                text.push(txt = this.text(X, y + addon, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr));
+		var bb = txt.getBBox();
+		var ds = dashsize;
+                if (prev >= bb.x - 5) {
+		    text.pop(text.length - 1).remove();
+		    ds = 1;
+                } else {
+                    prev = bb.x + bb.width;
+                }
+
+		type != "-" && type != " " && (path = path.concat(["M", X + .5, y - (type == "+" ? ds : !!orientation * ds * 2), "l", 0, ds * 2 + 1]));
+                
+                label += d;
+                X += dx;
+            }
+            if (Math.round(X - dx - x - length)) {
+                type != "-" && type != " " && (path = path.concat(["M", x + length + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1]));
+                text.push(this.text(x + length, y + addon, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr));
+            }
+        }
+        var res = this.path(path);
+        res.text = text;
+        res.all = this.set([res, text]);
+        res.remove = function () {
+            this.text.remove();
+            this.constructor.prototype.remove.call(this);
+        };
+        return res;
+    };
+
+    Raphael.el.lighter = function (times) {
+        times = times || 2;
+        var fs = [this.attrs.fill, this.attrs.stroke];
+        this.fs = this.fs || [fs[0], fs[1]];
+        fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);
+        fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);
+        fs[0].b = Math.min(fs[0].b * times, 1);
+        fs[0].s = fs[0].s / times;
+        fs[1].b = Math.min(fs[1].b * times, 1);
+        fs[1].s = fs[1].s / times;
+        this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"});
+    };
+    Raphael.el.darker = function (times) {
+        times = times || 2;
+        var fs = [this.attrs.fill, this.attrs.stroke];
+        this.fs = this.fs || [fs[0], fs[1]];
+        fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);
+        fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);
+        fs[0].s = Math.min(fs[0].s * times, 1);
+        fs[0].b = fs[0].b / times;
+        fs[1].s = Math.min(fs[1].s * times, 1);
+        fs[1].b = fs[1].b / times;
+        this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"});
+    };
+    Raphael.el.original = function () {
+        if (this.fs) {
+            this.attr({fill: this.fs[0], stroke: this.fs[1]});
+            delete this.fs;
+        }
+    };
+})();
\ No newline at end of file

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/load-big.gif
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/load-big.gif?rev=953041&view=auto
==============================================================================
Binary file - no diff available.

Propchange: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/load-big.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/load.gif
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/load.gif?rev=953041&view=auto
==============================================================================
Binary file - no diff available.

Propchange: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/load.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.css
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.css?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.css (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.css Wed Jun  9 15:26:22 2010
@@ -0,0 +1,54 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+body { font-family: sans-serif; }
+
+div.fileSelector { border: solid 3px black; position: absolute; background: white; 
+		   -moz-border-radius: 10px; border-radius: 10px; 
+		   padding: 5px; font-family: sans-serif;
+		   right: 10px; top: 10px;
+		 }
+div.fileSelector a { cursor: pointer; }
+.fileSelector li.selectedFile { background: lightgreen; }
+
+div.selector { border: solid 3px black; position: absolute; background: white; 
+		   -moz-border-radius: 10px; border-radius: 10px; 
+		   padding: 5px; 
+		   right: 10px; top: 10px; background: #aaaaaa; opacity: 0.7;
+		 }
+div.selector a { cursor: pointer; }
+.fileSelector li.selectedFile { background: lightgreen; }
+
+#fileLoader  { -moz-border-radius: 10px; border-radius: 10px; background: #aaaaaa; opacity: 0.7; position: absolute; left: 20px; top: 20px; }
+#loadingScreen { position: absolute; top: 100px; margin-left: 40%; margin-right: 40%; width: 500px; background: #aaaaaa; opacity: 0.7; -moz-border-radius: 10px; border-radius: 10px; text-align: center }
+#filterinput { width: 500px; height: 100px; }
+/* main interface */
+#actions { float: right; }
+#views { float: left; }
+
+.closebutton { position: absolute; right: 5px; float: right; display: block; cursor: pointer; }
+
+.actionbutton { color: blue; text-decoration: none; padding: 3px; cursor: pointer; }
+span:hover.actionbutton { background: lightblue;  }
+
+#status { text-align: center; }
+
+#canvas { width: 100%; height: 1000px; }
+
+#logtable { width: 100%; }
+.popUp { border: 3px solid black; -moz-border-radius: 10px; border-radius: 10px; position: absolute; background: white; padding: 10px; min-width: 300px; }
+
+.errorpage { position: absolute; top: 100px; margin-left: 40%; margin-right: 40%; width: 500px; background: #aaaaaa; opacity: 0.7; -moz-border-radius: 10px; border-radius: 10px; padding: 10px; }
\ No newline at end of file

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,262 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+LogGraph = function(canvas, status) {
+    this.canvas = document.getElementById(canvas);
+    this.status = document.getElementById(status);
+    this.starttime = 0;
+    this.endtime = 0;
+    this.period = 0;
+    this.numEntries = 0;
+    this.currentRender = 0;
+    this.filter = "";
+
+    this.saveFilters = function () {
+	localStorage.starttime = this.starttime;
+	localStorage.endtime = this.endtime;
+	localStorage.period = this.period;
+	localStorage.filter = this.filter;
+	
+    };
+    this.loadFilters = function () {
+	if (localStorage.starttime) { this.starttime = parseInt(localStorage.starttime); }
+	if (localStorage.endtime) { this.endtime = parseInt(localStorage.endtime); }
+	if (localStorage.period) { this.period = parseInt(localStorage.period); }
+	if (localStorage.filter) { this.filter = localStorage.filter; }
+    };
+    this.loadFilters();
+    var self = this;
+
+    var updateStatus = function (starttime, period, filter, numEntries) {
+	self.starttime = starttime;
+	self.endtime = starttime + period;
+	self.period = period;
+	self.filter = filter;
+	self.saveFilters(); 
+       
+	self.status.innerHTML = dateFormat(starttime, "HH:MM:ss,l") + " &rArr; " + dateFormat(self.endtime, "HH:MM:ss,l") + " &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp; " + numEntries + " entries  &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp; " +  (filter ? filter : "No filter");
+	
+	if (self.currentRender) {
+	    self.currentRender();
+	}
+    };
+	
+    YUI().use("io-base", function(Y) {
+	    var uri = "/info";
+	    if (self.starttime) {
+		var uri = "/info?start=" + self.starttime + "&period=" + self.period + "&filter=" + self.filter;
+	    }
+	    
+	    function complete(id, o, args) {
+		var data = eval("(" + o.responseText + ")"); // Response data.
+		var period = data.endTime - data.startTime;
+		updateStatus(data.startTime, period, self.filter, data.numEntries);
+	    };
+	    
+	    Y.on('io:complete', complete, Y, []);
+	    var request = Y.io(uri);
+	});
+    
+    this.addLogs = function() {
+	new LogGraph.fileSelector(function (files) { new LogGraph.fileLoader(files); });
+    };
+
+    this.editFilters = function() {
+	new LogGraph.filterSelector(this.starttime, this.period, this.filter, updateStatus);
+    };	
+	
+    this.getCleanCanvas = function () {
+	this.canvas.innerHTML = "";
+	return this.canvas;
+    };
+
+    this.showLoadingScreen = function () {
+	this.loadingScreen = document.createElement("div");
+	this.loadingScreen.id = "loadingScreen";
+	this.loadingScreen.innerHTML = "<img src=\"load-big.gif\" /> <p>Loading...</p>";
+	document.body.appendChild(this.loadingScreen);
+    };
+
+    this.hideLoadingScreen = function () {
+	document.body.removeChild(this.loadingScreen);
+	this.loadingScreen.style.visibility = "hidden";
+    };
+
+
+    /***
+     * TODO: refactor these to load the data first, before handing to a draw funciton. 
+     *       We shouldn't pass the async q into the drawing function
+     */
+    this.showLogs = function() {
+	var self= this;
+	YUI().use('async-queue', function(Y) {
+		var q = new Y.AsyncQueue(self.showLoadingScreen,
+					 // The second callback will pause the Queue and send an XHR for data
+					 function () {
+					     q.pause();
+					     var loggraph = new LogGraph.LogTable(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);
+					     self.currentRender = self.showLogs;
+					 },
+					 self.hideLoadingScreen);
+		q.run();
+	    }
+	    );
+    };
+
+    this.serverGraph = function() {
+	var self= this;
+	YUI().use('async-queue', function(Y) {
+		var q = new Y.AsyncQueue(self.showLoadingScreen,
+					 // The second callback will pause the Queue and send an XHR for data
+					 function () {
+					     q.pause();
+					     var servergraph = new LogGraph.ServerGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);
+					     self.currentRender = self.showLogs;
+					 },
+					 self.hideLoadingScreen);
+		q.run();
+	    }
+	    );
+    };
+    
+    this.sessionGraph = function() {
+	var self= this;
+	YUI().use('async-queue', function(Y) {
+		var q = new Y.AsyncQueue(self.showLoadingScreen,
+					 // The second callback will pause the Queue and send an XHR for data
+					 function () {
+					     q.pause();
+					     var sessiongraph = new LogGraph.SessionGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);
+					     self.currentRender = self.sessionGraph;
+					 },
+					 self.hideLoadingScreen);
+		q.run();
+	    }
+	    );
+    };
+    
+    this.showStats = function() {
+	var self= this;
+	YUI().use('async-queue', function(Y) {
+		var q = new Y.AsyncQueue(self.showLoadingScreen,
+					 // The second callback will pause the Queue and send an XHR for data
+					 function () {
+					     q.pause();
+					     var statgraph = new LogGraph.StatsGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter);
+					     self.currentRender = self.showStats;
+					 },
+					 self.hideLoadingScreen);
+		q.run();
+	    }
+	    );
+    };
+};
+
+LogGraph.error = function(description) {
+    var errorPage = document.createElement("div");
+    errorPage.className = "errorpage";
+    var p = document.createElement("p");
+    p.innerHTML = description;
+    errorPage.appendChild(p);
+    
+    var span = document.createElement("span");
+    p = document.createElement("p");
+    span.className = "actionButton";
+    span.innerHTML = "OK";
+    span.onclick = function (evt) {
+	document.body.removeChild(errorPage);
+	delete errorPage;
+    }
+    p.appendChild(span);
+    errorPage.appendChild(p);
+
+    document.body.appendChild(errorPage);
+};
+
+LogGraph.ticker =function(allow_dups) {
+    this.ticks = new Array();
+    this.current_tick = 0;
+    this.allow_dups = allow_dups;;
+    
+    this.tick = function(time) {
+	if (time == this.ticks[this.ticks.length - 1] && this.allow_dups == true) 
+	    return this.current_tick;
+	
+	this.ticks.push(time);
+	return this.current_tick++;
+    };
+    
+    this.current = function() {
+	return this.current_tick;
+    };
+    
+    this.reset = function() {
+	while (this.ticks.length) {
+	    this.ticks.pop();
+	}
+	this.current_tick = 0;
+    };
+};
+
+
+LogGraph.timescale = function(starttime, endtime) {
+    this.starttime = starttime;
+    this.endtime = endtime;
+    this.millis = endtime - starttime;
+    
+    this.draw = function(paper) {
+	var scale = paper.set();
+	scale.push(paper.path("M0 0 L" + paper.width + " 0"));
+	
+	for (var i = 0; i < paper.width; i += 100) {
+	    scale.push(paper.path("M" + i + " 0 L" + i + " 5"));
+	    //		var time = dateFormat((this.starttime + (i*ms_per_pixel)), "h:MM:ss,l");
+		//	paper.text(i + 5, 10, time);
+	}
+	
+	scale.attr({"stroke-width": 2});
+    };
+};
+
+/*
+  Fetch data from an uri and process it, the process data func returns true if any of the data is useful  
+*/
+LogGraph.loadData = function (asyncq, uri, processdata) {
+    YUI().use("io-base", function(Y) {
+	    function success(id, o, args) {
+		var data = eval("(" + o.responseText + ")"); // Response data.
+		if (data.error) {
+		    LogGraph.error(data.error);
+		} else {
+		    if (!processdata(data)) {
+			LogGraph.error("No data. Perhaps you should loosen your filter criteria.");
+		    }
+		}
+		asyncq.run();
+	    };
+	    function failure(id, o, args) {
+		LogGraph.error("Error contacting server: (" + o.status + ") " + o.statusText);
+		asyncq.run();
+	    };
+
+	    Y.on('io:success', success, Y, []);
+	    Y.on('io:failure', failure, Y, []);
+	    
+	    var request = Y.io(uri);
+	});
+}
\ No newline at end of file

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.log.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.log.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.log.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.log.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+LogGraph.LogTable = function (asyncq, canvas, starttime, endtime, filter) {
+    this.starttime = starttime;
+    this.endtime = endtime;
+    this.filter = filter;
+
+    var table = document.createElement("table");
+    table.id = "logtable";
+    canvas.appendChild(table);
+
+    this.addLogLine = function(time, text) {
+	var tr = document.createElement("tr");
+	table.appendChild(tr);
+	
+	var td = document.createElement("td");
+	td.innerHTML = dateFormat(time, "h:MM:ss,l");
+	tr.appendChild(td);
+
+	td = document.createElement("td");
+	td.innerHTML = text;
+	tr.appendChild(td);
+    }
+
+    var self = this;
+    var processdata = function(data) {
+	var events = data["events"];
+	var count = 0;
+	for (var i in events) {
+	    var e = events[i];
+	    if (e.type == "text") {
+		self.addLogLine(e.time, e.text);
+		count++;
+	    }
+	}
+	return count != 0;
+    };
+
+    var uri = "/data?start=" + self.starttime + "&end=" + self.endtime + "&filter=" + self.filter; 
+    LogGraph.loadData(asyncq, uri, processdata);
+};

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.server.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.server.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.server.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.server.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,329 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+LogGraph.ServerGraph = function(asyncq, canvas, starttime, endtime, filter) {
+    this.starttime = starttime;
+    this.endtime = endtime;
+    this.millis = endtime - starttime;
+    this.nextserverid = 0;
+    this.serveroffset = 100;
+    this.filter = filter;
+    
+    this.pixels_per_tick =  20;
+    this.ticker = new LogGraph.ticker();
+
+    
+    var paper = Raphael(canvas, 1, 1);
+
+    var self = this;
+
+    this.timescale = new LogGraph.timescale(starttime, endtime);
+    this.objects = new Array();
+    
+    this.add = function(obj) {
+	this.objects.push(obj);
+    }
+    
+    this.tick_to_x = function (timestamp) {
+	var x = timestamp * this.pixels_per_tick; 
+	return x;
+    }; 
+    
+    this._drawTime  = function(paper, x, time) {
+	var p = paper.path("M" + x + " 0 L" + x + " " + paper.height);
+	var t = paper.text(x, 10, dateFormat(time, "h:MM:ss,l"));
+	
+	t.hide();
+	p.mouseover(function(evt) {
+		t.show();
+		p.attr({stroke: "red"});
+	    });
+	p.mouseout(function(evt) {
+		t.hide();
+		p.attr({stroke: "lightgray"});
+	    });
+	
+	return p;
+    };
+    
+    this.draw = function(paper) {
+	var grid = paper.set();
+	for (var i = 0; i < paper.height; i += 20) {
+	    grid.push(paper.path("M0 " + i + " L" + paper.width + " " + i));
+	}
+	var lasttick = this.starttime;
+	var scale = 500; // 500 ms
+	
+	var y = 0;
+	
+	for (var t = 0, len = this.ticker.ticks.length; t < len; t++) {
+	    var basex = t * this.pixels_per_tick;
+	    var thistick = this.ticker.ticks[t];
+	    var nexttick = t + 1 == this.ticker.ticks.length ? this.endtime : this.ticker.ticks[t+1];
+	    if (nexttick == thistick) {
+		continue;
+	    }
+	    var time = thistick - lasttick;
+	    var first = scale - (lasttick % scale);
+	    
+	    /*		for (var i = 0; (first+scale*i) < time; i++) {
+			
+			var toffset = first+scale*i;
+			var x = basex + LogGraph._pixels_per_tick * toffset/time;
+			grid.push(this._drawTime(paper, x, lasttick + toffset, grid));
+			
+			}*/
+	    
+	    
+	    //grid.push(paper.path("M" + i + " 0 L" + i + " " + paper.height));
+	    lasttick = thistick;
+	}
+	grid.attr({stroke: "lightgray"});
+	this.timescale.draw(paper);
+	
+	for (o in this.objects) {
+	    this.objects[o].draw(paper);
+	}
+    };
+
+
+    var processdata = function(data) {
+	var servermap = {};
+	var servers = data.servers;
+	var count = 0;
+	for (s in servers) {
+	    var server = new LogGraph.ServerGraph.server(self, "Server " + servers[s]);
+	    servermap[servers[s]] = server;
+	    self.add(server);
+	    count++;
+	}
+	
+	var messages = {};
+	var events = data.events;
+	for (var i in events) {
+	    var e = events[i];
+	    var t = e.time;
+	    if (e.type == "stateChange") {
+		servermap[e.server].addState(e.state, self.ticker.tick(e.time));
+	    }
+	    if (e.type == "postmessage") {
+		src = servermap[e.src];
+		dst = servermap[e.dst];
+		var key = "key:s" + e.src + ",d" + e.dst + ",z" + e.zxid;
+		    
+		var m = new LogGraph.ServerGraph.message(self, src, self.ticker.tick(e.time), dst, e.zxid);
+		messages[key] = m;
+	    } 
+	    if (e.type == "delivermessage") {
+		var key = "key:s" + e.src + ",d" + e.dst + ",z" + e.zxid;
+		
+		var m = messages[key];
+		if (m) {
+		    m.dsttime = self.ticker.tick(e.time);
+		    m.name = "Propose";
+		    self.add(m);
+		    delete messages[key];
+		}
+	    } 
+	    if (e.type == "exception") {
+		servermap[e.server].addException(self.ticker.tick(e.time), e.text, e.time);
+	    }
+	    count++;
+	}
+	
+	for (var i in messages) {
+	    var m = messages[i];
+	    m.markIncomplete();
+	    self.add(m);
+	    count++;
+	}
+
+	if (count != 0) {
+	    paper.setSize(self.tick_to_x(self.ticker.current()), 1000);	    
+	    
+	    var line = paper.path("M0 0 L0 1000");	    
+	    line.attr({"stroke": "red", "stroke-dasharray": "- "});
+	    var base = canvas.offsetLeft;// + ((canvas.offsetWidth - paper.width)/2);
+	    canvas.onmousemove = function (evt) {
+		var x = evt.screenX - base;
+		
+		line.attr({"path": "M" + x + " 0 L"+ x +" 1000"});
+		
+	    };
+
+	    self.draw(paper);
+	    return true;
+	} else {
+	    return false;
+	}
+    };
+		
+    var uri = "/data?start=" + self.starttime + "&end=" + self.endtime + "&filter=" + filter;
+
+    LogGraph.loadData(asyncq, uri, processdata);    
+};
+
+LogGraph.ServerGraph.server = function (graph, name) {
+    this.graph = graph;
+    this.serverid = graph.nextserverid++;
+    this.name = name;
+    this.y = (this.serverid * 300 + graph.serveroffset);
+    this.states = new Array();
+    this.exception = new Array();
+    
+    this.addState = function(state, time) {
+	this.states.push([state, time]);
+    }
+    
+    this.addException = function(tick, exception, time) {
+	this.exception.push(new LogGraph.ServerGraph.exception(this.graph, tick, exception, time));
+    }
+    
+    this.draw = function(paper) {
+	var st = paper.set();
+	st.push(paper.path("M0 " + this.y + " L" + paper.width + " " + this.y));
+	st.push(paper.text(20, this.y - 10, this.name));
+	st.attr({stroke: "gray"});
+	
+	var numstates = this.states.length;
+	
+	for (s = 0; s < numstates; s++) {
+	    var style = {};
+	    switch (this.states[s][0]) {
+	    case "INIT": style = {stroke: "yellow", "stroke-width":3}; break;
+	    case "FOLLOWING": style = {stroke: "lightgreen", "stroke-width":7}; break;
+	    case "LEADING": style = {stroke: "green", "stroke-width":10}; break;
+	    case "LOOKING": style = {stroke: "orange", "stroke-width":5}; break;
+	    }
+	    var startx = this.graph.tick_to_x(this.states[s][1]);
+	    var endx = s + 1 < numstates ? this.graph.tick_to_x(this.states[(s+1)][1]) : paper.width;
+	    var p = paper.path("M" + startx + " " + this.y + " L" + endx + " " + this.y);
+	    p.attr(style);
+	}
+	
+	for (e in this.exception) {
+	    this.exception[e].draw(paper, this);
+	}
+    }
+};    
+    
+LogGraph.ServerGraph.message = function(graph, src, srctime, dst, zxid) {
+    this.graph = graph;
+    this.src = src;
+    this.srctime = srctime;
+    this.dst = dst;
+    this.dsttime = 0; //dsttime;
+    this.name = "Unknown";
+    this.zxid = zxid;
+    this.moreinfo = "No extra information";
+    this.incomplete = false;
+    
+    this.markIncomplete = function() {
+	this.incomplete = true;
+	this.dsttime = this.srctime;
+    }
+
+    this.draw = function(paper) {
+	var srcx = this.graph.tick_to_x(this.srctime);
+	var dstx = this.graph.tick_to_x(this.dsttime);
+	
+	var arrow = paper.set();
+	var p = paper.path("M" + srcx + " " + this.src.y + " L" + dstx + " " + this.dst.y);
+	arrow.push(p);
+	
+	var tx = (srcx + dstx)/2;
+	var ty = (this.src.y + this.dst.y)/2;
+	var t = paper.text(tx, ty, this.name);
+	
+	var gradiant = (this.dst.y - this.src.y)/(dstx - srcx);
+	var angle = Math.atan(gradiant) * 57.2958;
+	t.rotate(angle, true);
+	
+	var arrowl = paper.path("M" + dstx + " " + this.dst.y + " L" + (dstx - 10) +" " + this.dst.y);
+	arrowl.rotate(angle + 20, dstx, this.dst.y);
+	arrow.push(arrowl);
+	var arrowr = paper.path("M" + dstx + " " + this.dst.y + " L" + (dstx - 10) +" " + this.dst.y);
+	arrowr.rotate(angle - 20, dstx, this.dst.y);
+	arrow.push(arrowr);
+	
+	arrow.attr({"stroke-width": 2, stroke: "gray"});
+	if (this.incomplete) {
+	    arrow.attr({"stroke-dasharray": "- .", stroke: "pink", "stroke-width": 2});
+	}
+	arrow.mouseover(function(evt) {
+		t.attr({"font-size": 20});
+		arrow.attr({stroke: "red", "stroke-width": 3});
+	    });
+	arrow.mouseout(function(evt) {
+		t.attr({"font-size": 10});
+		
+		if (this.incomplete) {
+		    arrow.attr({stroke: "pink", "stroke-width": 2});
+		} else {
+		    arrow.attr({stroke: "gray", "stroke-width": 2});
+		}
+	    });
+	
+	
+
+	arrow.click(function(evt) { 
+		var popup = document.createElement("div");
+		popup.className = "popUp";
+		popup.innerHTML = "zxid: " + parseInt(this.zxid).toString(16);
+
+		popup.style.top = evt.clientY;
+		popup.style.left = evt.clientX;
+		document.body.appendChild(popup);
+
+		popup.onclick = function(evt) { 
+		    document.body.removeChild(popup);
+		};
+	    });
+    }
+};
+    
+LogGraph.ServerGraph.exception = function(graph, tick, exceptiontext, time) {
+    this.graph = graph;
+    this.time = time;
+    this.text = exceptiontext;
+    this.tick = tick;
+    
+    var self = this;
+
+    this.draw = function(paper, server) {
+	var center = this.graph.tick_to_x(this.tick);
+	var p = paper.circle(center, server.y, 5);
+	p.attr({stroke: "orange", fill: "red"});
+	
+	p.mouseover(function(evt) {
+		p.popup = document.createElement("div");
+		p.popup.className = "popUp";
+		p.popup.innerHTML = self.text.replace("\n", "<br/>");;
+		p.popup.style.top = server.y + 50;
+		p.popup.style.left = center + 25;
+		document.body.appendChild(p.popup);
+
+		p.animate({r: 10}, 500, "elastic");
+	    });
+	p.mouseout(function(evt) {
+		document.body.removeChild(p.popup);
+		p.animate({r: 5}, 100);
+	    });
+    }
+};
+    

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.session.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.session.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.session.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.session.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,202 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+LogGraph.SessionGraph = function (asyncq, canvas, starttime, endtime, filter) {
+    this.sessions = new Array();
+    this.counter = 0;
+    this.exceptions = new Array();
+    
+    this.pix_per_ticks = 4;
+    this.pix_per_session = 7;
+
+    var paper = Raphael(canvas, 1, 1);
+    this.ticker = new LogGraph.ticker();
+    var self = this;
+
+    this.starttime = starttime;
+    this.endtime = endtime;
+    this.filter = filter;
+
+    this.findOrCreateSession = function(id) {
+	if (this.sessions[id] == undefined) {
+	    this.sessions[id] = new LogGraph.SessionGraph.session(this, ++this.counter, id);
+	}
+	return this.sessions[id];
+    }
+    
+    this.height = function () { return this.counter * this.pix_per_session + 10; };
+    this.width = function () { return (self.ticker.current() * this.pix_per_ticks); };
+
+    this.draw = function(paper) {
+	
+
+	var line = paper.path("M0 0 L0 " + this.height());	    
+	line.attr({"stroke": "red", "stroke-dasharray": "- "});
+	var base = canvas.offsetLeft;
+	var width = this.width();
+	canvas.onmousemove = function (evt) {
+	    var x = evt.clientX - base;
+
+	    line.attr({"path": "M" + x + " 0 L" + x + " " + self.height() });
+	};	
+	
+	for (var i in this.sessions) {
+	    var s = this.sessions[i];
+	    s.draw(paper);
+	}
+    };
+
+    var processdata = function(data) {
+	var count = 0;
+	for (var i in data.events) {
+	    var e = data.events[i];
+	    if (e.type == "transaction") {
+		e.tick = self.ticker.tick(e.time, true);
+		var session = self.findOrCreateSession(e.client);
+		session.addEvent(e);
+		count++;
+	    }
+	}
+	paper.setSize(self.width(), self.height());
+	
+	if (count != 0) {
+	    self.draw(paper);
+	    return true;
+	} else {
+	    return false;
+	}
+    };
+    
+    var uri = "/data?start=" + self.starttime + "&end=" + self.endtime + "&filter=" + filter;
+
+    LogGraph.loadData(asyncq, uri, processdata);    
+};
+
+LogGraph.SessionGraph.sessionevent = function () {
+    this.time = time;
+    this.type = type;
+    this.client = client;
+    this.cxid = cxid;
+    this.zxid = zxid;
+    this.op = op;
+    this.extra = extra;
+};
+
+LogGraph.SessionGraph.sessionEventPopup = function (obj, e, x, y) {
+    obj.click(function(evt) {
+	    var popup = document.createElement("div");
+	    popup.className = "popUp";
+
+	    var closebutton = document.createElement("div");
+	    closebutton.className = "closebutton";
+	    closebutton.title = "Close popup";
+	    closebutton.innerHTML = "&times;";
+	    popup.appendChild(closebutton);
+	    closebutton.onclick= function(evt) { popup.style.visibility = "hidden"; document.body.removeChild(popup) };
+	    var txt = document.createElement("span");
+	    txt.innerHTML = "session: " + e.client + "<br/>op: " + e.op + "<br/>zxid: " + e.zxid + "<br/>time: " + e.time + "<br/>extra: " + e.extra;
+	    popup.appendChild(txt);
+	    
+	    popup.style.top = y;
+	    popup.style.left = x;
+	    document.body.appendChild(popup);
+	    
+	    YUI().use('dd-drag', function(Y) {
+		    //Selector of the node to make draggable
+		    var dd = new Y.DD.Drag({
+			    node: popup
+			});   
+		});
+	});
+};
+    
+LogGraph.SessionGraph.session = function (graph, index, id) {
+    this.index = index;
+    this.id = id;
+    this.graph = graph;
+    
+    this.events = new Array();
+    this.starttick = 0;
+    this.endtick = undefined;
+    
+    this.addEvent = function(e) {
+	this.events.push(e);
+	
+	if (e.op == "createSession") {
+	    //		document.write("createSession for " + id.toString(16));
+	    this.starttick = e.tick;
+	} else if (e.op == "closeSession") {
+	    this.endtick = e.tick;
+	}
+    },
+    
+    this._attach_action = function (sess, label) {
+	sess.mouseover(function(evt) {
+		label.show();
+		sess.attr({stroke: "gray"});
+	    });
+	
+	sess.mouseout(function(evt) {
+		label.hide();
+		sess.attr({stroke: "black"});
+	    });
+    },
+    
+    this.drawEvent = function (paper, y, e) {
+	var x = e.tick * this.graph.pix_per_ticks;;
+	var s = paper.path("M" + x + " " + (y - 3) + " L" + x + " " + (y + 3));
+	s.attr({"stroke-width": 2});
+	if (e.op == "error") {
+	    s.attr({"stroke": "red"});
+	} 
+	s.mouseover(function(evt) {
+		s.attr({"stroke-width": 5});
+	    });
+	
+	s.mouseout(function(evt) {
+		s.attr({"stroke-width": 2});
+	    });
+	
+	LogGraph.SessionGraph.sessionEventPopup(s, e, x, y);
+    },
+    
+    this.draw = function(paper) {
+	var y = this.index*this.graph.pix_per_session;;
+	var start = this.starttick * this.graph.pix_per_ticks;
+	var end = this.endtick * this.graph.pix_per_ticks;
+	
+	var sess = paper.set();
+	
+	if (this.endtick == undefined) {
+	    end = this.graph.width();
+	} 
+
+	sess.push(paper.path("M" + start + " " + y + " L" + end + " " + y));
+	for (var i in this.events) {
+	    var e = this.events[i];
+	    this.drawEvent(paper, y, e);
+	}
+	
+	//sess.attr({"stroke-width": 3});
+	label = paper.text(start + 100, y, this.id);
+	label.attr({"font-size": "14px"});
+	label.hide();
+	this._attach_action(sess, label);
+    }
+};
+

Added: hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.stats.js
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.stats.js?rev=953041&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.stats.js (added)
+++ hadoop/zookeeper/trunk/src/contrib/loggraph/web/org/apache/zookeeper/graph/resources/loggraph.stats.js Wed Jun  9 15:26:22 2010
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+LogGraph.StatsGraph = function (asyncq, canvas, starttime, endtime, filter) {
+    var processdata = function(data) {
+	var r = Raphael(canvas);
+	var x = data.map(function (x) { return x.time; });
+	var y = data.map(function (x) { return x.count; });
+	var xlabels = data.map(function (x) { return dateFormat(x.time, "HH:MM:ss,l"); } );
+	var h1 = function () {
+	    this.tags = r.set();
+	    for (var i = 0, ii = this.y.length; i < ii; i++) {
+		this.tags.push(r.g.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{fill: "#fff"}, {fill: this.symbols[i].attr("fill")}]));
+	    }
+	};
+	var h2 = function () {
+	    this.tags && this.tags.remove();
+	};
+	r.g.linechart(40, 40, 1000, 500,  x, y, {shade: true, axis: "0 0 1 1", symbol: "x", southlabels: xlabels, axisxstep: xlabels.length - 1 , westAxisLabel: "Write requests", southAxisLabel: "Time (min)"}).hoverColumn(h1, h2);
+
+	return true;
+	//r.g.barchart(0, 0, 1000, 100,  y, {shade: true, symbol: "x"}).hoverColumn(h1, h2);
+    };
+    
+    var uri = "/throughput?scale=minutes";
+    LogGraph.loadData(asyncq, uri, processdata);    
+};
+
+