labs-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r477728 [1/2] - in /labs/agora: ./ src/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/agora/ src/java/org/apache/agora/resources/ src/java/org/apache/agora/resources/icons/ src/python/ src/site/ src/site/images/ src/site/...
Date Tue, 21 Nov 2006 16:20:15 GMT
Author: stefano
Date: Tue Nov 21 08:20:13 2006
New Revision: 477728

URL: http://svn.apache.org/viewvc?view=rev&rev=477728
Log:
adding agora

Added:
    labs/agora/
    labs/agora/LICENSE.txt   (with props)
    labs/agora/README.txt   (with props)
    labs/agora/build.xml
    labs/agora/changes.xml
    labs/agora/default.properties
    labs/agora/doap.rdf
    labs/agora/src/
    labs/agora/src/java/
    labs/agora/src/java/MANIFEST.MF
    labs/agora/src/java/org/
    labs/agora/src/java/org/apache/
    labs/agora/src/java/org/apache/agora/
    labs/agora/src/java/org/apache/agora/Agora.java   (with props)
    labs/agora/src/java/org/apache/agora/DataTree.java   (with props)
    labs/agora/src/java/org/apache/agora/Graph.java   (with props)
    labs/agora/src/java/org/apache/agora/GraphVisualizer.java   (with props)
    labs/agora/src/java/org/apache/agora/MessageEvaluator.java   (with props)
    labs/agora/src/java/org/apache/agora/MessageGraph.java   (with props)
    labs/agora/src/java/org/apache/agora/resources/
    labs/agora/src/java/org/apache/agora/resources/icons/
    labs/agora/src/java/org/apache/agora/resources/icons/file.gif   (with props)
    labs/agora/src/java/org/apache/agora/resources/icons/logo-small.gif   (with props)
    labs/agora/src/java/org/apache/agora/resources/icons/logo.gif   (with props)
    labs/agora/src/java/org/apache/agora/resources/icons/selected.gif   (with props)
    labs/agora/src/java/org/apache/agora/resources/icons/start.gif   (with props)
    labs/agora/src/java/org/apache/agora/resources/icons/stop.gif   (with props)
    labs/agora/src/python/
    labs/agora/src/python/process.py   (with props)
    labs/agora/src/site/
    labs/agora/src/site/guide.html   (with props)
    labs/agora/src/site/images/
    labs/agora/src/site/images/agora-logo.gif   (with props)
    labs/agora/src/site/images/attraction.gif   (with props)
    labs/agora/src/site/images/community-logo.gif   (with props)
    labs/agora/src/site/images/drag.gif   (with props)
    labs/agora/src/site/images/fixed.gif   (with props)
    labs/agora/src/site/images/highlight.gif   (with props)
    labs/agora/src/site/images/multiple.gif   (with props)
    labs/agora/src/site/images/repulsion.gif   (with props)
    labs/agora/src/site/images/single.gif   (with props)
    labs/agora/src/site/images/snapshot.gif   (with props)
    labs/agora/src/site/images/src/
    labs/agora/src/site/images/src/logo.psd   (with props)
    labs/agora/src/site/images/zoom.gif   (with props)
    labs/agora/src/site/index.html   (with props)
    labs/agora/src/site/styles/
    labs/agora/src/site/styles/style.css   (with props)

Added: labs/agora/LICENSE.txt
URL: http://svn.apache.org/viewvc/labs/agora/LICENSE.txt?view=auto&rev=477728
==============================================================================
--- labs/agora/LICENSE.txt (added)
+++ labs/agora/LICENSE.txt Tue Nov 21 08:20:13 2006
@@ -0,0 +1,50 @@
+
+ ============================================================================
+                   The Apache Software License, Version 1.1
+ ============================================================================
+ 
+ Copyright (C) 2002-2003 The Apache Software Foundation. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+ 
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+    this list of conditions and the following disclaimer.
+ 
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+ 
+ 3. The end-user documentation included with the redistribution, if any, must
+    include  the following  acknowledgment:  "This product includes  software
+    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+    Alternately, this  acknowledgment may  appear in the software itself,  if
+    and wherever such third-party acknowledgments normally appear.
+ 
+ 4. The names "Apache", "Agora" and  "Apache Software Foundation" must not be
+    used to  endorse or promote  products derived from  this software without
+    prior written permission. For written permission, please contact
+    apache@apache.org.
+ 
+ 5. Products  derived from this software may not  be called "Apache", nor may
+    "Apache" appear  in their name,  without prior written permission  of the
+    Apache Software Foundation.
+ 
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+                                   - o -
+
+ This software consists of voluntary contributions made on behalf of the 
+ Apache Software Foundation and was originally created by Stefano Mazzocchi 
+ <stefano at apache.org>.  For more  information on the Apache Software 
+ Foundation, please see <http://www.apache.org/>.
+ 

Propchange: labs/agora/LICENSE.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/README.txt
URL: http://svn.apache.org/viewvc/labs/agora/README.txt?view=auto&rev=477728
==============================================================================
--- labs/agora/README.txt (added)
+++ labs/agora/README.txt Tue Nov 21 08:20:13 2006
@@ -0,0 +1,89 @@
+
+                        A p a c h e    A g o r a
+                        ------------------------
+
+               by Stefano Mazzocchi <stefano at apache.org>
+
+
+ What is this?
+ -------------
+ 
+Agora is a virtual community visualizer. The idea is to be able to visualize 
+virtual communities in order to provide insights into their composition, 
+properties and evolution in time.
+
+
+ Why was it created?
+ -------------------
+ 
+Mainly bacause of personal curiosity: I wanted to see if a simple
+mathematical model of human behavior applied to virtual communities would
+yield results that matched the general perception that the community
+participants share in their minds. Since it gave impressive results with
+the communities I'm familiar with, I decided to make it available to others
+to understand if the results were due to my personal bias or reflected
+a wider audience.
+
+
+ What comes in the box?
+ ----------------------
+
+Agora is composed of two parts:
+
+ - the script that processes MBOX files
+ 
+ - the application that allows you to select the mailboxes, 
+   generate the network and visualize it.
+ 
+The visualizer can be run as a standalone graphical application or as an
+applet in a browser. It's up to you to choose which one you like the most. 
+
+NOTE: you'll need a Java 1.2+ compatible virtual machine for Agora, both
+if you run it as an applet, or as an application. If you don't have it
+installed or your browser doesn't support that, go to 
+http://java.sun.com/ and download the Java Plugin.
+
+
+ how do I try it?
+ ----------------
+
+Type
+
+ java -jar agora.jar http://people.apache.org/~stefano/agora/data/archives.dat
+
+to visualize the Apache communities (that file is kept up to date with
+our mail archives)
+      
+NOTE: you must have the 'java' interepreter (1.2 or above) available in your 
+PATH for this to work.
+
+
+ how do I process my own messages?
+ ---------------------------------
+
+The script that comes with Agora is only able to read uncompressed MBOX files.
+Prepare a collection of the MBOX files that you want to visualize in a directory, 
+then type:
+
+ python process.py -m /path/to/mailboxes
+
+this script will crawl all the mailboxes contained in that path and generate the
+according preprocessed information in the local ./data folder.
+
+WARNING: the scripts will recursively process all mbox files even in subfolders. 
+the same structure and folder names will be used in the visualizer.
+
+NOTE: you must have the 'python' (2.3 or above) interpreer available in your 
+Path for this to work.
+
+When you are done, type
+
+ java -jar agora.jar data/archives.dat
+
+to visualize your communities.
+      
+      
+                                   - o -
+
+
+Thanks for your interest in Apache Agora.

