zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [21/45] zookeeper git commit: ZOOKEEPER-3030: MAVEN MIGRATION - Step 1.3 - move contrib directories
Date Mon, 06 Aug 2018 12:13:46 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/AndOp.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/AndOp.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/AndOp.java
new file mode 100644
index 0000000..581bdaa
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/AndOp.java
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.LogEntry;
+import org.apache.zookeeper.graph.FilterOp;
+import org.apache.zookeeper.graph.FilterException;
+
+public class AndOp extends FilterOp {
+    public boolean matches(LogEntry entry) throws FilterException {
+	for (FilterOp f : subOps) {
+	    if (!f.matches(entry)) {
+		return false;
+	    }
+	}
+	return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/Arg.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/Arg.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/Arg.java
new file mode 100644
index 0000000..4fda3cf
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/Arg.java
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.FilterOp.*;
+
+public class Arg<T> {
+    private ArgType type;
+    protected T value;
+    
+    protected Arg(ArgType type) {
+	this.type = type;
+    }
+    
+    public ArgType getType() { return type; }
+    public T getValue() { return value; }
+
+    public String toString() {
+	return "[" + type + ":" + value + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/EqualsOp.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/EqualsOp.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/EqualsOp.java
new file mode 100644
index 0000000..409815a
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/EqualsOp.java
@@ -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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.LogEntry;
+import org.apache.zookeeper.graph.FilterOp;
+import org.apache.zookeeper.graph.FilterException;
+
+public class EqualsOp extends FilterOp {
+    public boolean matches(LogEntry entry) throws FilterException {
+
+	Object last = null;
+	for (Arg a : args) {
+	    Object v = a.getValue();
+	    if (a.getType() == FilterOp.ArgType.SYMBOL) {
+		String key = (String)a.getValue();
+		v = entry.getAttribute(key);
+	    }
+
+	    if (last != null
+		&& !last.equals(v)) {
+		return false;
+	    }
+	    last = v;
+	}
+
+	return true;
+    }
+}    

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/GreaterThanOp.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/GreaterThanOp.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/GreaterThanOp.java
new file mode 100644
index 0000000..244dd3d
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/GreaterThanOp.java
@@ -0,0 +1,70 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.LogEntry;
+import org.apache.zookeeper.graph.FilterOp;
+import org.apache.zookeeper.graph.FilterException;
+
+public class GreaterThanOp extends FilterOp {
+    public boolean matches(LogEntry entry) throws FilterException {
+	Arg first = args.get(0);
+	
+	if (first != null) {
+	    FilterOp.ArgType type = first.getType();
+	    if (type == FilterOp.ArgType.SYMBOL) {
+		String key = (String)first.getValue();
+		Object v = entry.getAttribute(key);
+		if (v instanceof String) {
+		    type = FilterOp.ArgType.STRING;
+		} else if (v instanceof Double || v instanceof Long || v instanceof Integer || v instanceof Short) {
+		    type = FilterOp.ArgType.NUMBER;
+		} else {
+		    throw new FilterException("LessThanOp: Invalid argument, first argument resolves to neither a String nor a Number");
+		}
+	    }
+	    
+	    Object last = null;
+	    for (Arg a : args) {
+		Object v = a.getValue();
+		if (a.getType() == FilterOp.ArgType.SYMBOL) {
+		    String key = (String)a.getValue();
+		    v = entry.getAttribute(key);
+		}
+
+		if (last != null) {
+		    if (type == FilterOp.ArgType.STRING) {
+			if (((String)last).compareTo((String)v) <= 0) {
+			    return false;
+			}
+		    } else if (type == FilterOp.ArgType.NUMBER) {
+			//			System.out.println("last[" + ((Number)last).longValue() + "] v["+ ((Number)v).longValue() + "]");
+			if (((Number)last).longValue() <= ((Number)v).longValue()) {
+			    return false;
+			}
+		    }
+		}
+		last = v;
+	    }
+	    return true;
+	} else { 
+	    return true; 
+	}
+    }
+	
+}    

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/LessThanOp.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/LessThanOp.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/LessThanOp.java
new file mode 100644
index 0000000..b7d9e09
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/LessThanOp.java
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.LogEntry;
+import org.apache.zookeeper.graph.FilterOp;
+import org.apache.zookeeper.graph.FilterException;
+
+public class LessThanOp extends FilterOp {
+    public boolean matches(LogEntry entry) throws FilterException {
+	Arg first = args.get(0);
+	
+	if (first != null) {
+	    FilterOp.ArgType type = first.getType();
+	    if (type == FilterOp.ArgType.SYMBOL) {
+		String key = (String)first.getValue();
+		Object v = entry.getAttribute(key);
+		if (v instanceof String) {
+		    type = FilterOp.ArgType.STRING;
+		} else if (v instanceof Double || v instanceof Long || v instanceof Integer || v instanceof Short) {
+		    type = FilterOp.ArgType.NUMBER;
+		} else {
+		    throw new FilterException("LessThanOp: Invalid argument, first argument resolves to neither a String nor a Number");
+		}
+	    }
+	    
+	    Object last = null;
+	    for (Arg a : args) {
+		Object v = a.getValue();
+		if (a.getType() == FilterOp.ArgType.SYMBOL) {
+		    String key = (String)a.getValue();
+		    v = entry.getAttribute(key);
+		}
+
+		if (last != null) {
+		    if (type == FilterOp.ArgType.STRING) {
+			if (((String)last).compareTo((String)v) >= 0) {
+			    return false;
+			}
+		    } else if (type == FilterOp.ArgType.NUMBER) {
+			if (((Number)last).doubleValue() >= ((Number)v).doubleValue()) {
+			    return false;
+			}
+		    }
+		}
+		last = v;
+	    }
+	    return true;
+	} else { 
+	    return true; 
+	}
+    }
+	
+}    

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NotOp.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NotOp.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NotOp.java
new file mode 100644
index 0000000..d8ed757
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NotOp.java
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.LogEntry;
+import org.apache.zookeeper.graph.FilterOp;
+import org.apache.zookeeper.graph.FilterException;
+
+public class NotOp extends FilterOp {
+    public boolean matches(LogEntry entry) throws FilterException {
+	if (subOps.size() != 1) {
+	    throw new FilterException("Not operation can only take one argument");
+	}
+	return !subOps.get(0).matches(entry);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NumberArg.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NumberArg.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NumberArg.java
new file mode 100644
index 0000000..d6b584d
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/NumberArg.java
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.FilterOp.*;
+
+public class NumberArg extends Arg<Long> {
+    public NumberArg(Long value) {
+	super(ArgType.NUMBER);
+	this.value = value;
+    }
+};
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/OrOp.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/OrOp.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/OrOp.java
new file mode 100644
index 0000000..d681589
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/OrOp.java
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.LogEntry;
+import org.apache.zookeeper.graph.FilterOp;
+import org.apache.zookeeper.graph.FilterException;
+
+public class OrOp extends FilterOp {
+    public boolean matches(LogEntry entry) throws FilterException {
+	for (FilterOp f : subOps) {
+	    if (f.matches(entry)) {
+		return true;
+	    }
+	}
+	return false;
+    }
+}    

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/StringArg.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/StringArg.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/StringArg.java
new file mode 100644
index 0000000..7345d3c
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/StringArg.java
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.FilterOp.*;
+
+public class StringArg extends Arg<String> {
+    public StringArg(String value) {
+	super(ArgType.STRING);
+	    this.value = value;
+    }
+};
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/SymbolArg.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/SymbolArg.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/SymbolArg.java
new file mode 100644
index 0000000..077553b
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/SymbolArg.java
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.FilterOp.*;
+
+public class SymbolArg extends Arg<String> {
+    public SymbolArg(String value) {
+	super(ArgType.SYMBOL);
+	this.value = value;
+    }
+};

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/XorOp.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/XorOp.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/XorOp.java
new file mode 100644
index 0000000..9e778b1
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/filterops/XorOp.java
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.filterops;
+
+import org.apache.zookeeper.graph.LogEntry;
+import org.apache.zookeeper.graph.FilterOp;
+import org.apache.zookeeper.graph.FilterException;
+
+public class XorOp extends FilterOp {
+    public boolean matches(LogEntry entry) throws FilterException {
+	int count = 0;
+	for (FilterOp f : subOps) {
+	    if (f.matches(entry)) {
+		count++;
+		if (count > 1) {
+		    return false;
+		}
+	    }
+	}
+	if (count == 1) {
+	    return true;
+	}
+	return false;
+    }
+}    

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/FileLoader.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/FileLoader.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/FileLoader.java
new file mode 100644
index 0000000..67e8945
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/FileLoader.java
@@ -0,0 +1,60 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.servlets;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import org.apache.zookeeper.graph.*;
+
+public class FileLoader extends JsonServlet
+{
+    private MergedLogSource source = null;
+    
+    public FileLoader(MergedLogSource src) throws Exception {
+	source = src;
+    }
+
+    String handleRequest(JsonRequest request) throws Exception
+    {
+	String output = "";
+		
+	String file = request.getString("path", "/");
+	JSONObject o = new JSONObject();
+	try {
+	    this.source.addSource(file);
+	    o.put("status", "OK");
+	
+	} catch (Exception e) {
+	    o.put("status", "ERR");
+	    o.put("error",  e.toString());
+	}
+	
+	return JSONValue.toJSONString(o);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Fs.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Fs.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Fs.java
new file mode 100644
index 0000000..e5b1a01
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Fs.java
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.servlets;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class Fs extends JsonServlet
+{
+    String handleRequest(JsonRequest request) throws Exception
+    {
+	String output = "";
+	JSONArray filelist = new JSONArray();
+
+	File base = new File(request.getString("path", "/"));
+	if (!base.exists() || !base.isDirectory()) {
+	    throw new FileNotFoundException("Couldn't find [" + request + "]");
+	}
+	File[] files = base.listFiles();
+	Arrays.sort(files, new Comparator<File>() { 
+		public int compare(File o1, File o2) {
+		    if (o1.isDirectory() != o2.isDirectory()) {
+			if (o1.isDirectory()) {
+			    return -1;
+			} else {
+			    return 1;
+			}
+		    }
+		    return o1.getName().compareToIgnoreCase(o2.getName());
+		} 
+	    });
+	
+	for (File f : files) {
+	    JSONObject o = new JSONObject();
+	    o.put("file", f.getName());
+	    o.put("type", f.isDirectory() ? "D" : "F");
+	    o.put("path", f.getCanonicalPath());
+	    filelist.add(o);
+	}
+	return JSONValue.toJSONString(filelist);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/GraphData.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/GraphData.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/GraphData.java
new file mode 100644
index 0000000..fc10eb1
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/GraphData.java
@@ -0,0 +1,85 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.servlets;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import org.apache.zookeeper.graph.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GraphData extends JsonServlet
+{
+    private static final Logger LOG = LoggerFactory.getLogger(GraphData.class);
+    private static final int DEFAULT_PERIOD = 1000;
+
+    private LogSource source = null;
+
+    public GraphData(LogSource src) throws Exception {
+	this.source = src; 
+    }
+
+    String handleRequest(JsonRequest request) throws Exception {
+	
+
+	long starttime = 0;
+	long endtime = 0;
+	long period = 0;
+	FilterOp fo = null;
+
+	starttime = request.getNumber("start", 0);
+	endtime = request.getNumber("end", 0);
+	period = request.getNumber("period", 0);
+	String filterstr = request.getString("filter", "");
+
+	if (filterstr.length() > 0) {
+	    fo = new FilterParser(filterstr).parse();
+	}
+	
+	if (starttime == 0) { starttime = source.getStartTime(); }
+	if (endtime == 0) { 
+	    if (period > 0) {
+		endtime = starttime + period;
+	    } else {
+		endtime = starttime + DEFAULT_PERIOD; 
+	    }
+	}
+
+	if (LOG.isDebugEnabled()) {
+	    LOG.debug("handle(start= " + starttime + ", end=" + endtime + ", period=" + period + ")");
+	}
+	
+	LogIterator iterator = (fo != null) ? 
+	    source.iterator(starttime, endtime, fo) : source.iterator(starttime, endtime);
+	return new JsonGenerator(iterator).toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/JsonServlet.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/JsonServlet.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/JsonServlet.java
new file mode 100644
index 0000000..910d44f
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/JsonServlet.java
@@ -0,0 +1,85 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.servlets;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import java.util.Map;
+
+abstract public class JsonServlet extends HttpServlet {
+    abstract String handleRequest(JsonRequest request) throws Exception;
+
+    protected class JsonRequest {
+	private Map map;
+
+	public JsonRequest(ServletRequest request) {
+	    map = request.getParameterMap();
+	}
+	
+	public long getNumber(String name, long defaultnum) {
+	    String[] vals = (String[])map.get(name);
+	    if (vals == null || vals.length == 0) {
+		return defaultnum;
+	    }
+
+	    try {
+		return Long.valueOf(vals[0]);
+	    } catch (NumberFormatException e) {
+		return defaultnum;
+	    }
+	}
+	
+	public String getString(String name, String defaultstr) {
+	    String[] vals = (String[])map.get(name);
+	    if (vals == null || vals.length == 0) {
+		return defaultstr;
+	    } else {
+		return vals[0];
+	    }
+	}
+    }
+
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        response.setContentType("text/plain;charset=utf-8");
+        response.setStatus(HttpServletResponse.SC_OK);
+	
+	try {
+	    String req = request.getRequestURI().substring(request.getServletPath().length());
+
+	    response.getWriter().println(handleRequest(new JsonRequest(request)));
+	} catch (Exception e) {
+	    JSONObject o = new JSONObject();
+	    o.put("error", e.toString());
+	    response.getWriter().println(JSONValue.toJSONString(o));
+	} catch (java.lang.OutOfMemoryError oom) {
+	    JSONObject o = new JSONObject();
+	    o.put("error", "Out of memory. Perhaps you've requested too many logs. Try narrowing you're filter criteria.");
+	    response.getWriter().println(JSONValue.toJSONString(o));
+	}
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/NumEvents.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/NumEvents.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/NumEvents.java
new file mode 100644
index 0000000..5961a12
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/NumEvents.java
@@ -0,0 +1,88 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.servlets;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import org.apache.zookeeper.graph.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class NumEvents extends JsonServlet
+{
+    private static final Logger LOG = LoggerFactory.getLogger(NumEvents.class);
+    private static final int DEFAULT_PERIOD = 1000;
+
+    private LogSource source = null;
+
+    public NumEvents(LogSource src) throws Exception {
+	this.source = src;
+    }
+
+    String handleRequest(JsonRequest request) throws Exception {
+	String output = "";
+
+	long starttime = 0;
+	long endtime = 0;
+	long period = 0;
+
+	starttime = request.getNumber("start", 0);
+	endtime = request.getNumber("end", 0);
+	period = request.getNumber("period", 0);
+
+	if (starttime == 0) { starttime = source.getStartTime(); }
+	if (endtime == 0) { 
+	    if (period > 0) {
+		endtime = starttime + period;
+	    } else {
+		endtime = source.getEndTime(); 
+	    }
+	}
+	
+	LogIterator iter = source.iterator(starttime, endtime);
+	JSONObject data = new JSONObject();
+	data.put("startTime", starttime);
+	data.put("endTime", endtime);
+	long size = 0;
+	
+	size = iter.size();
+	
+	data.put("numEntries",  size);
+	if (LOG.isDebugEnabled()) {
+	    LOG.debug("handle(start= " + starttime + ", end=" + endtime + ", numEntries=" + size +")");
+	}
+	iter.close();
+	return JSONValue.toJSONString(data);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/StaticContent.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/StaticContent.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/StaticContent.java
new file mode 100644
index 0000000..d91acb6
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/StaticContent.java
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.servlets;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class StaticContent extends HttpServlet {
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+	String path = request.getRequestURI().substring(request.getServletPath().length());
+
+	InputStream resource = ClassLoader.getSystemResourceAsStream("org/apache/zookeeper/graph/resources" + path);	  
+	if (resource == null) {
+	    response.getWriter().println(path + " not found!");
+	    response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+	    return;
+	}
+	try {
+	  while (resource.available() > 0) {
+	    response.getWriter().write(resource.read());
+	  }
+	} finally {
+	  resource.close();
+	}
+	//        response.setContentType("text/plain;charset=utf-8");
+        response.setStatus(HttpServletResponse.SC_OK);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Throughput.java
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Throughput.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Throughput.java
new file mode 100644
index 0000000..80ed1dc
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/servlets/Throughput.java
@@ -0,0 +1,126 @@
+/**
+ * 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.
+ */
+package org.apache.zookeeper.graph.servlets;
+
+import java.io.IOException;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.DataOutputStream;
+import java.io.PrintStream;
+
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Set;
+
+import org.apache.zookeeper.graph.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+
+public class Throughput extends JsonServlet
+{
+    private static final int MS_PER_SEC = 1000;
+    private static final int MS_PER_MIN = MS_PER_SEC*60;
+    private static final int MS_PER_HOUR = MS_PER_MIN*60;
+
+    private LogSource source = null;
+
+    public Throughput(LogSource src) throws Exception {
+	this.source = src; 
+    }
+
+    public String handleRequest(JsonRequest request) throws Exception {
+	long starttime = 0;
+	long endtime = 0;
+	long period = 0;
+	long scale = 0;
+	
+	starttime = request.getNumber("start", 0);
+	endtime = request.getNumber("end", 0);
+	period = request.getNumber("period", 0);
+	
+
+	if (starttime == 0) { starttime = source.getStartTime(); }
+	if (endtime == 0) { 
+	    if (period > 0) {
+		endtime = starttime + period;
+	    } else {
+		endtime = source.getEndTime(); 
+	    }
+	}
+	
+	String scalestr = request.getString("scale", "minutes");
+	if (scalestr.equals("seconds")) {
+	    scale = MS_PER_SEC;
+	} else if (scalestr.equals("hours")) {
+	    scale = MS_PER_HOUR;
+	} else {
+	    scale = MS_PER_MIN;
+	} 	
+	
+	LogIterator iter = source.iterator(starttime, endtime);
+	
+	long current = 0;
+	long currentms = 0;
+	Set<Long> zxids_ms = new HashSet<Long>();
+	long zxidcount = 0;
+
+	JSONArray events = new JSONArray();
+	while (iter.hasNext()) {
+	    LogEntry e = iter.next();
+	    if (e.getType() != LogEntry.Type.TXN) {
+		continue;
+	    }
+
+	    TransactionEntry cxn = (TransactionEntry)e;
+	    
+	    long ms = cxn.getTimestamp();
+	    long inscale = ms/scale;
+
+	    if (currentms != ms && currentms != 0) {
+		zxidcount += zxids_ms.size();
+		zxids_ms.clear();
+	    }
+
+	    if (inscale != current && current != 0) {
+		JSONObject o = new JSONObject();
+		o.put("time", current*scale);
+		o.put("count", zxidcount);
+		events.add(o);
+		zxidcount = 0;
+	    }
+	    current = inscale;
+	    currentms = ms;
+
+	    zxids_ms.add(cxn.getZxid());
+	}
+	JSONObject o = new JSONObject();
+	o.put("time", current*scale);
+	o.put("count", zxidcount);
+	events.add(o);
+
+	iter.close();
+	
+	return JSONValue.toJSONString(events);
+    }
+
+};

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph-dev.sh
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph-dev.sh b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph-dev.sh
new file mode 100755
index 0000000..e04434e
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph-dev.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# 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.
+
+make_canonical () {
+    cd $1; pwd;
+}
+
+SCRIPTDIR=`dirname $0`
+BUILDDIR=`make_canonical $SCRIPTDIR/../../../../../build/contrib/loggraph`
+LIBDIR=`make_canonical $BUILDDIR/lib`
+WEBDIR=`make_canonical $SCRIPTDIR/../web`
+ZKDIR=`make_canonical $SCRIPTDIR/../../../../../build/`
+
+if [ ! -x $BUILDDIR ]; then
+    echo "\n\n*** You need to build loggraph before running it ***\n\n";
+    exit;
+fi
+
+for i in `ls $LIBDIR`; do 
+    CLASSPATH=$LIBDIR/$i:$CLASSPATH
+done
+
+for i in $ZKDIR/zookeeper-*.jar; do
+    CLASSPATH="$i:$CLASSPATH"
+done
+
+CLASSPATH=$BUILDDIR/classes:$WEBDIR:$CLASSPATH
+echo $CLASSPATH
+java -Dlog4j.configuration=org/apache/zookeeper/graph/log4j.properties -Xdebug -Xrunjdwp:transport=dt_socket,address=4444,server=y,suspend=n -cp $CLASSPATH org.apache.zookeeper.graph.LogServer $*

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph.sh
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph.sh b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph.sh
new file mode 100755
index 0000000..0259dc6
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/resources/loggraph.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+# 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.
+
+make_canonical () {
+    cd $1; pwd;
+}
+
+SCRIPTDIR=`dirname $0`
+BUILDDIR=`make_canonical $SCRIPTDIR/../../../../../build/contrib/loggraph`
+LIBDIR=`make_canonical $BUILDDIR/lib`
+ZKDIR=`make_canonical $SCRIPTDIR/../../../../../build/`
+
+if [ ! -x $BUILDDIR ]; then
+    echo "\n\n*** You need to build loggraph before running it ***\n\n";
+    exit;
+fi
+
+for i in `ls $LIBDIR`; do 
+    CLASSPATH=$LIBDIR/$i:$CLASSPATH
+done
+
+for i in `ls $BUILDDIR/*.jar`; do 
+    CLASSPATH=$i:$CLASSPATH
+done
+
+for i in $ZKDIR/zookeeper-*.jar; do
+    CLASSPATH="$i:$CLASSPATH"
+done
+
+java -cp $CLASSPATH org.apache.zookeeper.graph.LogServer $*
+
+
+
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/log4j.properties
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/log4j.properties b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/log4j.properties
new file mode 100644
index 0000000..ab8960b
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/log4j.properties
@@ -0,0 +1,11 @@
+log4j.rootLogger=TRACE, CONSOLE
+
+# Print the date in ISO 8601 format
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.Threshold=TRACE
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n
+
+log4j.logger.org.apache.zookeeper.graph.LogSkipList=off
+log4j.logger.org.apache.zookeeper.graph.RandomAccessFileReader=off
+#log4j.logger.org.apache.zookeeper.graph.Log4JSource=off
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/date.format.js
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/date.format.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/date.format.js
new file mode 100644
index 0000000..5515009
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/date.format.js
@@ -0,0 +1,126 @@
+/*
+ * Date Format 1.2.3
+ * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
+ * MIT license
+ *
+ * Includes enhancements by Scott Trenda <scott.trenda.net>
+ * and Kris Kowal <cixar.com/~kris.kowal/>
+ *
+ * Accepts a date, a mask, or a date and a mask.
+ * Returns a formatted version of the given date.
+ * The date defaults to the current date/time.
+ * The mask defaults to dateFormat.masks.default.
+ */
+
+var dateFormat = function () {
+	var	token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+		timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+		timezoneClip = /[^-+\dA-Z]/g,
+		pad = function (val, len) {
+			val = String(val);
+			len = len || 2;
+			while (val.length < len) val = "0" + val;
+			return val;
+		};
+
+	// Regexes and supporting functions are cached through closure
+	return function (date, mask, utc) {
+		var dF = dateFormat;
+
+		// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+		if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
+			mask = date;
+			date = undefined;
+		}
+
+		// Passing date through Date applies Date.parse, if necessary
+		date = date ? new Date(date) : new Date;
+		if (isNaN(date)) throw SyntaxError("invalid date");
+
+		mask = String(dF.masks[mask] || mask || dF.masks["default"]);
+
+		// Allow setting the utc argument via the mask
+		if (mask.slice(0, 4) == "UTC:") {
+			mask = mask.slice(4);
+			utc = true;
+		}
+
+		var	_ = utc ? "getUTC" : "get",
+			d = date[_ + "Date"](),
+			D = date[_ + "Day"](),
+			m = date[_ + "Month"](),
+			y = date[_ + "FullYear"](),
+			H = date[_ + "Hours"](),
+			M = date[_ + "Minutes"](),
+			s = date[_ + "Seconds"](),
+			L = date[_ + "Milliseconds"](),
+			o = utc ? 0 : date.getTimezoneOffset(),
+			flags = {
+				d:    d,
+				dd:   pad(d),
+				ddd:  dF.i18n.dayNames[D],
+				dddd: dF.i18n.dayNames[D + 7],
+				m:    m + 1,
+				mm:   pad(m + 1),
+				mmm:  dF.i18n.monthNames[m],
+				mmmm: dF.i18n.monthNames[m + 12],
+				yy:   String(y).slice(2),
+				yyyy: y,
+				h:    H % 12 || 12,
+				hh:   pad(H % 12 || 12),
+				H:    H,
+				HH:   pad(H),
+				M:    M,
+				MM:   pad(M),
+				s:    s,
+				ss:   pad(s),
+				l:    pad(L, 3),
+				L:    pad(L > 99 ? Math.round(L / 10) : L),
+				t:    H < 12 ? "a"  : "p",
+				tt:   H < 12 ? "am" : "pm",
+				T:    H < 12 ? "A"  : "P",
+				TT:   H < 12 ? "AM" : "PM",
+				Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+				o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+				S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+			};
+
+		return mask.replace(token, function ($0) {
+			return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+		});
+	};
+}();
+
+// Some common format strings
+dateFormat.masks = {
+	"default":      "ddd mmm dd yyyy HH:MM:ss",
+	shortDate:      "m/d/yy",
+	mediumDate:     "mmm d, yyyy",
+	longDate:       "mmmm d, yyyy",
+	fullDate:       "dddd, mmmm d, yyyy",
+	shortTime:      "h:MM TT",
+	mediumTime:     "h:MM:ss TT",
+	longTime:       "h:MM:ss TT Z",
+	isoDate:        "yyyy-mm-dd",
+	isoTime:        "HH:MM:ss",
+	isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",
+	isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+};
+
+// Internationalization strings
+dateFormat.i18n = {
+	dayNames: [
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+	],
+	monthNames: [
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+		"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+	]
+};
+
+// For convenience...
+Date.prototype.format = function (mask, utc) {
+	return dateFormat(this, mask, utc);
+};
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.bar.js
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.bar.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.bar.js
new file mode 100644
index 0000000..2f7212a
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.bar.js
@@ -0,0 +1,385 @@
+/*
+ * 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.barchart = function (x, y, width, height, values, opts) {
+    opts = opts || {};
+    var type = {round: "round", sharp: "sharp", soft: "soft"}[opts.type] || "square",
+        gutter = parseFloat(opts.gutter || "20%"),
+        chart = this.set(),
+        bars = this.set(),
+        covers = this.set(),
+        covers2 = this.set(),
+        total = Math.max.apply(Math, values),
+        stacktotal = [],
+        paper = this,
+        multi = 0,
+        colors = opts.colors || this.g.colors,
+        len = values.length;
+    if (this.raphael.is(values[0], "array")) {
+        total = [];
+        multi = len;
+        len = 0;
+        for (var i = values.length; i--;) {
+            bars.push(this.set());
+            total.push(Math.max.apply(Math, values[i]));
+            len = Math.max(len, values[i].length);
+        }
+        if (opts.stacked) {
+            for (var i = len; i--;) {
+                var tot = 0;
+                for (var j = values.length; j--;) {
+                    tot +=+ values[j][i] || 0;
+                }
+                stacktotal.push(tot);
+            }
+        }
+        for (var i = values.length; i--;) {
+            if (values[i].length < len) {
+                for (var j = len; j--;) {
+                    values[i].push(0);
+                }
+            }
+        }
+        total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
+    }
+    
+    total = (opts.to) || total;
+    var barwidth = width / (len * (100 + gutter) + gutter) * 100,
+        barhgutter = barwidth * gutter / 100,
+        barvgutter = opts.vgutter == null ? 20 : opts.vgutter,
+        stack = [],
+        X = x + barhgutter,
+        Y = (height - 2 * barvgutter) / total;
+    if (!opts.stretch) {
+        barhgutter = Math.round(barhgutter);
+        barwidth = Math.floor(barwidth);
+    }
+    !opts.stacked && (barwidth /= multi || 1);
+    for (var i = 0; i < len; i++) {
+        stack = [];
+        for (var j = 0; j < (multi || 1); j++) {
+            var h = Math.round((multi ? values[j][i] : values[i]) * Y),
+                top = y + height - barvgutter - h,
+                bar = this.g.finger(Math.round(X + barwidth / 2), top + h, barwidth, h, true, type).attr({stroke: colors[multi ? j : i], fill: colors[multi ? j : i]});
+            if (multi) {
+                bars[j].push(bar);
+            } else {
+                bars.push(bar);
+            }
+            bar.y = top;
+            bar.x = Math.round(X + barwidth / 2);
+            bar.w = barwidth;
+            bar.h = h;
+            bar.value = multi ? values[j][i] : values[i];
+            if (!opts.stacked) {
+                X += barwidth;
+            } else {
+                stack.push(bar);
+            }
+        }
+        if (opts.stacked) {
+            var cvr;
+            covers2.push(cvr = this.rect(stack[0].x - stack[0].w / 2, y, barwidth, height).attr(this.g.shim));
+            cvr.bars = this.set();
+            var size = 0;
+            for (var s = stack.length; s--;) {
+                stack[s].toFront();
+            }
+            for (var s = 0, ss = stack.length; s < ss; s++) {
+                var bar = stack[s],
+                    cover,
+                    h = (size + bar.value) * Y,
+                    path = this.g.finger(bar.x, y + height - barvgutter - !!size * .5, barwidth, h, true, type, 1);
+                cvr.bars.push(bar);
+                size && bar.attr({path: path});
+                bar.h = h;
+                bar.y = y + height - barvgutter - !!size * .5 - h;
+                covers.push(cover = this.rect(bar.x - bar.w / 2, bar.y, barwidth, bar.value * Y).attr(this.g.shim));
+                cover.bar = bar;
+                cover.value = bar.value;
+                size += bar.value;
+            }
+            X += barwidth;
+        }
+        X += barhgutter;
+    }
+    covers2.toFront();
+    X = x + barhgutter;
+    if (!opts.stacked) {
+        for (var i = 0; i < len; i++) {
+            for (var j = 0; j < (multi || 1); j++) {
+                var cover;
+                covers.push(cover = this.rect(Math.round(X), y + barvgutter, barwidth, height - barvgutter).attr(this.g.shim));
+                cover.bar = multi ? bars[j][i] : bars[i];
+                cover.value = cover.bar.value;
+                X += barwidth;
+            }
+            X += barhgutter;
+        }
+    }
+    chart.label = function (labels, isBottom) {
+        labels = labels || [];
+        this.labels = paper.set();
+        var L, l = -Infinity;
+        if (opts.stacked) {
+            for (var i = 0; i < len; i++) {
+                var tot = 0;
+                for (var j = 0; j < (multi || 1); j++) {
+                    tot += multi ? values[j][i] : values[i];
+                    if (j == multi - 1) {
+                        var label = paper.g.labelise(labels[i], tot, total);
+                        L = paper.g.text(bars[i * (multi || 1) + j].x, y + height - barvgutter / 2, label).insertBefore(covers[i * (multi || 1) + j]);
+                        var bb = L.getBBox();
+                        if (bb.x - 7 < l) {
+                            L.remove();
+                        } else {
+                            this.labels.push(L);
+                            l = bb.x + bb.width;
+                        }
+                    }
+                }
+            }
+        } else {
+            for (var i = 0; i < len; i++) {
+                for (var j = 0; j < (multi || 1); j++) {
+                    var label = paper.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total);
+                    L = paper.g.text(bars[i * (multi || 1) + j].x, isBottom ? y + height - barvgutter / 2 : bars[i * (multi || 1) + j].y - 10, label).insertBefore(covers[i * (multi || 1) + j]);
+                    var bb = L.getBBox();
+                    if (bb.x - 7 < l) {
+                        L.remove();
+                    } else {
+                        this.labels.push(L);
+                        l = bb.x + bb.width;
+                    }
+                }
+            }
+        }
+        return this;
+    };
+    chart.hover = function (fin, fout) {
+        covers2.hide();
+        covers.show();
+        covers.mouseover(fin).mouseout(fout);
+        return this;
+    };
+    chart.hoverColumn = function (fin, fout) {
+        covers.hide();
+        covers2.show();
+        fout = fout || function () {};
+        covers2.mouseover(fin).mouseout(fout);
+        return this;
+    };
+    chart.click = function (f) {
+        covers2.hide();
+        covers.show();
+        covers.click(f);
+        return this;
+    };
+    chart.each = function (f) {
+        if (!Raphael.is(f, "function")) {
+            return this;
+        }
+        for (var i = covers.length; i--;) {
+            f.call(covers[i]);
+        }
+        return this;
+    };
+    chart.eachColumn = function (f) {
+        if (!Raphael.is(f, "function")) {
+            return this;
+        }
+        for (var i = covers2.length; i--;) {
+            f.call(covers2[i]);
+        }
+        return this;
+    };
+    chart.clickColumn = function (f) {
+        covers.hide();
+        covers2.show();
+        covers2.click(f);
+        return this;
+    };
+    chart.push(bars, covers, covers2);
+    chart.bars = bars;
+    chart.covers = covers;
+    return chart;
+};
+Raphael.fn.g.hbarchart = function (x, y, width, height, values, opts) {
+    opts = opts || {};
+    var type = {round: "round", sharp: "sharp", soft: "soft"}[opts.type] || "square",
+        gutter = parseFloat(opts.gutter || "20%"),
+        chart = this.set(),
+        bars = this.set(),
+        covers = this.set(),
+        covers2 = this.set(),
+        total = Math.max.apply(Math, values),
+        stacktotal = [],
+        paper = this,
+        multi = 0,
+        colors = opts.colors || this.g.colors,
+        len = values.length;
+    if (this.raphael.is(values[0], "array")) {
+        total = [];
+        multi = len;
+        len = 0;
+        for (var i = values.length; i--;) {
+            bars.push(this.set());
+            total.push(Math.max.apply(Math, values[i]));
+            len = Math.max(len, values[i].length);
+        }
+        if (opts.stacked) {
+            for (var i = len; i--;) {
+                var tot = 0;
+                for (var j = values.length; j--;) {
+                    tot +=+ values[j][i] || 0;
+                }
+                stacktotal.push(tot);
+            }
+        }
+        for (var i = values.length; i--;) {
+            if (values[i].length < len) {
+                for (var j = len; j--;) {
+                    values[i].push(0);
+                }
+            }
+        }
+        total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
+    }
+    
+    total = (opts.to) || total;
+    var barheight = Math.floor(height / (len * (100 + gutter) + gutter) * 100),
+        bargutter = Math.floor(barheight * gutter / 100),
+        stack = [],
+        Y = y + bargutter,
+        X = (width - 1) / total;
+    !opts.stacked && (barheight /= multi || 1);
+    for (var i = 0; i < len; i++) {
+        stack = [];
+        for (var j = 0; j < (multi || 1); j++) {
+            var val = multi ? values[j][i] : values[i],
+                bar = this.g.finger(x, Y + barheight / 2, Math.round(val * X), barheight - 1, false, type).attr({stroke: colors[multi ? j : i], fill: colors[multi ? j : i]});
+            if (multi) {
+                bars[j].push(bar);
+            } else {
+                bars.push(bar);
+            }
+            bar.x = x + Math.round(val * X);
+            bar.y = Y + barheight / 2;
+            bar.w = Math.round(val * X);
+            bar.h = barheight;
+            bar.value = +val;
+            if (!opts.stacked) {
+                Y += barheight;
+            } else {
+                stack.push(bar);
+            }
+        }
+        if (opts.stacked) {
+            var cvr = this.rect(x, stack[0].y - stack[0].h / 2, width, barheight).attr(this.g.shim);
+            covers2.push(cvr);
+            cvr.bars = this.set();
+            var size = 0;
+            for (var s = stack.length; s--;) {
+                stack[s].toFront();
+            }
+            for (var s = 0, ss = stack.length; s < ss; s++) {
+                var bar = stack[s],
+                    cover,
+                    val = Math.round((size + bar.value) * X),
+                    path = this.g.finger(x, bar.y, val, barheight - 1, false, type, 1);
+                cvr.bars.push(bar);
+                size && bar.attr({path: path});
+                bar.w = val;
+                bar.x = x + val;
+                covers.push(cover = this.rect(x + size * X, bar.y - bar.h / 2, bar.value * X, barheight).attr(this.g.shim));
+                cover.bar = bar;
+                size += bar.value;
+            }
+            Y += barheight;
+        }
+        Y += bargutter;
+    }
+    covers2.toFront();
+    Y = y + bargutter;
+    if (!opts.stacked) {
+        for (var i = 0; i < len; i++) {
+            for (var j = 0; j < multi; j++) {
+                var cover = this.rect(x, Y, width, barheight).attr(this.g.shim);
+                covers.push(cover);
+                cover.bar = bars[j][i];
+                Y += barheight;
+            }
+            Y += bargutter;
+        }
+    }
+    chart.label = function (labels, isRight) {
+        labels = labels || [];
+        this.labels = paper.set();
+        for (var i = 0; i < len; i++) {
+            for (var j = 0; j < multi; j++) {
+                var  label = paper.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total);
+                var X = isRight ? bars[i * (multi || 1) + j].x - barheight / 2 + 3 : x + 5,
+                    A = isRight ? "end" : "start",
+                    L;
+                this.labels.push(L = paper.g.text(X, bars[i * (multi || 1) + j].y, label).attr({"text-anchor": A}).insertBefore(covers[0]));
+                if (L.getBBox().x < x + 5) {
+                    L.attr({x: x + 5, "text-anchor": "start"});
+                } else {
+                    bars[i * (multi || 1) + j].label = L;
+                }
+            }
+        }
+        return this;
+    };
+    chart.hover = function (fin, fout) {
+        covers2.hide();
+        covers.show();
+        fout = fout || function () {};
+        covers.mouseover(fin).mouseout(fout);
+        return this;
+    };
+    chart.hoverColumn = function (fin, fout) {
+        covers.hide();
+        covers2.show();
+        fout = fout || function () {};
+        covers2.mouseover(fin).mouseout(fout);
+        return this;
+    };
+    chart.each = function (f) {
+        if (!Raphael.is(f, "function")) {
+            return this;
+        }
+        for (var i = covers.length; i--;) {
+            f.call(covers[i]);
+        }
+        return this;
+    };
+    chart.eachColumn = function (f) {
+        if (!Raphael.is(f, "function")) {
+            return this;
+        }
+        for (var i = covers2.length; i--;) {
+            f.call(covers2[i]);
+        }
+        return this;
+    };
+    chart.click = function (f) {
+        covers2.hide();
+        covers.show();
+        covers.click(f);
+        return this;
+    };
+    chart.clickColumn = function (f) {
+        covers.hide();
+        covers2.show();
+        covers2.click(f);
+        return this;
+    };
+    chart.push(bars, covers, covers2);
+    chart.bars = bars;
+    chart.covers = covers;
+    return chart;
+};

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.dot.js
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.dot.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.dot.js
new file mode 100644
index 0000000..2821e62
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.dot.js
@@ -0,0 +1,110 @@
+/*
+ * 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.dotchart = function (x, y, width, height, valuesx, valuesy, size, opts) {
+    function drawAxis(ax) {
+        +ax[0] && (ax[0] = paper.g.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2, opts.axisxlabels || null, opts.axisxtype || "t"));
+        +ax[1] && (ax[1] = paper.g.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3, opts.axisylabels || null, opts.axisytype || "t"));
+        +ax[2] && (ax[2] = paper.g.axis(x + gutter, y + height - gutter + maxR, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0, opts.axisxlabels || null, opts.axisxtype || "t"));
+        +ax[3] && (ax[3] = paper.g.axis(x + gutter - maxR, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1, opts.axisylabels || null, opts.axisytype || "t"));
+    }
+    opts = opts || {};
+    var xdim = this.g.snapEnds(Math.min.apply(Math, valuesx), Math.max.apply(Math, valuesx), valuesx.length - 1),
+        minx = xdim.from,
+        maxx = xdim.to,
+        gutter = opts.gutter || 10,
+        ydim = this.g.snapEnds(Math.min.apply(Math, valuesy), Math.max.apply(Math, valuesy), valuesy.length - 1),
+        miny = ydim.from,
+        maxy = ydim.to,
+        len = Math.max(valuesx.length, valuesy.length, size.length),
+        symbol = this.g.markers[opts.symbol] || "disc",
+        res = this.set(),
+        series = this.set(),
+        max = opts.max || 100,
+        top = Math.max.apply(Math, size),
+        R = [],
+        paper = this,
+        k = Math.sqrt(top / Math.PI) * 2 / max;
+
+    for (var i = 0; i < len; i++) {
+        R[i] = Math.min(Math.sqrt(size[i] / Math.PI) * 2 / k, max);
+    }
+    gutter = Math.max.apply(Math, R.concat(gutter));
+    var axis = this.set(),
+        maxR = Math.max.apply(Math, R);
+    if (opts.axis) {
+        var ax = (opts.axis + "").split(/[,\s]+/);
+        drawAxis(ax);
+        var g = [], b = [];
+        for (var i = 0, ii = ax.length; i < ii; i++) {
+            var bb = ax[i].all ? ax[i].all.getBBox()[["height", "width"][i % 2]] : 0;
+            g[i] = bb + gutter;
+            b[i] = bb;
+        }
+        gutter = Math.max.apply(Math, g.concat(gutter));
+        for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {
+            ax[i].remove();
+            ax[i] = 1;
+        }
+        drawAxis(ax);
+        for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {
+            axis.push(ax[i].all);
+        }
+        res.axis = axis;
+    }
+    var kx = (width - gutter * 2) / ((maxx - minx) || 1),
+        ky = (height - gutter * 2) / ((maxy - miny) || 1);
+    for (var i = 0, ii = valuesy.length; i < ii; i++) {
+        var sym = this.raphael.is(symbol, "array") ? symbol[i] : symbol,
+            X = x + gutter + (valuesx[i] - minx) * kx,
+            Y = y + height - gutter - (valuesy[i] - miny) * ky;
+        sym && R[i] && series.push(this.g[sym](X, Y, R[i]).attr({fill: opts.heat ? this.g.colorValue(R[i], maxR) : Raphael.fn.g.colors[0], "fill-opacity": opts.opacity ? R[i] / max : 1, stroke: "none"}));
+    }
+    var covers = this.set();
+    for (var i = 0, ii = valuesy.length; i < ii; i++) {
+        var X = x + gutter + (valuesx[i] - minx) * kx,
+            Y = y + height - gutter - (valuesy[i] - miny) * ky;
+        covers.push(this.circle(X, Y, maxR).attr(this.g.shim));
+        opts.href && opts.href[i] && covers[i].attr({href: opts.href[i]});
+        covers[i].r = +R[i].toFixed(3);
+        covers[i].x = +X.toFixed(3);
+        covers[i].y = +Y.toFixed(3);
+        covers[i].X = valuesx[i];
+        covers[i].Y = valuesy[i];
+        covers[i].value = size[i] || 0;
+        covers[i].dot = series[i];
+    }
+    res.covers = covers;
+    res.series = series;
+    res.push(series, axis, covers);
+    res.hover = function (fin, fout) {
+        covers.mouseover(fin).mouseout(fout);
+        return this;
+    };
+    res.click = function (f) {
+        covers.click(f);
+        return this;
+    };
+    res.each = function (f) {
+        if (!Raphael.is(f, "function")) {
+            return this;
+        }
+        for (var i = covers.length; i--;) {
+            f.call(covers[i]);
+        }
+        return this;
+    };
+    res.href = function (map) {
+        var cover;
+        for (var i = covers.length; i--;) {
+            cover = covers[i];
+            if (cover.X == map.x && cover.Y == map.y && cover.value == map.value) {
+                cover.attr({href: map.href});
+            }
+        }
+    };
+    return res;
+};

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.line.js
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.line.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.line.js
new file mode 100644
index 0000000..eb56e59
--- /dev/null
+++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.line.js
@@ -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;
+};


Mime
View raw message