Propchange: labs/agora/README.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/build.xml
URL: http://svn.apache.org/viewvc/labs/agora/build.xml?view=auto&rev=477728
==============================================================================
--- labs/agora/build.xml (added)
+++ labs/agora/build.xml Tue Nov 21 08:20:13 2006
@@ -0,0 +1,215 @@
+<!--+
+    | Apache Agora build file
+    +-->
+
+<project name="Apache Agora" default="jar" basedir=".">
+
+    <property file="${user.home}/build.properties"/>
+    <property file="${user.home}/.ant.properties"/>
+    <property file="./default.properties"/>
+
+    <path id="project.class.path">
+        <pathelement location="${build}/classes"/>
+        <pathelement path="${java.class.path}"/>
+    </path>
+
+    <!--+
+        | Initializes the build
+        +-->
+    <target name="init">
+        <filter token="name" value="${name}"/>
+        <filter token="year" value="${year}"/>
+        <filter token="version" value="${version}"/>
+        <filter token="dataURL" value="${site.dataURL}"/>
+    </target>
+    
+    <!--+
+        | Compiles the source code 
+        +-->
+    <target name="compile" depends="init" description="Compiles the source code">
+
+        <mkdir dir="${build}/classes"/>
+        <mkdir dir="${build}/src"/>
+
+        <copy todir="${build}/src" filtering="on">
+          <fileset dir="${src}/java">
+            <include name="**/*.java"/>
+          </fileset>
+        </copy>
+        
+        <javac srcdir="${build}/src"
+            destdir="${build}/classes"
+            debug="${build.debug}"
+            optimize="${build.optimize}"
+            deprecation="${build.deprecation}"
+            target="1.2">
+            <classpath refid="project.class.path" />
+            <include name="**/*.java"/>
+        </javac>
+
+        <copy todir="${build}/classes" filtering="off">
+            <fileset dir="${src}/java">
+                <exclude name="**/*.java"/>
+                <exclude name="**/package.html"/>
+            </fileset>
+        </copy>
+    </target>
+
+    <!--+
+        | Copies and filters the manifest and license.
+        +-->
+    <target name="prepare-conf" depends="init">
+        <mkdir dir="${build}/conf"/>
+        <copy todir="${build}/conf" flatten="true" filtering="on">
+            <fileset dir="." includes="LICENSE.txt"/>
+            <fileset dir="${src}/java" includes="MANIFEST.MF"/>
+        </copy>
+    </target>
+    
+    <!--+
+        | Creates the jar archive
+        +-->
+    <target name="jar" depends="prepare-conf, compile" description="Generates the jar">
+        <jar jarfile="${build}/${jar.name}"
+             basedir="${build}/classes"
+             compress="${build.compress}"
+             manifest="${build}/conf/MANIFEST.MF"
+        />
+    </target>
+
+    <!--+
+        | Generates the javadocs
+        +-->
+    <target name="javadoc" depends="compile" description="Generates the javadocs">
+
+        <mkdir dir="${build}/javadocs"/>
+        <javadoc packagenames="org.apache.*"
+            sourcepath="${src}/java"
+            destdir="${build}/javadocs">
+            <classpath refid="project.class.path" />
+            <doclet name="com.sun.tools.doclets.standard.Standard">
+                <param name="-author"/>
+                <param name="-version"/>
+                <param name="-doctitle" value="${Name}"/>
+                <param name="-windowtitle" value="${Name} API"/>
+                <param name="-link" value="http://java.sun.com/j2se/1.4.2/docs/api/"/>
+                <param name="-bottom" value="&quot;Copyright &#169; ${year} Apache Software Foundation. All Rights Reserved.&quot;"/>
+            </doclet>
+        </javadoc>
+    </target>
+
+    <!--+
+        | Prepares the distribution files
+        +-->
+    <target name="prepare-dist" depends="jar,javadoc" description="Prepares the distribution">
+
+        <copy todir="${dist}" filtering="on">
+            <fileset dir=".">
+                <include name="*.txt"/>
+                <include name="*.xml"/>
+                <include name="*.properties"/>
+            </fileset>
+        </copy>
+        
+        <copy file="${build}/${jar.name}" toFile="${dist}/${jar.name}" filtering="off"/>
+
+        <copy todir="${dist}" filtering="on">
+            <fileset dir="${src}/python">
+                <exclude name="**/*.pyc"/>
+            </fileset>
+        </copy>
+    
+        <copy todir="${dist}/src/java" filtering="on">
+            <fileset dir="${src}/java">
+                <exclude name="**/*.jpg"/>
+                <exclude name="**/*.gif"/>
+                <exclude name="**/*.png"/>
+            </fileset>
+        </copy>
+    
+        <copy todir="${dist}/src/java" filtering="off">
+            <fileset dir="${src}/java">
+                <include name="**/*.jpg"/>
+                <include name="**/*.gif"/>
+                <include name="**/*.png"/>
+            </fileset>
+        </copy>
+        
+        <copy todir="${dist}/docs" filtering="on">
+            <fileset dir="${src}/site">
+                <exclude name="**/*.jpg"/>
+                <exclude name="**/*.gif"/>
+                <exclude name="**/*.png"/>
+                <exclude name="index.html"/>
+            </fileset>
+        </copy>
+
+        <copy file="${src}/site/guide.html" tofile="${dist}/docs/index.html"/>
+
+        <copy todir="${dist}/docs" filtering="off">
+            <fileset dir="${src}/site">
+                <include name="**/*.jpg"/>
+                <include name="**/*.gif"/>
+                <include name="**/*.png"/>
+            </fileset>
+        </copy>
+
+        <copy todir="${dist}/docs/api" filtering="on">
+            <fileset dir="${build}/javadocs"/>
+        </copy>        
+
+    </target>
+
+    <!--+
+        | Creates the distribution archive
+        +-->
+    <target name="dist" depends="prepare-dist" description="Creates the distribution">
+        <zip zipfile="${name}-${version}.zip" basedir="${dist}"/>
+    </target>
+
+    <!--+
+        | Prepares the site
+        +-->
+    <target name="site" depends="dist" description="Prepares the web site">
+
+        
+        <copy todir="${site}" filtering="on">
+            <fileset dir="${src}/site">
+                <exclude name="**/*.jpg"/>
+                <exclude name="**/*.gif"/>
+                <exclude name="**/*.png"/>
+            </fileset>
+        </copy>
+
+        <copy file="${build}/${jar.name}" toFile="${site}/lib/${jar.name}" filtering="off"/>
+
+        <copy todir="${site}" filtering="off">
+            <fileset dir="${src}/site">
+                <include name="**/*.jpg"/>
+                <include name="**/*.gif"/>
+                <include name="**/*.png"/>
+            </fileset>
+        </copy>
+
+        <copy todir="${site}/api" filtering="on">
+            <fileset dir="${build}/javadocs"/>
+        </copy>        
+    
+        <copy file="${name}-${version}.zip" tofile="${site}/dist/${name}-${version}.zip"/>
+
+    </target>
+    
+    <!--+
+        | Cleans up
+        +-->
+    <target name="clean" description="Cleans up the project">
+        <delete dir="${site}"/>
+        <delete dir="${dist}"/>
+        <delete dir="${build}"/>
+        <delete>
+    		<fileset dir="." includes="*.zip"/>
+  		</delete> 
+    </target>
+
+</project>
+

Added: labs/agora/changes.xml
URL: http://svn.apache.org/viewvc/labs/agora/changes.xml?view=auto&rev=477728
==============================================================================
--- labs/agora/changes.xml (added)
+++ labs/agora/changes.xml Tue Nov 21 08:20:13 2006
@@ -0,0 +1,64 @@
+<!--+
+    |   History of changes
+    +-->
+
+<changes title="History of Changes">
+
+ <devs>
+  <!-- in strict alphabetical order -->
+  <person name="Stefano Mazzocchi" email="stefano@apache.org" id="SM"/>
+ </devs>
+
+ <release version="1.2" date="@date@">
+  <action dev="SM" type="change">
+   Moved to labs.apache.org.
+  </action>
+  <action dev="SM" type="add">
+   Added the ability to zoom into the graphs by right-clicking 
+   (or control-clicking for single-button mice) and show the labels
+   of the nodes closeby (they are drawn radially from the mouse
+   location to reduce label overlap).
+  </action>
+  <action dev="SM" type="change">
+   Moved the datacloud aggregation and processing into the application.
+   This allows a nicer usability of the tool so that users can create
+   dataclouds on the fly using preprocessed mailbox information
+   that can be published on the web.
+  </action>
+  <action dev="SM" type="add">
+   Added the ability to introduce time-based "link decay" which
+   simulates the fact that the importance of a reply decays with
+   time.
+  </action>
+  <action dev="SM" type="change">
+   Modified the mailbox processing scripts to produce message data
+   instead of dataclouds. Message data is fetched by the application
+   to produce the datacloud according to the selection of the processed
+   message archives that the user selects.
+  </action>
+  <action dev="SM" type="change">
+   Improved the overall prettyness of the drawing by extensive use of Java2D
+   functions like rounded rectangles and transparency. The overall drawing
+   performance has been reduced, but there is the ability to turn off part
+   of the drawing to improve performance.
+  </action>
+  <action dev="SM" type="add">
+   Introduction of a "grouping" capabilities that draws circles around the nodes
+   that participated in a particular community. This allows better identification
+   of the 'node clusters' which belong to different communities.
+  </action>
+ </release>
+ 
+ <release version="1.1" date="Jan 16, 2003">
+  <action dev="SM" type="add">
+    Changed the rendering system from dynamic SVG to java applet due to
+    severe performance limitations of the SVGViewer.
+  </action>
+ </release>
+
+ <release version="1.0" date="Dec 7, 2002">
+  <action dev="SM" type="add">
+    Initial code
+  </action>
+ </release>
+</changes>

Added: labs/agora/default.properties
URL: http://svn.apache.org/viewvc/labs/agora/default.properties?view=auto&rev=477728
==============================================================================
--- labs/agora/default.properties (added)
+++ labs/agora/default.properties Tue Nov 21 08:20:13 2006
@@ -0,0 +1,30 @@
+# -------------------------------------------------------------------
+# B U I L D  P R O P E R T I E S
+# -------------------------------------------------------------------
+# Specifies default property values
+# Overridden by ../default.properties and all ant.properties
+# Not user-editable; use ant.properties files instead
+
+# General Parameters ------------------------------------------------
+name=agora
+Name=Apache Agora
+version=1.2
+year=2002-2003
+
+# Locations ---------------------------------------------------
+src = src
+build = build
+dist = dist
+site = site
+
+# File Names --------------------------------------------------------
+jar.name = ${name}.jar
+
+# Build Settings -------------------------------------------------
+build.debug = off
+build.optimize = on
+build.deprecation = on
+build.compress = on
+
+# Site Settings ----------------------------------------------------
+site.dataURL = data/archives.dat
\ No newline at end of file

Added: labs/agora/doap.rdf
URL: http://svn.apache.org/viewvc/labs/agora/doap.rdf?view=auto&rev=477728
==============================================================================
--- labs/agora/doap.rdf (added)
+++ labs/agora/doap.rdf Tue Nov 21 08:20:13 2006
@@ -0,0 +1,22 @@
+<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns="http://usefulinc.com/ns/doap#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:admin="http://webns.net/mvcb/">
+ <name>Apache Agora</name>
+ <shortname>Agora</shortname>
+ <shortdesc>Virtual Community Visualizer</shortdesc>
+ <description>An application to mine and visualize mailing lists as virtual communities and visually understand their shape and behavior.</description>
+ <homepage rdf:resource="http://labs.apache.org/agora/"/>
+ <programming-language>java</programming-language>
+ <programming-language>python</programming-language>
+ <license rdf:resource="http://usefulinc.com/doap/licenses/asl20"/>
+ <maintainer>
+  <foaf:Person>
+     <foaf:name>Stefano Mazzocchi</foaf:name>
+     <foaf:homepage rdf:resource="http://people.apache.org/~stefano/"/>
+     <foaf:mbox_sha1sum>7342689cd4a32a1549b7c803fcbf8454b2c7b91b</foaf:mbox_sha1sum>
+  </foaf:Person>
+ </maintainer>
+ <repository>
+   <SVNRepository>
+     <location rdf:resource="http://svn.apache.org/repos/asf/labs/agora/"/>
+   </SVNRepository>
+ </repository> 
+</Project>
\ No newline at end of file

Added: labs/agora/src/java/MANIFEST.MF
URL: http://svn.apache.org/viewvc/labs/agora/src/java/MANIFEST.MF?view=auto&rev=477728
==============================================================================
--- labs/agora/src/java/MANIFEST.MF (added)
+++ labs/agora/src/java/MANIFEST.MF Tue Nov 21 08:20:13 2006
@@ -0,0 +1,4 @@
+Software-Name: agora
+Software-Owner: Apache Software Foundation
+Software-Version: 1.1
+Main-Class: org.apache.agora.Agora

Added: labs/agora/src/java/org/apache/agora/Agora.java
URL: http://svn.apache.org/viewvc/labs/agora/src/java/org/apache/agora/Agora.java?view=auto&rev=477728
==============================================================================
--- labs/agora/src/java/org/apache/agora/Agora.java (added)
+++ labs/agora/src/java/org/apache/agora/Agora.java Tue Nov 21 08:20:13 2006
@@ -0,0 +1,500 @@
+/* 
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+ 
+ Copyright (C) 2002-2003 The Apache Software Foundation. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+ 
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+ 
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+ 
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+ 
+ 4. The names "Apache", "Agora" and  "Apache Software Foundation" must not be
+	used to  endorse or promote  products derived from  this software without
+	prior written permission. For written permission, please contact
+	apache@apache.org.
+ 
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+ 
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+								   - o -
+
+ This software consists of voluntary contributions made on behalf of the 
+ Apache Software Foundation and was originally created by Stefano Mazzocchi 
+ <stefano at apache.org>.  For more  information on the Apache Software 
+ Foundation, please see <http://www.apache.org/>.
+ 
+*/
+
+package org.apache.agora;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JApplet;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextField;
+import javax.swing.UIManager;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;
+
+/**
+ * @author Stefano Mazzocchi <stefano@apache.org>
+ */
+public class Agora extends JApplet implements ActionListener, ItemListener {
+
+    public static final String NAME = "Apache Agora";
+	public static final String VERSION = "1.2";
+	
+	static final String ICON_PATH = "resources/icons/";
+	static final String LOGO_SMALL_ICON = ICON_PATH + "logo-small.gif"; 
+	static final String LOGO_ICON = ICON_PATH + "logo.gif"; 
+	static final String START_ICON = ICON_PATH + "start.gif"; 
+	static final String STOP_ICON = ICON_PATH + "stop.gif"; 
+	static final String UNSELECTED_ICON = ICON_PATH + "file.gif"; 
+	static final String SELECTED_ICON = ICON_PATH + "selected.gif"; 
+    
+    GraphVisualizer visualizer;
+    MessageGraph graph;
+    DataTree tree;
+
+    boolean running = false;
+    
+	JLabel delayLabel = new JLabel("Delay(ms)");
+	JLabel massLabel = new JLabel("Mass");
+	JLabel dragLabel = new JLabel("Drag");
+	JLabel attractionLabel = new JLabel("Attraction");
+	JLabel repulsionLabel = new JLabel("Repulsion");
+    
+    JButton dataLoadButton;
+    JButton dataClearButton;
+    
+    JButton controlButton;
+    JButton circleButton;
+    JButton scrambleButton;
+    JButton shakeButton;
+    JButton highlightButton;
+    JButton clearButton;
+
+    JCheckBox randomCheckbox;
+    JCheckBox antialiasCheckbox;
+    JCheckBox nodesCheckbox;
+    JCheckBox edgesCheckbox;
+    JCheckBox edgeValuesCheckbox;
+    JCheckBox groupsCheckbox;
+    JCheckBox timeCheckbox;
+    JCheckBox backgroundCheckbox;
+    
+    JTextField delayField;
+    JTextField massField;
+    JTextField dragField;
+    JTextField attractionField;
+    JTextField repulsionField;
+    JTextField highlightField;
+
+	ImageIcon startIcon;
+	ImageIcon stopIcon;
+	ImageIcon logoIcon;
+
+    // called by the applet sandbox
+    public void init() {
+    	try {
+			String data = getParameter("data");
+			String base = getDocumentBase().toString();
+			URL dataURL = new URL(base.substring(0,base.lastIndexOf('/') + 1) + data);
+			initPanel(dataURL);
+		} catch (Exception e) {
+			System.out.println(e + " " + e.getMessage());
+		}
+    }
+    
+    // called manually by the command line frame
+    public void init(String data) {
+    	try {
+    		URL dataURL = null;
+			try {
+				dataURL = new URL(data);
+			} catch (MalformedURLException e) {
+    			dataURL = new File(data).toURL();
+			}
+			initPanel(dataURL);
+		} catch (Exception e) {
+			System.out.println(e + " " + e.getMessage());
+		}
+    }
+
+	class TreeListener implements TreeSelectionListener {
+		public void valueChanged(TreeSelectionEvent e) {
+			TreePath[] paths = (TreePath[]) e.getPaths();
+			for (int i = 0; i < paths.length; i++) {
+				if (e.isAddedPath(i)) {
+					tree.processPath(paths[i]);
+				}
+			}
+			visualizer.repaint();
+		}
+	}
+	            
+    public void initPanel(URL dataURL) throws IOException {
+ 
+ 		MessageEvaluator evaluator = new MessageEvaluator();
+		evaluator.setBorder(BorderFactory.createTitledBorder("Link Decay")); 
+		evaluator.setMajorTickSpacing(2);
+		evaluator.setMinorTickSpacing(1);
+		evaluator.setPaintTicks(true);
+		evaluator.setPaintLabels(true); 
+			
+		graph = new MessageGraph(evaluator);
+        visualizer = new GraphVisualizer(graph);
+		tree = new DataTree(dataURL,graph);
+		tree.addTreeSelectionListener(new TreeListener());
+
+		JScrollPane treePane = new JScrollPane(tree); 
+
+		dataClearButton = new JButton("Clear");
+		dataLoadButton = new JButton("Load");
+		
+		dataClearButton.addActionListener(this);
+		dataLoadButton.addActionListener(this);
+		
+		JPanel dataButtons = new JPanel();
+		dataButtons.setLayout(new BorderLayout());
+		dataButtons.add(dataClearButton, BorderLayout.WEST);
+		dataButtons.add(dataLoadButton, BorderLayout.EAST);
+		
+		JPanel dataControls = new JPanel();
+		dataControls.setLayout(new BorderLayout());
+		dataControls.add(evaluator, BorderLayout.NORTH);
+		dataControls.add(dataButtons, BorderLayout.SOUTH);
+
+		logoIcon = createImageIcon(LOGO_ICON);
+
+		JLabel logoLabel = new JLabel();
+		logoLabel.setIcon(logoIcon);
+
+		JLabel nameLabel = new JLabel();        
+		nameLabel.setText(NAME + " " + VERSION);
+
+		JPanel about = new JPanel();
+		about.setLayout(new BoxLayout(about, BoxLayout.X_AXIS));
+		about.add(nameLabel);
+		about.add(Box.createRigidArea(new Dimension(5,0)));
+		about.add(logoLabel);
+
+		JPanel dataPane = new JPanel();
+		dataPane.setLayout(new BorderLayout());
+		dataPane.add(about, BorderLayout.NORTH);
+		dataPane.add(treePane, BorderLayout.CENTER);
+		dataPane.add(dataControls, BorderLayout.SOUTH);
+		dataPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+		
+		startIcon = createImageIcon(START_ICON);
+		stopIcon = createImageIcon(STOP_ICON);
+
+		if ((startIcon != null) && (stopIcon != null)) {
+			controlButton = new JButton("Start", startIcon);
+			controlButton.setVerticalTextPosition(AbstractButton.CENTER);
+			controlButton.setHorizontalTextPosition(AbstractButton.TRAILING);
+		} else {
+			controlButton = new JButton("Start");
+		}
+		
+		circleButton = new JButton("Circle");
+		scrambleButton = new JButton("Scramble");
+		shakeButton = new JButton("Shake");
+		highlightButton = new JButton("Highlight");
+		clearButton = new JButton("Clear");
+		
+        randomCheckbox = new JCheckBox("Random Jumps",visualizer.random);
+        antialiasCheckbox = new JCheckBox("Antialias",visualizer.antialias);
+        nodesCheckbox = new JCheckBox("Nodes",visualizer.drawnodes);
+        edgesCheckbox = new JCheckBox("Edges",visualizer.drawedges);
+        edgeValuesCheckbox = new JCheckBox("Edge Values",visualizer.drawedgevalues);
+        groupsCheckbox = new JCheckBox("Groups",visualizer.drawgroups);
+        timeCheckbox = new JCheckBox("Timing",visualizer.timing);
+		backgroundCheckbox = new JCheckBox("Background",visualizer.background);
+		    
+        delayField = new JTextField(Integer.toString(visualizer.delay),4);
+        massField = new JTextField(Float.toString(visualizer.mass),4);
+        dragField = new JTextField(Float.toString(visualizer.drag),4);
+        attractionField = new JTextField(Float.toString(visualizer.attraction),4);
+        repulsionField = new JTextField(Float.toString(visualizer.repulsion),4);
+        highlightField = new JTextField("@apache.org",15);
+    
+        delayField.addActionListener(this);
+        massField.addActionListener(this);
+        dragField.addActionListener(this);
+        attractionField.addActionListener(this);
+        repulsionField.addActionListener(this);
+        highlightField.addActionListener(this);
+        controlButton.addActionListener(this);
+        circleButton.addActionListener(this);
+        scrambleButton.addActionListener(this);
+        shakeButton.addActionListener(this);
+        highlightButton.addActionListener(this);
+        clearButton.addActionListener(this);
+        
+        randomCheckbox.addItemListener(this);
+        antialiasCheckbox.addItemListener(this);
+        nodesCheckbox.addItemListener(this);
+        edgesCheckbox.addItemListener(this);
+		edgeValuesCheckbox.addItemListener(this);
+		groupsCheckbox.addItemListener(this);
+        timeCheckbox.addItemListener(this);
+		backgroundCheckbox.addItemListener(this);
+
+        JPanel controls = new JPanel();
+        controls.setLayout(new BoxLayout(controls, BoxLayout.X_AXIS));
+        controls.add(controlButton);
+		controls.add(Box.createHorizontalGlue());
+        controls.add(circleButton);
+        controls.add(scrambleButton);
+        controls.add(shakeButton);
+		controls.add(Box.createHorizontalGlue());
+        controls.add(randomCheckbox);
+		controls.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        JPanel highlight = new JPanel();
+		highlight.setLayout(new BoxLayout(highlight, BoxLayout.X_AXIS));
+        highlight.add(highlightField);
+		highlight.add(Box.createRigidArea(new Dimension(5,0)));
+        highlight.add(highlightButton);
+		highlight.add(Box.createRigidArea(new Dimension(5,0)));
+        highlight.add(clearButton);
+		highlight.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        JPanel parameters = new JPanel();
+		parameters.setLayout(new BoxLayout(parameters, BoxLayout.X_AXIS));
+        parameters.add(delayLabel);
+		parameters.add(Box.createRigidArea(new Dimension(5,0)));
+		parameters.add(delayField);
+		parameters.add(Box.createRigidArea(new Dimension(30,0)));
+        parameters.add(massLabel);
+		parameters.add(Box.createRigidArea(new Dimension(5,0)));
+		parameters.add(massField);
+		parameters.add(Box.createRigidArea(new Dimension(30,0)));
+        parameters.add(dragLabel);
+		parameters.add(Box.createRigidArea(new Dimension(5,0)));
+		parameters.add(dragField);
+		parameters.add(Box.createRigidArea(new Dimension(30,0)));
+        parameters.add(attractionLabel);
+		parameters.add(Box.createRigidArea(new Dimension(5,0)));
+		parameters.add(attractionField);
+		parameters.add(Box.createRigidArea(new Dimension(30,0)));
+		parameters.add(repulsionLabel);
+		parameters.add(Box.createRigidArea(new Dimension(5,0)));
+		parameters.add(repulsionField);
+		parameters.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        
+		JPanel drawing = new JPanel();
+		drawing.setLayout(new BoxLayout(drawing, BoxLayout.X_AXIS));
+		drawing.add(antialiasCheckbox);
+		drawing.add(nodesCheckbox);
+		drawing.add(edgesCheckbox);
+		drawing.add(edgeValuesCheckbox);
+		drawing.add(groupsCheckbox);
+		drawing.add(timeCheckbox);
+		drawing.add(backgroundCheckbox);
+		drawing.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+		        
+		JTabbedPane tools = new JTabbedPane(JTabbedPane.TOP);
+        tools.addTab("Controls",controls);
+		tools.addTab("Drawing", drawing);
+		tools.addTab("Highlight",highlight);
+		tools.addTab("Parameters",parameters);
+		
+		JPanel graphPane = new JPanel();
+		graphPane.setLayout(new BorderLayout());
+		graphPane.add(visualizer, BorderLayout.CENTER);
+		graphPane.add(tools, BorderLayout.SOUTH);
+
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,dataPane,graphPane);
+
+		this.getContentPane().add(split);
+    }
+	
+    public void start() {
+		super.start();
+    	if (running) internalStart();
+    }
+    
+    public void stop() {
+		super.stop();
+        if (running) internalStop();
+    }
+
+	public void internalStart() {
+		running = true;
+		visualizer.start();
+		controlButton.setText("Stop");
+		if (stopIcon != null) controlButton.setIcon(stopIcon);
+	}
+
+	public void internalStop() {
+		running = false;
+		visualizer.stop();
+		controlButton.setText("Start");
+		if (startIcon != null) controlButton.setIcon(startIcon);
+	}
+
+    public String getAppletInfo() {
+        return NAME;
+    }    
+
+    public void itemStateChanged(ItemEvent e) {
+        Object source = e.getItemSelectable();
+        boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
+        if (source == randomCheckbox) {
+            visualizer.random = selected;
+        } else if (source == antialiasCheckbox) {
+            visualizer.antialias = selected;
+        } else if (source == nodesCheckbox) {
+            visualizer.drawnodes = selected;
+        } else if (source == edgesCheckbox) {
+            visualizer.drawedges = selected;
+		} else if (source == edgeValuesCheckbox) {
+			visualizer.drawedgevalues = selected;
+		} else if (source == groupsCheckbox) {
+			visualizer.drawgroups = selected;
+        } else if (source == timeCheckbox) {
+            visualizer.timing = selected;
+		} else if (source == backgroundCheckbox) {
+			visualizer.background = selected;
+        }
+        visualizer.repaint();
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        Object source = e.getSource();
+        if (source == controlButton) {
+            if (visualizer.isRunning()) {
+            	internalStop();
+            } else {
+            	internalStart();
+            }
+        } else if (source == circleButton) {
+            visualizer.circle();
+        } else if (source == scrambleButton) {
+            visualizer.scramble();
+        } else if (source == shakeButton) {
+            visualizer.shake();
+		} else if (source == dataLoadButton) {
+			graph.load(true);
+		} else if (source == dataClearButton) {
+			graph.clear();
+			tree.clear();
+        } else if (source == delayField) {
+            visualizer.delay = Integer.parseInt(delayField.getText());
+        } else if (source == massField) {
+            visualizer.mass = Float.parseFloat(massField.getText());
+        } else if (source == dragField) {
+            visualizer.drag = Float.parseFloat(dragField.getText());
+        } else if (source == attractionField) {
+            visualizer.attraction = Float.parseFloat(attractionField.getText());
+        } else if (source == repulsionField) {
+            visualizer.repulsion = Float.parseFloat(repulsionField.getText());
+        } else if ((source == highlightField) || (source == highlightButton)) {
+            visualizer.getGraph().highlightNode(highlightField.getText(),true);
+        } else if (source == clearButton) {
+            visualizer.getGraph().clearHighlights();
+        }
+		visualizer.repaint();
+    }
+	
+	protected static ImageIcon createImageIcon(String path) {
+		URL imgURL = Agora.class.getResource(path);
+		if (imgURL != null) {
+			return new ImageIcon(imgURL);
+		} else {
+			System.err.println("Couldn't find image resource: " + path);
+			return null;
+		}
+	}
+	
+	public static void error(String msg) {
+		System.err.println(msg);
+	}
+
+	public static void log(String msg) {
+		System.out.println(msg);
+	}
+	    
+    public static void main(String[] args) {
+        if (args.length == 0) {
+            System.out.println("Usage: " + Agora.class + " dataURI");
+            System.exit(1);
+        }
+        
+        try {
+            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        } catch (Exception e) { }
+
+		Agora agora = new Agora();
+		agora.init(args[0]);
+
+        JFrame frame = new JFrame(NAME);
+        URL logo = Agora.class.getResource(LOGO_SMALL_ICON);
+        if (logo != null) {
+        	frame.setIconImage(Toolkit.getDefaultToolkit().createImage(logo));
+        } else {
+			System.err.println("Couldn't find image resource: " + LOGO_ICON);
+        }
+		frame.getContentPane().add(agora, BorderLayout.CENTER);
+        frame.addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+        });
+        frame.setSize(800, 600);
+        frame.setVisible(true);
+        frame.show();
+    }    
+}

Propchange: labs/agora/src/java/org/apache/agora/Agora.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/src/java/org/apache/agora/DataTree.java
URL: http://svn.apache.org/viewvc/labs/agora/src/java/org/apache/agora/DataTree.java?view=auto&rev=477728
==============================================================================
--- labs/agora/src/java/org/apache/agora/DataTree.java (added)
+++ labs/agora/src/java/org/apache/agora/DataTree.java Tue Nov 21 08:20:13 2006
@@ -0,0 +1,249 @@
+/* 
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+ 
+ Copyright (C) 2002-2003 The Apache Software Foundation. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+ 
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+ 
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+ 
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+ 
+ 4. The names "Apache", "Agora" and  "Apache Software Foundation" must not be
+	used to  endorse or promote  products derived from  this software without
+	prior written permission. For written permission, please contact
+	apache@apache.org.
+ 
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+ 
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+								   - o -
+
+ This software consists of voluntary contributions made on behalf of the 
+ Apache Software Foundation and was originally created by Stefano Mazzocchi 
+ <stefano at apache.org>.  For more  information on the Apache Software 
+ Foundation, please see <http://www.apache.org/>.
+ 
+*/
+
+package org.apache.agora;
+
+import java.awt.Component;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.swing.ImageIcon;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+
+/**
+ * @author Stefano Mazzocchi <stefano@apache.org>
+ */
+public class DataTree extends JTree {
+
+	List selectedObjects = new ArrayList();
+	
+	URL dataURL;
+	
+	MessageGraph graph;
+
+	class Renderer extends DefaultTreeCellRenderer {
+
+		ImageIcon selectedIcon;
+		ImageIcon unselectedIcon;
+
+		public Renderer() {
+			unselectedIcon = Agora.createImageIcon(Agora.UNSELECTED_ICON);
+			selectedIcon = Agora.createImageIcon(Agora.SELECTED_ICON);
+		}
+
+		public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+			super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+			if (leaf) {
+				if (isSelected(value)) {
+					setIcon(selectedIcon);
+				} else {
+					setIcon(unselectedIcon);
+				} 
+			}
+			return this;
+		}
+
+		protected boolean isSelected(Object value) {
+			DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
+			return selectedObjects.contains(node);
+		}
+	} 	
+	
+	public DataTree(URL dataURL, MessageGraph graph) {
+		this.dataURL = dataURL;
+		this.graph = graph;
+		this.setModel(getModel(dataURL));
+		this.setCellRenderer(new Renderer());
+	}
+	
+	/**
+	 * Reads a URL which contains the layout of the preprocessed files and
+	 * create a tree model that can be used by the JTree widget.
+	 * 
+	 * The format of the layout file uses the following convention:
+	 * 
+	 *   +:name -> creates a new folder named "name" [tree node]
+	 *   *:name -> creates a new file name "name" [tree leaf]
+	 *   -: -> closes the folder at this level
+	 * 
+	 * NOTE: this file is normally generated by the script that preprocesses
+	 * the mailboxes.
+	 * 
+	 * @param url the URL of the file archive layout description
+	 * @return the tree model
+	 */
+	TreeModel getModel(URL url) {
+
+		DefaultMutableTreeNode root = new DefaultMutableTreeNode("Data");
+		DefaultMutableTreeNode parent = root;
+		
+		String line;
+		BufferedReader reader = null;		
+
+		try {
+			reader = new BufferedReader(new InputStreamReader(url.openStream()));
+			while (true) {
+				line = reader.readLine();
+				if ((line == null) || (line.length() == 0)) break;
+	
+				String path = line.substring(2);
+				if (line.startsWith("*:")) {
+					parent.add(new DefaultMutableTreeNode(path));
+				} else if (line.startsWith("+:")) {
+					DefaultMutableTreeNode node = new DefaultMutableTreeNode(path); 
+					parent.add(node);
+					parent = node;
+				} else if (line.startsWith("-:")) {
+					parent = (DefaultMutableTreeNode) parent.getParent();
+				} else {
+					Agora.error("Syntax error in file list: " + line);
+				}
+			}
+		} catch (IOException e) {
+			Agora.error("Caught IOException: " + e.getMessage());
+		} finally {
+			try {
+				if (reader != null) reader.close();
+			} catch (IOException e) {
+			}
+		}
+
+		return new DefaultTreeModel(root);
+	}
+	
+	public String getPath(Object[] objs) {
+		StringBuffer buffer = new StringBuffer(); 
+		for (int i = 1; i < objs.length; i++) {
+			DefaultMutableTreeNode node = (DefaultMutableTreeNode) objs[i];
+			buffer.append('/');
+			buffer.append(node.getUserObject());
+		}
+		return buffer.toString();
+	}
+	
+	public void processPath(TreePath path) {
+		DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
+		if (node.isLeaf()) {
+			Object o = node.getUserObject();
+			if (this.selectedObjects.contains(node)) {
+				this.graph.removeMessageGroup(node);
+				this.selectedObjects.remove(node);
+			} else {
+				try {
+					String file = getPath(path.getPath());
+					String group = getPath(((DefaultMutableTreeNode) node.getParent()).getPath()).intern(); 
+					addMessages(file,group);
+					this.selectedObjects.add(node);
+				} catch (IOException e) {
+					Agora.error("Error reading file: " + e.getMessage());
+				}
+			}
+		}
+	}
+	
+	public void addMessages(String file, String group) throws IOException {
+
+		String path = this.dataURL.getPath();
+		String base = path.substring(0, path.lastIndexOf('/') + 1);
+		URL url = new URL(dataURL.getProtocol(), dataURL.getHost(), dataURL.getPort(), base + file);
+
+		BufferedReader reader = null;
+		String line;
+		int counter = 0;
+	
+		try {
+			reader = new BufferedReader(new InputStreamReader(url.openStream()));		
+			while (true) {
+				line = reader.readLine();
+				if ((line == null) || (line.length() == 0)) break;
+	
+				StringTokenizer st = new StringTokenizer(line," ");
+				if (st.countTokens() < 3) {
+					Agora.error("Syntax error in datafile at line: " + line);
+				} else {
+					try {
+						String messageID = st.nextToken().intern();
+						long timestamp = Long.parseLong(st.nextToken());
+						String email = st.nextToken().intern();
+						String reference = (st.hasMoreTokens()) ? st.nextToken().intern() : null;
+						this.graph.addMessage(messageID,timestamp,email,reference,group);
+						counter++;
+					} catch (NumberFormatException e) {
+						Agora.error("Syntax error in datafile at line: " + line);
+					}
+				}
+			}
+		} catch (IOException e) {
+			Agora.error("Caught IOException: " + e.getMessage());
+		} finally {
+			try {
+				if (reader != null) reader.close();
+			} catch (IOException e) {
+			}
+		}
+	}
+	
+	public void clear() {
+		this.selectedObjects.clear();
+		this.repaint();
+	}
+}

Propchange: labs/agora/src/java/org/apache/agora/DataTree.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/src/java/org/apache/agora/Graph.java
URL: http://svn.apache.org/viewvc/labs/agora/src/java/org/apache/agora/Graph.java?view=auto&rev=477728
==============================================================================
--- labs/agora/src/java/org/apache/agora/Graph.java (added)
+++ labs/agora/src/java/org/apache/agora/Graph.java Tue Nov 21 08:20:13 2006
@@ -0,0 +1,138 @@
+/* 
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+ 
+ Copyright (C) 2002-2003 The Apache Software Foundation. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+ 
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+ 
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+ 
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+ 
+ 4. The names "Apache", "Agora" and  "Apache Software Foundation" must not be
+	used to  endorse or promote  products derived from  this software without
+	prior written permission. For written permission, please contact
+	apache@apache.org.
+ 
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+ 
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+								   - o -
+
+ This software consists of voluntary contributions made on behalf of the 
+ Apache Software Foundation and was originally created by Stefano Mazzocchi 
+ <stefano at apache.org>.  For more  information on the Apache Software 
+ Foundation, please see <http://www.apache.org/>.
+ 
+*/
+
+
+package org.apache.agora;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Stefano Mazzocchi <stefano@apache.org>
+ */
+public class Graph {
+
+	int edges = 0;
+	
+	List nodes = new ArrayList();
+	
+	Map groups = new HashMap(5);
+	
+	class Group {
+		String name;
+		List nodes = new ArrayList(10);
+		
+		Group(String name) {
+			this.name = name;
+		}
+	}
+
+	class Edge {
+		float value = 0.0f;
+		Node from;
+		Node to;
+		
+		Edge(float value, Node from, Node to) {
+			this.value = value;
+			this.from = from;
+			this.to = to;
+		}
+	}
+	
+	class Node {
+		float x;
+		float y;
+		float vx;
+		float vy;
+		float fx;
+		float fy;
+		String name;
+		List groups = new ArrayList(3);
+		boolean fixed = false;
+		boolean highlighted = false;
+		Map edgesTo = new HashMap(5);
+		Map edgesFrom = new HashMap(5);
+
+		Node() {
+			this.x = (float) ((Math.random() - 0.5d) * 200.0d);
+			this.y = (float) ((Math.random() - 0.5d) * 200.0d); 
+		}
+	}
+
+	public void addGroup(Object o, String name) {
+		if (!groups.containsKey(o)) {
+			Group group = new Group(name);
+			groups.put(o,group);
+		}
+	}
+	
+	public void highlightNode(String text, boolean highlight) {
+		Iterator i = nodes.iterator();
+		while (i.hasNext()) {
+			Node n = (Node) i.next();
+			if ((n != null) && (n.name.indexOf(text) > -1)) {
+				n.highlighted = highlight;
+			}
+		}
+	}
+	
+	public void clearHighlights() {
+		Iterator i = nodes.iterator();
+		while (i.hasNext()) {
+			Node n = (Node) i.next();
+			if (n != null) n.highlighted = false;
+		}
+	}
+}

Propchange: labs/agora/src/java/org/apache/agora/Graph.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/src/java/org/apache/agora/GraphVisualizer.java
URL: http://svn.apache.org/viewvc/labs/agora/src/java/org/apache/agora/GraphVisualizer.java?view=auto&rev=477728
==============================================================================
--- labs/agora/src/java/org/apache/agora/GraphVisualizer.java (added)
+++ labs/agora/src/java/org/apache/agora/GraphVisualizer.java Tue Nov 21 08:20:13 2006
@@ -0,0 +1,631 @@
+/* 
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+ 
+ Copyright (C) 2002-2003 The Apache Software Foundation. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+ 
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+ 
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+ 
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+ 
+ 4. The names "Apache", "Agora" and  "Apache Software Foundation" must not be
+	used to  endorse or promote  products derived from  this software without
+	prior written permission. For written permission, please contact
+	apache@apache.org.
+ 
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+ 
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+								   - o -
+
+ This software consists of voluntary contributions made on behalf of the 
+ Apache Software Foundation and was originally created by Stefano Mazzocchi 
+ <stefano at apache.org>.  For more  information on the Apache Software 
+ Foundation, please see <http://www.apache.org/>.
+ 
+*/
+
+
+package org.apache.agora;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.util.Iterator;
+
+import javax.swing.JComponent;
+
+import org.apache.agora.Graph.Edge;
+import org.apache.agora.Graph.Group;
+import org.apache.agora.Graph.Node;
+
+/**
+ * @author Stefano Mazzocchi <stefano@apache.org>
+ */
+public class GraphVisualizer extends JComponent implements Runnable {
+
+	final static float BORDER = 3.0f;
+	final static float BORDERs = BORDER * 2.0f;
+	
+	final float MIN_ALPHA = 1.0f;
+	final float MAX_ALPHA = MIN_ALPHA + 80.0f;
+	final float ALPHA_INC = 20.0f;
+	final float ZOOM_FACTOR = 2.0f;
+    
+	final Color fixedColor = Color.green;
+	final Color selectColor = Color.red;
+	final Color edgeColor = new Color(150,150,150,100);
+	final Color edgeValueColor = new Color(50,50,50,100);
+	final Color nodeColor = Color.red;
+	final Color timeColor = Color.black;
+	final Color tooltipBorderColor = Color.black;
+	final Color pickedBGColor = new Color(255,255,0,100);
+	final Color pickedFontColor = Color.black;
+	final Color highlightBGColor = new Color(255,255,0,150);
+	final Color highlightFontColor = Color.black;
+	final Color groupColor = new Color(0,0,0,200);
+	final Color groupFontColor = groupColor;
+	final Color groupBGColor = new Color(255,255,255,100);
+	final Color groupBorderColor = Color.black;
+    	
+	final Font bigFont = new Font("Verdana", Font.BOLD, 12);
+	final Font smallFont = new Font("Verdana", Font.PLAIN, 10);
+	final Font tinyFont = new Font("Verdana", Font.PLAIN, 9);
+            
+	int delay = 50; // time (milliseconds)
+	float mass = 10.0f; // mass (kg)
+	float drag = 2.0f; // drag coefficient (kg / second)
+	float attraction = 1.0f; // force (kg * pixel / second^2) [/100]
+	float repulsion = 1.0f; // force (kg * pixel / second^2) [*100]
+	float REPULSION_END = 40.0f; // distance (pixel)
+	
+	float REPULSION_ENDs = 2.0f * REPULSION_END;
+
+	boolean random = false;
+	boolean antialias = true;
+	boolean drawedges = true;
+	boolean drawnodes = true;
+	boolean timing = true;
+	boolean drawgroups = true;
+	boolean drawedgevalues = false;
+	boolean background = false;
+
+    Node pick;
+    boolean pickfixed;
+    
+    boolean zoom = false;
+    float zoomX = 0.0f;
+    float zoomY = 0.0f;
+    float alpha = MIN_ALPHA;
+    
+    class MyMouseListener extends MouseAdapter {
+        public void mousePressed(MouseEvent e) {
+        	if (e.isPopupTrigger()) {
+				zoom = true;
+				zoomX = (float) e.getX() - cx;
+				zoomY = (float) e.getY() - cy;
+        	} else {
+	            float x = (float) e.getX() - cx;
+	            float y = (float) e.getY() - cy;
+	            double bestdist = Double.MAX_VALUE;
+	            Iterator i = graph.nodes.iterator();
+	            while (i.hasNext()) {
+	            	Node n = (Node) i.next();
+	                if (n != null) {
+	                    float dx = n.x - x;
+	                    float dy = n.y - y;
+	                    float dist = dx * dx + dy * dy;
+	                    if (dist < bestdist) {
+	                        pick = n;
+	                        bestdist = dist;
+	                    }
+	                }                   
+	            }
+	            if (pick != null) {
+	                pickfixed = pick.fixed;
+	                pick.fixed = true;
+	                pick.x = x;
+	                pick.y = y;
+	            }
+        	}
+			repaint();
+        }
+
+        public void mouseReleased(MouseEvent e) {
+			if (zoom) {
+				zoom = false;
+			} else {
+	            if (pick != null) {
+	                int x = e.getX() - (int) cx;
+	                int y = e.getY() - (int) cy;
+	                pick.x = x;
+	                pick.y = y;
+					keepInsideCanvas(pick);
+	                if (e.getClickCount() == 2) {
+	                    pick.fixed = !pickfixed;
+	                } else {
+	                    pick.fixed = pickfixed;
+	                }
+	                pick = null;
+	            }
+			}
+			repaint();
+        }
+    }
+    
+    class MyMouseMotionListener extends MouseMotionAdapter {
+        public void mouseDragged(MouseEvent e) {
+            if (pick != null) {
+                int x = e.getX() - (int) cx;
+                int y = e.getY() - (int) cy;
+                pick.x = x;
+                pick.y = y;
+                keepInsideCanvas(pick);
+                repaint();
+            } else if (zoom) {
+				zoomX = (float) e.getX() - cx;
+				zoomY = (float) e.getY() - cy;
+				repaint();
+            }
+        }
+    }
+
+    Graph graph;
+    
+    Thread relaxer;
+    
+    float cx;
+    float cy;
+
+    public GraphVisualizer(Graph graph) {
+        this.addMouseMotionListener(new MyMouseMotionListener());
+        this.addMouseListener(new MyMouseListener());
+        this.graph = graph;
+    }
+    
+    public void setGraph(Graph graph) {
+    	this.graph = graph;
+    }
+    
+    public Graph getGraph() {
+    	return this.graph;
+    }
+    
+	public boolean isRunning() {
+		 return relaxer != null;
+	 }
+
+    public void start() {
+        relaxer = new Thread(this);
+        relaxer.start();
+    }
+
+    public void stop() {
+        relaxer = null;
+    }
+
+	public void reshape(int x, int y, int w, int h) {
+		super.reshape(x,y,w,h);
+		this.cx = w / 2.0f;
+		this.cy = h / 2.0f;
+	}
+	
+    public void run() {
+        Thread thisThread = Thread.currentThread();
+        while (relaxer == thisThread) {
+            if (random && (Math.random() < 0.03)) {
+                Node n = (Node) graph.nodes.get((int)(Math.random() * graph.nodes.size()));
+                if (!n.fixed) {
+                    n.x += 100 * Math.random() - 50;
+                    n.y += 100 * Math.random() - 50;
+                    keepInsideCanvas(n);                    
+                }
+            }
+            simulate();
+            try {
+                Thread.sleep(delay);
+            } catch (InterruptedException e) {
+                break;
+            }
+        }
+    }
+
+    void circle() {
+        float r = Math.min(cx, cy) - 50.0f;
+        float alpha = (float) (2.0d * Math.PI / graph.nodes.size());
+
+		int j = 0;
+		Iterator i = graph.nodes.iterator();
+		while (i.hasNext()) {
+			Node n = (Node) i.next();            
+            n.x = (float) (r * Math.sin(alpha * j));
+            n.y = (float) (r * Math.cos(alpha * j++));
+        }
+        repaint();
+    }
+
+    void scramble() {
+		Iterator i = graph.nodes.iterator();
+		while (i.hasNext()) {
+			Node n = (Node) i.next();            
+            if (!n.fixed) {
+                n.x = (float) ((double) (cx - 50.0f) * (Math.random() - 0.5d));
+                n.y = (float) ((double) (cy - 50.0f) * (Math.random() - 0.5d));
+            }
+        }
+        repaint();
+    }
+
+    void shake() {
+		int j = 0;
+		Iterator i = graph.nodes.iterator();
+		while (i.hasNext()) {
+			Node n = (Node) i.next();            
+            if (!n.fixed) {
+                n.x += 80 * Math.random() - 40;
+                n.y += 80 * Math.random() - 40;
+                keepInsideCanvas(n);
+            }
+        }            
+        repaint();
+    }
+
+    void keepInsideCanvas(Node n) {
+        if (n.x < -cx) {
+            n.x = -cx;
+        } else if (n.x > cx) {
+            n.x = cx;
+        }
+        if (n.y < -cy) {
+            n.y = cy;
+        } else if (n.y > cy) {
+            n.y = cy;
+        }
+    }
+    
+    long simulationTime;
+    long drawingTime;
+	    
+    float attractive(float d, float weight) {
+        return attraction * weight * d / 100.0f;
+    }
+    
+    float repulsive(float d) {
+        if (d < REPULSION_END) {
+            float r = 100.0f * repulsion * (d - REPULSION_END) / (d * (d - REPULSION_ENDs));
+            return Math.min(r,500.0f);
+        } else {
+            return 0.0f;
+        }
+    }
+
+    void simulate() {
+        long startTime = 0;
+        
+        if (timing) startTime = System.currentTimeMillis();
+        
+        Iterator i = graph.nodes.iterator();
+        while (i.hasNext()) {
+        	Node n = (Node) i.next();
+        	
+            float xi = n.x;
+            float yi = n.y;
+            float vxi = n.vx;
+            float vyi = n.vy;
+    
+            float fx = 0.0f;
+            float fy = 0.0f;
+
+			Iterator j = graph.nodes.iterator();
+			while (j.hasNext()) {
+				Node m = (Node) j.next();
+            
+                float xj = m.x;
+                float yj = m.y;
+
+                // calculate euclidean distance
+                float deltax = xi - xj;
+                float deltay = yi - yj;
+                float d2 = deltax * deltax + deltay * deltay;
+                float d = (float) Math.sqrt(d2);
+                if (d == 0) d = 0.0001f; // avoid divide by zero
+
+				Edge edge = (Edge) n.edgesTo.get(m);
+				
+				float weight = (edge != null) ? edge.value : 0.0f;
+
+	            // attractive force
+                float af = attractive(d,weight);
+
+                // repulsion force
+                float rf = repulsive(d);
+
+                // resulting force
+                float f = rf - af;
+                
+                // apply the forces
+                fx += (deltax / d) * f;
+                fy += (deltay / d) * f;
+            }
+    
+            // repulsion force from the borders
+            fx += repulsive(xi + cx) - repulsive(cx - xi);
+            fy += repulsive(yi + cy) - repulsive(cy - yi);
+            
+            // drag
+            fx -= drag * vxi;
+            fy -= drag * vyi;
+    
+            // update speed with acceleration
+            vxi += fx / mass;
+            vyi += fy / mass;
+    
+            // update location with speed
+            xi += vxi;
+            yi += vyi;
+
+            if (!n.fixed) {
+                n.x = xi;
+                n.y = yi;
+                n.vx = vxi;
+                n.vy = vyi;
+                keepInsideCanvas(n);
+            }
+        }
+
+        if (timing) simulationTime = System.currentTimeMillis() - startTime;
+        
+        repaint();
+    }
+    
+    public float zoom(float x, float y) {
+    	if (alpha > MIN_ALPHA) {
+			x -= zoomX;
+			y -= zoomY;
+			return ZOOM_FACTOR * (float) Math.exp(-((x*x)+(y*y))/(alpha*alpha));
+    	} else {
+    		return 0.0f;
+    	}
+    }
+        
+    public void paintComponent(Graphics g) {
+        long startTime = 0;
+        
+        if (timing) startTime = System.currentTimeMillis();
+
+		Graphics2D g2 = (Graphics2D) g;
+        
+        if (antialias) {
+            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+        }
+
+		if (background) {
+			g2.setColor(Color.white);
+			g2.fill(new Rectangle2D.Float(0.0f,0.0f,2.0f*cx,2.0f*cy));
+		}
+		
+        if (drawedges) {
+			g2.setFont(tinyFont);
+			FontMetrics fm = g2.getFontMetrics(tinyFont);
+			float ascent = fm.getAscent();
+
+			Iterator nodes = graph.nodes.iterator();
+			while (nodes.hasNext()) {        	
+				Node n1 = (Node) nodes.next();
+				Iterator edges = n1.edgesTo.keySet().iterator();
+				while (edges.hasNext()) {        	
+					Node n2 = (Node) edges.next();
+                    if ((n1 != null) && (n2 != null)) {
+                    	float z1 = zoom(n1.x,n1.y);
+                    	float z2 = zoom(n2.x,n2.y);
+                    	float x1 = n1.x + (n1.x - zoomX) * z1 + cx;
+                    	float x2 = n2.x + (n2.x - zoomX) * z2 + cx;
+                    	float y1 = n1.y + (n1.y - zoomY) * z1 + cy;
+                    	float y2 = n2.y + (n2.y - zoomY) * z2 + cy;
+                    	g2.setColor(edgeColor);
+                    	g2.draw(new Line2D.Float(x1,y1,x2,y2));
+						if (drawedgevalues) {
+							float x = (x2 + x1) / 2.0f;
+							float y = (y2 + y1) / 2.0f + ascent;
+							String value = String.valueOf(((Edge) n1.edgesTo.get(n2)).value);
+							g2.setColor(edgeValueColor);
+							g2.drawString(value, x, y);
+						}
+                    }
+                }
+            }
+        }
+                
+        if (drawnodes) {
+			Iterator i = graph.nodes.iterator();
+			while (i.hasNext()) {        	
+                Node n = (Node) i.next();
+                if (n != null) {
+                	float z = zoom(n.x,n.y);
+                	float x = n.x + (n.x - zoomX) * z + cx;
+                	float y = n.y + (n.y - zoomY) * z + cy;
+                    Shape nodeshape = new Rectangle2D.Float(x-3.0f,y-3.0f,6.0f,6.0f);
+                    if (n == pick) {
+                        g2.setColor(selectColor);
+                        g2.fill(nodeshape);
+                    } else {
+                        g2.setColor((n.fixed) ? fixedColor : nodeColor);
+                        g2.draw(nodeshape);
+                    }
+                }
+            }
+        }
+        
+        if (drawgroups) {
+			g2.setFont(smallFont);
+			FontMetrics fm = g2.getFontMetrics(smallFont);
+			float ascent = fm.getAscent();
+			float descent = fm.getDescent();
+			float height = ascent + descent + 2*BORDER;
+
+			Iterator i = graph.groups.values().iterator();
+			while (i.hasNext()) {
+				Group group = (Group) i.next();
+				Iterator j = group.nodes.iterator();
+				float minX = Float.MAX_VALUE;
+				float minY = Float.MAX_VALUE;
+				float maxX = -Float.MAX_VALUE;
+				float maxY = -Float.MAX_VALUE;
+				while (j.hasNext()) {
+					Node n = (Node) j.next();
+					if (n.x < minX) minX = n.x;
+					if (n.x > maxX) maxX = n.x;
+					if (n.y < minY) minY = n.y;
+					if (n.y > maxY) maxY = n.y;
+				}
+				float dx = maxX - minX + 5.0f;
+				float dy = maxY - minY + 5.0f;
+				float width = fm.stringWidth(group.name) + BORDERs;
+				g2.setColor(groupColor);
+				g2.draw(new Ellipse2D.Float(minX + cx, minY + cy,dx,dy));
+				float sx = (dx - width) / 2.0f + minX + cx;
+				float sy = (dy - height) / 2.0f + minY + cy;
+				g2.setColor(groupFontColor);
+				g2.drawString(group.name, sx + BORDER, sy + ascent + BORDER);
+			}
+        }
+        
+        AffineTransform t = g2.getTransform();
+        
+		Iterator i = graph.nodes.iterator();
+		while (i.hasNext()) {        
+			Node n = (Node) i.next();
+            if ((n != null) && (n.name != null)) {
+            	Font font = ((n == pick) || zoom) ? bigFont : smallFont;
+				g2.setFont(font);
+				FontMetrics fm = g2.getFontMetrics(font);
+				float width = fm.stringWidth(n.name) + BORDERs;
+				float ascent = fm.getAscent();
+				float descent = fm.getDescent();
+				float height = ascent + descent + BORDERs;
+				float halfHeight = height / 2.0f;
+
+				if (zoom) {
+					float z = zoom(n.x,n.y);
+					if (z > ZOOM_FACTOR*0.95f) {
+						float x = n.x + (n.x - zoomX) * z;
+						float y = n.y + (n.y - zoomY) * z;
+						float dx = x - zoomX;
+						float dy = y - zoomY;
+						double theta;
+						if (Math.abs(dx) < Math.abs(dy)) {
+							theta = Math.acos(dx/dy);
+							if (dy < 0.0f) theta += Math.PI;
+						} else {
+							theta = Math.asin(dy/dx);
+							if (dx < 0.0f) theta += Math.PI;
+						}
+						float d = (float) Math.sqrt((dx*dx)+(dy*dy));
+
+						if (dx < 0.0f) {
+							theta -= Math.PI;
+							d = -d - width;
+						}
+						
+						g2.translate(zoomX + cx, zoomY + cy);
+						g2.rotate(theta);
+						
+						Shape rectangle = new RoundRectangle2D.Float(d, -halfHeight, width, height, height, height);
+						g2.setColor(highlightBGColor);
+						g2.fill(rectangle);
+						g2.setColor(tooltipBorderColor);
+						g2.draw(rectangle);
+						g2.setColor(highlightFontColor);
+						g2.drawString(n.name, d + BORDER, +BORDER);                    	
+						g2.setTransform(t);												
+					}
+				} else {	
+	                float x = n.x;
+	                if ((x + width + 2*BORDER) > cx) {
+	                    x -= width;
+	                }
+					x += cx;
+	
+	                float y = n.y;
+	                if ((y - 2*BORDER) < -cy ) {
+	                    y += height;
+	                }
+					y += cy;
+
+					if ((n == pick) || (n.fixed) || (n.highlighted)) {
+						Shape rectangle = new RoundRectangle2D.Float(x, y - halfHeight, width, height, height, height);
+						Color bgColor = (n == pick) ? pickedBGColor : highlightBGColor;
+						Color fontColor = (n == pick) ? pickedFontColor : highlightFontColor;
+						g2.setColor(bgColor);
+						g2.fill(rectangle);
+						g2.setColor(tooltipBorderColor);
+						g2.draw(rectangle);
+						g2.setColor(fontColor);
+						g2.drawString(n.name, x + BORDER, y + BORDER);                    	
+					}
+                }
+            }
+        }            
+
+        if (timing) {
+            drawingTime = System.currentTimeMillis() - startTime;
+            g.setColor(timeColor);
+            g.setFont(smallFont);
+            g.drawString("calculation: " + simulationTime + " ms", 5, 15);
+            g.drawString("drawing: " + drawingTime + " ms", 5, 25);
+            g.drawString("nodes: " + graph.nodes.size(), 5, 35);
+			g.drawString("edges: " + graph.edges, 5, 45);
+        }
+        
+        if (zoom) {
+			if (alpha < MAX_ALPHA) {
+				alpha += ALPHA_INC;
+				repaint();
+			}
+        } else {
+			if (alpha > MIN_ALPHA) {
+				alpha -= ALPHA_INC;
+				repaint();
+			}
+        }
+    }
+}
+

Propchange: labs/agora/src/java/org/apache/agora/GraphVisualizer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/src/java/org/apache/agora/MessageEvaluator.java
URL: http://svn.apache.org/viewvc/labs/agora/src/java/org/apache/agora/MessageEvaluator.java?view=auto&rev=477728
==============================================================================
--- labs/agora/src/java/org/apache/agora/MessageEvaluator.java (added)
+++ labs/agora/src/java/org/apache/agora/MessageEvaluator.java Tue Nov 21 08:20:13 2006
@@ -0,0 +1,91 @@
+/* 
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+ 
+ Copyright (C) 2002-2003 The Apache Software Foundation. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+ 
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+ 
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+ 
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+ 
+ 4. The names "Apache", "Agora" and  "Apache Software Foundation" must not be
+	used to  endorse or promote  products derived from  this software without
+	prior written permission. For written permission, please contact
+	apache@apache.org.
+ 
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+ 
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+								   - o -
+
+ This software consists of voluntary contributions made on behalf of the 
+ Apache Software Foundation and was originally created by Stefano Mazzocchi 
+ <stefano at apache.org>.  For more  information on the Apache Software 
+ Foundation, please see <http://www.apache.org/>.
+ 
+*/
+
+
+package org.apache.agora;
+
+import java.util.Date;
+
+import javax.swing.JSlider;
+
+import org.apache.agora.MessageGraph.Message;
+
+/**
+ * @author Stefano Mazzocchi <stefano@apache.org>
+ */
+public class MessageEvaluator extends JSlider {
+	
+	final static int MIN_VALUE = 0;
+	final static int MAX_VALUE = 12;
+	final static int INIT_VALUE = 0;
+	
+	final static double ln2 = Math.log(2);
+	final static double secondsInMonth = 60 * 60 * 24 * 30;
+
+	long now;
+	
+	public MessageEvaluator() {
+		super(MIN_VALUE,MAX_VALUE,INIT_VALUE);
+		now = new Date().getTime()/1000;
+	}
+			
+	public float evaluateMessage(Message msg) {
+		float decay = (float) getValue();
+		if (decay != 0.0f) {
+			double elapsedMonths = ((double) (now - msg.timestamp)) / secondsInMonth;
+			double normalizedDecay = elapsedMonths / decay;
+			return (float) Math.exp(-ln2*normalizedDecay*normalizedDecay);
+		} else {
+			return 1.0f;
+		}
+	}
+}

Propchange: labs/agora/src/java/org/apache/agora/MessageEvaluator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/src/java/org/apache/agora/MessageGraph.java
URL: http://svn.apache.org/viewvc/labs/agora/src/java/org/apache/agora/MessageGraph.java?view=auto&rev=477728
==============================================================================
--- labs/agora/src/java/org/apache/agora/MessageGraph.java (added)
+++ labs/agora/src/java/org/apache/agora/MessageGraph.java Tue Nov 21 08:20:13 2006
@@ -0,0 +1,241 @@
+/* 
+ ============================================================================
+				   The Apache Software License, Version 1.1
+ ============================================================================
+ 
+ Copyright (C) 2002-2003 The Apache Software Foundation. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+ 
+ 1. Redistributions of  source code must  retain the above copyright  notice,
+	this list of conditions and the following disclaimer.
+ 
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+ 
+ 3. The end-user documentation included with the redistribution, if any, must
+	include  the following  acknowledgment:  "This product includes  software
+	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+	Alternately, this  acknowledgment may  appear in the software itself,  if
+	and wherever such third-party acknowledgments normally appear.
+ 
+ 4. The names "Apache", "Agora" and  "Apache Software Foundation" must not be
+	used to  endorse or promote  products derived from  this software without
+	prior written permission. For written permission, please contact
+	apache@apache.org.
+ 
+ 5. Products  derived from this software may not  be called "Apache", nor may
+	"Apache" appear  in their name,  without prior written permission  of the
+	Apache Software Foundation.
+ 
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+								   - o -
+
+ This software consists of voluntary contributions made on behalf of the 
+ Apache Software Foundation and was originally created by Stefano Mazzocchi 
+ <stefano at apache.org>.  For more  information on the Apache Software 
+ Foundation, please see <http://www.apache.org/>.
+ 
+*/
+
+
+package org.apache.agora;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Stefano Mazzocchi <stefano@apache.org>
+ */
+public class MessageGraph extends Graph {
+
+	MessageEvaluator evaluator;
+	
+	List users = new ArrayList();
+	Map messages = new HashMap();
+	
+	class User extends Node {
+		Set aliases = new HashSet(3);
+		
+		User(String name) {
+			this.name = name;
+		}
+	}
+	
+	class Message {
+		long timestamp;
+		String user;
+		String reference;
+		String group;
+				
+		Message(long timestamp, String user, String reference, String group) {
+			this.timestamp = timestamp;
+			this.user = user;
+			this.reference = reference;
+			this.group = group;
+		}
+	}
+		
+	public MessageGraph(MessageEvaluator evaluator) {
+		super();
+		this.evaluator = evaluator;
+	}
+			
+	public void addMessage(String messageID, long timestamp, String email, String reference, String group) {
+		messages.put(messageID,new Message(timestamp,email,reference,group));
+	}
+	
+	public void removeMessageGroup(Object group) {
+		Iterator i = messages.values().iterator();
+		while (i.hasNext()) {
+			Message msg = (Message) i.next();
+			if (msg.group == group) {
+				i.remove();
+			}
+		}
+	}
+
+	public User getUser(String email) {
+		Iterator i = users.iterator();
+		while (i.hasNext()) {
+			User user = (User) i.next();
+			if (user.aliases.contains(email)) {
+				return user;
+			}
+		}
+		return null;
+	}
+	
+	/*
+	 * load the graph with topological data extracted from the message sets.
+	 * 
+	 * The algorithm for topological extraction is based on the concept of
+	 * "reply": when a person sends a message replying to a message written
+	 * by somebody else, a link is created.
+	 * 
+	 * The streght of this link is based calculated by the pluggable
+	 * MessageEvaluator.
+	 * 
+	 * The nodes that are passive (that is: only received responses and 
+	 * never reply) are pruned from the graph. This reduces visual noise
+	 * and increases performance since these nodes don't add significant
+	 * topological information to the graph.
+	 */
+	public void load(boolean prune) {
+		
+		List _nodes = new ArrayList();
+
+		// process messages
+		Iterator i = messages.values().iterator();
+		while (i.hasNext()) {
+			Message message = (Message) i.next();
+			Message reference = (Message) messages.get(message.reference);
+			
+			// A null reference means that the referring message was not loaded.
+			// for this reason, this message is dicarded since it doesn't
+			// contain topological information within this dataset
+			if (reference != null) { 
+				User sender = getUser(message.user);
+				if (sender == null) {
+					sender = new User(message.user);
+					sender.aliases.add(message.user);
+					users.add(sender);
+				}
+				
+				User receiver = getUser(reference.user);
+				if (receiver == null) {
+					receiver = new User(reference.user);
+					receiver.aliases.add(reference.user);
+					users.add(receiver);
+				}
+				
+				// replies to self don't add topological information so they are ignored
+				if (sender != receiver) {
+					Group group = (Group) groups.get(message.group);
+					if (group == null) {
+						group = new Group(message.group);
+						groups.put(message.group,group);
+					}
+					if (!group.nodes.contains(sender)) group.nodes.add(sender);
+					if (!sender.groups.contains(group)) sender.groups.add(group);
+					
+					float f = evaluator.evaluateMessage(message);
+					
+					Edge edge = (Edge) sender.edgesTo.get(receiver);
+					if (edge != null) {
+						edge.value += f;
+					} else {
+						edge = new Edge(f,sender,receiver);
+						edges++;
+					}
+					
+					sender.edgesTo.put(receiver,edge);
+					receiver.edgesFrom.put(sender,edge);
+						
+					if (!_nodes.contains(sender)) _nodes.add(sender);
+					if (!_nodes.contains(receiver)) _nodes.add(receiver);
+				}
+			}
+		}
+
+		// prune the graph from all the passive nodes (nodes that have zero fan out)
+		// note that pruning needs to be done in subsequent phases, because
+		// after the one pruning pass, other nodes might have become passive
+		if (prune) {
+			while (true) {
+				boolean potentialReprune = false;
+				Iterator j = _nodes.iterator();
+				while (j.hasNext()) {
+					User user = (User) j.next();
+					if (user.edgesTo.keySet().isEmpty()) {
+						j.remove();
+						Iterator k = user.groups.iterator();
+						while (k.hasNext()) {
+							Group g = (Group) k.next();
+							g.nodes.remove(user);
+						} 
+						Iterator edges = user.edgesFrom.keySet().iterator();
+						while (edges.hasNext()) {
+							User u = (User) edges.next();
+							u.edgesTo.remove(user);
+						}
+						potentialReprune = true;
+					}
+				}
+				if (!potentialReprune) break;
+			}
+		}
+		
+		this.nodes = _nodes;
+		
+		Agora.log("Message processed: " + messages.size());
+		Agora.log("Users found: " + users.size());
+		Agora.log("Users pruned: " + (users.size() - nodes.size()));
+	}
+	
+	public void clear() {
+		edges = 0;
+		nodes.clear();
+		users.clear();
+		messages.clear();
+		groups.clear();
+		System.gc();
+	}
+}

Propchange: labs/agora/src/java/org/apache/agora/MessageGraph.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: labs/agora/src/java/org/apache/agora/resources/icons/file.gif
URL: http://svn.apache.org/viewvc/labs/agora/src/java/org/apache/agora/resources/icons/file.gif?view=auto&rev=477728
==============================================================================
Binary file - no diff available.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org


Mime
View raw message