Index: fedd/abac-src/atnvis/src/ATNVisualizer.java
===================================================================
--- fedd/abac-src/atnvis/src/ATNVisualizer.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/ATNVisualizer.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,1426 @@
+package com.algomagic.atn.vis;
+import att.grappa.*;
+
+import java.util.*;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class ATNVisualizer extends JFrame 
+    implements ATNVisualizerConstants, GrappaConstants {
+
+    private Properties _properties;
+    private SidePanel[] _sides;
+
+    private Collection _updates;
+
+    private ControlPanel _controls;
+    private ProgressPanel _progressPanel;
+    private PlayBackManager _playBackManager;
+
+
+    public ATNVisualizer( String log1, String log2 ) {
+	loadProperties( );
+
+	initATNVisualizer( log1, log2 );
+	parseUpdates( log1, log2 );
+
+	_playBackManager = new PlayBackManager( );
+	_controls.addObserver( _playBackManager );
+	_playBackManager.addObserver( _progressPanel );
+
+
+	show( );
+    }
+
+
+    private void initATNVisualizer( String log1, String log2 ) {
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	_sides = new SidePanel[2];
+
+
+
+	_sides[LEFT_SIDE] = new SidePanel( LEFT_SIDE );
+	_sides[RIGHT_SIDE] = null;
+
+	JPanel main = new JPanel( );
+	main.setLayout( new BoxLayout( main, BoxLayout.X_AXIS ) );
+	main.add( _sides[LEFT_SIDE] );
+
+
+	if( log2 != null ) {
+	    _sides[RIGHT_SIDE] = new SidePanel( RIGHT_SIDE );
+	    main.add( Box.createHorizontalStrut( 10 ) );
+	    main.add( _sides[RIGHT_SIDE] );
+	}
+
+
+	JPanel bottom = new JPanel( );
+
+	bottom.setLayout( new BoxLayout( bottom, BoxLayout.X_AXIS ) );
+	bottom.add( _controls = new ControlPanel( ) );
+	bottom.add( _progressPanel = new ProgressPanel( ) );
+	
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.Y_AXIS ) );
+	contentPane.add( main );
+	contentPane.add( bottom );
+
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+	show( );
+    }
+
+
+    private void parseUpdates( String log1, String log2 ) {
+	_updates = new ArrayList( );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice", "MedSup: ReliefNet.provisioner <- Alice",
+				      IMPLICATION_EDGE ) );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+
+	if( _sides[RIGHT_SIDE] != null ) {
+
+	    _updates.add( new MessageBeginUpdate( _sides[RIGHT_SIDE], "<Message>\n<NodeOp type=\"root\">\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Credential  definedRole=\"MedSup.discount\" subject=\"ReliefNet.provisioner\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>Verifier Processed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	    // 2
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+	    
+	    // 3
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice", 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  IMPLICATION_EDGE ) );
+
+	    
+	    // 4 
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+	    
+
+	    _updates.add( new MessageEndUpdate( _sides[RIGHT_SIDE] ) );
+			  
+
+	    
+	    // 6
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice", 
+					  "MedSup: MedixFund.purchasingA <- Alice" ) );
+
+
+	    
+	    // 7
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+
+	    // 8
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedixFund.purchasingA <- Alice", 
+					  "Alice: MedixFund.cPartner <- MedSup" ) );
+
+
+
+	    // 9
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup", 
+					  "Alice: ReliefNet.member <- MedSup" ) );
+
+
+	    // 10
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+
+	}
+
+	_updates.add( new MessageBeginUpdate( _sides[LEFT_SIDE],
+					      "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"ReliefNet.provisioner\" subject=\"MedixFund.purchasingA\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n<EdgeOp type=\"control\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</EdgeOp>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"MedixFund.cPartner\" subject=\"ReliefNet.member\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n<ProcessingState>Verifier Processed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], "MedSup: ReliefNet.provisioner <- Alice", "MedSup: MedixFund.purchasingA <- Alice" ) );
+
+
+	// 7
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+
+	// 8
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedixFund.purchasingA <- Alice", 
+				      "Alice: MedixFund.cPartner <- MedSup" ) );
+
+
+	// 9
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup", 
+				      "Alice: ReliefNet.member <- MedSup" ) );
+
+
+	// 10
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	_updates.add( new MessageEndUpdate( _sides[LEFT_SIDE] ) );
+
+
+	// 12
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedSup <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      "Alice: MedSup <- MedSup" ) );
+
+
+	// 13
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	// 14
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	// 15
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      OPPONENT_PROC ) );
+	
+	
+
+	if( _sides[RIGHT_SIDE] != null ) {
+
+	    _updates.add( new MessageBeginUpdate( _sides[RIGHT_SIDE],
+						  "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedSup</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Fully Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"ReliefNet.member\" subject=\"MedSup\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	    // 13
+
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedSup <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  "Alice: MedSup <- MedSup" ) );
+
+
+	    // 14
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+	    // 15
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    // 16
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  OPPONENT_PROC ) );
+	
+
+
+	    _updates.add( new MessageEndUpdate( _sides[RIGHT_SIDE] ) );
+
+	    
+	    // 18
+
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: Alice <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedixFund.purchasingA <- Alice", 
+					  "MedSup: Alice <- Alice" ) );
+
+
+
+	    // 19
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+	    // 20
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	
+	    // 21
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  SATISFIED,
+					  FULLY_PROC ) );
+	
+
+	    // 22
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  OPPONENT_PROC ) );
+
+
+
+	}
+
+
+	_updates.add( new MessageBeginUpdate( _sides[LEFT_SIDE],
+					      "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>Alice</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Fully Processed</ProcessingState>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n</Message>") );
+
+
+
+
+	// 18
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: Alice <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedixFund.purchasingA <- Alice", 
+				      "MedSup: Alice <- Alice" ) );
+
+
+
+	// 19
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	// 20
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	
+	// 21
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      SATISFIED,
+				      FULLY_PROC ) );
+	
+
+	// 22
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new MessageEndUpdate( _sides[LEFT_SIDE] ) );
+
+
+
+ 	formatGraph( _sides[LEFT_SIDE].getGraph( ) );
+
+	if( _sides[RIGHT_SIDE] != null ) {
+ 	    formatGraph( _sides[RIGHT_SIDE].getGraph( ) );
+	}
+
+    }
+
+
+    private void hideGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+
+	g.resync( );
+	g.repaint( );
+
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+
+    
+    private void setNodeProps( Node n, String prefix ) {
+
+	for( int i=0; i < NODE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + NODE_ATTRS_PROP[i] );
+	    if( strValue == null ) {
+		continue;
+	    }
+
+	    System.out.print( prefix + NODE_ATTRS_PROP[i] );
+	    System.out.println( ":" + strValue );
+
+// 	    if( NODE_ATTRS_PROP[i].equals( "peripheries" ) ) {
+// 		n.setDefaultAttribute( NODE_ATTRS[i], new Integer( strValue ) );
+// 		continue;
+// 	    }
+	    
+
+	    if( NODE_ATTRS_INT[i] ) {
+		Attribute a = new Attribute( NODE, NODE_ATTRS[i], new Integer( strValue ) );
+		n.setAttribute( a );
+// 		n.setAttribute( NODE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		Attribute a = new Attribute( NODE, NODE_ATTRS[i], strValue );
+		n.setAttribute( a );
+// 		n.setAttribute( NODE_ATTRS[i], strValue );
+	    }
+	}
+    }
+
+    private void setEdgeProps( Edge e, String prefix ) {
+	for( int i=0; i < EDGE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + EDGE_ATTRS_PROP[i] );
+
+	    if( strValue == null ) {
+		continue;
+	    }
+	    
+	    if( EDGE_ATTRS_INT[i] ) {
+		e.setAttribute( EDGE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		e.setAttribute( EDGE_ATTRS[i], strValue );
+	    }
+	}
+    }
+
+
+
+
+    private void setNodeProperties( Node n, String type, String satisfaction, String process ) {
+	setNodeProps( n, DEFAULT_NODE );
+	setNodeProps( n, SYSTEM_PREFIX + "node." + type + "." );
+	setNodeProps( n, SYSTEM_PREFIX + "node.processed." + process + "." );
+	setNodeProps( n, SYSTEM_PREFIX + "node.satisfied." + satisfaction + "." );
+    }
+
+    private void setEdgeProperties( Edge e, String type ) {
+	setEdgeProps( e, DEFAULT_EDGE );
+	setEdgeProps( e, SYSTEM_PREFIX + "edge." + type + "." );
+    }
+
+
+
+
+    private void setSolid( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "filled" );
+ 	e.setAttribute( COLOR_ATTR, ".5,.5,.5" );
+	
+	if( e instanceof Node ) {
+	    e.setDefaultAttribute( PERIPHERIES_ATTR, new Integer( 2 ) );
+	}
+    }
+
+    private void setBold( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "bold" );
+	e.setAttribute( STYLE_ATTR, "bold" );
+    }
+
+    private void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	_properties = new Properties( );
+
+	if( file.exists( ) ) {
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( Exception e ) { }
+	}
+
+    }
+
+
+    private class SidePanel extends JPanel {
+	GrappaPanel _grappaPanel;
+	Graph _graph;
+
+	JPanel _listPanel;
+	MessagePanel _messagePanel;
+	JPanel _graphPanel;
+
+	JPanel _tallPanel;
+	JPanel _thinPanel;
+	
+	JPanel _top;
+	JPanel _complete;
+
+	int _side;
+
+	public Graph getGraph( ) {
+	    return _graph;
+	}
+
+
+	public SidePanel( int side ) {
+	    super( );
+	    Class clazz = this.getClass( );
+
+
+	    _side = side;
+
+	    _tallPanel = new JPanel( );
+	    _tallPanel.setLayout( new BoxLayout( _tallPanel, BoxLayout.Y_AXIS ) );
+
+ 	    JButton tall = new JButton( );
+	    tall.setMaximumSize( new Dimension( 10, 2000 ) );
+	    tall.setPreferredSize( new Dimension( 10, 2000 ) );
+	    tall.setMinimumSize( new Dimension( 10, 0 ) );
+
+	    tall.addActionListener( new ActionListener( ) {
+		    boolean removed = false;
+		    
+		    public void actionPerformed( ActionEvent e ) {
+			if( ! removed ) {
+			    _top.remove( _listPanel );
+			    removed = true;
+			} else {
+			    if( _side == LEFT_SIDE ) {
+				_top.add( _listPanel, 0 );
+			    } else {
+				_top.add( _listPanel, 2 );
+			    }
+
+			    removed = false;
+			}
+			
+			validate( );
+			repaint( );
+
+		    }
+
+		} );
+
+
+	    _tallPanel.add( tall );
+
+
+	    _thinPanel = new JPanel( );
+	    _thinPanel.setLayout( new BoxLayout( _thinPanel, BoxLayout.X_AXIS ) );
+
+	    JButton thin = new JButton( );
+	    thin.setMaximumSize( new Dimension( 2000, 10 ) );
+	    thin.setPreferredSize( new Dimension( 2000, 10 ) );
+	    thin.setMinimumSize( new Dimension( 0, 10 ) );
+
+	    thin.addActionListener( new ActionListener( ) {
+		    boolean removed = false;
+		    
+		    public void actionPerformed( ActionEvent e ) {
+			if( ! removed ) {
+			    _complete.remove( _messagePanel );
+			    removed = true;
+			} else {
+			    _complete.add( _messagePanel, 2 );
+			    removed = false;
+			}
+
+			validate( );
+			repaint( );
+		    }
+
+		} );
+
+
+	    _thinPanel.add( thin );
+
+	    _listPanel = new ListPanel( );
+
+	    _messagePanel = new MessagePanel( );
+
+ 	    _graphPanel = new JPanel( new BorderLayout( ) );
+
+	    setPanelBorder( _graphPanel, "Trust Negotiation Graph" );
+
+	    _listPanel.setMaximumSize( new Dimension( 150, 2000 ) );
+	    _listPanel.setPreferredSize( new Dimension( 150, 2000 ) );
+	    _listPanel.setMinimumSize( new Dimension( 150, 0 ) );
+
+	    _messagePanel.setMaximumSize( new Dimension( 2000, 150 ) );
+	    _messagePanel.setPreferredSize( new Dimension( 2000, 150 ) );
+	    _messagePanel.setMinimumSize( new Dimension( 0, 150 ) );
+
+
+	    _top = new JPanel( );
+ 	    _top.setLayout( new BoxLayout( _top, BoxLayout.X_AXIS ) );
+	    
+
+	    if( _side == LEFT_SIDE ) {
+		_top.add( _listPanel );
+		_top.add( _tallPanel );
+		_top.add( _graphPanel );
+	    } else {
+		_top.add( _graphPanel );
+		_top.add( _tallPanel );
+		_top.add( _listPanel );
+	    }
+
+
+	    _complete = new JPanel( );
+	    _complete.setLayout( new BoxLayout( _complete, BoxLayout.Y_AXIS ) );
+
+	    _complete.add( _top );
+ 	    _complete.add( _thinPanel );
+ 	    _complete.add( _messagePanel );
+
+	    _graph = new Graph( "Trust Negotiation Graph: " + _side );
+ 	    _grappaPanel = new GrappaPanel( _graph );
+	    _grappaPanel.setScaleToFit( false );
+
+ 	    JScrollPane jsp = new JScrollPane( );
+ 	    jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	    jsp.getViewport( ).setBackground( Color.white );
+ 	    jsp.setViewportView( _grappaPanel );
+	
+	    _graphPanel.add( jsp, BorderLayout.CENTER );
+
+	    setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+	    add( _complete );
+
+	}
+
+	public void setMessage( String message ) {
+	    _messagePanel.setMessage( message );
+	}
+
+    }
+
+
+    private class ControlPanel extends JPanel implements ActionListener {
+	JButton play, pause, stepForward, stepBack, rewind, fastForward, stop;
+	InternalObservable _observable;
+
+	public ControlPanel( ) {
+	    super( );
+	    
+	    _observable = new InternalObservable( );
+	    Class clazz = this.getClass( );
+
+	    play = new JButton( new ImageIcon( clazz.getResource( "/resources/Play24.gif" ), "play" ) );
+	    play.setActionCommand( "play" );
+	    play.addActionListener( this );
+	    play.setEnabled( true );
+
+	    pause = new JButton( new ImageIcon( clazz.getResource( "/resources/Pause24.gif" ), "pause" ) );
+	    pause.setActionCommand( "pause" );
+	    pause.addActionListener( this );
+	    pause.setEnabled( false );
+
+
+	    stepForward = new JButton( new ImageIcon( clazz.getResource( "/resources/StepForward24.gif" ), "step forward" ) );
+	    stepForward.setActionCommand( "stepf" );
+	    stepForward.addActionListener( this );
+	    stepForward.setEnabled( true );
+
+	    stepBack = new JButton( new ImageIcon( clazz.getResource( "/resources/StepBack24.gif" ), "step back" ) );
+	    stepBack.setActionCommand( "stepb" );
+	    stepBack.addActionListener( this );
+	    stepBack.setEnabled( true );
+
+	    rewind = new JButton( new ImageIcon( clazz.getResource( "/resources/Rewind24.gif" ), "rewind" ) );
+	    rewind.setActionCommand( "rewind" );
+	    rewind.addActionListener( this );
+	    rewind.setEnabled( true );
+
+	    fastForward = new JButton( new ImageIcon( clazz.getResource( "/resources/FastForward24.gif" ), "fast forward" ) );
+	    fastForward.setActionCommand( "ff" );
+	    fastForward.addActionListener( this );
+	    fastForward.setEnabled( true );
+
+// 	    stop = new JButton( new ImageIcon( clazz.getResource( "/resources/Stop24.gif" ), "stop" ) );
+// 	    stop.setActionCommand( "stop" );
+// 	    stop.addActionListener( this );
+
+
+	    setStyle( play );
+	    setStyle( pause );
+	    setStyle( stepForward );
+	    setStyle( stepBack );
+	    setStyle( rewind );
+	    setStyle( fastForward );
+// 	    setStyle( stop );
+
+	    setLayout( new BoxLayout( this, BoxLayout.X_AXIS ) );
+	    add( rewind );
+	    add( stepBack );
+	    add( play );
+	    add( pause );
+// 	    add( stop );
+	    add( stepForward );
+	    add( fastForward );
+
+	    JCheckBox loop = new JCheckBox( "loop", (new Boolean( _properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( ) );
+	    loop.addItemListener( new ItemListener( ) {
+		    public void itemStateChanged( ItemEvent e ) {
+			int s = e.getStateChange( );
+			Boolean state = Boolean.TRUE;
+
+			if( s == ItemEvent.DESELECTED ) {
+			    state = Boolean.FALSE;
+			}
+			
+			_observable.notify( state );
+
+		    }
+
+		} );
+
+
+	    add( Box.createHorizontalStrut( 10 ) );
+	    add( loop );
+
+	    JSpinner spinner = new JSpinner( new SpinnerNumberModel( Integer.parseInt( _properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) ), 
+								     0, 
+								     5000, 
+								     100 ) );
+
+	    JLabel spinnerLabel = new JLabel( "delay (msec)" );
+
+	    spinner.addChangeListener( new ChangeListener( ) {
+		    public void stateChanged( ChangeEvent e ) {
+			_observable.notify( e.getSource( ) );
+		    }
+		} );
+
+
+	    add( spinner );
+	    add( Box.createHorizontalStrut( 5 ) );
+	    add( spinnerLabel );
+
+	    setPanelBorder( this, "Controls" );
+	}
+
+
+	public void addObserver( Observer o ) {
+	    _observable.addObserver( o );
+	}
+
+
+	private void setStyle( JButton b ) {
+	    b.setMinimumSize( new Dimension( 24, 24 ) );
+	    b.setMaximumSize( new Dimension( 24, 24 ) );
+	    b.setPreferredSize( new Dimension( 24, 24 ) );
+	    
+	    b.setBorderPainted( false );
+	}
+
+	public void actionPerformed( ActionEvent e ) {
+	    String cmd = e.getActionCommand( );
+	    if( cmd.equals( "play" ) ) {
+		stepForward.setEnabled( false );
+		stepBack.setEnabled( false );
+		rewind.setEnabled( false );
+		fastForward.setEnabled( false );
+		play.setEnabled( false );
+		pause.setEnabled( true );
+	    }
+
+	    else if( cmd.equals( "pause" ) ) {
+		stepForward.setEnabled( true );
+		stepBack.setEnabled( true );
+		rewind.setEnabled( true );
+		fastForward.setEnabled( true );
+		play.setEnabled( true );
+		pause.setEnabled( false );
+	    }
+
+
+
+
+
+	    _observable.notify( e.getActionCommand( ) );
+	}
+
+
+	private class InternalObservable extends Observable {
+	    public void notify( Object arg ) {
+		setChanged( );
+		notifyObservers( arg );
+	    }
+
+	    
+	}
+
+    }
+
+
+    private class ListPanel extends JPanel implements Observer {
+	public ListPanel( ) {
+	    super( );
+
+	    JList oCreds = new JList( );
+	    JScrollPane oCredsJSP = new JScrollPane( oCreds );
+	    setPanelBorder( oCredsJSP, "Opponent Creds." );
+
+	    JList vCreds = new JList( );
+	    JScrollPane vCredsJSP = new JScrollPane( vCreds );
+	    setPanelBorder( vCredsJSP, "Verifier Creds." );
+
+	    JList acPolicy = new JList( );
+	    JScrollPane acPolicyJSP = new JScrollPane( acPolicy );
+	    setPanelBorder( acPolicyJSP, "AC Policies" );
+
+	    JList ackPolicy = new JList( );
+	    JScrollPane ackPolicyJSP = new JScrollPane( ackPolicy );
+	    setPanelBorder( ackPolicyJSP, "Ack Policies" );
+
+
+	    setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+
+	    JList list = new JList( );
+	    JScrollPane jsp = new JScrollPane( list );
+	    
+	    add( oCredsJSP );
+	    add( vCredsJSP );
+	    add( acPolicyJSP );
+	    add( ackPolicyJSP );
+
+
+	}
+
+
+	public void update( Observable o, Object arg ) {
+
+
+	}
+
+    }
+
+
+    private class MessagePanel extends JPanel {
+	JTextArea _message;
+
+	public MessagePanel( ) {
+	    super( );
+	    setLayout( new BorderLayout( ) );
+
+	    _message = new JTextArea( );
+	    JScrollPane jsp = new JScrollPane( _message );
+
+	    add( jsp, BorderLayout.CENTER );
+
+	    setPanelBorder( this, "Message" );
+
+	}
+
+	public void setMessage( String message ) {
+	    _message.setText( message );
+	}
+
+
+    }
+
+    
+    private class ProgressPanel extends JPanel implements Observer {
+	JProgressBar _progress;
+
+	public ProgressPanel( ) {
+	    super( );
+	    setLayout( new BorderLayout( ) );
+
+// 	    _progress = new JProgressBar( 0, _updates.size( ) );
+	    _progress = new JProgressBar( 0, 1 );
+	    _progress.setValue( 0 );
+	    _progress.setStringPainted( true );
+
+
+	    add( _progress, BorderLayout.CENTER );
+
+	    setPanelBorder( this, "Negotiation Progress" );
+	}
+
+
+	public void setMax( int n ) {
+	    _progress.setMaximum( n );
+	}
+
+	public void update( Observable o, Object arg ) {
+	    _progress.setValue( ((Integer)arg).intValue( ) );
+
+	}
+
+
+    }
+
+
+    private void setPanelBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+
+
+    private class PlayBackManager extends Observable implements Observer {
+	private int _delay = Integer.parseInt( _properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) );
+	private boolean _loop = (new Boolean( _properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( );
+	private Update[] _updateArray = (Update[]) _updates.toArray( new Update[0] );
+	private int _index = 0;
+	private boolean _clear = true;
+
+
+	private boolean _playing = false;
+
+
+	public PlayBackManager( ) {
+	    _progressPanel.setMax( _updateArray.length );
+	}
+
+	public void update( Observable o, Object arg ) {
+	    if( arg instanceof String ) {
+		String cmd = (String)arg;
+
+		if( cmd.equals( "play" ) ) {
+		    _playing = true;
+		    new Thread( new PlayThread( ) ).start( );
+		} else if( cmd.equals( "pause" ) ) {
+		    _playing = false;
+		} else if( cmd.equals( "stepf" ) ) {
+		    stepf( );
+		} else if( cmd.equals( "ff" ) ) {
+		    ff( );
+		} else if( cmd.equals( "rewind" ) ) {
+		    rewind( );
+		}
+
+	    } else if( arg instanceof JSpinner ) {
+		SpinnerNumberModel snm = (SpinnerNumberModel)((JSpinner)arg).getModel( );
+		_delay = snm.getNumber( ).intValue( );
+	    } else if (arg instanceof Boolean ) {
+		_loop = ((Boolean)arg).booleanValue( );
+	    }
+	}
+
+
+	private synchronized void stepf( ) {
+	    if( _index == 0 && _clear == false ) {
+		clearAll( );
+		_clear = true;
+
+		setChanged( );
+		notifyObservers( new Integer( _index ) );
+
+		return;
+	    }
+
+	    _clear = false;
+
+
+	    _updateArray[_index].execute( );
+	    _index++;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+
+	    
+	    if( _index == _updateArray.length ) {
+		_index = 0;
+		if( _playing == true && _loop == false ) {
+		    _playing = false;
+		}
+	    }
+
+
+	}
+
+	private synchronized void stepb( ) {
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+	}
+	
+	private synchronized void ff( ) {
+	    for( int i = _index; i < _updateArray.length; i++ ) {
+		_updateArray[i].execute( );
+	    }
+
+	    _index = 0;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+
+	}
+
+
+	private synchronized void rewind( ) {
+	    clearAll( );
+	    _index = 0;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+	}
+
+
+	private class PlayThread implements Runnable {
+	    public void run( ) {
+		while( _playing ) {
+		    try {
+			stepf( );
+			Thread.currentThread( ).sleep( _delay );
+		    } catch( InterruptedException ie ) {
+			throw new RuntimeException( ie );
+		    }
+		}
+		
+	    }
+	}
+
+
+    }
+
+
+    protected abstract class  Update {
+	public abstract void execute( );
+	public abstract void fixRef( );
+    }
+
+
+    private class TestUpdate extends Update {
+	private int _i;
+
+	public TestUpdate( int i ) {
+	    _i = i;
+	}
+
+	public void execute( ) {
+	    System.out.println( _i );
+	}
+	
+	public void fixRef( ) {
+
+	}
+
+    }
+
+    private class MessageBeginUpdate extends Update {
+	SidePanel _sp;
+	String _message;
+
+	public MessageBeginUpdate( SidePanel sp, String message ) {
+	    _sp = sp;
+	    _message = message;
+	}
+
+
+	public void execute( ) {
+	    _sp.setMessage( _message );
+	}
+	
+	public void fixRef( ) {
+
+	}
+	
+    }
+    
+    private class MessageEndUpdate extends Update {
+	SidePanel _sp;
+
+	public MessageEndUpdate( SidePanel sp ) {
+	    _sp = sp;
+	}
+
+
+	public void execute( ) {
+	    _sp.setMessage( "" );
+	}
+	
+	public void fixRef( ) {
+
+	}
+    }
+    
+	
+
+
+
+
+
+
+    private class NodeUpdate extends Update {
+	SidePanel _sp;
+	String _name;
+	Node _n;
+
+	String _type;
+	String _satisfactionState;
+	String _processingState;
+
+	public NodeUpdate( SidePanel sp, String name ) {
+	    _sp = sp;
+	    _name = name;
+
+	    Graph g = _sp.getGraph( );
+
+	    _n = g.findNodeByName( name );
+	    if( _n == null ) {
+		_n = new Node( g, name );
+		setInvis( _n );
+		g.addNode( _n );
+	    }
+
+	}
+
+	public NodeUpdate( SidePanel sp, 
+			   String name, 
+			   String type,
+			   String satisfactionState, 
+			   String processingState ) {
+	    this( sp, name );
+
+	    _type = type;
+
+
+	    _satisfactionState = satisfactionState;
+	    _processingState = processingState;
+
+
+	}
+
+	public void fixRef( ) {
+	    _n = _sp.getGraph( ).findNodeByName( _name );
+	}
+
+
+	public void execute( ) {
+	    fixRef( );
+
+	    setNodeProperties( _n, _type, _satisfactionState, _processingState );
+
+	    Graph g = _sp.getGraph( );
+
+	    g.resync( );
+	    g.repaint( );
+	}
+    }
+
+    
+    private class EdgeUpdate extends Update {
+	SidePanel _sp;
+	String _headNodeName;
+	String _tailNodeName;
+	Edge _e;
+
+	String _type;
+
+
+	public EdgeUpdate( SidePanel sp, 
+			   String headNodeName, 
+			   String tailNodeName, 
+			   String type ) {
+	    this( sp, headNodeName, tailNodeName );
+	    _type = type;
+	}
+
+
+
+	public EdgeUpdate( SidePanel sp, String headNodeName, String tailNodeName ) {
+	    _sp = sp;
+	    _headNodeName = headNodeName;
+	    _tailNodeName = tailNodeName;
+
+	    Graph g = _sp.getGraph( );
+	    Node head = g.findNodeByName( _headNodeName );
+	    Node tail = g.findNodeByName( _tailNodeName );
+
+
+	    _e = getEdgeBetween( g, head, tail );
+
+	    if( _e == null ) {
+		_e = new Edge( g, head, tail );
+		setInvis( _e );
+		g.addEdge( _e );
+	    }
+
+	}
+
+
+	public void fixRef( ) {
+	    Graph g = _sp.getGraph( );
+	    Node head = g.findNodeByName( _headNodeName );
+	    Node tail = g.findNodeByName( _tailNodeName );
+
+
+	    _e = getEdgeBetween( g, head, tail );
+	}
+
+	public void execute( ) {
+	    fixRef( );
+	    setEdgeProperties( _e, _type );
+
+	    Graph g = _sp.getGraph( );
+
+	    g.resync( );
+	    g.repaint( );
+	}
+    }
+
+
+    private void clearAll( ) {
+	for( int i = 0; i < _sides.length; i++ ) {
+	    if( _sides[i] != null ) {
+		hideGraph( _sides[i].getGraph( ) );
+	    }
+	}
+
+	
+    }
+
+    private Graph loadGraph( String dotFile ) {
+	Parser parser = null;
+	try {
+	    parser = new Parser( new FileInputStream( dotFile ) );
+	    parser.parse( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	return parser.getGraph( );
+    }
+
+
+
+    public static void main( String[] args ) {
+	ATNVisualizer atnVis = null;
+
+	if( args.length == 1 ) {
+	    atnVis = new ATNVisualizer( args[0], null );
+	} else if ( args.length == 2 ) {
+	    atnVis = new ATNVisualizer( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: ATNVisualizer <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+
+    private void printGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Node n = (Node) nodes.nextElement( );
+	    n.printAllAttributes = true;
+
+	    System.out.println( n.getName( ) );
+
+	    Enumeration e = n.getAttributePairs( );
+	    while( e.hasMoreElements( ) ) {
+		System.out.println( e.nextElement( ) );
+	    }
+
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Edge e = (Edge) edges.nextElement( );
+	    e.printAllAttributes = true;
+
+	    System.out.println( e.getName( ) );
+
+	    Enumeration en = e.getAttributePairs( );
+	    while( en.hasMoreElements( ) ) {
+		System.out.println( en.nextElement( ) );
+	    }
+	}
+
+	System.out.println( "======================================================================" );
+
+	g.printSubgraph( new PrintWriter( System.err, true ) );
+    }
+
+
+    private Edge getEdgeBetween( Graph g, Node head, Node tail ) {
+	Enumeration edges = g.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/ATNVisualizer.java.tmp
===================================================================
--- fedd/abac-src/atnvis/src/ATNVisualizer.java.tmp	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/ATNVisualizer.java.tmp	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,525 @@
+package com.algomagic.atn.vis;
+import att.grappa.*;
+
+import java.util.Properties;
+import java.util.Enumeration;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+
+public class ATNVisualizer extends JFrame 
+    implements ATNVisualizerConstants, GrappaConstants {
+
+    private Properties _properties;
+    private GrappaPanel _grappaPanel;
+    private Graph _graph;
+
+    
+
+    public ATNVisualizer( String log1, String log2 ) {
+	initATNVisualizer( log1, log2 );
+    }
+
+
+    private void initATNVisualizer( String log1, String log2 ) {
+	loadProperties( );
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	SidePanel leftSide = new SidePanel( log1, LEFT_SIDE );
+	SidePanel rightSide = null;
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.X_AXIS ) );
+  	contentPane.add( leftSide );
+
+
+	if( log2 != null ) {
+	    rightSide = new SidePanel( log2, RIGHT_SIDE );
+	    contentPane.add( rightSide );
+	}
+
+
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+	show( );
+
+	leftSide.resetDividerLocations( );
+
+	if( log2 != null ) {
+	    rightSide.resetDividerLocations( );
+	}
+
+    }
+
+    private void hideGraph( Graph g ) {
+	Enumeration nodes = _graph.nodeElements( );
+	Enumeration edges = _graph.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+
+    }
+
+    private Graph loadGraph( String dotFile ) {
+	Parser parser = null;
+	try {
+	    parser = new Parser( new FileInputStream( dotFile ) );
+	    parser.parse( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	return parser.getGraph( );
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+    private void redrawAndPause( int millis ) {
+	_graph.resync( );
+	_graph.repaint( );
+	try { Thread.currentThread( ).sleep( millis ); }
+	catch( Exception e ) { }
+    }
+
+
+    private void setSolid( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+	e.setAttribute( STYLE_ATTR, "solid" );
+    }
+
+
+    private void setBold( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "bold" );
+	e.setAttribute( STYLE_ATTR, "bold" );
+    }
+
+    private void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+
+
+    private Edge getEdgeBetween( Node head, Node tail ) {
+	Enumeration edges = _graph.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	if( file.exists( ) ) {
+	    _properties = new Properties( );
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( FileNotFoundException fnfe ) {
+		_properties = getDefaultProperties( );
+	    } catch( IOException ioe ) {
+		_properties = getDefaultProperties( );
+	    }
+	} else {
+	    _properties = getDefaultProperties( );
+	}
+    }
+
+
+    private Properties getDefaultProperties( ) {
+	Properties p = new Properties( );
+	p.setProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT );
+	p.setProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT );
+	p.setProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT );
+
+	return p;
+    }
+
+
+    public static void main( String[] args ) {
+	ATNVisualizer atnVis = null;
+
+	if( args.length == 1 ) {
+	    atnVis = new ATNVisualizer( args[0], null );
+	} else if ( args.length == 2 ) {
+	    atnVis = new ATNVisualizer( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: ATNVisualizer <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+
+
+    private class SidePanel extends JPanel {
+	GrappaPanel _grappaPanel;
+	Graph _graph;
+
+	JPanel _listPanel;
+	JPanel _messagePanel;
+	JPanel _graphPanel;
+	JCheckBox _scaleButton;
+	
+	JSplitPane _top;
+	JSplitPane _complete;
+
+	int _side;
+	boolean _graphScaleToFit;
+	Dimension _unScaledDim;
+
+	public SidePanel( String transcriptFile, int side ) {
+	    super( );
+
+	    _side = side;
+
+	    _listPanel = new JPanel( new BorderLayout( ) );
+	    _messagePanel = new JPanel( new BorderLayout( ) );
+	    _graphPanel = new JPanel( new BorderLayout( ) );
+
+
+	    _messagePanel.setMaximumSize( new Dimension( 2000, 100 ) );
+
+
+
+// 	    _graphPanel.addComponentListener( new ComponentAdapter( ) {
+// 		    public void componentResized( ComponentEvent e ) {
+// 			if( _graphScaleToFit == true ) {
+// 			    setGraphToFit( e.getComponent( ).getSize( ) );
+// 			}
+// 		    }
+
+// 		});
+
+
+// 	    _scaleButton = new JCheckBox( "scale graph to fit" );
+// 	    _scaleButton.setSelected( true );
+// 	    _scaleButton.addItemListener( new ItemListener( ) {
+// 		    public void itemStateChanged( ItemEvent e ) {
+// 			if( e.getStateChange( ) == ItemEvent.DESELECTED ) {
+// 			    setGraphScaleToFit( false );
+// 			} else {
+// 			    setGraphScaleToFit( true );
+// 			}
+// 		    }
+// 		});
+	    
+
+	    
+	    setPanelBorder( _listPanel, "Creds and Policies" );
+	    setPanelBorder( _messagePanel, "Output Log" );
+	    setPanelBorder( _graphPanel, "Trust Negotiation Graph" );
+
+
+	    if( _side == LEFT_SIDE ) {
+		_top = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, 
+				       _listPanel, 
+				       _graphPanel );
+	    } else {
+		_top = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, 
+				       _graphPanel,
+				       _listPanel);
+		
+
+		_top.setResizeWeight( 1.0 );
+
+
+	    }
+
+	    _complete = new JSplitPane( JSplitPane.VERTICAL_SPLIT,
+					_top,
+					_messagePanel );
+
+	    _complete.setResizeWeight( 1.0 );
+
+
+	    _complete.addComponentListener( new ComponentAdapter( ) {
+		    public void componentResized( ComponentEvent e ) {
+			System.out.println( "resized: " + e.getComponent( ).getSize( ) );
+		    }
+
+		    public void componentMoved( ComponentEvent e ) {
+			System.out.println( "moved: " + e.getComponent( ).getSize( ) );
+		    }
+
+
+
+		});
+
+
+ 	    _graph = loadGraph( transcriptFile );
+ 	    formatGraph( _graph );
+
+
+ 	    _grappaPanel = new GrappaPanel( _graph );
+	    _grappaPanel.setScaleToFit( false );
+
+ 	    JScrollPane jsp = new JScrollPane( );
+ 	    jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	    jsp.getViewport( ).setBackground( Color.white );
+ 	    jsp.setViewportView( _grappaPanel );
+	
+	    _graphPanel.add( jsp, BorderLayout.CENTER );
+
+	    setLayout( new BorderLayout( ) );
+	    add( _complete, BorderLayout.CENTER );
+
+
+	    _top.setOneTouchExpandable( true );
+	    _complete.setOneTouchExpandable( true );
+	}
+
+
+	public void resetDividerLocations( ) {
+	    if( _side == LEFT_SIDE ) {
+		_top.setDividerLocation( 0.25 );
+	    } else {
+		_top.setDividerLocation( 0.75 );
+	    }
+	    _complete.setDividerLocation( 0.75 );
+
+	}
+
+	public void setGraphScaleToFit( boolean b ) {
+	    _graphScaleToFit = b;
+
+	    if( b == false ) {
+		setGraphToFit( _unScaledDim );
+	    } else {
+		setGraphToFit( _graphPanel.getSize( ) );
+	    }
+
+	}
+
+
+	public void setGraphToFit( Dimension d ) {
+
+	    d.setSize( d.getWidth( ) - 50, d.getHeight( ) - 50 );
+
+	    _grappaPanel.setScaleToSize( d );
+	    _graph.resync( );
+	    _graph.repaint( );
+
+	}
+
+
+    }
+
+
+
+    private void setPanelBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+
+
+
+
+    private void printGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Node n = (Node) nodes.nextElement( );
+	    n.printAllAttributes = true;
+
+	    System.out.println( n.getName( ) );
+
+	    Enumeration e = n.getAttributePairs( );
+	    while( e.hasMoreElements( ) ) {
+		System.out.println( e.nextElement( ) );
+	    }
+
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Edge e = (Edge) edges.nextElement( );
+	    e.printAllAttributes = true;
+
+	    System.out.println( e.getName( ) );
+
+	    Enumeration en = e.getAttributePairs( );
+	    while( en.hasMoreElements( ) ) {
+		System.out.println( en.nextElement( ) );
+	    }
+	}
+
+	System.out.println( "======================================================================" );
+
+	g.printSubgraph( new PrintWriter( System.err, true ) );
+    }
+
+
+
+    public void animate( ) {
+	Node a,b,c,d,e,f,g;
+
+	a = _graph.findNodeByName( "A" );
+	b = _graph.findNodeByName( "B" );
+	c = _graph.findNodeByName( "C" );
+	d = _graph.findNodeByName( "D" );
+	e = _graph.findNodeByName( "E" );
+	f = _graph.findNodeByName( "F" );
+	g = _graph.findNodeByName( "G" );
+
+
+	Edge ab, bc, cd, ce, ef, fg;
+
+	ab = getEdgeBetween( a,b );
+	bc = getEdgeBetween( b,c );
+	cd = getEdgeBetween( c,d );
+	ce = getEdgeBetween( c,e );
+	ef = getEdgeBetween( e,f );
+	fg = getEdgeBetween( f,g );
+	
+
+	while (true) {
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( a );
+	    redrawAndPause( 1000 );
+
+	    setBold( b );
+	    setBold( ab );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+
+	    setSolid( a );
+	    setSolid( b );
+	    setSolid( ab );
+
+	    // ----------------------------------------------------------------------
+
+	    redrawAndPause( 1000 );
+
+	    setBold( c );
+	    setBold( bc );
+
+	    redrawAndPause( 1000 );
+
+	    setBold( e );
+	    setBold( ce );
+
+	    redrawAndPause( 1000 );
+
+	    setBold( f );
+	    setBold( ef );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setSolid( c );
+	    setSolid( bc );
+	    setSolid( e );
+	    setSolid( ce );
+	    setSolid( f );
+	    setSolid( ef );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( g );
+	    setBold( fg );
+
+	    redrawAndPause( 1000 );
+	
+	    // ----------------------------------------------------------------------
+
+	    setSolid( g );
+	    setSolid( fg );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( d );
+	    setBold( cd );
+	
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setSolid( d );
+	    setSolid( cd );
+
+	    redrawAndPause( 2000 );
+
+	    // ----------------------------------------------------------------------
+
+	    hideGraph( _graph );
+
+	    redrawAndPause( 1000 );
+
+	}
+
+    }
+
+
+
+
+
+}
Index: fedd/abac-src/atnvis/src/ATNVisualizerConstants.java
===================================================================
--- fedd/abac-src/atnvis/src/ATNVisualizerConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/ATNVisualizerConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,120 @@
+package com.algomagic.atn.vis;
+
+import att.grappa.GrappaConstants;
+
+public interface ATNVisualizerConstants extends GrappaConstants {
+    public static final String SYSTEM_PREFIX = "atnvis.";
+
+    public static final String CONFIG_FILE_PROP = SYSTEM_PREFIX + "ConfigFile";
+    public static final String WINDOW_TITLE_PROP = SYSTEM_PREFIX + "window.Title";
+    public static final String WINDOW_HEIGHT_PROP = SYSTEM_PREFIX + "window.Height";
+    public static final String WINDOW_WIDTH_PROP = SYSTEM_PREFIX + "window.Width";
+
+    public static final String DELAY_PROP = SYSTEM_PREFIX + "defaultDelay";
+    public static final String LOOP_PROP = SYSTEM_PREFIX + "loop";
+
+
+    public static final String CONFIG_FILE_DEFAULT = "atnvis.properties";
+    public static final String WINDOW_TITLE_DEFAULT = "ATN Visualization";
+    public static final String WINDOW_HEIGHT_DEFAULT = "800";
+    public static final String WINDOW_WIDTH_DEFAULT = "600";
+
+    public static final String DELAY_DEFAULT = "500";
+    public static final String LOOP_DEFAULT = "true";
+
+    public static final int LEFT_SIDE = 0;
+    public static final int RIGHT_SIDE = 1;
+
+    public static final String OPPONENT_PROC = "Opponent";
+    public static final String VERIFIER_PROC = "Verifier";
+    public static final String FULLY_PROC = "Fully";
+    public static final String NOT_PROC = "Not";
+
+    public static final String SATISFIED = "True";
+    public static final String NOT_SATISFIED = "False";
+
+    public static final String STANDARD_TARGET = "StandardTarget";
+    public static final String INTERSECTION_TARGET = "IntersectionTarget";
+    public static final String LINKING_GOAL = "LinkingGoal";
+
+    public static final String IMPLICATION_EDGE = "Implication";
+    public static final String LINKING_MONITOR_EDGE = "LinkingMonitor";
+    public static final String LINKING_SOLUTION_EDGE = "LinkingSolution";
+    public static final String LINKING_IMPLICATION_EDGE = "LinkingImplication";
+    public static final String INTERSECTION_EDGE = "Intersection";
+    public static final String CONTROL_EDGE = "Control";
+
+    public static final String DEFAULT_NODE = SYSTEM_PREFIX + "node.Default.";
+    public static final String DEFAULT_EDGE = SYSTEM_PREFIX + "edge.Default.";
+
+
+    public static final String[] NODE_ATTRS = {
+	SHAPE_ATTR,
+	SIDES_ATTR,
+	PERIPHERIES_ATTR,
+	STYLE_ATTR,
+	COLOR_ATTR,
+	FONTNAME_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR };
+
+
+
+    public static final String[] NODE_ATTRS_PROP = {
+	"shape",
+	"sides",
+	"peripheries",
+	"style",
+	"color",
+	"fontname",
+	"fontcolor",
+	"fontsize",
+	"fontstyle" };
+
+    public static final boolean[] NODE_ATTRS_INT = {
+	false,
+	true,
+	true,
+	false,
+	false,
+	false,
+	false,
+	true,
+	false };
+
+
+    public static final String[] EDGE_ATTRS = {
+	STYLE_ATTR,
+	FONTNAME_ATTR,
+	COLOR_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR,
+	DIR_ATTR };
+
+    public static final String[] EDGE_ATTRS_PROP = {
+	"style",
+	"fontname",
+	"color",
+	"fontcolor",
+	"fontsize",
+	"fontstyle", 
+	"direction"  };
+
+
+    public static final boolean[] EDGE_ATTRS_INT = {
+	false,
+	false,
+	false,
+	false,
+	true,
+	false,
+	false };
+
+    
+
+
+
+
+}
Index: fedd/abac-src/atnvis/src/AbstractUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/AbstractUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/AbstractUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,18 @@
+package com.algomagic.atn;
+
+public abstract class AbstractUpdate implements Update {
+    protected int _side;
+    protected boolean _skip = false;
+    protected boolean _undo = false;
+
+    public int getSide( ) { return _side; }
+    public boolean getSkip( ) { return _skip; }
+    public void setSkip( boolean skip ) { _skip = skip; }
+    public boolean getUndo( ) { return _undo; }
+    public void setUndo( boolean undo ) { _undo = undo; }
+
+}
+
+
+
+
Index: fedd/abac-src/atnvis/src/BatchGraphUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/BatchGraphUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/BatchGraphUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,55 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class BatchGraphUpdate {
+
+    private List _updates;
+
+    public BatchGraphUpdate( List updates ) {
+	_updates = updates;
+    }
+
+    public BatchGraphUpdate( ) {
+	_updates = new ArrayList( );
+    }
+
+    public void add( ElementAttribute e ) {
+	_updates.add( e );
+    }
+
+    public boolean isEmpty( ) {
+	return _updates.isEmpty( );
+    }
+
+
+    public void apply( ) {
+	for( Iterator i = _updates.iterator( ); i.hasNext( ); ) {
+	    ElementAttribute e = (ElementAttribute)i.next( );
+// 	    System.out.println( e );
+
+	    e.apply( );
+	} 
+
+// 	System.out.println(  );
+// 	System.out.println(  );
+
+
+    }
+
+
+    public void undo( ) {
+	for( int i = _updates.size( )-1; i>=0; i-- ) {
+	    ElementAttribute e = (ElementAttribute)_updates.get(i);
+// 	    System.out.println( e );
+
+	    e.undo( );
+	} 
+
+// 	System.out.println(  );
+// 	System.out.println(  );
+
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/BatchUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/BatchUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/BatchUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,42 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class BatchUpdate {
+
+    private List _updates;
+
+    public BatchUpdate( List updates ) {
+	_updates = updates;
+    }
+
+    public BatchUpdate( ) {
+	_updates = new ArrayList( );
+    }
+
+    public void addElementAttribute( ElementAttribute e ) {
+	_updates.add( e );
+    }
+
+    public boolean isEmpty( ) {
+	return _updates.isEmpty( );
+    }
+
+
+    public void apply( ) {
+	for( Iterator i = _updates.iterator( ); i.hasNext( ); ) {
+	    ElementAttribute e = (ElementAttribute)i.next( );
+	    e.apply( );
+	} 
+    }
+
+
+    public void undo( ) {
+	for( Iterator i = _updates.iterator( ); i.hasNext( ); ) {
+	    ElementAttribute e = (ElementAttribute)i.next( );
+	    e.undo( );
+	} 
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/ClusterUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/ClusterUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/ClusterUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,113 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public class ClusterUpdate extends AbstractUpdate implements Update {
+    private int _cluster;
+    private boolean _start;
+    private boolean _local;
+
+    public ClusterUpdate( int cluster, boolean start, boolean local, int side ) {
+	_cluster = cluster;
+	_start = start;
+	_local = local;
+	_side = side;
+    }
+
+    public int initialize( VisualizationPanel visPanel ) {
+// 	Graph graph = visPanel.getGraph( );
+//  	Subgraph sg = graph.findSubgraphByName( _cluster );
+//  	if( sg == null ) {
+//  	    new Subgraph( graph, _cluster );
+//  	}
+
+	return 3;
+    }
+
+    public boolean apply( VisualizationPanel visPanel ) {
+
+// 	Subgraph sg = visPanel.getGraph( ).findSubgraphByName( _cluster );
+// 	if( sg == null ) {
+// 	    return;
+// 	}
+
+	
+// 	Subgraph current = visPanel.getCurrentCluster( );
+// 	if( current != null && _start ) {
+// 	    hide( current );
+// 	}
+
+// 	visPanel.setCurrentCluster( sg );
+	if( _start && _local ) {
+// 	    System.out.println( "raising local tab" );
+	    visPanel.setRaised( _local );
+
+	    visPanel.setLocal( true );
+	} else {
+	    visPanel.setLocal( false );
+	}
+
+
+// 	if( _start && _local ) {
+// 	    hide( sg );
+// 	} 
+	
+// 	if( _start && !_local ) {
+// 	    show( sg );
+// 	} 
+
+// 	if( !_start ) {
+// 	    show( sg );
+// 	}
+
+	return true;
+
+    }
+
+
+    public void undo( VisualizationPanel visPanel ) {
+	if( _start && _local ) {
+	    visPanel.setLocal( false );
+	} else if( !_start && _local ) {
+	    visPanel.setLocal( true );
+	} else if( _start && !_local ) {
+	    visPanel.setLocal( true );
+	} else {
+	    visPanel.setLocal( false );
+	}
+
+    }
+
+
+
+//     private void show( Subgraph sg ) {
+// 	sg.setAttribute( "style", "solid" );
+// 	sg.setAttribute( "color", "black" );
+//     }
+
+//     private void hide( Subgraph sg ) {
+// 	sg.setAttribute( "style", "dotted" );
+// 	sg.setAttribute( "color", "whitesmoke" );
+//     }
+
+    public int getCluster( ) {
+	return _cluster;
+    }
+
+
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+
+    public boolean getStart( ) {
+	return _start;
+    }
+
+    public Element getElement( VisualizationPanel visPanel ) {
+	throw new RuntimeException( );
+    }
+    
+
+}
Index: fedd/abac-src/atnvis/src/ControlPanel.java
===================================================================
--- fedd/abac-src/atnvis/src/ControlPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/ControlPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,199 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class ControlPanel 
+    extends JPanel 
+    implements ActionListener, VisualizationConstants
+{
+
+    JButton _play, _pause, _stepForward, _stepBack, _rewind, _fastForward, _stop;
+    InternalObservable _observable;
+    Visualization _vis;
+
+
+    public ControlPanel( Properties properties, Visualization vis ) {
+	super( );
+
+	_vis = vis;
+	_observable = new InternalObservable( );
+	Class clazz = this.getClass( );
+
+	_play = new JButton( new ImageIcon( clazz.getResource( "/resources/Play24.gif" ), "play" ) );
+	_play.setActionCommand( "play" );
+	_play.addActionListener( this );
+	_play.setEnabled( true );
+
+	_pause = new JButton( new ImageIcon( clazz.getResource( "/resources/Pause24.gif" ), "pause" ) );
+	_pause.setActionCommand( "pause" );
+	_pause.addActionListener( this );
+	_pause.setEnabled( false );
+
+	_stepForward = new JButton( new ImageIcon( clazz.getResource( "/resources/StepForward24.gif" ), "step forward" ) );
+	_stepForward.setActionCommand( "stepf" );
+	_stepForward.addActionListener( this );
+	_stepForward.setEnabled( true );
+	_stepForward.setMnemonic( 70 );
+
+
+	_stepBack = new JButton( new ImageIcon( clazz.getResource( "/resources/StepBack24.gif" ), "step back" ) );
+	_stepBack.setActionCommand( "stepb" );
+	_stepBack.addActionListener( this );
+	_stepBack.setEnabled( true );
+	_stepBack.setMnemonic( 66 );
+
+
+	_rewind = new JButton( new ImageIcon( clazz.getResource( "/resources/Rewind24.gif" ), "rewind" ) );
+	_rewind.setActionCommand( "rewind" );
+	_rewind.addActionListener( this );
+	_rewind.setEnabled( true );
+	
+
+
+	_fastForward = new JButton( new ImageIcon( clazz.getResource( "/resources/FastForward24.gif" ), "fast forward" ) );
+	_fastForward.setActionCommand( "ff" );
+	_fastForward.addActionListener( this );
+	_fastForward.setEnabled( true );
+
+
+	setStyle( _play );
+	setStyle( _pause );
+	setStyle( _stepForward );
+	setStyle( _stepBack );
+	setStyle( _rewind );
+	setStyle( _fastForward );
+
+	setLayout( new BoxLayout( this, BoxLayout.X_AXIS ) );
+	add( _rewind );
+	add( _stepBack );
+	add( _play );
+	add( _pause );
+	add( _stepForward );
+	add( _fastForward );
+
+	JCheckBox loop = 
+	    new JCheckBox( "loop", (new Boolean( properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( ) );
+
+	loop.addItemListener( new ItemListener( ) {
+		public void itemStateChanged( ItemEvent e ) {
+		    int s = e.getStateChange( );
+		    Boolean state = Boolean.TRUE;
+
+		    if( s == ItemEvent.DESELECTED ) {
+			state = Boolean.FALSE;
+		    }
+			
+		    _observable.notify( state );
+
+		}
+	    } );
+
+
+	add( Box.createHorizontalStrut( 10 ) );
+	add( loop );
+
+
+	JCheckBox raise = 
+	    new JCheckBox( "auto raise", true );
+	raise.addItemListener( new ItemListener( ) {
+
+		public void itemStateChanged( ItemEvent e ) {
+		    int s = e.getStateChange( );
+		    boolean state = true;
+
+		    if( s == ItemEvent.DESELECTED ) {
+			state = false;
+		    }
+		    
+		    _vis.setAutoRaise( state );
+		}
+
+
+
+	    } );
+
+
+	add( Box.createHorizontalStrut( 10 ) );
+	add( raise );
+
+
+
+	JSpinner spinner = 
+	    new JSpinner( new SpinnerNumberModel( Integer.parseInt( properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) ), 
+						  0, 
+						  5000, 
+						  100 ) );
+
+
+	JLabel spinnerLabel = new JLabel( "delay (msec)" );
+
+	spinner.addChangeListener( new ChangeListener( ) {
+		public void stateChanged( ChangeEvent e ) {
+		    _observable.notify( e.getSource( ) );
+		}
+	    } );
+
+
+	add( spinner );
+	add( Box.createHorizontalStrut( 5 ) );
+	add( spinnerLabel );
+
+
+	PanelHelper.setBorder( this, "Controls" );
+    }
+
+
+    public void addObserver( Observer o ) {
+	_observable.addObserver( o );
+    }
+
+
+    private void setStyle( JButton b ) {
+	b.setMinimumSize( new Dimension( 24, 24 ) );
+	b.setMaximumSize( new Dimension( 24, 24 ) );
+	b.setPreferredSize( new Dimension( 24, 24 ) );
+	    
+	b.setBorderPainted( false );
+    }
+
+    public void actionPerformed( ActionEvent e ) {
+	String cmd = e.getActionCommand( );
+	if( cmd.equals( "play" ) ) {
+	    _stepForward.setEnabled( false );
+	    _stepBack.setEnabled( false );
+	    _rewind.setEnabled( false );
+	    _fastForward.setEnabled( false );
+	    _play.setEnabled( false );
+	    _pause.setEnabled( true );
+	}
+
+	else if( cmd.equals( "pause" ) ) {
+	    _stepForward.setEnabled( true );
+	    _stepBack.setEnabled( true );
+	    _rewind.setEnabled( true );
+	    _fastForward.setEnabled( true );
+	    _play.setEnabled( true );
+	    _pause.setEnabled( false );
+	}
+
+
+	_observable.notify( e.getActionCommand( ) );
+    }
+
+
+    private class InternalObservable extends Observable {
+	public void notify( Object arg ) {
+	    setChanged( );
+	    notifyObservers( arg );
+	}
+    }
+
+}
+
Index: fedd/abac-src/atnvis/src/EdgeUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/EdgeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/EdgeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,146 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import att.grappa.*;
+
+public class EdgeUpdate 
+    extends AbstractUpdate 
+    implements Update, VisualizationConstants
+{
+    private String _parentNodeName;
+    private NodeUpdate _childNode;
+    private String _type;
+    private Collection _evidence;
+    private boolean _local;
+
+    public EdgeUpdate( String parentNodeName,
+		       NodeUpdate childNode,
+		       String type,
+		       boolean local,
+		       Collection evidence,
+		       int side ) {
+	_parentNodeName = parentNodeName;
+	_childNode = childNode;
+	_type = type;
+	_local = local;
+	_evidence = evidence;
+	_side = side;
+    }
+
+    public int initialize( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+
+	_childNode.initialize( visPanel );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	if( n1 != null && n2 != null ) {
+	    new Edge( graph, n1, n2 );
+	} else {
+	    if( n1 == null && n1 == null ) {
+		throw new RuntimeException( _parentNodeName + " === " + _childNode.getName( ) );
+	    } else if( n1 == null ) {
+		throw new RuntimeException( _parentNodeName );
+	    } else if( n2 == null ) {
+		throw new RuntimeException( _childNode.getName( ) );
+	    }
+	}
+
+	if( _local ) {
+	    visPanel.addCredentials( _evidence, _local );
+	}
+	    
+	return 3;
+    }
+
+
+    public Collection getEvidence( ) {
+	return _evidence;
+    }
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+    public String getType( ) {
+	return _type;
+    }
+
+
+    public boolean apply( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	Edge e = getEdgeBetween( graph, n1, n2 );
+	visPanel.setEdgeProperties( e, _type, _local );
+
+	visPanel.clearSelection( );
+	
+	_childNode.setNew( );
+	_childNode.apply( visPanel );
+
+	if( _local == false ) {
+	    visPanel.addCredentials( _evidence, _local );
+	}
+
+	visPanel.highlightCredentials( _evidence, _local );
+
+	return true;
+    }
+
+    public void undo( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	Edge e = getEdgeBetween( graph, n1, n2 );
+	_childNode.undo( visPanel );
+
+
+	if( visPanel.getLocal( ) == false ) {
+	    visPanel.setShadow( e );
+	} else {
+	    visPanel.setInvis( e );
+	}
+	
+    }
+
+
+    public Element getElement( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	return getEdgeBetween( graph, n1, n2 );
+    }
+
+    public Node getChild( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	return graph.findNodeByName( _childNode.getName( ) );
+    }
+
+    public String getChildName( ) {
+	return _childNode.getName( );
+    }
+
+
+
+    private Edge getEdgeBetween( Graph g, Node head, Node tail ) {
+	Enumeration edges = head.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+}
+
Index: fedd/abac-src/atnvis/src/ElementAttribute.java
===================================================================
--- fedd/abac-src/atnvis/src/ElementAttribute.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/ElementAttribute.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,31 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public class ElementAttribute {
+    private Element _e;
+    private String _attr;
+    private Object _value;
+    private Object _undoValue;
+
+    public ElementAttribute( Element e, String attr, Object value, Object undoValue ) {
+	_e = e;
+	_attr = attr;
+	_value = value;
+	_undoValue = undoValue;
+    }
+
+    public void apply( ) {
+	_e.setAttribute( _attr, _value );
+    }
+	
+    public void undo( ) {
+	_e.setAttribute( _attr, _undoValue );
+    }
+
+
+    public String toString( ) {
+	return _e + " : " + _attr + " : " + _value + " : " + _undoValue;
+    }
+
+}
Index: fedd/abac-src/atnvis/src/LogParser.java
===================================================================
--- fedd/abac-src/atnvis/src/LogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/LogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,10 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+
+public interface LogParser {
+
+    public List parse( Visualization vis, String log1, String log2 );
+
+}
Index: fedd/abac-src/atnvis/src/META-INF/MANIFEST.MF
===================================================================
--- fedd/abac-src/atnvis/src/META-INF/MANIFEST.MF	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/META-INF/MANIFEST.MF	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Main-Class: com.algomagic.atn.Visualization
+Created-By: Ant 1.4.1
+Class-Path: grappa.jar
+
Index: fedd/abac-src/atnvis/src/NodeState.java
===================================================================
--- fedd/abac-src/atnvis/src/NodeState.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/NodeState.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,150 @@
+package com.algomagic.atn;
+
+public class NodeState implements VisualizationConstants {
+    private String _satisfied;
+    private boolean _opponentProcessed;
+    private boolean _verifierProcessed;
+    private boolean _hidden;
+    private boolean _bolded;
+
+    private String _name;
+    private String _type;
+
+    public NodeState( NodeState ns ) {
+	_name = ns.getName( );
+	_satisfied = ns.getSatisfied( );
+	_type = ns.getType( );
+	_hidden = ns.getHidden( );
+	_bolded = ns.getBolded( );
+    }
+
+
+    public NodeState( String name, String type ) {
+	_name = name;
+	_type = type;
+	
+	_satisfied = UNKNOWN;
+	_opponentProcessed = false;
+	_verifierProcessed = false;
+	_hidden = true;
+	_bolded = false;
+    }
+
+
+    public int updateState( NodeUpdate update ) {
+	_hidden = false;
+
+// 	if( _satisfied.equals( update.getSatisfied( ) ) ) {
+// 	    return false;
+// 	}
+
+	int s = setSatisfied( update.getSatisfied( ) );
+	int p = setProcessed( update.getProcessed( ) );
+
+	return s+p;
+    }
+
+    public int setSatisfied( String state ) {
+	int ret = 0;
+
+	if( _satisfied.equals( SATISFIED ) ) {
+	    return 0;
+	}
+	
+	if( state == null ) {
+	    _satisfied = UNKNOWN;
+	}
+
+	if( _satisfied.toLowerCase( ).equals( state.toLowerCase( ) ) ) {
+	    return ret;
+	}
+
+	_satisfied = state;
+	return 2;
+    }
+
+    public int setProcessed( String state ) {
+	int ret = 0;
+
+	if( state.toLowerCase( ).equals( VERIFIER_PROC.toLowerCase( ) ) ) {
+	    if( _verifierProcessed == false ) {
+		ret = 1;
+	    }
+
+	    _verifierProcessed = true;
+	} else if ( state.toLowerCase( ).equals( OPPONENT_PROC.toLowerCase( ) ) ) {
+	    if( _opponentProcessed == false ) {
+		ret = 1;
+	    }
+
+	    _opponentProcessed = true;
+	} else if ( state.toLowerCase( ).equals( FULLY_PROC.toLowerCase( ) ) ) {
+	    if( _opponentProcessed == false || _verifierProcessed == false ) {
+		ret = 1;
+	    }
+
+	    _opponentProcessed = true;
+	    _verifierProcessed = true;
+	}
+
+	return ret;
+    }
+
+    public String getSatisfied( ) { 
+	return _satisfied; 
+    }
+
+    public String getProcessed( ) {
+	if( _opponentProcessed && _verifierProcessed ) {
+	    return FULLY_PROC;
+	}
+	
+	if( _opponentProcessed ) {
+	    return OPPONENT_PROC;
+	}
+
+	if( _verifierProcessed ) {
+	    return VERIFIER_PROC;
+	}
+
+	return NOT_PROC;
+    }
+
+    public void setHidden( boolean state ) {
+	_hidden = state;
+    }
+
+    public boolean getHidden( ) {
+	return _hidden;
+    }
+
+
+    public String getType( ) {
+	return _type;
+    }
+
+
+    public String getName( ) {
+	return _name;
+    }
+
+    public void setBolded( boolean state ) {
+	_bolded = state;
+    }
+
+    public boolean getBolded( ) {
+	return _bolded;
+    }
+
+
+    public void clearState( ) {
+	_satisfied = UNKNOWN;
+	_opponentProcessed = false;
+	_verifierProcessed = false;
+	_hidden = true;
+	_bolded = false;
+    }
+
+
+}
+
Index: fedd/abac-src/atnvis/src/NodeUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/NodeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/NodeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,130 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+
+public class NodeUpdate 
+    extends AbstractUpdate 
+    implements Update, VisualizationConstants 
+{
+    private String _name;
+    private String _type;
+    private String _cluster;
+
+    private String _satisfied;
+    private String _processed;
+
+    private boolean _local;
+
+    private NodeState _oldState;
+    private boolean _newNode;
+
+    public NodeUpdate( String name, 
+		       String type,
+		       String cluster,
+		       String satisfied,
+		       String processed,
+		       int side,
+		       boolean local ) {
+	_name = name;
+	_type = type;
+	_cluster = cluster;
+	_satisfied = satisfied;
+	_processed = processed;
+	_side = side;
+	_local = local;
+	_newNode = false;
+    }
+
+    public String toString( ) {
+	return "NodeUpdate: " + _name + " " + _type + " " + _cluster + " " + _satisfied + " " + _processed;
+    }
+
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+    public int initialize( VisualizationPanel visPanel ) {
+	Graph g = visPanel.getGraph( );
+
+	Node n = g.findNodeByName( _name );
+	boolean newNode;
+	int changed;
+
+	if( n == null ) {
+	    new Node( g, _name );
+	    NodeState ns = new NodeState( _name, _type );
+	    changed = ns.updateState( this );
+
+	    newNode = visPanel.addNodeState( ns );
+	    _newNode = true;
+	    return 3;
+
+	} else {
+
+	    NodeState ns = visPanel.getNodeState( _name );
+	    changed = ns.updateState( this );
+
+	    return changed;
+	}
+
+    }
+
+    public Element getElement( VisualizationPanel visPanel ) {
+	Graph g = visPanel.getGraph( );
+	return g.findNodeByName( _name );
+    }
+
+    public boolean apply( VisualizationPanel visPanel ) {
+	Graph g = visPanel.getGraph( );
+	Node n = g.findNodeByName( _name );
+	if( n != null ) {
+	    NodeState ns = visPanel.getNodeState( _name );
+	    _oldState = new NodeState( ns );
+
+	    ns.updateState( this );
+	    visPanel.setNodeProperties( n, ns, _local, _newNode );
+	    return true;
+	}
+	return false;
+    }
+
+    public void undo( VisualizationPanel visPanel ) {
+	if( _oldState == null ) {
+	    throw new RuntimeException( );
+	}
+	
+	Graph g = visPanel.getGraph( );
+	Node n = g.findNodeByName( _name );
+
+	if( n == null ) {
+	    throw new RuntimeException( );
+	}
+
+	NodeState ns = visPanel.getNodeState( _name );
+	ns.setHidden( _oldState.getHidden( ) );
+	ns.setSatisfied( _oldState.getSatisfied( ) );
+
+	visPanel.setNodeProperties( n, _oldState, _local, _newNode );
+
+    }
+
+    public String getName( ) {
+	return _name;
+    }
+
+    public String getSatisfied( ) {
+	return _satisfied;
+    }
+
+    public String getProcessed( ) {
+	return _processed;
+    }
+
+    public void setNew( ) {
+	_newNode = true;
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/NullParser.java
===================================================================
--- fedd/abac-src/atnvis/src/NullParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/NullParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,10 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class NullParser implements LogParser {
+    public List parse( Visualization vis, String log1, String log2 ) {
+	return new ArrayList( );
+    }
+}
+
Index: fedd/abac-src/atnvis/src/PanelHelper.java
===================================================================
--- fedd/abac-src/atnvis/src/PanelHelper.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/PanelHelper.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,19 @@
+package com.algomagic.atn;
+
+import javax.swing.*;
+import javax.swing.border.*;
+
+
+public class PanelHelper {
+
+    public static void setBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+}
Index: fedd/abac-src/atnvis/src/PanelUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/PanelUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/PanelUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,79 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class PanelUpdate {
+    BatchGraphUpdate _graphUpdate;
+    int _tab;
+    int _side;
+    Collection _evidence;
+    boolean _undo;
+    boolean _raise;
+    boolean _add;
+    boolean _hl;
+
+
+    public PanelUpdate( BatchGraphUpdate graphUpdate, int side, int tab, Collection evidence, boolean raise, boolean add, boolean hl ) {
+	_graphUpdate = graphUpdate;
+	_tab = tab;
+	_evidence = evidence;
+	_side = side;
+	_undo = false;
+	_raise = raise;
+	_add = add;
+	_hl = hl;
+    } 
+
+    public void apply( VisualizationPanel visPanel ) {
+	if( _undo ) {
+	    _graphUpdate.undo( );
+	    if( _evidence != null && _add ) {
+		visPanel.removeCredentials( _evidence, _tab );
+	    }
+
+	} else {
+// 	    if( _raise ) {
+// 		visPanel.setRaised( _tab );
+// 	    }
+
+	    visPanel.setRaised( _tab );
+
+	    _graphUpdate.apply( );
+
+	    if( _evidence != null && _hl ) {
+		visPanel.highlightCredentials( _evidence, _tab );
+	    }
+
+	    if( _evidence != null && _add ) {
+		visPanel.addCredentials( _evidence, _tab );
+	    }
+	    
+
+// 	    if( _evidence != null && _tab >= 0 ) {
+// // 		if( _tab != 0 ) {
+// // 		    visPanel.addCredentials( _evidence, _tab );
+// // 		}
+
+// 		visPanel.highlightCredentials( _evidence, _tab );
+// 	    }
+
+
+	}
+    }
+
+    public void setUndo( boolean undo ) {
+	_undo = undo;
+    }
+
+    public int getSide( ) {
+	return _side;
+    }
+
+
+    public boolean isEmpty( ) {
+	return _graphUpdate.isEmpty( );
+    }
+
+
+
+}
Index: fedd/abac-src/atnvis/src/PlayBackController.java
===================================================================
--- fedd/abac-src/atnvis/src/PlayBackController.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/PlayBackController.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,162 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import javax.swing.*;
+
+public class PlayBackController 
+    extends Observable 
+    implements Observer, VisualizationConstants 
+
+{
+    private int _delay;
+    private boolean _loop;
+    private List _updates;
+    private int _index = 0;
+    private boolean _clear = true;
+    private boolean _playing = false;
+
+    public PlayBackController( List updates, Properties properties ) {
+	_delay = Integer.parseInt( properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) );
+	_loop = (new Boolean( properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( );
+	_updates = updates;
+    }
+
+    public void update( Observable o, Object arg ) {
+	if( arg instanceof String ) {
+	    String cmd = (String)arg;
+
+	    if( cmd.equals( "play" ) ) {
+		_playing = true;
+		new Thread( new PlayThread( ) ).start( );
+	    } else if( cmd.equals( "pause" ) ) {
+		_playing = false;
+	    } else if( cmd.equals( "stepf" ) ) {
+		stepf( );
+	    } else if( cmd.equals( "stepb" ) ) {
+		stepb( );
+	    } else if( cmd.equals( "ff" ) ) {
+		ff( );
+	    } else if( cmd.equals( "rewind" ) ) {
+		rewind( );
+	    }
+
+	} else if( arg instanceof JSpinner ) {
+	    SpinnerNumberModel snm = (SpinnerNumberModel)((JSpinner)arg).getModel( );
+	    _delay = snm.getNumber( ).intValue( );
+	} else if (arg instanceof Boolean ) {
+	    _loop = ((Boolean)arg).booleanValue( );
+	}
+    }
+
+
+    public int getIndex( ) {
+	return _index;
+    }
+
+
+    private synchronized void stepf( ) {
+	if( _index == _updates.size( ) ) {
+	    _index = 0;
+	    if( _playing == true && _loop == false ) {
+		_playing = false;
+	    }
+	}
+
+
+	if( _index == 0 && _clear == false ) {
+	    _clear = true;
+
+	    setChanged( );
+	    notifyObservers( "CLEAR" );
+
+	    return;
+	}
+
+	_clear = false;
+
+	PanelUpdate u = (PanelUpdate)_updates.get(_index);
+	u.setUndo( false );
+
+	setChanged( );
+	notifyObservers( u );
+	_index++;
+
+    }
+
+    private synchronized void stepb( ) {
+// 	System.out.println( "steck back " + _index );
+// 	System.out.print( "stepb: " + _index + " " );
+
+
+	if( _index == 0 ) {
+	    ff( );
+// 	    System.out.println(  _index );
+
+	    return;
+	}
+	_index--;
+
+	PanelUpdate u = (PanelUpdate)_updates.get( _index );
+	u.setUndo( true );
+
+ 	setChanged( );
+ 	notifyObservers( u );
+// 	System.out.println(  _index );
+	
+	if( _index == 0 ) {
+	    _clear = true;
+	}
+
+    }
+	
+    private synchronized void ff( ) {
+	int i;
+
+
+// 	System.out.print( "ff: " + _index + " " );
+
+	for( i=_index; i < _updates.size( ); i++ ) {
+	    setChanged( );
+	    PanelUpdate u = (PanelUpdate)_updates.get(i);
+	    u.setUndo( false );
+
+	    _index=i;
+	    notifyObservers( u );
+	    
+// 	    System.out.println( "here" );
+
+	}
+
+	_clear = false;
+	_index=i;
+
+// 	System.out.println(  _index );
+    }
+
+
+    private synchronized void rewind( ) {
+	_index = 0;
+	_clear = true;
+	
+	setChanged( );
+	notifyObservers( "CLEAR" );
+    }
+
+
+    private class PlayThread implements Runnable {
+	public void run( ) {
+	    while( _playing ) {
+		try {
+		    stepf( );
+		    Thread.currentThread( ).sleep( _delay );
+		} catch( InterruptedException ie ) {
+		    throw new RuntimeException( ie );
+		}
+	    }
+		
+	}
+    }
+
+}
+
+
Index: fedd/abac-src/atnvis/src/ProgressPanel.java
===================================================================
--- fedd/abac-src/atnvis/src/ProgressPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/ProgressPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,35 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import java.awt.*;
+import javax.swing.*;
+
+
+public class ProgressPanel 
+    extends JPanel 
+    implements Observer 
+{
+    JProgressBar _progress;
+
+    public ProgressPanel( ) {
+	super( );
+	setLayout( new BorderLayout( ) );
+
+	_progress = new JProgressBar( 0, 1 );
+	_progress.setValue( 0 );
+	_progress.setStringPainted( true );
+
+	add( _progress, BorderLayout.CENTER );
+
+	PanelHelper.setBorder( this, "Negotiation Progress" );
+    }
+
+    public void setMax( int n ) {
+	_progress.setMaximum( n-1 );
+    }
+
+    public void update( Observable o, Object arg ) {
+	PlayBackController pbc = (PlayBackController)o;
+	_progress.setValue( pbc.getIndex( ) );
+    }
+}
Index: fedd/abac-src/atnvis/src/PropertyLogParser.java
===================================================================
--- fedd/abac-src/atnvis/src/PropertyLogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/PropertyLogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,376 @@
+package com.algomagic.atn;
+
+import java.io.*;
+import java.util.*;
+
+public class PropertyLogParser 
+    implements LogParser, VisualizationConstants 
+{
+
+    private Properties _log;
+    private List _updates;
+    private Visualization _vis;
+
+
+    public PropertyLogParser( ) {
+
+    }
+
+    public List parse( Visualization vis, String log1, String log2 ) {
+	_vis = vis;
+	List updates = null;
+	List updates1 = parse( log1, LEFT_SIDE );
+	List updates2 = null;
+
+	if( log2 != null ) {
+	    updates2 = parse( log2, RIGHT_SIDE );
+	    return interleave( updates1, updates2 );
+	} 
+
+	return updates1;
+    }
+
+
+    private List interleave( List updates1, List updates2 ) {
+	List updates = new ArrayList( );
+	Iterator first, second;
+
+
+	ClusterUpdate u = (ClusterUpdate) updates1.get( 0 );
+	if( u.getLocal( ) ) {
+	    first = updates1.iterator( );
+	    second = updates2.iterator( );
+	} else {
+	    first = updates2.iterator( );
+	    second = updates1.iterator( );
+	}
+
+
+	Object o;
+	ClusterUpdate c;
+
+	while( first.hasNext( ) ) {
+	    o = first.next( );
+
+	    updates.add( o );
+
+	    if( o instanceof ClusterUpdate ) {
+		c = (ClusterUpdate)o;
+		if( ! c.getStart( ) ) {
+		    break;
+		}
+
+	    }
+	}
+
+	Iterator tmp = first;
+	first = second;
+	second = tmp;
+
+
+	while( first.hasNext( ) && second.hasNext( ) ) {
+
+	    while( first.hasNext( ) ) {
+		o = first.next( );
+
+		updates.add( o );
+
+		if( o instanceof ClusterUpdate ) {
+		    c = (ClusterUpdate)o;
+		    if( ! c.getStart( ) && c.getLocal( ) ) {
+			break;
+		    }
+
+		}
+	    }
+
+	    while( second.hasNext( ) ) {
+		o = second.next( );
+
+		updates.add( o );
+
+		if( o instanceof ClusterUpdate ) {
+		    c = (ClusterUpdate)o;
+		    if( ! c.getStart( ) && c.getLocal( ) ) {
+			break;
+		    }
+
+		}
+	    }
+
+	}
+
+	if( first.hasNext( ) ) {
+	    while( first.hasNext( ) ) {
+		updates.add( first.next( ) );
+	    }
+	} else if( second.hasNext( ) ) {
+	    while( second.hasNext( ) ) {
+		updates.add( second.next( ) );
+	    }
+	}
+
+	for( int i = 0; i<(updates.size( )-1); i++ ) {
+	    Update u1 = (Update)updates.get( i );
+	    Update u2 = (Update)updates.get( i+1 );
+
+	    if( u1 instanceof ClusterUpdate && u2 instanceof ClusterUpdate ) {
+		ClusterUpdate c1 = (ClusterUpdate)u1;
+		ClusterUpdate c2 = (ClusterUpdate)u2;
+
+		if( (!c1.getStart( ) && c1.getLocal( )) && (c2.getStart( ) && !c2.getLocal( )) ) {
+		    updates.set( i, c2 );
+		    updates.set( i+1, c1 );
+		}
+	    }
+	}
+
+
+
+	return updates;
+    }
+
+
+    private List parse( String log, int side ) {
+	_log = new Properties( );
+	_updates = new ArrayList( );
+	
+	File f = new File( log );
+	if( f.exists( ) ) {
+	    try {
+		_log.load( new FileInputStream( f ) );
+	    } catch( Exception e ) { }
+	}
+	
+
+	
+	_vis.setName( _log.getProperty( "subject" ), side );
+
+	Collection c = new ArrayList( );
+	for( int i=1; _log.containsKey( "policy." + i ); i++ ) {
+	    c.add( _log.getProperty( "policy." + i ) );
+	}
+
+	_vis.setPolicies( c, side );
+
+
+	boolean init = false;
+
+
+	for( int i=1; _log.containsKey( getKey(i) ) || i==1; i++ ) {
+	    String location = _log.getProperty( getKey(i) );
+	    boolean local = true;
+	    int index = i;
+
+
+
+	    if( !_log.containsKey( getKey( i, 1 ) ) ) {
+		continue;
+	    }
+
+
+	    if( location.equals( "remote" ) ) {
+		local = false;
+		
+		if( !init ) {
+
+		    _updates.add( new ClusterUpdate( i,
+						     true,
+						     local,
+						     side ) );
+		}
+	    } else if( location.equals( "local" ) ) {
+		local = true;
+
+		if( !init ) {
+		    _updates.add( new ClusterUpdate( i,
+						     true,
+						     local,
+						     side ) );
+		}
+	    } else if( location.equals( "init" ) ) {
+		if( !_log.containsKey( getKey( 1, 1 ) ) ) {
+		    continue;
+		} else {
+		    init = true;
+		    local = true;
+		    index = 2;
+ 		    _updates.add( new ClusterUpdate( index,
+						     true,
+						     local,
+						     side ) );
+		}
+	    }
+
+
+	    for( int j=1; _log.containsKey( getKey(i,j) ); j++ ) {
+		String type = _log.getProperty( getKey(i,j) );
+		
+		if( type.equals( "edge" ) ) {
+		    parseEdge( i, j, local, side, index );
+		} else if( type.equals( "node" ) ) {
+		    parseNode( i, j, local, side, index );
+		}
+	    }
+
+
+	    if( index==i) {
+
+		if( location.equals( "remote" ) ) {
+		    _updates.add( new ClusterUpdate( i,
+						     false,
+						     local,
+						     side ) );
+		} else {
+		    _updates.add( new ClusterUpdate( i,
+						     false,
+						     local,
+						     side ) );
+		}
+		
+		
+	    }
+
+
+	    init = false;
+
+	}
+
+
+	return _updates;
+    }
+
+    private void parseNode( int i, int j, boolean local, int side, int c ) {
+	String prefix = getPrefix(i,j);
+	String name, type, cluster, satisfied, processed;
+	name = _log.getProperty( prefix + "name" );
+	if( name == null ) {
+	    throw new RuntimeException( prefix );
+	}
+	
+	type = _log.getProperty( prefix + "nodeType" );
+	cluster = getCluster(c);
+	satisfied = _log.getProperty( prefix + "satisfied" );
+	processed = _log.getProperty( prefix + "processing" );
+
+// 	if( processed == null ) {
+// 	    processed = NOT_PROC;
+// 	} else if( processed.equals( "verifier" ) ) {
+// 	    processed = VERIFIER_PROC;
+// 	} else if( processed.equals( "opponent" ) ) {
+// 	    processed = OPPONENT_PROC;
+// 	}
+
+// 	if( satisfied == null ) {
+//   	    satisfied = UNKNOWN;
+// 	}
+
+
+	if( processed == null ) {
+	    processed = NOT_PROC;
+	} else if( processed.toLowerCase( ).equals( "verifier" ) ) {
+	    processed = VERIFIER_PROC;
+	} else if( processed.toLowerCase( ).equals( "opponent" ) ) {
+	    processed = OPPONENT_PROC;
+	} else if ( processed.toLowerCase( ).equals( "fully" ) ) {
+	    processed = FULLY_PROC;
+	}
+
+	if( satisfied == null ) {
+	    satisfied = UNKNOWN;
+	} else if( satisfied.toLowerCase( ).equals( "satisfied" ) ) {
+	    satisfied = SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "unsatisfied" ) ) {
+	    satisfied = NOT_SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "unknown" ) ) {
+	    satisfied = UNKNOWN;
+	}
+
+	NodeUpdate nu = new NodeUpdate( name, type, cluster, satisfied, processed, side, local );
+	_updates.add( nu );
+    }
+
+
+    private void parseEdge( int i, int j, boolean local, int side, int c ) {
+	String prefix = getPrefix(i,j);
+	String type, parentName, childName, childType, processed, satisfied;
+
+	type = _log.getProperty( prefix + "edgeType" );
+	parentName = _log.getProperty( prefix + "parentName" );
+	childName = _log.getProperty( prefix + "childName" );
+	childType = _log.getProperty( prefix + "childType" );
+	processed = _log.getProperty( prefix + "childProcessing" );
+	satisfied = _log.getProperty( prefix + "childSatisfied" );
+
+	if( type == null || parentName == null || childName == null ) {
+	    throw new RuntimeException( prefix );
+	}
+
+
+	if( childType == null ) {
+	    childType = "StandardTarget";
+	}
+
+
+	if( processed == null ) {
+	    processed = NOT_PROC;
+	} else if( processed.toLowerCase( ).equals( "verifier" ) ) {
+	    processed = VERIFIER_PROC;
+	} else if( processed.toLowerCase( ).equals( "opponent" ) ) {
+	    processed = OPPONENT_PROC;
+	} else if ( processed.toLowerCase( ).equals( "fully" ) ) {
+	    processed = FULLY_PROC;
+	}
+
+	if( satisfied == null ) {
+	    satisfied = UNKNOWN;
+	} else if( satisfied.toLowerCase( ).equals( "satisfied" ) ) {
+	    satisfied = SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "failed" ) ) {
+	    satisfied = NOT_SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "unknown" ) ) {
+	    satisfied = UNKNOWN;
+	}
+
+
+	if( childType != null && childType.toLowerCase( ).equals( "trivialtarget" ) ) {
+	    satisfied = SATISFIED;
+	}
+	
+
+	NodeUpdate nu = new NodeUpdate( childName, childType, getCluster(c), satisfied, processed, side, local );
+	_updates.add( new EdgeUpdate( parentName, nu, type, local, collectEvidence(i,j), side ) );
+    }
+
+
+    private Collection collectEvidence( int i, int j ) {
+	Collection c = new ArrayList( );
+
+	String key;
+	for( int k=1; _log.containsKey( key = getPrefix(i,j) + "evidence." + Integer.toString(k) ); k++ ) {
+	    c.add( _log.getProperty( key ) );
+	}
+
+	return c;
+    }
+
+
+
+    private String getKey( int i ) {
+	return "update." + Integer.toString( i ) + ".location";
+    }
+
+    private String getKey( int i, int j ) {
+	return getPrefix( i, j ) + "type";
+    }
+
+    private String getPrefix( int i, int j ) {
+	return "update." + Integer.toString( i ) + "." + Integer.toString( j ) + ".";
+    }
+
+    private String getCluster( int i ) {
+	return "cluster" + Integer.toString( i );
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/Test.java
===================================================================
--- fedd/abac-src/atnvis/src/Test.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/Test.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,141 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+
+public class Test 
+    extends JFrame 
+{
+
+    private GrappaPanel _grappaPanel;
+    private Graph _graph;
+    private Subgraph[] _subgraphs;
+
+
+
+    public Test( ) {
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	_graph = new Graph( "Trust Negotiation Graph: " );
+	_grappaPanel = new GrappaPanel( _graph );
+	_grappaPanel.setScaleToFit( false );
+	
+	JScrollPane jsp = new JScrollPane( );
+	jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+	jsp.getViewport( ).setBackground( Color.white );
+	jsp.setViewportView( _grappaPanel );
+
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BorderLayout( ) );
+	contentPane.add( jsp, BorderLayout.CENTER );
+	setSize( 500, 500 );
+
+
+	_subgraphs = new Subgraph[2];
+	_subgraphs[0] = new Subgraph( _graph, "cluster 0" );
+	_subgraphs[1] = new Subgraph( _graph, "cluster 1" );
+
+
+	Node n1 = new Node( _subgraphs[0], "node1" );
+	Node n2 = new Node( _subgraphs[0], "node2" );
+	Node n3 = new Node( _subgraphs[1], "node3" );
+	Node n4 = new Node( _subgraphs[1], "node4" );
+	Node n5 = new Node( _subgraphs[1], "node5" );
+	
+
+// 	_subgraphs[0].addNode( n1 );
+// 	_subgraphs[0].addNode( n2 );
+// 	_subgraphs[1].addNode( n3 );
+// 	_subgraphs[1].addNode( n4 );
+
+
+	Edge e = new Edge( _subgraphs[0], n1, n2 );
+	Edge e2 = new Edge( _subgraphs[0], n2, n3 );
+	new Edge( _subgraphs[1], n3, n4 );
+	new Edge( _subgraphs[1], n3, n5 );
+	new Edge( _subgraphs[1], n5, n4 );
+	
+
+// 	_subgraphs[0].addEdge( e1 );
+// 	_graph.addEdge( e2 );
+// 	_subgraphs[1].addEdge( e3 );
+
+
+	e.setAttribute( "style", "bold,solid,filled" );
+	e2.setAttribute( "style", "solid" );
+
+	formatGraph( _graph );
+
+// 	_graph.setAttribute( "style", "invis" );
+
+
+	Subgraph sg = _graph.findSubgraphByName( "cluster 0" );
+	sg.setAttribute( "color", "red" );
+	sg.setAttribute( "style", "dotted" );
+	sg.setAttribute( "label", "this is a cluster" );
+
+
+	Node n = _graph.findNodeByName( "node1" );
+	n.setAttribute( "style", "filled" );
+	n.setAttribute( "color", "green" );
+	n.setAttribute( "bgcolor", "blue" );
+	n.setAttribute( "fillcolor", "red" );
+
+	n = _graph.findNodeByName( "node2" );
+	n.setAttribute( "style", "solid" );
+	n.setAttribute( "color", "black" );
+
+
+	sg = _graph.findSubgraphByName( "cluster 1" );
+	sg.setAttribute( "style", "dotted" );
+	sg.setAttribute( "fillcolor", "white" );
+	sg.setAttribute( "color", "white" );
+	sg.setAttribute( "bgcolor", "white" );
+
+
+
+
+
+	show( );
+    }
+
+
+    public static void main( String[] args ) {
+	Test t = new Test( );
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/TipAdapter.java
===================================================================
--- fedd/abac-src/atnvis/src/TipAdapter.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/TipAdapter.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,53 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public class TipAdapter extends GrappaAdapter {
+
+    public TipAdapter( ) {
+	super( );
+    }
+
+
+
+    public void grappaClicked(Subgraph subg, 
+			      Element elem, 
+			      GrappaPoint pt, 
+			      int modifiers, 
+			      int clickCount, 
+			      GrappaPanel panel) {
+    }
+
+    public void grappaDragged(Subgraph subg, 
+			      GrappaPoint currentPt, 
+			      int currentModifiers, 
+			      Element pressedElem, 
+			      GrappaPoint pressedPt, 
+			      int pressedModifiers, 
+			      GrappaBox outline, 
+			      GrappaPanel panel) {
+    }
+
+
+    public void grappaPressed(Subgraph subg, 
+			      Element elem, 
+			      GrappaPoint pt, 
+			      int modifiers, 
+			      GrappaPanel panel) {
+
+    }
+
+    public void grappaReleased(Subgraph subg, 
+			       Element elem, 
+			       GrappaPoint pt, 
+			       int modifiers, 
+			       Element pressedElem, 
+			       GrappaPoint pressedPt, 
+			       int pressedModifiers, 
+			       GrappaBox outline, 
+			       GrappaPanel panel) { 
+    }
+
+
+
+}
Index: fedd/abac-src/atnvis/src/Update.java
===================================================================
--- fedd/abac-src/atnvis/src/Update.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/Update.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,18 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public interface Update {
+
+    public int initialize( VisualizationPanel visPanel );
+    public boolean apply( VisualizationPanel visPanel );
+    public void undo( VisualizationPanel visPanel);
+    public int getSide( );
+    public boolean getSkip( );
+    public void setSkip( boolean skip );
+    public Element getElement( VisualizationPanel visPanel );
+    public boolean getUndo( );
+    public void setUndo( boolean undo );
+    public boolean getLocal( );
+
+}
Index: fedd/abac-src/atnvis/src/Visualization.java
===================================================================
--- fedd/abac-src/atnvis/src/Visualization.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/Visualization.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,250 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+import java.util.*;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class Visualization extends JFrame
+    implements VisualizationConstants {
+
+    private Properties _properties;
+    private VisualizationPanel[] _visPanels;
+
+    private ControlPanel _controls;
+    private ProgressPanel _progress;
+
+    private String[] _names = new String[2];
+    private Collection[] _policies = new Collection[2];
+
+    public void setName( String name, int side ) {
+	_names[side] = name;
+    }
+
+    public void setPolicies( Collection pol, int side ) {
+	_policies[side] = pol;
+    }
+
+
+
+    public void setAutoRaise( boolean state ) {
+	_visPanels[LEFT_SIDE].setAutoRaise( state );
+	if( _visPanels[RIGHT_SIDE] != null ) {
+	    _visPanels[RIGHT_SIDE].setAutoRaise( state );
+	}
+	
+    }
+
+
+    public Visualization( String log1, String log2 ) {
+
+
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	loadProperties( );
+	initializeFrame( log2 != null );
+
+	LogParser parser = null;
+
+	try {
+	    parser = 
+		(LogParser)Class.forName( _properties.getProperty( PARSER_PROP, 
+								   PARSER_DEFAULT ) ).newInstance( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	
+	java.util.List updates = parser.parse( this, log1, log2 );
+
+	updates = _visPanels[LEFT_SIDE].initialize( updates );
+	_visPanels[LEFT_SIDE].addCredentials( _policies[LEFT_SIDE], 2 );
+	_visPanels[LEFT_SIDE].setName( _names[LEFT_SIDE] );
+
+
+// 	System.out.println( _policies[LEFT_SIDE] );
+// 	System.out.println( _policies[RIGHT_SIDE] );
+
+
+	if( log2 != null ) {
+	    updates = _visPanels[RIGHT_SIDE].initialize(  updates );
+	    _visPanels[RIGHT_SIDE].addCredentials( _policies[RIGHT_SIDE], 2 );
+	    _visPanels[RIGHT_SIDE].setName( _names[RIGHT_SIDE] );
+
+	}
+	
+
+
+	java.util.List l = new ArrayList( );
+
+	for( Iterator i = updates.iterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+	    PanelUpdate pu = null;;
+
+	    if( u.getSide( ) == LEFT_SIDE ) {
+		pu = _visPanels[LEFT_SIDE].apply( u );
+	    } else if( log2 != null ) {
+		pu = _visPanels[RIGHT_SIDE].apply( u );
+	    }
+
+	    if( !pu.isEmpty( ) ) {
+		l.add( pu );
+	    }
+
+	}
+
+
+// 	_visPanels[LEFT_SIDE].reset( updates );
+// 	if( log2 != null ) {
+// 	    _visPanels[RIGHT_SIDE].reset( updates );
+// 	}
+	
+
+	PlayBackController pbc = new PlayBackController( l, _properties );
+	pbc.addObserver( _progress );
+	pbc.addObserver( _visPanels[LEFT_SIDE] );
+	_visPanels[LEFT_SIDE].hideGraph( );
+
+	if( log2 != null ) {
+	    pbc.addObserver( _visPanels[RIGHT_SIDE] );
+	    _visPanels[RIGHT_SIDE].hideGraph( );
+	}
+
+
+	_progress.setMax( l.size( ) );
+	_controls.addObserver( pbc );
+
+
+// // 	Object[] o = getKeyListeners( );
+// 	for( int i = 0; o != null && i<o.length; i++ ) {
+// 	    removeKeyListener( (KeyListener)o[i] );
+// 	}
+
+
+
+// 	addKeyListener( new KeyListener( ) {
+// 		public void keyTyped( KeyEvent e ) {
+// 		    System.out.println( "typed: " + e );
+// 		}
+
+// 		public void keyPressed( KeyEvent e ) {
+// 		    System.out.println( "pressed: " + e );
+// 		}
+
+// 		public void keyReleased( KeyEvent e ) {
+// 		    System.out.println( "released: " + e );
+// 		}
+
+
+// 	    });
+
+
+// 	addFocusListener( new FocusListener( ) {
+// 		public void focusGained( FocusEvent e ) {
+// 		    System.out.println( "focus gained: " + e );
+// 		}
+
+// 		public void focusLost( FocusEvent e ) {
+// 		    System.out.println( "focus lost: " + e ); 
+// // 		    requestFocus( );
+// 		}
+
+
+// 	    });
+		       
+
+
+ 	show( );
+// 	requestFocus( true );
+
+    }
+
+    private void initializeFrame( boolean twoSided ) {
+	JPanel mainPanel = new JPanel( );
+	mainPanel.setLayout( new BoxLayout( mainPanel, BoxLayout.X_AXIS ) );
+
+	_visPanels = new VisualizationPanel[2];
+	_visPanels[LEFT_SIDE] = new VisualizationPanel( LEFT_SIDE, _properties );
+	mainPanel.add( _visPanels[LEFT_SIDE] );
+
+	if( twoSided ) {
+	    _visPanels[RIGHT_SIDE] = new VisualizationPanel( RIGHT_SIDE, _properties );
+	    mainPanel.add( Box.createHorizontalStrut( 10 ) );
+	    mainPanel.add( _visPanels[RIGHT_SIDE] );
+	}
+	
+	_controls = new ControlPanel( _properties, this );
+	_progress = new ProgressPanel( );
+
+	JPanel toolPanel = new JPanel( );
+
+	toolPanel.setMaximumSize( new Dimension( 2000, 50 ) );
+	toolPanel.setPreferredSize( new Dimension( 2000, 50 ) );
+
+
+	toolPanel.setLayout( new BoxLayout( toolPanel, BoxLayout.X_AXIS ) );
+	toolPanel.add( _controls );
+	toolPanel.add( _progress );
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.Y_AXIS ) );
+	contentPane.add( mainPanel );
+	contentPane.add( toolPanel );
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+    }
+
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	_properties = new Properties( );
+
+	if( file.exists( ) ) {
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( Exception e ) { }
+	}
+
+    }
+
+
+    public static void main( String[] args ) {
+	Visualization vis = null;
+
+	if( args.length == 1 ) {
+	    vis = new Visualization( args[0], null );
+	} else if ( args.length == 2 ) {
+	    vis = new Visualization( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: Visualization <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/VisualizationConstants.java
===================================================================
--- fedd/abac-src/atnvis/src/VisualizationConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/VisualizationConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,120 @@
+package com.algomagic.atn;
+
+import att.grappa.GrappaConstants;
+
+public interface VisualizationConstants extends GrappaConstants {
+    public static final String SYSTEM_PREFIX = "atnvis.";
+
+    public static final String CONFIG_FILE_PROP = SYSTEM_PREFIX + "ConfigFile";
+    public static final String WINDOW_TITLE_PROP = SYSTEM_PREFIX + "window.Title";
+    public static final String WINDOW_HEIGHT_PROP = SYSTEM_PREFIX + "window.Height";
+    public static final String WINDOW_WIDTH_PROP = SYSTEM_PREFIX + "window.Width";
+
+    public static final String DELAY_PROP = SYSTEM_PREFIX + "defaultDelay";
+    public static final String LOOP_PROP = SYSTEM_PREFIX + "loop";
+
+    public static final String PARSER_PROP = SYSTEM_PREFIX + "parser";
+    public static final String PARSER_DEFAULT = "com.algomagic.atn.NullParser";
+    
+    public static final String SCALE_PROP = SYSTEM_PREFIX + "graph.Scale";
+    public static final String SCALE_DEFAULT = "1.0";
+
+    public static final String IGNOREPROC_PROP = SYSTEM_PREFIX + "parser.IgnoreProcessing";
+    public static final String IGNOREPROC_DEFAULT = "true";
+
+
+    public static final String SHADOW_PROP = SYSTEM_PREFIX + "graph.ShadowColor";
+    public static final String SHADOW_DEFAULT = "grey90";
+
+
+    public static final String CONFIG_FILE_DEFAULT = "atnvis.properties";
+    public static final String WINDOW_TITLE_DEFAULT = "ATN Visualization";
+    public static final String WINDOW_HEIGHT_DEFAULT = "800";
+    public static final String WINDOW_WIDTH_DEFAULT = "600";
+
+    public static final String DELAY_DEFAULT = "500";
+    public static final String LOOP_DEFAULT = "true";
+
+    public static final int LEFT_SIDE = 0;
+    public static final int RIGHT_SIDE = 1;
+
+    public static final String OPPONENT_PROC = "Opponent";
+    public static final String VERIFIER_PROC = "Verifier";
+    public static final String FULLY_PROC = "Fully";
+    public static final String NOT_PROC = "Unprocessed";
+
+    public static final String SATISFIED = "Satisfied";
+    public static final String NOT_SATISFIED = "Failed";
+    public static final String UNKNOWN = "Unknown";
+
+    public static final String STANDARD_TARGET = "StandardTarget";
+    public static final String ROLE_TARGET = "RoleTarget";
+    public static final String LINKING_ROLE_TARGET = "LinkingRoleTarget";
+    public static final String TRIVIAL_TARGET = "TrivialTarget";
+    public static final String INTERSECTION_TARGET = "IntersectionTarget";
+    public static final String LINKING_GOAL = "LinkingGoal";
+
+    public static final String IMPLICATION_EDGE = "Implication";
+    public static final String LINKING_MONITOR_EDGE = "LinkingMonitor";
+    public static final String LINKING_SOLUTION_EDGE = "LinkingSolution";
+    public static final String LINKING_IMPLICATION_EDGE = "LinkingImplication";
+    public static final String INTERSECTION_EDGE = "Intersection";
+    public static final String CONTROL_EDGE = "Control";
+
+    public static final String DEFAULT_NODE = SYSTEM_PREFIX + "node.Default.";
+    public static final String DEFAULT_EDGE = SYSTEM_PREFIX + "edge.Default.";
+
+
+    public static final String[] NODE_ATTRS = {
+	SHAPE_ATTR,
+	SIDES_ATTR,
+	PERIPHERIES_ATTR,
+	STYLE_ATTR,
+	COLOR_ATTR,
+	FONTNAME_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR };
+
+
+
+    public static final String[] NODE_ATTRS_PROP = {
+	"shape",
+	"sides",
+	"peripheries",
+	"style",
+	"color",
+	"fontname",
+	"fontcolor",
+	"fontsize",
+	"fontstyle" };
+
+    public static final boolean[] NODE_ATTRS_INT = {
+	false,
+	true,
+	true,
+	false,
+	false,
+	false,
+	false,
+	true,
+	false };
+
+
+    public static final String[] EDGE_ATTRS = {
+	STYLE_ATTR,
+	COLOR_ATTR,
+	DIR_ATTR };
+
+    public static final String[] EDGE_ATTRS_PROP = {
+	"style",
+	"color",
+	"direction" };
+
+
+    public static final boolean[] EDGE_ATTRS_INT = {
+	false,
+	false,
+	false };
+
+}
Index: fedd/abac-src/atnvis/src/VisualizationPanel.java
===================================================================
--- fedd/abac-src/atnvis/src/VisualizationPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/VisualizationPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,1000 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class VisualizationPanel 
+    extends JPanel 
+    implements Observer, VisualizationConstants {
+
+    private int _side;
+    private Properties _properties;
+
+    private GrappaPanel _grappaPanel;
+    private Graph _graph;
+
+    private JPanel _complete;
+    private JPanel _graphPanel;
+    private CredentialPanel _credentialPanel;
+
+    private ImageIcon _collapse;
+    private ImageIcon _expand;
+
+    private HashMap _nodeStates;
+    private Subgraph _currentCluster;
+
+    private boolean _local;
+    private java.util.List _bolded;
+    private HashMap _remoteClusters;
+    private HashMap _remoteEvidence;
+
+    private HashMap _localClusters;
+    
+    private String _shadowColor;
+    private int _currentIndex;
+
+    private BatchGraphUpdate _batchUpdate;
+    private boolean _ignoreProcessing;
+    private HashSet _boldedNodes;
+    private boolean _basicProps;
+
+    private String _name;
+
+    public void setName( String name ) {
+	_name = name;
+	PanelHelper.setBorder( _graphPanel, "Trust Target Graph: " + name );
+// 	_graph.setAttribute( TIP_ATTR, "Trust Target Graph: " + name );
+// 	_graph.setAttribute( TIP_ATTR, null );
+
+	_grappaPanel.setToolTipText( null );
+    }
+
+
+    class CredentialPanel extends JPanel {
+	JTabbedPane _tabs;
+	JList _local;
+	JList _remote;
+	JList _policy;
+
+	DefaultListModel _localCreds;
+	DefaultListModel _remoteCreds;
+	DefaultListModel _policyCreds;
+
+	boolean _autoRaise;
+
+	public CredentialPanel( ) {
+	    super( );
+
+	    _autoRaise = true;
+
+	    _tabs = new JTabbedPane( );
+
+	    _localCreds = new DefaultListModel( );
+	    _remoteCreds = new DefaultListModel( );
+	    _policyCreds = new DefaultListModel( );
+
+
+	    _local = new JList( _localCreds );
+	    _remote = new JList( _remoteCreds );
+	    _policy = new JList( _policyCreds );
+
+
+	    _tabs.addTab( "Local Credentials", new JScrollPane( _local ) );
+	    _tabs.addTab( "Remote Credentials", new JScrollPane( _remote ) );
+	    _tabs.addTab( "Policies", new JScrollPane( _policy ) );
+
+ 
+	    setLayout( new BorderLayout( ) );
+	    add( _tabs, BorderLayout.CENTER );
+
+	    PanelHelper.setBorder( this, "Credentials" );
+	}
+	
+
+	public void clearSelection( ) {
+	    _local.clearSelection( );
+	    _remote.clearSelection( );
+	}
+
+
+	public void setAutoRaise( boolean state ) {
+	    _autoRaise = state;
+	}
+
+
+	public void setRaised( int tab ) {
+	    clearSelection( );
+
+	    if( _autoRaise ) {
+// 		System.out.println( "side: " + _side + "  tab: " + tab );
+
+		_tabs.setSelectedIndex( tab );
+	    }
+	}
+
+
+	public void setRaised( boolean local ) {
+	    clearSelection( );
+
+	    if( _autoRaise ) {
+		if( local ) {
+		    _tabs.setSelectedIndex( 0 );
+		} else {
+		    _tabs.setSelectedIndex( 1 );
+		}
+	    }
+	}
+	
+
+	public void addCredentials( Collection evidence, int tab ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( tab == 0 ) {
+		m = _localCreds;
+	    } else if( tab == 1 ) {
+		m = _remoteCreds;
+	    } else {
+		m = _policyCreds;
+	    }
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( !m.contains( o ) ) {
+		    m.addElement( o );
+		}
+// 		m.addElement( i.next( ) );
+	    }
+	}
+
+
+	public void removeCredentials( Collection evidence, int tab ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( tab == 0 ) {
+		m = _localCreds;
+	    } else if( tab == 1 ) {
+		m = _remoteCreds;
+	    } else {
+		m = _policyCreds;
+	    }
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( m.contains( o ) ) {
+		    m.removeElement( o );
+		}
+// 		m.addElement( i.next( ) );
+	    }
+	}
+
+
+	public void addCredentials( Collection evidence, boolean local ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( local ) {
+		m = _localCreds;
+	    } else {
+		m = _remoteCreds;
+	    }
+
+
+
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( !m.contains( o ) ) {
+		    m.addElement( o );
+		}
+	    }
+
+	}
+
+
+	public void removeCredentials( Collection evidence, boolean local ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( local ) {
+		m = _localCreds;
+	    } else {
+		m = _remoteCreds;
+	    }
+
+
+
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( m.contains( o ) ) {
+		    m.removeElement( o );
+		}
+	    }
+
+	}
+
+	public void highlightCredentials( Collection evidence, int tab ) {
+
+	    DefaultListModel m;
+	    JList l;
+
+	    if( tab == 0 ) {
+		m = _localCreds;
+		l = _local;
+	    } else {
+		m = _remoteCreds;
+		l = _remote;
+	    }
+
+
+	    clearSelection( );
+
+	    int[] indices = new int[evidence.size( )];
+	    int count = 0;
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		indices[count] = m.indexOf( i.next( ) );
+		count++;
+	    }
+
+	    l.setSelectedIndices( indices );
+	}
+
+
+	public void highlightCredentials( Collection evidence, boolean local ) {
+	    DefaultListModel m;
+	    JList l;
+
+	    if( local ) {
+		m = _localCreds;
+		l = _local;
+	    } else {
+		m = _remoteCreds;
+		l = _remote;
+	    }
+
+
+	    clearSelection( );
+
+	    int[] indices = new int[evidence.size( )];
+	    int count = 0;
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		indices[count] = m.indexOf( i.next( ) );
+		count++;
+	    }
+
+	    l.setSelectedIndices( indices );
+
+	}
+
+	public void removeRemoteCreds( ) {
+// 	    System.out.println( "removing remote creds" );
+
+	    _remoteCreds.clear( );
+	}
+
+    }
+
+
+    public void setAutoRaise( boolean state ) {
+	_credentialPanel.setAutoRaise( state );
+    }
+
+    public void clearSelection( ) {
+	_credentialPanel.clearSelection( );
+    }
+
+
+    public void setRaised( boolean local ) {
+	_credentialPanel.setRaised( local );
+    }
+
+    public void setRaised( int tab ) {
+	_credentialPanel.setRaised( tab );
+    }
+
+
+    public void addCredentials( Collection evidence, boolean local ) {
+	if( evidence != null ) {
+	    _credentialPanel.addCredentials( evidence, local );
+	}
+    }
+
+    public void removeCredentials( Collection evidence, boolean local ) {
+	if( evidence != null ) {
+	    _credentialPanel.removeCredentials( evidence, local );
+	}
+    }
+
+
+    public void highlightCredentials( Collection evidence, boolean local ) {
+	if( evidence != null ) {
+	    _credentialPanel.highlightCredentials( evidence, local );
+	}
+    }
+    
+    public void addCredentials( Collection evidence, int tab ) {
+	if( evidence != null ) {
+	    _credentialPanel.addCredentials( evidence, tab );
+	}
+    }
+
+    public void removeCredentials( Collection evidence, int tab ) {
+	if( evidence != null ) {
+	    _credentialPanel.removeCredentials( evidence, tab );
+	}
+    }
+
+    public void highlightCredentials( Collection evidence, int tab ) {
+	if( evidence != null ) {
+	    _credentialPanel.highlightCredentials( evidence, tab );
+	}
+    }
+    
+
+    public VisualizationPanel( int side, Properties properties ) {
+	super( );
+
+	_side = side;
+	_properties = properties;
+	_currentCluster = null;
+	_local = true;
+	_basicProps = false;
+
+	_nodeStates = new HashMap( );
+	_bolded = new ArrayList( );
+	_remoteClusters = new HashMap( );
+	_remoteEvidence = new HashMap( );
+	_localClusters = new HashMap( );
+	_batchUpdate = new BatchGraphUpdate( );
+	_boldedNodes = new HashSet( );
+
+
+	_ignoreProcessing = (new Boolean( _properties.getProperty( IGNOREPROC_PROP, IGNOREPROC_DEFAULT ) )).booleanValue( );
+// 	System.out.println( _properties.getProperty( IGNOREPROC_PROP, IGNOREPROC_DEFAULT ) );
+// 	System.out.println( _ignoreProcessing );
+
+
+	_shadowColor = _properties.getProperty( SHADOW_PROP, SHADOW_DEFAULT );
+
+
+	Class clazz = this.getClass( );
+	_collapse = new ImageIcon( clazz.getResource( "/resources/collapse.gif" ), "collapse" );
+	_expand = new ImageIcon( clazz.getResource( "/resources/expand.gif" ), "expand" );
+
+
+	JPanel hiderPanel = new JPanel( );
+	hiderPanel.setLayout( new BoxLayout( hiderPanel, BoxLayout.X_AXIS ) );
+
+	JButton hider = new JButton( _collapse );
+	hider.setMaximumSize( new Dimension( 2000, 10 ) );
+	hider.setPreferredSize( new Dimension( 2000, 10 ) );
+	hider.setMinimumSize( new Dimension( 0, 10 ) );
+
+	hider.addActionListener( new ActionListener( ) {
+		boolean removed = false;
+		
+		public void actionPerformed( ActionEvent e ) {
+		    JButton button = (JButton)e.getSource( );
+
+		    if( ! removed ) {
+			_complete.remove( _credentialPanel );
+			button.setIcon( _expand );
+			removed = true;
+		    } else {
+			_complete.add( _credentialPanel, 2 );
+			button.setIcon( _collapse );
+			removed = false;
+		    }
+
+		    validate( );
+		    repaint( );
+		}
+
+	    } );
+
+	hiderPanel.add( hider );
+
+	_graph = new Graph( "Trust Target Graph: " + _side );
+
+	_grappaPanel = new GrappaPanel( _graph );
+	_grappaPanel.setScaleToFit( false );
+	
+// 	JScrollPane jsp = new JScrollPane( );
+// 	jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+// 	jsp.getViewport( ).setBackground( Color.white );
+// 	jsp.setViewportView( _grappaPanel );
+	
+	JScrollPane jsp = new JScrollPane( _grappaPanel );
+// 	jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	jsp.getViewport( ).setBackground( Color.white );
+// 	jsp.setViewportView( _grappaPanel );
+	
+
+	_graphPanel = new JPanel( new BorderLayout( ) );
+	PanelHelper.setBorder( _graphPanel, "Trust Target Graph" );
+	_graphPanel.add( jsp, BorderLayout.CENTER );
+
+	
+	_credentialPanel = new CredentialPanel( );
+	_credentialPanel.setMaximumSize( new Dimension( 2000, 150 ) );
+	_credentialPanel.setPreferredSize( new Dimension( 2000, 150 ) );
+	_credentialPanel.setMinimumSize( new Dimension( 0, 150 ) );
+
+	_complete = new JPanel( );
+	_complete.setLayout( new BoxLayout( _complete, BoxLayout.Y_AXIS ) );
+
+	_complete.add( _graphPanel );
+	_complete.add( hiderPanel );
+	_complete.add( _credentialPanel );
+
+
+	_grappaPanel.addGrappaListener( new TipAdapter( ) );
+
+
+	setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+	add( _complete );
+
+    }
+
+
+
+
+
+    public boolean addNodeState( NodeState ns ) {
+	if( _nodeStates.containsKey( ns.getName( ) ) ) {
+	    return false;
+	}
+
+	_nodeStates.put( ns.getName( ), ns );
+
+	return true;
+    }
+
+    public NodeState getNodeState( String name ) {
+	return (NodeState)_nodeStates.get( name );
+    }
+
+
+
+    public void reset( java.util.List updates ) {
+	_basicProps = true;
+
+	for( ListIterator i = updates.listIterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+
+	    if( u.getSide( ) == _side ) {
+		u.apply( this );
+	    }
+	}
+
+	_basicProps = false;
+	hideGraph( _graph );
+
+    }
+
+
+    public java.util.List initialize( java.util.List updates ) {
+	java.util.List filteredUpdates = new ArrayList( );
+
+	for( ListIterator i = updates.listIterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+	    if( u.getSide( ) == _side ) {
+		int changed = u.initialize( this );
+
+		// if changed == 1, processing state changed
+		//    changed == 2, satisfaction state changed
+		//    changed == 3, processing and satisfaction changed
+		//    changed == 0, no change
+
+
+		if( changed == 3 ||
+		    (!_ignoreProcessing && changed >= 1 ) ||
+		    (_ignoreProcessing && changed >= 2 ) ) {
+
+		    filteredUpdates.add( u );
+		}
+	    } else {
+		filteredUpdates.add( u );
+	    }
+	}
+
+
+	boolean isRemoteCluster = false;
+	int clusterNumber = -1;
+	HashSet remoteCluster = null;
+	Collection remoteEvidence = null;
+
+
+	for( ListIterator i = filteredUpdates.listIterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+	    if( u.getSide( ) == _side ) {
+// 		if( u instanceof NodeUpdate ) {
+// 		    System.out.println( u );
+// 		}
+
+		u.apply( this );
+
+		if( u instanceof ClusterUpdate ) {
+		    ClusterUpdate cu = (ClusterUpdate)u;
+		    if( !cu.getLocal( ) ) {
+			if( cu.getStart( ) ) {
+			    isRemoteCluster = true;
+			    clusterNumber = cu.getCluster( );
+			    remoteCluster = new HashSet( );
+			    remoteEvidence = new ArrayList( );
+			} else {
+			    isRemoteCluster = false;
+			    _remoteClusters.put( new Integer( clusterNumber ), remoteCluster );
+			    _remoteEvidence.put( new Integer( clusterNumber ), remoteEvidence );
+			}
+		    }
+		} else if( isRemoteCluster ) {
+		    remoteCluster.add( u );
+		    if( u instanceof EdgeUpdate ) {
+			Collection c = ((EdgeUpdate)u).getEvidence( );
+			remoteEvidence.addAll( c );
+		    }
+		}
+
+	    }
+	}
+
+
+	formatGraph( _graph );
+ 	hideGraph( _graph );
+	_credentialPanel.removeRemoteCreds( );
+
+
+	String scaleStr = _properties.getProperty( SCALE_PROP, SCALE_DEFAULT );
+	double scale = Double.parseDouble( scaleStr );
+
+	_grappaPanel.multiplyScaleFactor( scale );
+
+	_graph.resync( );
+	_graph.repaint( );
+
+
+	return filteredUpdates;
+    }
+
+
+
+    public PanelUpdate apply( Update u ) {
+	_batchUpdate = new BatchGraphUpdate( );
+
+	if( u.getSide( ) != _side ) {
+	    throw new RuntimeException( );
+	}
+	    
+
+	u.apply( this );	    
+
+	boolean raise = false;
+	int tab = -1;
+
+	boolean add = false;
+	boolean hl = true;
+
+	Collection c = null;
+
+	if( u instanceof ClusterUpdate ) {
+	    ClusterUpdate cu = (ClusterUpdate)u;
+	    if( !cu.getStart( ) && cu.getLocal( ) ) {
+		unSetBolded( !cu.getUndo( ), cu.getCluster( ) );
+	    } else if( cu.getStart( ) && !cu.getLocal( ) ) {
+		setShadowed( !cu.getUndo( ), cu.getCluster( ) );
+		c = (Collection) _remoteEvidence.get( new Integer( cu.getCluster( ) ) );
+		add = true;
+		hl = false;
+	    }
+	}
+
+
+	if( u.getLocal( ) ) {
+	    tab = 0;
+	    raise = true;
+	} else {
+	    tab = 1;
+	    raise = true;
+	}
+
+
+	if( u instanceof EdgeUpdate ) {
+	    EdgeUpdate eu = (EdgeUpdate)u;
+	    c = eu.getEvidence( );
+
+	    if( eu.getType( ).equals( CONTROL_EDGE ) ) {
+		if( u.getLocal( ) ) {
+		    tab = 2;
+		    raise = true;
+		}
+	    }
+	}
+
+
+	    
+	return new PanelUpdate( _batchUpdate, _side, tab, c, raise, add, hl );
+    }
+
+
+    public void update( Observable o, Object arg ) {
+	clearSelection( );
+
+	if( arg instanceof PanelUpdate ) {
+
+	    PanelUpdate u = (PanelUpdate)arg;
+	    if( u.getSide( ) != _side ) {
+ 		return;
+	    }
+
+
+// 	    if( u instanceof ClusterUpdate ) {
+// 		ClusterUpdate cu = (ClusterUpdate)u;
+// 		if( !cu.getStart( ) && cu.getLocal( ) ) {
+// 		    unSetBolded( !cu.getUndo( ), cu.getCluster( ) );
+// 		} else if( cu.getStart( ) && !cu.getLocal( ) ) {
+// 		    setShadowed( !cu.getUndo( ), cu.getCluster( ) );
+// 		}
+// 	    }
+
+	    u.apply( this );
+
+	    _graph.resync( );
+	    _graph.repaint( );
+
+	    
+// 	    if( u.getUndo( ) ) {
+// // 		System.out.println( "UNDO" );
+// 		u.undo( this );
+// 	    } else {
+// 		u.apply( this );	    
+// 	    }
+
+// 	    _graph.resync( );
+// 	    _graph.repaint( );
+
+	} else if( arg instanceof String ) {
+
+	    String s = (String)arg; 
+	    if( s.equals( "CLEAR" ) ) {
+// 		System.out.println( "CLEAR" );
+
+		hideGraph( _graph );
+// 		_credentialPanel.removeRemoteCreds( );
+	    }
+	}
+    }
+
+
+    public Graph getGraph( ) {
+	return _graph;
+    }
+
+    public Subgraph getCurrentCluster( ) {
+	return _currentCluster;
+    }
+
+    public void setCurrentCluster( Subgraph sg ) {
+	_currentCluster = sg;
+    }
+
+
+
+
+
+    private void setShadowed( boolean shadow, int clusterNum ) {
+	HashSet cluster  = (HashSet)_remoteClusters.get( new Integer( clusterNum ) );
+
+	for( Iterator i = cluster.iterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+
+	    if( u instanceof NodeUpdate ) {
+		NodeUpdate nu = (NodeUpdate)u;
+
+		NodeState ns = getNodeState( nu.getName( ) );
+		if( ns.getHidden( ) == false ) {
+		    continue;
+		}
+
+	    }
+
+	    Element e = u.getElement( this );
+
+	    if( shadow ) {
+		setShadow( e );
+	    } else {
+		setInvis( e );
+	    }
+
+	    if( u instanceof EdgeUpdate ) {
+		EdgeUpdate eu = (EdgeUpdate)u;
+
+		NodeState ns = getNodeState( eu.getChildName( ) );
+		if( ns.getHidden( ) == false ) {
+		    continue;
+		}
+
+		e = eu.getChild( this );
+		
+		if( shadow ) {
+		    setShadow( e );
+		} else {
+		    setInvis( e );
+		}
+
+	    }
+
+
+	}
+
+
+    }
+
+
+
+    public void setShadow( Element e ) {
+	setAttribute( e, "color", _shadowColor );
+	setAttribute( e, "style", "solid" );
+	setAttribute( e, "fontcolor", _shadowColor );
+    }
+
+
+    private void unSetBolded( boolean unbold, int cluster ) {
+	_boldedNodes = new HashSet( );
+
+	if( !unbold ) {
+	    _local = true;
+	    _bolded = (java.util.List)_localClusters.get( new Integer( cluster ) );
+	}
+
+	if( unbold ) {
+	    for( Iterator i = _bolded.iterator( ); i.hasNext( ); ) {
+
+		ElementAtt e = (ElementAtt)i.next( );
+		e.apply( );
+	    }
+	} else {
+
+	    for( int i=_bolded.size()-1; i>=0;i-- ) {
+		ElementAtt e = (ElementAtt)_bolded.get(i);
+		e.undo( );
+	    }
+	}
+
+	if( !unbold ) {
+	    _local = false;
+	} else {
+	    _localClusters.put( new Integer( cluster ), _bolded );
+	    _bolded = new ArrayList( );
+	}
+
+    }
+
+
+    private class ElementAtt {
+	private Element _e;
+	private String _att;
+	private String _value;
+	private Object _undoValue;
+
+	public ElementAtt( Element e, String att, String value, String undoValue ) {
+	    _e = e;
+	    _att = att;
+	    _value = value;
+	    _undoValue = undoValue;
+	}
+
+	public void apply( ) {
+	    _undoValue = setAttribute( _e,  _att, _value );
+	}
+
+	public void undo( ) {
+	    _e.setAttribute( _att, _undoValue );
+	}
+
+
+    }
+
+
+
+
+
+    private Object setAttribute( Element e, String attr, Object value ) {
+	Object previousValue = e.setAttribute( attr, value );
+	if( _batchUpdate != null ) {
+	    _batchUpdate.add( new ElementAttribute( e, attr, value, previousValue ) );
+	}
+
+	return previousValue;
+    }
+
+
+
+    private void setNodeProps( Node n, String prefix, boolean setBold ) {
+
+	for( int i=0; i < NODE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + NODE_ATTRS_PROP[i] );
+	    if( strValue == null ) {
+		continue;
+	    }
+
+
+	    if( NODE_ATTRS_INT[i] ) {
+		setAttribute( n, NODE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		
+		if( NODE_ATTRS[i].equals( FONTSTYLE_ATTR ) && ( setBold || _boldedNodes.contains( n ) ) ) {
+		    _bolded.add( new ElementAtt( n, FONTSTYLE_ATTR, strValue,"bold" ) );
+		    strValue = "bold";
+		} 
+
+		setAttribute( n, NODE_ATTRS[i], strValue );
+
+	    }
+	}
+    }
+
+
+
+    private void setEdgeProps( Edge e, String prefix, boolean local ) {
+	for( int i=0; i < EDGE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + EDGE_ATTRS_PROP[i] );
+	    String undoValue = _properties.getProperty( prefix + EDGE_ATTRS_PROP[i] + ".bold" );
+
+	    String change = strValue;
+
+
+	    if( strValue == null ) {
+		continue;
+	    }
+	    
+	    if( local ) {
+		if( undoValue != null ) {
+		    _bolded.add( new ElementAtt( e, EDGE_ATTRS[i], strValue, undoValue ) );
+		    change = undoValue;
+		}
+
+	    }
+	    
+	    setAttribute( e, EDGE_ATTRS[i], change );
+	}
+    }
+
+    
+    public void setNodeProperties( Node n, NodeState ns, boolean local, boolean newNode ) {
+	if( ns.getHidden( ) ) {
+
+	    if( _local == false ) {
+		setShadow( n );
+	    } else {
+		setInvis( n );
+	    }
+	    return;
+	}
+
+	if( ns.getBolded( ) == false && ( local && newNode ) ) {
+	    ns.setBolded( true );
+	}
+
+	if( local&&newNode ) {
+	    _boldedNodes.add( n );
+	}
+
+	setNodeProperties( n, ns.getType( ), ns.getSatisfied( ), ns.getProcessed( ), local&&newNode );
+    }
+
+
+    private void setNodeProperties( Node n, String type, String satisfaction, String process, boolean setBold ) {
+	setNodeProps( n, DEFAULT_NODE, setBold );
+	setNodeProps( n, SYSTEM_PREFIX + "node." + type + ".", setBold );
+
+	if( _basicProps ) {
+	    return;
+	}
+
+
+	setNodeProps( n, SYSTEM_PREFIX + "node.satisfied." + satisfaction + ".", setBold );
+
+	if( !_ignoreProcessing ) {
+	    setNodeProps( n, SYSTEM_PREFIX + "node.processed." + process + ".", setBold );
+	}
+    }
+
+    public void setEdgeProperties( Edge e, String type, boolean local ) {
+	setEdgeProps( e, DEFAULT_EDGE, local );
+	setEdgeProps( e, SYSTEM_PREFIX + "edge." + type + ".", local );
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+
+    public void hideGraph( ) {
+
+	hideSubgraph( _graph );
+	_graph.resync( );
+	_graph.repaint( );
+	_credentialPanel.removeRemoteCreds( );
+    }
+
+
+    public void updateGraph( ) {
+	_graph.resync( );
+	_graph.repaint( );
+    }
+
+
+    public void hideGraph( Graph g) {
+	_credentialPanel.removeRemoteCreds( );
+
+	hideSubgraph( g );
+
+	for( Iterator i = _nodeStates.values( ).iterator( ); i.hasNext( ); ) {
+	    NodeState ns = (NodeState) i.next( );
+	    ns.clearState( );
+	}
+
+	g.resync( );
+	g.repaint( );
+
+    }
+
+    private void hideSubgraph( Subgraph sg ) {
+// 	System.out.println( "HIDING GRAPH" );
+
+	Enumeration nodes = sg.nodeElements( );
+	Enumeration edges = sg.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+    }
+
+
+    public void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+    public void setLocal( boolean local ) {
+	_local = local;
+    }
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/AbstractUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/AbstractUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/AbstractUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,18 @@
+package com.algomagic.atn;
+
+public abstract class AbstractUpdate implements Update {
+    protected int _side;
+    protected boolean _skip = false;
+    protected boolean _undo = false;
+
+    public int getSide( ) { return _side; }
+    public boolean getSkip( ) { return _skip; }
+    public void setSkip( boolean skip ) { _skip = skip; }
+    public boolean getUndo( ) { return _undo; }
+    public void setUndo( boolean undo ) { _undo = undo; }
+
+}
+
+
+
+
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/BatchGraphUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/BatchGraphUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/BatchGraphUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,55 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class BatchGraphUpdate {
+
+    private List _updates;
+
+    public BatchGraphUpdate( List updates ) {
+	_updates = updates;
+    }
+
+    public BatchGraphUpdate( ) {
+	_updates = new ArrayList( );
+    }
+
+    public void add( ElementAttribute e ) {
+	_updates.add( e );
+    }
+
+    public boolean isEmpty( ) {
+	return _updates.isEmpty( );
+    }
+
+
+    public void apply( ) {
+	for( Iterator i = _updates.iterator( ); i.hasNext( ); ) {
+	    ElementAttribute e = (ElementAttribute)i.next( );
+// 	    System.out.println( e );
+
+	    e.apply( );
+	} 
+
+// 	System.out.println(  );
+// 	System.out.println(  );
+
+
+    }
+
+
+    public void undo( ) {
+	for( int i = _updates.size( )-1; i>=0; i-- ) {
+	    ElementAttribute e = (ElementAttribute)_updates.get(i);
+// 	    System.out.println( e );
+
+	    e.undo( );
+	} 
+
+// 	System.out.println(  );
+// 	System.out.println(  );
+
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/BatchUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/BatchUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/BatchUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,42 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class BatchUpdate {
+
+    private List _updates;
+
+    public BatchUpdate( List updates ) {
+	_updates = updates;
+    }
+
+    public BatchUpdate( ) {
+	_updates = new ArrayList( );
+    }
+
+    public void addElementAttribute( ElementAttribute e ) {
+	_updates.add( e );
+    }
+
+    public boolean isEmpty( ) {
+	return _updates.isEmpty( );
+    }
+
+
+    public void apply( ) {
+	for( Iterator i = _updates.iterator( ); i.hasNext( ); ) {
+	    ElementAttribute e = (ElementAttribute)i.next( );
+	    e.apply( );
+	} 
+    }
+
+
+    public void undo( ) {
+	for( Iterator i = _updates.iterator( ); i.hasNext( ); ) {
+	    ElementAttribute e = (ElementAttribute)i.next( );
+	    e.undo( );
+	} 
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/ClusterUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/ClusterUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/ClusterUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,113 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public class ClusterUpdate extends AbstractUpdate implements Update {
+    private int _cluster;
+    private boolean _start;
+    private boolean _local;
+
+    public ClusterUpdate( int cluster, boolean start, boolean local, int side ) {
+	_cluster = cluster;
+	_start = start;
+	_local = local;
+	_side = side;
+    }
+
+    public int initialize( VisualizationPanel visPanel ) {
+// 	Graph graph = visPanel.getGraph( );
+//  	Subgraph sg = graph.findSubgraphByName( _cluster );
+//  	if( sg == null ) {
+//  	    new Subgraph( graph, _cluster );
+//  	}
+
+	return 3;
+    }
+
+    public boolean apply( VisualizationPanel visPanel ) {
+
+// 	Subgraph sg = visPanel.getGraph( ).findSubgraphByName( _cluster );
+// 	if( sg == null ) {
+// 	    return;
+// 	}
+
+	
+// 	Subgraph current = visPanel.getCurrentCluster( );
+// 	if( current != null && _start ) {
+// 	    hide( current );
+// 	}
+
+// 	visPanel.setCurrentCluster( sg );
+	if( _start && _local ) {
+// 	    System.out.println( "raising local tab" );
+	    visPanel.setRaised( _local );
+
+	    visPanel.setLocal( true );
+	} else {
+	    visPanel.setLocal( false );
+	}
+
+
+// 	if( _start && _local ) {
+// 	    hide( sg );
+// 	} 
+	
+// 	if( _start && !_local ) {
+// 	    show( sg );
+// 	} 
+
+// 	if( !_start ) {
+// 	    show( sg );
+// 	}
+
+	return true;
+
+    }
+
+
+    public void undo( VisualizationPanel visPanel ) {
+	if( _start && _local ) {
+	    visPanel.setLocal( false );
+	} else if( !_start && _local ) {
+	    visPanel.setLocal( true );
+	} else if( _start && !_local ) {
+	    visPanel.setLocal( true );
+	} else {
+	    visPanel.setLocal( false );
+	}
+
+    }
+
+
+
+//     private void show( Subgraph sg ) {
+// 	sg.setAttribute( "style", "solid" );
+// 	sg.setAttribute( "color", "black" );
+//     }
+
+//     private void hide( Subgraph sg ) {
+// 	sg.setAttribute( "style", "dotted" );
+// 	sg.setAttribute( "color", "whitesmoke" );
+//     }
+
+    public int getCluster( ) {
+	return _cluster;
+    }
+
+
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+
+    public boolean getStart( ) {
+	return _start;
+    }
+
+    public Element getElement( VisualizationPanel visPanel ) {
+	throw new RuntimeException( );
+    }
+    
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/ControlPanel.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/ControlPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/ControlPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,199 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class ControlPanel 
+    extends JPanel 
+    implements ActionListener, VisualizationConstants
+{
+
+    JButton _play, _pause, _stepForward, _stepBack, _rewind, _fastForward, _stop;
+    InternalObservable _observable;
+    Visualization _vis;
+
+
+    public ControlPanel( Properties properties, Visualization vis ) {
+	super( );
+
+	_vis = vis;
+	_observable = new InternalObservable( );
+	Class clazz = this.getClass( );
+
+	_play = new JButton( new ImageIcon( clazz.getResource( "/resources/Play24.gif" ), "play" ) );
+	_play.setActionCommand( "play" );
+	_play.addActionListener( this );
+	_play.setEnabled( true );
+
+	_pause = new JButton( new ImageIcon( clazz.getResource( "/resources/Pause24.gif" ), "pause" ) );
+	_pause.setActionCommand( "pause" );
+	_pause.addActionListener( this );
+	_pause.setEnabled( false );
+
+	_stepForward = new JButton( new ImageIcon( clazz.getResource( "/resources/StepForward24.gif" ), "step forward" ) );
+	_stepForward.setActionCommand( "stepf" );
+	_stepForward.addActionListener( this );
+	_stepForward.setEnabled( true );
+	_stepForward.setMnemonic( 70 );
+
+
+	_stepBack = new JButton( new ImageIcon( clazz.getResource( "/resources/StepBack24.gif" ), "step back" ) );
+	_stepBack.setActionCommand( "stepb" );
+	_stepBack.addActionListener( this );
+	_stepBack.setEnabled( true );
+	_stepBack.setMnemonic( 66 );
+
+
+	_rewind = new JButton( new ImageIcon( clazz.getResource( "/resources/Rewind24.gif" ), "rewind" ) );
+	_rewind.setActionCommand( "rewind" );
+	_rewind.addActionListener( this );
+	_rewind.setEnabled( true );
+	
+
+
+	_fastForward = new JButton( new ImageIcon( clazz.getResource( "/resources/FastForward24.gif" ), "fast forward" ) );
+	_fastForward.setActionCommand( "ff" );
+	_fastForward.addActionListener( this );
+	_fastForward.setEnabled( true );
+
+
+	setStyle( _play );
+	setStyle( _pause );
+	setStyle( _stepForward );
+	setStyle( _stepBack );
+	setStyle( _rewind );
+	setStyle( _fastForward );
+
+	setLayout( new BoxLayout( this, BoxLayout.X_AXIS ) );
+	add( _rewind );
+	add( _stepBack );
+	add( _play );
+	add( _pause );
+	add( _stepForward );
+	add( _fastForward );
+
+	JCheckBox loop = 
+	    new JCheckBox( "loop", (new Boolean( properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( ) );
+
+	loop.addItemListener( new ItemListener( ) {
+		public void itemStateChanged( ItemEvent e ) {
+		    int s = e.getStateChange( );
+		    Boolean state = Boolean.TRUE;
+
+		    if( s == ItemEvent.DESELECTED ) {
+			state = Boolean.FALSE;
+		    }
+			
+		    _observable.notify( state );
+
+		}
+	    } );
+
+
+	add( Box.createHorizontalStrut( 10 ) );
+	add( loop );
+
+
+	JCheckBox raise = 
+	    new JCheckBox( "auto raise", true );
+	raise.addItemListener( new ItemListener( ) {
+
+		public void itemStateChanged( ItemEvent e ) {
+		    int s = e.getStateChange( );
+		    boolean state = true;
+
+		    if( s == ItemEvent.DESELECTED ) {
+			state = false;
+		    }
+		    
+		    _vis.setAutoRaise( state );
+		}
+
+
+
+	    } );
+
+
+	add( Box.createHorizontalStrut( 10 ) );
+	add( raise );
+
+
+
+	JSpinner spinner = 
+	    new JSpinner( new SpinnerNumberModel( Integer.parseInt( properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) ), 
+						  0, 
+						  5000, 
+						  100 ) );
+
+
+	JLabel spinnerLabel = new JLabel( "delay (msec)" );
+
+	spinner.addChangeListener( new ChangeListener( ) {
+		public void stateChanged( ChangeEvent e ) {
+		    _observable.notify( e.getSource( ) );
+		}
+	    } );
+
+
+	add( spinner );
+	add( Box.createHorizontalStrut( 5 ) );
+	add( spinnerLabel );
+
+
+	PanelHelper.setBorder( this, "Controls" );
+    }
+
+
+    public void addObserver( Observer o ) {
+	_observable.addObserver( o );
+    }
+
+
+    private void setStyle( JButton b ) {
+	b.setMinimumSize( new Dimension( 24, 24 ) );
+	b.setMaximumSize( new Dimension( 24, 24 ) );
+	b.setPreferredSize( new Dimension( 24, 24 ) );
+	    
+	b.setBorderPainted( false );
+    }
+
+    public void actionPerformed( ActionEvent e ) {
+	String cmd = e.getActionCommand( );
+	if( cmd.equals( "play" ) ) {
+	    _stepForward.setEnabled( false );
+	    _stepBack.setEnabled( false );
+	    _rewind.setEnabled( false );
+	    _fastForward.setEnabled( false );
+	    _play.setEnabled( false );
+	    _pause.setEnabled( true );
+	}
+
+	else if( cmd.equals( "pause" ) ) {
+	    _stepForward.setEnabled( true );
+	    _stepBack.setEnabled( true );
+	    _rewind.setEnabled( true );
+	    _fastForward.setEnabled( true );
+	    _play.setEnabled( true );
+	    _pause.setEnabled( false );
+	}
+
+
+	_observable.notify( e.getActionCommand( ) );
+    }
+
+
+    private class InternalObservable extends Observable {
+	public void notify( Object arg ) {
+	    setChanged( );
+	    notifyObservers( arg );
+	}
+    }
+
+}
+
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/EdgeUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/EdgeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/EdgeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,146 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import att.grappa.*;
+
+public class EdgeUpdate 
+    extends AbstractUpdate 
+    implements Update, VisualizationConstants
+{
+    private String _parentNodeName;
+    private NodeUpdate _childNode;
+    private String _type;
+    private Collection _evidence;
+    private boolean _local;
+
+    public EdgeUpdate( String parentNodeName,
+		       NodeUpdate childNode,
+		       String type,
+		       boolean local,
+		       Collection evidence,
+		       int side ) {
+	_parentNodeName = parentNodeName;
+	_childNode = childNode;
+	_type = type;
+	_local = local;
+	_evidence = evidence;
+	_side = side;
+    }
+
+    public int initialize( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+
+	_childNode.initialize( visPanel );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	if( n1 != null && n2 != null ) {
+	    new Edge( graph, n1, n2 );
+	} else {
+	    if( n1 == null && n1 == null ) {
+		throw new RuntimeException( _parentNodeName + " === " + _childNode.getName( ) );
+	    } else if( n1 == null ) {
+		throw new RuntimeException( _parentNodeName );
+	    } else if( n2 == null ) {
+		throw new RuntimeException( _childNode.getName( ) );
+	    }
+	}
+
+	if( _local ) {
+	    visPanel.addCredentials( _evidence, _local );
+	}
+	    
+	return 3;
+    }
+
+
+    public Collection getEvidence( ) {
+	return _evidence;
+    }
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+    public String getType( ) {
+	return _type;
+    }
+
+
+    public boolean apply( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	Edge e = getEdgeBetween( graph, n1, n2 );
+	visPanel.setEdgeProperties( e, _type, _local );
+
+	visPanel.clearSelection( );
+	
+	_childNode.setNew( );
+	_childNode.apply( visPanel );
+
+	if( _local == false ) {
+	    visPanel.addCredentials( _evidence, _local );
+	}
+
+	visPanel.highlightCredentials( _evidence, _local );
+
+	return true;
+    }
+
+    public void undo( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	Edge e = getEdgeBetween( graph, n1, n2 );
+	_childNode.undo( visPanel );
+
+
+	if( visPanel.getLocal( ) == false ) {
+	    visPanel.setShadow( e );
+	} else {
+	    visPanel.setInvis( e );
+	}
+	
+    }
+
+
+    public Element getElement( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	Node n1 = graph.findNodeByName( _parentNodeName );
+	Node n2 = graph.findNodeByName( _childNode.getName( ) );
+
+	return getEdgeBetween( graph, n1, n2 );
+    }
+
+    public Node getChild( VisualizationPanel visPanel ) {
+	Graph graph = visPanel.getGraph( );
+	return graph.findNodeByName( _childNode.getName( ) );
+    }
+
+    public String getChildName( ) {
+	return _childNode.getName( );
+    }
+
+
+
+    private Edge getEdgeBetween( Graph g, Node head, Node tail ) {
+	Enumeration edges = head.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+}
+
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/ElementAttribute.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/ElementAttribute.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/ElementAttribute.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,31 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public class ElementAttribute {
+    private Element _e;
+    private String _attr;
+    private Object _value;
+    private Object _undoValue;
+
+    public ElementAttribute( Element e, String attr, Object value, Object undoValue ) {
+	_e = e;
+	_attr = attr;
+	_value = value;
+	_undoValue = undoValue;
+    }
+
+    public void apply( ) {
+	_e.setAttribute( _attr, _value );
+    }
+	
+    public void undo( ) {
+	_e.setAttribute( _attr, _undoValue );
+    }
+
+
+    public String toString( ) {
+	return _e + " : " + _attr + " : " + _value + " : " + _undoValue;
+    }
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/LogParser.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/LogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/LogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,10 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+
+public interface LogParser {
+
+    public List parse( Visualization vis, String log1, String log2 );
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/NodeState.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/NodeState.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/NodeState.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,152 @@
+package com.algomagic.atn;
+
+public class NodeState implements VisualizationConstants {
+    private String _satisfied;
+    private boolean _opponentProcessed;
+    private boolean _verifierProcessed;
+    private boolean _hidden;
+    private boolean _bolded;
+
+    private String _name;
+    private String _type;
+
+    public NodeState( NodeState ns ) {
+	_name = ns.getName( );
+	_satisfied = ns.getSatisfied( );
+	_type = ns.getType( );
+	_hidden = ns.getHidden( );
+	_bolded = ns.getBolded( );
+    }
+
+
+    public NodeState( String name, String type ) {
+	_name = name;
+	_type = type;
+	
+	_satisfied = UNKNOWN;
+	_opponentProcessed = false;
+	_verifierProcessed = false;
+	_hidden = true;
+	_bolded = false;
+    }
+
+
+    public int updateState( NodeUpdate update ) {
+	_hidden = false;
+
+// 	if( _satisfied.equals( update.getSatisfied( ) ) ) {
+// 	    return false;
+// 	}
+
+	int s = setSatisfied( update.getSatisfied( ) );
+	int p = setProcessed( update.getProcessed( ) );
+
+	return s+p;
+    }
+
+    public int setSatisfied( String state ) {
+	int ret = 0;
+
+	if( _satisfied.equals( SATISFIED ) || _satisfied.equals( NOT_SATISFIED) ) {
+	    return 0;
+	}
+	
+	if( state == null ) {
+	    _satisfied = UNKNOWN;
+	}
+
+	if( _satisfied.toLowerCase( ).equals( state.toLowerCase( ) ) ) {
+	    return ret;
+	}
+
+	_satisfied = state;
+	return 2;
+    }
+
+    public int setProcessed( String state ) {
+	int ret = 0;
+
+	if( state.toLowerCase( ).equals( VERIFIER_PROC.toLowerCase( ) ) ) {
+	    if( _verifierProcessed == false ) {
+		ret = 1;
+	    }
+
+	    _verifierProcessed = true;
+	} else if ( state.toLowerCase( ).equals( OPPONENT_PROC.toLowerCase( ) ) ) {
+	    if( _opponentProcessed == false ) {
+		ret = 1;
+	    }
+
+	    _opponentProcessed = true;
+	} else if ( state.toLowerCase( ).equals( FULLY_PROC.toLowerCase( ) ) ) {
+	    if( _opponentProcessed == false || _verifierProcessed == false ) {
+		ret = 1;
+	    }
+
+	    _opponentProcessed = true;
+	    _verifierProcessed = true;
+	}
+
+	return ret;
+    }
+
+    public String getSatisfied( ) { 
+	return _satisfied; 
+    }
+
+    public String getProcessed( ) {
+	if( _opponentProcessed && _verifierProcessed ) {
+	    return FULLY_PROC;
+	}
+	
+	if( _opponentProcessed ) {
+	    return OPPONENT_PROC;
+	}
+
+	if( _verifierProcessed ) {
+	    return VERIFIER_PROC;
+	}
+
+	return NOT_PROC;
+    }
+
+    public void setHidden( boolean state ) {
+	_hidden = state;
+    }
+
+    public boolean getHidden( ) {
+	return _hidden;
+    }
+
+
+    public String getType( ) {
+	return _type;
+    }
+
+
+    public String getName( ) {
+	return _name;
+    }
+
+    public void setBolded( boolean state ) {
+	_bolded = state;
+    }
+
+    public boolean getBolded( ) {
+	return _bolded;
+    }
+
+
+    public void clearState( ) {
+    if( _satisfied.equals( SATISFIED ) || _satisfied.equals( NOT_SATISFIED) ) {
+        _satisfied = UNKNOWN;
+    }
+	_opponentProcessed = false;
+	_verifierProcessed = false;
+	_hidden = true;
+	_bolded = false;
+    }
+
+
+}
+
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/NodeUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/NodeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/NodeUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,130 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+
+public class NodeUpdate 
+    extends AbstractUpdate 
+    implements Update, VisualizationConstants 
+{
+    private String _name;
+    private String _type;
+    private String _cluster;
+
+    private String _satisfied;
+    private String _processed;
+
+    private boolean _local;
+
+    private NodeState _oldState;
+    private boolean _newNode;
+
+    public NodeUpdate( String name, 
+		       String type,
+		       String cluster,
+		       String satisfied,
+		       String processed,
+		       int side,
+		       boolean local ) {
+	_name = name;
+	_type = type;
+	_cluster = cluster;
+	_satisfied = satisfied;
+	_processed = processed;
+	_side = side;
+	_local = local;
+	_newNode = false;
+    }
+
+    public String toString( ) {
+	return "NodeUpdate: " + _name + " " + _type + " " + _cluster + " " + _satisfied + " " + _processed;
+    }
+
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+    public int initialize( VisualizationPanel visPanel ) {
+	Graph g = visPanel.getGraph( );
+
+	Node n = g.findNodeByName( _name );
+	boolean newNode;
+	int changed;
+
+	if( n == null ) {
+	    new Node( g, _name );
+	    NodeState ns = new NodeState( _name, _type );
+	    changed = ns.updateState( this );
+
+	    newNode = visPanel.addNodeState( ns );
+	    _newNode = true;
+	    return 3;
+
+	} else {
+
+	    NodeState ns = visPanel.getNodeState( _name );
+	    changed = ns.updateState( this );
+
+	    return changed;
+	}
+
+    }
+
+    public Element getElement( VisualizationPanel visPanel ) {
+	Graph g = visPanel.getGraph( );
+	return g.findNodeByName( _name );
+    }
+
+    public boolean apply( VisualizationPanel visPanel ) {
+	Graph g = visPanel.getGraph( );
+	Node n = g.findNodeByName( _name );
+	if( n != null ) {
+	    NodeState ns = visPanel.getNodeState( _name );
+	    _oldState = new NodeState( ns );
+
+	    ns.updateState( this );
+	    visPanel.setNodeProperties( n, ns, _local, _newNode );
+	    return true;
+	}
+	return false;
+    }
+
+    public void undo( VisualizationPanel visPanel ) {
+	if( _oldState == null ) {
+	    throw new RuntimeException( );
+	}
+	
+	Graph g = visPanel.getGraph( );
+	Node n = g.findNodeByName( _name );
+
+	if( n == null ) {
+	    throw new RuntimeException( );
+	}
+
+	NodeState ns = visPanel.getNodeState( _name );
+	ns.setHidden( _oldState.getHidden( ) );
+	ns.setSatisfied( _oldState.getSatisfied( ) );
+
+	visPanel.setNodeProperties( n, _oldState, _local, _newNode );
+
+    }
+
+    public String getName( ) {
+	return _name;
+    }
+
+    public String getSatisfied( ) {
+	return _satisfied;
+    }
+
+    public String getProcessed( ) {
+	return _processed;
+    }
+
+    public void setNew( ) {
+	_newNode = true;
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/NullParser.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/NullParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/NullParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,10 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class NullParser implements LogParser {
+    public List parse( Visualization vis, String log1, String log2 ) {
+	return new ArrayList( );
+    }
+}
+
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/PanelHelper.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/PanelHelper.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/PanelHelper.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,19 @@
+package com.algomagic.atn;
+
+import javax.swing.*;
+import javax.swing.border.*;
+
+
+public class PanelHelper {
+
+    public static void setBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/PanelUpdate.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/PanelUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/PanelUpdate.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,79 @@
+package com.algomagic.atn;
+
+import java.util.*;
+
+public class PanelUpdate {
+    BatchGraphUpdate _graphUpdate;
+    int _tab;
+    int _side;
+    Collection _evidence;
+    boolean _undo;
+    boolean _raise;
+    boolean _add;
+    boolean _hl;
+
+
+    public PanelUpdate( BatchGraphUpdate graphUpdate, int side, int tab, Collection evidence, boolean raise, boolean add, boolean hl ) {
+	_graphUpdate = graphUpdate;
+	_tab = tab;
+	_evidence = evidence;
+	_side = side;
+	_undo = false;
+	_raise = raise;
+	_add = add;
+	_hl = hl;
+    } 
+
+    public void apply( VisualizationPanel visPanel ) {
+	if( _undo ) {
+	    _graphUpdate.undo( );
+	    if( _evidence != null && _add ) {
+		visPanel.removeCredentials( _evidence, _tab );
+	    }
+
+	} else {
+// 	    if( _raise ) {
+// 		visPanel.setRaised( _tab );
+// 	    }
+
+	    visPanel.setRaised( _tab );
+
+	    _graphUpdate.apply( );
+
+	    if( _evidence != null && _hl ) {
+		visPanel.highlightCredentials( _evidence, _tab );
+	    }
+
+	    if( _evidence != null && _add ) {
+		visPanel.addCredentials( _evidence, _tab );
+	    }
+	    
+
+// 	    if( _evidence != null && _tab >= 0 ) {
+// // 		if( _tab != 0 ) {
+// // 		    visPanel.addCredentials( _evidence, _tab );
+// // 		}
+
+// 		visPanel.highlightCredentials( _evidence, _tab );
+// 	    }
+
+
+	}
+    }
+
+    public void setUndo( boolean undo ) {
+	_undo = undo;
+    }
+
+    public int getSide( ) {
+	return _side;
+    }
+
+
+    public boolean isEmpty( ) {
+	return _graphUpdate.isEmpty( );
+    }
+
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/PlayBackController.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/PlayBackController.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/PlayBackController.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,162 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import javax.swing.*;
+
+public class PlayBackController 
+    extends Observable 
+    implements Observer, VisualizationConstants 
+
+{
+    private int _delay;
+    private boolean _loop;
+    private List _updates;
+    private int _index = 0;
+    private boolean _clear = true;
+    private boolean _playing = false;
+
+    public PlayBackController( List updates, Properties properties ) {
+	_delay = Integer.parseInt( properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) );
+	_loop = (new Boolean( properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( );
+	_updates = updates;
+    }
+
+    public void update( Observable o, Object arg ) {
+	if( arg instanceof String ) {
+	    String cmd = (String)arg;
+
+	    if( cmd.equals( "play" ) ) {
+		_playing = true;
+		new Thread( new PlayThread( ) ).start( );
+	    } else if( cmd.equals( "pause" ) ) {
+		_playing = false;
+	    } else if( cmd.equals( "stepf" ) ) {
+		stepf( );
+	    } else if( cmd.equals( "stepb" ) ) {
+		stepb( );
+	    } else if( cmd.equals( "ff" ) ) {
+		ff( );
+	    } else if( cmd.equals( "rewind" ) ) {
+		rewind( );
+	    }
+
+	} else if( arg instanceof JSpinner ) {
+	    SpinnerNumberModel snm = (SpinnerNumberModel)((JSpinner)arg).getModel( );
+	    _delay = snm.getNumber( ).intValue( );
+	} else if (arg instanceof Boolean ) {
+	    _loop = ((Boolean)arg).booleanValue( );
+	}
+    }
+
+
+    public int getIndex( ) {
+	return _index;
+    }
+
+
+    private synchronized void stepf( ) {
+	if( _index == _updates.size( ) ) {
+	    _index = 0;
+	    if( _playing == true && _loop == false ) {
+		_playing = false;
+	    }
+	}
+
+
+	if( _index == 0 && _clear == false ) {
+	    _clear = true;
+
+	    setChanged( );
+	    notifyObservers( "CLEAR" );
+
+	    return;
+	}
+
+	_clear = false;
+
+	PanelUpdate u = (PanelUpdate)_updates.get(_index);
+	u.setUndo( false );
+
+	setChanged( );
+	notifyObservers( u );
+	_index++;
+
+    }
+
+    private synchronized void stepb( ) {
+// 	System.out.println( "steck back " + _index );
+// 	System.out.print( "stepb: " + _index + " " );
+
+
+	if( _index == 0 ) {
+	    ff( );
+// 	    System.out.println(  _index );
+
+	    return;
+	}
+	_index--;
+
+	PanelUpdate u = (PanelUpdate)_updates.get( _index );
+	u.setUndo( true );
+
+ 	setChanged( );
+ 	notifyObservers( u );
+// 	System.out.println(  _index );
+	
+	if( _index == 0 ) {
+	    _clear = true;
+	}
+
+    }
+	
+    private synchronized void ff( ) {
+	int i;
+
+
+// 	System.out.print( "ff: " + _index + " " );
+
+	for( i=_index; i < _updates.size( ); i++ ) {
+	    setChanged( );
+	    PanelUpdate u = (PanelUpdate)_updates.get(i);
+	    u.setUndo( false );
+
+	    _index=i;
+	    notifyObservers( u );
+	    
+// 	    System.out.println( "here" );
+
+	}
+
+	_clear = false;
+	_index=i;
+
+// 	System.out.println(  _index );
+    }
+
+
+    private synchronized void rewind( ) {
+	_index = 0;
+	_clear = true;
+	
+	setChanged( );
+	notifyObservers( "CLEAR" );
+    }
+
+
+    private class PlayThread implements Runnable {
+	public void run( ) {
+	    while( _playing ) {
+		try {
+		    stepf( );
+		    Thread.currentThread( ).sleep( _delay );
+		} catch( InterruptedException ie ) {
+		    throw new RuntimeException( ie );
+		}
+	    }
+		
+	}
+    }
+
+}
+
+
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/ProgressPanel.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/ProgressPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/ProgressPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,35 @@
+package com.algomagic.atn;
+
+import java.util.*;
+import java.awt.*;
+import javax.swing.*;
+
+
+public class ProgressPanel 
+    extends JPanel 
+    implements Observer 
+{
+    JProgressBar _progress;
+
+    public ProgressPanel( ) {
+	super( );
+	setLayout( new BorderLayout( ) );
+
+	_progress = new JProgressBar( 0, 1 );
+	_progress.setValue( 0 );
+	_progress.setStringPainted( true );
+
+	add( _progress, BorderLayout.CENTER );
+
+	PanelHelper.setBorder( this, "Negotiation Progress" );
+    }
+
+    public void setMax( int n ) {
+	_progress.setMaximum( n-1 );
+    }
+
+    public void update( Observable o, Object arg ) {
+	PlayBackController pbc = (PlayBackController)o;
+	_progress.setValue( pbc.getIndex( ) );
+    }
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/PropertyLogParser.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/PropertyLogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/PropertyLogParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,376 @@
+package com.algomagic.atn;
+
+import java.io.*;
+import java.util.*;
+
+public class PropertyLogParser 
+    implements LogParser, VisualizationConstants 
+{
+
+    private Properties _log;
+    private List _updates;
+    private Visualization _vis;
+
+
+    public PropertyLogParser( ) {
+
+    }
+
+    public List parse( Visualization vis, String log1, String log2 ) {
+	_vis = vis;
+	List updates = null;
+	List updates1 = parse( log1, LEFT_SIDE );
+	List updates2 = null;
+
+	if( log2 != null ) {
+	    updates2 = parse( log2, RIGHT_SIDE );
+	    return interleave( updates1, updates2 );
+	} 
+
+	return updates1;
+    }
+
+
+    private List interleave( List updates1, List updates2 ) {
+	List updates = new ArrayList( );
+	Iterator first, second;
+
+
+	ClusterUpdate u = (ClusterUpdate) updates1.get( 0 );
+	if( u.getLocal( ) ) {
+	    first = updates1.iterator( );
+	    second = updates2.iterator( );
+	} else {
+	    first = updates2.iterator( );
+	    second = updates1.iterator( );
+	}
+
+
+	Object o;
+	ClusterUpdate c;
+
+	while( first.hasNext( ) ) {
+	    o = first.next( );
+
+	    updates.add( o );
+
+	    if( o instanceof ClusterUpdate ) {
+		c = (ClusterUpdate)o;
+		if( ! c.getStart( ) ) {
+		    break;
+		}
+
+	    }
+	}
+
+	Iterator tmp = first;
+	first = second;
+	second = tmp;
+
+
+	while( first.hasNext( ) && second.hasNext( ) ) {
+
+	    while( first.hasNext( ) ) {
+		o = first.next( );
+
+		updates.add( o );
+
+		if( o instanceof ClusterUpdate ) {
+		    c = (ClusterUpdate)o;
+		    if( ! c.getStart( ) && c.getLocal( ) ) {
+			break;
+		    }
+
+		}
+	    }
+
+	    while( second.hasNext( ) ) {
+		o = second.next( );
+
+		updates.add( o );
+
+		if( o instanceof ClusterUpdate ) {
+		    c = (ClusterUpdate)o;
+		    if( ! c.getStart( ) && c.getLocal( ) ) {
+			break;
+		    }
+
+		}
+	    }
+
+	}
+
+	if( first.hasNext( ) ) {
+	    while( first.hasNext( ) ) {
+		updates.add( first.next( ) );
+	    }
+	} else if( second.hasNext( ) ) {
+	    while( second.hasNext( ) ) {
+		updates.add( second.next( ) );
+	    }
+	}
+
+	for( int i = 0; i<(updates.size( )-1); i++ ) {
+	    Update u1 = (Update)updates.get( i );
+	    Update u2 = (Update)updates.get( i+1 );
+
+	    if( u1 instanceof ClusterUpdate && u2 instanceof ClusterUpdate ) {
+		ClusterUpdate c1 = (ClusterUpdate)u1;
+		ClusterUpdate c2 = (ClusterUpdate)u2;
+
+		if( (!c1.getStart( ) && c1.getLocal( )) && (c2.getStart( ) && !c2.getLocal( )) ) {
+		    updates.set( i, c2 );
+		    updates.set( i+1, c1 );
+		}
+	    }
+	}
+
+
+
+	return updates;
+    }
+
+
+    private List parse( String log, int side ) {
+	_log = new Properties( );
+	_updates = new ArrayList( );
+	
+	File f = new File( log );
+	if( f.exists( ) ) {
+	    try {
+		_log.load( new FileInputStream( f ) );
+	    } catch( Exception e ) { }
+	}
+	
+
+	
+	_vis.setName( _log.getProperty( "subject" ), side );
+
+	Collection c = new ArrayList( );
+	for( int i=1; _log.containsKey( "policy." + i ); i++ ) {
+	    c.add( _log.getProperty( "policy." + i ) );
+	}
+
+	_vis.setPolicies( c, side );
+
+
+	boolean init = false;
+
+
+	for( int i=1; _log.containsKey( getKey(i) ) || i==1; i++ ) {
+	    String location = _log.getProperty( getKey(i) );
+	    boolean local = true;
+	    int index = i;
+
+
+
+	    if( !_log.containsKey( getKey( i, 1 ) ) ) {
+		continue;
+	    }
+
+
+	    if( location.equals( "remote" ) ) {
+		local = false;
+		
+		if( !init ) {
+
+		    _updates.add( new ClusterUpdate( i,
+						     true,
+						     local,
+						     side ) );
+		}
+	    } else if( location.equals( "local" ) ) {
+		local = true;
+
+		if( !init ) {
+		    _updates.add( new ClusterUpdate( i,
+						     true,
+						     local,
+						     side ) );
+		}
+	    } else if( location.equals( "init" ) ) {
+		if( !_log.containsKey( getKey( 1, 1 ) ) ) {
+		    continue;
+		} else {
+		    init = true;
+		    local = true;
+		    index = 2;
+ 		    _updates.add( new ClusterUpdate( index,
+						     true,
+						     local,
+						     side ) );
+		}
+	    }
+
+
+	    for( int j=1; _log.containsKey( getKey(i,j) ); j++ ) {
+		String type = _log.getProperty( getKey(i,j) );
+		
+		if( type.equals( "edge" ) ) {
+		    parseEdge( i, j, local, side, index );
+		} else if( type.equals( "node" ) ) {
+		    parseNode( i, j, local, side, index );
+		}
+	    }
+
+
+	    if( index==i) {
+
+		if( location.equals( "remote" ) ) {
+		    _updates.add( new ClusterUpdate( i,
+						     false,
+						     local,
+						     side ) );
+		} else {
+		    _updates.add( new ClusterUpdate( i,
+						     false,
+						     local,
+						     side ) );
+		}
+		
+		
+	    }
+
+
+	    init = false;
+
+	}
+
+
+	return _updates;
+    }
+
+    private void parseNode( int i, int j, boolean local, int side, int c ) {
+	String prefix = getPrefix(i,j);
+	String name, type, cluster, satisfied, processed;
+	name = _log.getProperty( prefix + "name" );
+	if( name == null ) {
+	    throw new RuntimeException( prefix );
+	}
+	
+	type = _log.getProperty( prefix + "nodeType" );
+	cluster = getCluster(c);
+	satisfied = _log.getProperty( prefix + "satisfied" );
+	processed = _log.getProperty( prefix + "processing" );
+
+// 	if( processed == null ) {
+// 	    processed = NOT_PROC;
+// 	} else if( processed.equals( "verifier" ) ) {
+// 	    processed = VERIFIER_PROC;
+// 	} else if( processed.equals( "opponent" ) ) {
+// 	    processed = OPPONENT_PROC;
+// 	}
+
+// 	if( satisfied == null ) {
+//   	    satisfied = UNKNOWN;
+// 	}
+
+
+	if( processed == null ) {
+	    processed = NOT_PROC;
+	} else if( processed.toLowerCase( ).equals( "verifier" ) ) {
+	    processed = VERIFIER_PROC;
+	} else if( processed.toLowerCase( ).equals( "opponent" ) ) {
+	    processed = OPPONENT_PROC;
+	} else if ( processed.toLowerCase( ).equals( "fully" ) ) {
+	    processed = FULLY_PROC;
+	}
+
+	if( satisfied == null ) {
+	    satisfied = UNKNOWN;
+	} else if( satisfied.toLowerCase( ).equals( "satisfied" ) ) {
+	    satisfied = SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "unsatisfied" ) ) {
+	    satisfied = NOT_SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "unknown" ) ) {
+	    satisfied = UNKNOWN;
+	}
+
+	NodeUpdate nu = new NodeUpdate( name, type, cluster, satisfied, processed, side, local );
+	_updates.add( nu );
+    }
+
+
+    private void parseEdge( int i, int j, boolean local, int side, int c ) {
+	String prefix = getPrefix(i,j);
+	String type, parentName, childName, childType, processed, satisfied;
+
+	type = _log.getProperty( prefix + "edgeType" );
+	parentName = _log.getProperty( prefix + "parentName" );
+	childName = _log.getProperty( prefix + "childName" );
+	childType = _log.getProperty( prefix + "childType" );
+	processed = _log.getProperty( prefix + "childProcessing" );
+	satisfied = _log.getProperty( prefix + "childSatisfied" );
+
+	if( type == null || parentName == null || childName == null ) {
+	    throw new RuntimeException( prefix );
+	}
+
+
+	if( childType == null ) {
+	    childType = "StandardTarget";
+	}
+
+
+	if( processed == null ) {
+	    processed = NOT_PROC;
+	} else if( processed.toLowerCase( ).equals( "verifier" ) ) {
+	    processed = VERIFIER_PROC;
+	} else if( processed.toLowerCase( ).equals( "opponent" ) ) {
+	    processed = OPPONENT_PROC;
+	} else if ( processed.toLowerCase( ).equals( "fully" ) ) {
+	    processed = FULLY_PROC;
+	}
+
+	if( satisfied == null ) {
+	    satisfied = UNKNOWN;
+	} else if( satisfied.toLowerCase( ).equals( "satisfied" ) ) {
+	    satisfied = SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "failed" ) ) {
+	    satisfied = NOT_SATISFIED;
+	} else if( satisfied.toLowerCase( ).equals( "unknown" ) ) {
+	    satisfied = UNKNOWN;
+	}
+
+
+	if( childType != null && childType.toLowerCase( ).equals( "trivialtarget" ) ) {
+	    satisfied = SATISFIED;
+	}
+	
+
+	NodeUpdate nu = new NodeUpdate( childName, childType, getCluster(c), satisfied, processed, side, local );
+	_updates.add( new EdgeUpdate( parentName, nu, type, local, collectEvidence(i,j), side ) );
+    }
+
+
+    private Collection collectEvidence( int i, int j ) {
+	Collection c = new ArrayList( );
+
+	String key;
+	for( int k=1; _log.containsKey( key = getPrefix(i,j) + "evidence." + Integer.toString(k) ); k++ ) {
+	    c.add( _log.getProperty( key ) );
+	}
+
+	return c;
+    }
+
+
+
+    private String getKey( int i ) {
+	return "update." + Integer.toString( i ) + ".location";
+    }
+
+    private String getKey( int i, int j ) {
+	return getPrefix( i, j ) + "type";
+    }
+
+    private String getPrefix( int i, int j ) {
+	return "update." + Integer.toString( i ) + "." + Integer.toString( j ) + ".";
+    }
+
+    private String getCluster( int i ) {
+	return "cluster" + Integer.toString( i );
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/Test.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/Test.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/Test.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,141 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+
+public class Test 
+    extends JFrame 
+{
+
+    private GrappaPanel _grappaPanel;
+    private Graph _graph;
+    private Subgraph[] _subgraphs;
+
+
+
+    public Test( ) {
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	_graph = new Graph( "Trust Negotiation Graph: " );
+	_grappaPanel = new GrappaPanel( _graph );
+	_grappaPanel.setScaleToFit( false );
+	
+	JScrollPane jsp = new JScrollPane( );
+	jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+	jsp.getViewport( ).setBackground( Color.white );
+	jsp.setViewportView( _grappaPanel );
+
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BorderLayout( ) );
+	contentPane.add( jsp, BorderLayout.CENTER );
+	setSize( 500, 500 );
+
+
+	_subgraphs = new Subgraph[2];
+	_subgraphs[0] = new Subgraph( _graph, "cluster 0" );
+	_subgraphs[1] = new Subgraph( _graph, "cluster 1" );
+
+
+	Node n1 = new Node( _subgraphs[0], "node1" );
+	Node n2 = new Node( _subgraphs[0], "node2" );
+	Node n3 = new Node( _subgraphs[1], "node3" );
+	Node n4 = new Node( _subgraphs[1], "node4" );
+	Node n5 = new Node( _subgraphs[1], "node5" );
+	
+
+// 	_subgraphs[0].addNode( n1 );
+// 	_subgraphs[0].addNode( n2 );
+// 	_subgraphs[1].addNode( n3 );
+// 	_subgraphs[1].addNode( n4 );
+
+
+	Edge e = new Edge( _subgraphs[0], n1, n2 );
+	Edge e2 = new Edge( _subgraphs[0], n2, n3 );
+	new Edge( _subgraphs[1], n3, n4 );
+	new Edge( _subgraphs[1], n3, n5 );
+	new Edge( _subgraphs[1], n5, n4 );
+	
+
+// 	_subgraphs[0].addEdge( e1 );
+// 	_graph.addEdge( e2 );
+// 	_subgraphs[1].addEdge( e3 );
+
+
+	e.setAttribute( "style", "bold,solid,filled" );
+	e2.setAttribute( "style", "solid" );
+
+	formatGraph( _graph );
+
+// 	_graph.setAttribute( "style", "invis" );
+
+
+	Subgraph sg = _graph.findSubgraphByName( "cluster 0" );
+	sg.setAttribute( "color", "red" );
+	sg.setAttribute( "style", "dotted" );
+	sg.setAttribute( "label", "this is a cluster" );
+
+
+	Node n = _graph.findNodeByName( "node1" );
+	n.setAttribute( "style", "filled" );
+	n.setAttribute( "color", "green" );
+	n.setAttribute( "bgcolor", "blue" );
+	n.setAttribute( "fillcolor", "red" );
+
+	n = _graph.findNodeByName( "node2" );
+	n.setAttribute( "style", "solid" );
+	n.setAttribute( "color", "black" );
+
+
+	sg = _graph.findSubgraphByName( "cluster 1" );
+	sg.setAttribute( "style", "dotted" );
+	sg.setAttribute( "fillcolor", "white" );
+	sg.setAttribute( "color", "white" );
+	sg.setAttribute( "bgcolor", "white" );
+
+
+
+
+
+	show( );
+    }
+
+
+    public static void main( String[] args ) {
+	Test t = new Test( );
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/TipAdapter.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/TipAdapter.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/TipAdapter.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,53 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public class TipAdapter extends GrappaAdapter {
+
+    public TipAdapter( ) {
+	super( );
+    }
+
+
+
+    public void grappaClicked(Subgraph subg, 
+			      Element elem, 
+			      GrappaPoint pt, 
+			      int modifiers, 
+			      int clickCount, 
+			      GrappaPanel panel) {
+    }
+
+    public void grappaDragged(Subgraph subg, 
+			      GrappaPoint currentPt, 
+			      int currentModifiers, 
+			      Element pressedElem, 
+			      GrappaPoint pressedPt, 
+			      int pressedModifiers, 
+			      GrappaBox outline, 
+			      GrappaPanel panel) {
+    }
+
+
+    public void grappaPressed(Subgraph subg, 
+			      Element elem, 
+			      GrappaPoint pt, 
+			      int modifiers, 
+			      GrappaPanel panel) {
+
+    }
+
+    public void grappaReleased(Subgraph subg, 
+			       Element elem, 
+			       GrappaPoint pt, 
+			       int modifiers, 
+			       Element pressedElem, 
+			       GrappaPoint pressedPt, 
+			       int pressedModifiers, 
+			       GrappaBox outline, 
+			       GrappaPanel panel) { 
+    }
+
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/Update.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/Update.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/Update.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,18 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+public interface Update {
+
+    public int initialize( VisualizationPanel visPanel );
+    public boolean apply( VisualizationPanel visPanel );
+    public void undo( VisualizationPanel visPanel);
+    public int getSide( );
+    public boolean getSkip( );
+    public void setSkip( boolean skip );
+    public Element getElement( VisualizationPanel visPanel );
+    public boolean getUndo( );
+    public void setUndo( boolean undo );
+    public boolean getLocal( );
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/Visualization.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/Visualization.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/Visualization.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,250 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+
+import java.util.*;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class Visualization extends JFrame
+    implements VisualizationConstants {
+
+    private Properties _properties;
+    private VisualizationPanel[] _visPanels;
+
+    private ControlPanel _controls;
+    private ProgressPanel _progress;
+
+    private String[] _names = new String[2];
+    private Collection[] _policies = new Collection[2];
+
+    public void setName( String name, int side ) {
+	_names[side] = name;
+    }
+
+    public void setPolicies( Collection pol, int side ) {
+	_policies[side] = pol;
+    }
+
+
+
+    public void setAutoRaise( boolean state ) {
+	_visPanels[LEFT_SIDE].setAutoRaise( state );
+	if( _visPanels[RIGHT_SIDE] != null ) {
+	    _visPanels[RIGHT_SIDE].setAutoRaise( state );
+	}
+	
+    }
+
+
+    public Visualization( String log1, String log2 ) {
+
+
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	loadProperties( );
+	initializeFrame( log2 != null );
+
+	LogParser parser = null;
+
+	try {
+	    parser = 
+		(LogParser)Class.forName( _properties.getProperty( PARSER_PROP, 
+								   PARSER_DEFAULT ) ).newInstance( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	
+	java.util.List updates = parser.parse( this, log1, log2 );
+
+	updates = _visPanels[LEFT_SIDE].initialize( updates );
+	_visPanels[LEFT_SIDE].addCredentials( _policies[LEFT_SIDE], 2 );
+	_visPanels[LEFT_SIDE].setName( _names[LEFT_SIDE] );
+
+
+// 	System.out.println( _policies[LEFT_SIDE] );
+// 	System.out.println( _policies[RIGHT_SIDE] );
+
+
+	if( log2 != null ) {
+	    updates = _visPanels[RIGHT_SIDE].initialize(  updates );
+	    _visPanels[RIGHT_SIDE].addCredentials( _policies[RIGHT_SIDE], 2 );
+	    _visPanels[RIGHT_SIDE].setName( _names[RIGHT_SIDE] );
+
+	}
+	
+
+
+	java.util.List l = new ArrayList( );
+
+	for( Iterator i = updates.iterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+	    PanelUpdate pu = null;;
+
+	    if( u.getSide( ) == LEFT_SIDE ) {
+		pu = _visPanels[LEFT_SIDE].apply( u );
+	    } else if( log2 != null ) {
+		pu = _visPanels[RIGHT_SIDE].apply( u );
+	    }
+
+	    if( !pu.isEmpty( ) ) {
+		l.add( pu );
+	    }
+
+	}
+
+
+// 	_visPanels[LEFT_SIDE].reset( updates );
+// 	if( log2 != null ) {
+// 	    _visPanels[RIGHT_SIDE].reset( updates );
+// 	}
+	
+
+	PlayBackController pbc = new PlayBackController( l, _properties );
+	pbc.addObserver( _progress );
+	pbc.addObserver( _visPanels[LEFT_SIDE] );
+	_visPanels[LEFT_SIDE].hideGraph( );
+
+	if( log2 != null ) {
+	    pbc.addObserver( _visPanels[RIGHT_SIDE] );
+	    _visPanels[RIGHT_SIDE].hideGraph( );
+	}
+
+
+	_progress.setMax( l.size( ) );
+	_controls.addObserver( pbc );
+
+
+// // 	Object[] o = getKeyListeners( );
+// 	for( int i = 0; o != null && i<o.length; i++ ) {
+// 	    removeKeyListener( (KeyListener)o[i] );
+// 	}
+
+
+
+// 	addKeyListener( new KeyListener( ) {
+// 		public void keyTyped( KeyEvent e ) {
+// 		    System.out.println( "typed: " + e );
+// 		}
+
+// 		public void keyPressed( KeyEvent e ) {
+// 		    System.out.println( "pressed: " + e );
+// 		}
+
+// 		public void keyReleased( KeyEvent e ) {
+// 		    System.out.println( "released: " + e );
+// 		}
+
+
+// 	    });
+
+
+// 	addFocusListener( new FocusListener( ) {
+// 		public void focusGained( FocusEvent e ) {
+// 		    System.out.println( "focus gained: " + e );
+// 		}
+
+// 		public void focusLost( FocusEvent e ) {
+// 		    System.out.println( "focus lost: " + e ); 
+// // 		    requestFocus( );
+// 		}
+
+
+// 	    });
+		       
+
+
+ 	show( );
+// 	requestFocus( true );
+
+    }
+
+    private void initializeFrame( boolean twoSided ) {
+	JPanel mainPanel = new JPanel( );
+	mainPanel.setLayout( new BoxLayout( mainPanel, BoxLayout.X_AXIS ) );
+
+	_visPanels = new VisualizationPanel[2];
+	_visPanels[LEFT_SIDE] = new VisualizationPanel( LEFT_SIDE, _properties );
+	mainPanel.add( _visPanels[LEFT_SIDE] );
+
+	if( twoSided ) {
+	    _visPanels[RIGHT_SIDE] = new VisualizationPanel( RIGHT_SIDE, _properties );
+	    mainPanel.add( Box.createHorizontalStrut( 10 ) );
+	    mainPanel.add( _visPanels[RIGHT_SIDE] );
+	}
+	
+	_controls = new ControlPanel( _properties, this );
+	_progress = new ProgressPanel( );
+
+	JPanel toolPanel = new JPanel( );
+
+	toolPanel.setMaximumSize( new Dimension( 2000, 50 ) );
+	toolPanel.setPreferredSize( new Dimension( 2000, 50 ) );
+
+
+	toolPanel.setLayout( new BoxLayout( toolPanel, BoxLayout.X_AXIS ) );
+	toolPanel.add( _controls );
+	toolPanel.add( _progress );
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.Y_AXIS ) );
+	contentPane.add( mainPanel );
+	contentPane.add( toolPanel );
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+    }
+
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	_properties = new Properties( );
+
+	if( file.exists( ) ) {
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( Exception e ) { }
+	}
+
+    }
+
+
+    public static void main( String[] args ) {
+	Visualization vis = null;
+
+	if( args.length == 1 ) {
+	    vis = new Visualization( args[0], null );
+	} else if ( args.length == 2 ) {
+	    vis = new Visualization( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: Visualization <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/VisualizationConstants.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/VisualizationConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/VisualizationConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,120 @@
+package com.algomagic.atn;
+
+import att.grappa.GrappaConstants;
+
+public interface VisualizationConstants extends GrappaConstants {
+    public static final String SYSTEM_PREFIX = "atnvis.";
+
+    public static final String CONFIG_FILE_PROP = SYSTEM_PREFIX + "ConfigFile";
+    public static final String WINDOW_TITLE_PROP = SYSTEM_PREFIX + "window.Title";
+    public static final String WINDOW_HEIGHT_PROP = SYSTEM_PREFIX + "window.Height";
+    public static final String WINDOW_WIDTH_PROP = SYSTEM_PREFIX + "window.Width";
+
+    public static final String DELAY_PROP = SYSTEM_PREFIX + "defaultDelay";
+    public static final String LOOP_PROP = SYSTEM_PREFIX + "loop";
+
+    public static final String PARSER_PROP = SYSTEM_PREFIX + "parser";
+    public static final String PARSER_DEFAULT = "com.algomagic.atn.NullParser";
+    
+    public static final String SCALE_PROP = SYSTEM_PREFIX + "graph.Scale";
+    public static final String SCALE_DEFAULT = "1.0";
+
+    public static final String IGNOREPROC_PROP = SYSTEM_PREFIX + "parser.IgnoreProcessing";
+    public static final String IGNOREPROC_DEFAULT = "true";
+
+
+    public static final String SHADOW_PROP = SYSTEM_PREFIX + "graph.ShadowColor";
+    public static final String SHADOW_DEFAULT = "grey90";
+
+
+    public static final String CONFIG_FILE_DEFAULT = "atnvis.properties";
+    public static final String WINDOW_TITLE_DEFAULT = "ATN Visualization";
+    public static final String WINDOW_HEIGHT_DEFAULT = "800";
+    public static final String WINDOW_WIDTH_DEFAULT = "600";
+
+    public static final String DELAY_DEFAULT = "500";
+    public static final String LOOP_DEFAULT = "true";
+
+    public static final int LEFT_SIDE = 0;
+    public static final int RIGHT_SIDE = 1;
+
+    public static final String OPPONENT_PROC = "Opponent";
+    public static final String VERIFIER_PROC = "Verifier";
+    public static final String FULLY_PROC = "Fully";
+    public static final String NOT_PROC = "Unprocessed";
+
+    public static final String SATISFIED = "Satisfied";
+    public static final String NOT_SATISFIED = "Failed";
+    public static final String UNKNOWN = "Unknown";
+
+    public static final String STANDARD_TARGET = "StandardTarget";
+    public static final String ROLE_TARGET = "RoleTarget";
+    public static final String LINKING_ROLE_TARGET = "LinkingRoleTarget";
+    public static final String TRIVIAL_TARGET = "TrivialTarget";
+    public static final String INTERSECTION_TARGET = "IntersectionTarget";
+    public static final String LINKING_GOAL = "LinkingGoal";
+
+    public static final String IMPLICATION_EDGE = "Implication";
+    public static final String LINKING_MONITOR_EDGE = "LinkingMonitor";
+    public static final String LINKING_SOLUTION_EDGE = "LinkingSolution";
+    public static final String LINKING_IMPLICATION_EDGE = "LinkingImplication";
+    public static final String INTERSECTION_EDGE = "Intersection";
+    public static final String CONTROL_EDGE = "Control";
+
+    public static final String DEFAULT_NODE = SYSTEM_PREFIX + "node.Default.";
+    public static final String DEFAULT_EDGE = SYSTEM_PREFIX + "edge.Default.";
+
+
+    public static final String[] NODE_ATTRS = {
+	SHAPE_ATTR,
+	SIDES_ATTR,
+	PERIPHERIES_ATTR,
+	STYLE_ATTR,
+	COLOR_ATTR,
+	FONTNAME_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR };
+
+
+
+    public static final String[] NODE_ATTRS_PROP = {
+	"shape",
+	"sides",
+	"peripheries",
+	"style",
+	"color",
+	"fontname",
+	"fontcolor",
+	"fontsize",
+	"fontstyle" };
+
+    public static final boolean[] NODE_ATTRS_INT = {
+	false,
+	true,
+	true,
+	false,
+	false,
+	false,
+	false,
+	true,
+	false };
+
+
+    public static final String[] EDGE_ATTRS = {
+	STYLE_ATTR,
+	COLOR_ATTR,
+	DIR_ATTR };
+
+    public static final String[] EDGE_ATTRS_PROP = {
+	"style",
+	"color",
+	"direction" };
+
+
+    public static final boolean[] EDGE_ATTRS_INT = {
+	false,
+	false,
+	false };
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/VisualizationPanel.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/VisualizationPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/VisualizationPanel.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,1000 @@
+package com.algomagic.atn;
+
+import att.grappa.*;
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class VisualizationPanel 
+    extends JPanel 
+    implements Observer, VisualizationConstants {
+
+    private int _side;
+    private Properties _properties;
+
+    private GrappaPanel _grappaPanel;
+    private Graph _graph;
+
+    private JPanel _complete;
+    private JPanel _graphPanel;
+    private CredentialPanel _credentialPanel;
+
+    private ImageIcon _collapse;
+    private ImageIcon _expand;
+
+    private HashMap _nodeStates;
+    private Subgraph _currentCluster;
+
+    private boolean _local;
+    private java.util.List _bolded;
+    private HashMap _remoteClusters;
+    private HashMap _remoteEvidence;
+
+    private HashMap _localClusters;
+    
+    private String _shadowColor;
+    private int _currentIndex;
+
+    private BatchGraphUpdate _batchUpdate;
+    private boolean _ignoreProcessing;
+    private HashSet _boldedNodes;
+    private boolean _basicProps;
+
+    private String _name;
+
+    public void setName( String name ) {
+	_name = name;
+	PanelHelper.setBorder( _graphPanel, "Trust Target Graph: " + name );
+// 	_graph.setAttribute( TIP_ATTR, "Trust Target Graph: " + name );
+// 	_graph.setAttribute( TIP_ATTR, null );
+
+	_grappaPanel.setToolTipText( null );
+    }
+
+
+    class CredentialPanel extends JPanel {
+	JTabbedPane _tabs;
+	JList _local;
+	JList _remote;
+	JList _policy;
+
+	DefaultListModel _localCreds;
+	DefaultListModel _remoteCreds;
+	DefaultListModel _policyCreds;
+
+	boolean _autoRaise;
+
+	public CredentialPanel( ) {
+	    super( );
+
+	    _autoRaise = true;
+
+	    _tabs = new JTabbedPane( );
+
+	    _localCreds = new DefaultListModel( );
+	    _remoteCreds = new DefaultListModel( );
+	    _policyCreds = new DefaultListModel( );
+
+
+	    _local = new JList( _localCreds );
+	    _remote = new JList( _remoteCreds );
+	    _policy = new JList( _policyCreds );
+
+
+	    _tabs.addTab( "Local Credentials", new JScrollPane( _local ) );
+	    _tabs.addTab( "Remote Credentials", new JScrollPane( _remote ) );
+	    _tabs.addTab( "Policies", new JScrollPane( _policy ) );
+
+ 
+	    setLayout( new BorderLayout( ) );
+	    add( _tabs, BorderLayout.CENTER );
+
+	    PanelHelper.setBorder( this, "Credentials" );
+	}
+	
+
+	public void clearSelection( ) {
+	    _local.clearSelection( );
+	    _remote.clearSelection( );
+	}
+
+
+	public void setAutoRaise( boolean state ) {
+	    _autoRaise = state;
+	}
+
+
+	public void setRaised( int tab ) {
+	    clearSelection( );
+
+	    if( _autoRaise ) {
+// 		System.out.println( "side: " + _side + "  tab: " + tab );
+
+		_tabs.setSelectedIndex( tab );
+	    }
+	}
+
+
+	public void setRaised( boolean local ) {
+	    clearSelection( );
+
+	    if( _autoRaise ) {
+		if( local ) {
+		    _tabs.setSelectedIndex( 0 );
+		} else {
+		    _tabs.setSelectedIndex( 1 );
+		}
+	    }
+	}
+	
+
+	public void addCredentials( Collection evidence, int tab ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( tab == 0 ) {
+		m = _localCreds;
+	    } else if( tab == 1 ) {
+		m = _remoteCreds;
+	    } else {
+		m = _policyCreds;
+	    }
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( !m.contains( o ) ) {
+		    m.addElement( o );
+		}
+// 		m.addElement( i.next( ) );
+	    }
+	}
+
+
+	public void removeCredentials( Collection evidence, int tab ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( tab == 0 ) {
+		m = _localCreds;
+	    } else if( tab == 1 ) {
+		m = _remoteCreds;
+	    } else {
+		m = _policyCreds;
+	    }
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( m.contains( o ) ) {
+		    m.removeElement( o );
+		}
+// 		m.addElement( i.next( ) );
+	    }
+	}
+
+
+	public void addCredentials( Collection evidence, boolean local ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( local ) {
+		m = _localCreds;
+	    } else {
+		m = _remoteCreds;
+	    }
+
+
+
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( !m.contains( o ) ) {
+		    m.addElement( o );
+		}
+	    }
+
+	}
+
+
+	public void removeCredentials( Collection evidence, boolean local ) {
+	    clearSelection( );
+	    DefaultListModel m;
+
+	    if( local ) {
+		m = _localCreds;
+	    } else {
+		m = _remoteCreds;
+	    }
+
+
+
+
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		Object o = i.next( );
+
+		if( m.contains( o ) ) {
+		    m.removeElement( o );
+		}
+	    }
+
+	}
+
+	public void highlightCredentials( Collection evidence, int tab ) {
+
+	    DefaultListModel m;
+	    JList l;
+
+	    if( tab == 0 ) {
+		m = _localCreds;
+		l = _local;
+	    } else {
+		m = _remoteCreds;
+		l = _remote;
+	    }
+
+
+	    clearSelection( );
+
+	    int[] indices = new int[evidence.size( )];
+	    int count = 0;
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		indices[count] = m.indexOf( i.next( ) );
+		count++;
+	    }
+
+	    l.setSelectedIndices( indices );
+	}
+
+
+	public void highlightCredentials( Collection evidence, boolean local ) {
+	    DefaultListModel m;
+	    JList l;
+
+	    if( local ) {
+		m = _localCreds;
+		l = _local;
+	    } else {
+		m = _remoteCreds;
+		l = _remote;
+	    }
+
+
+	    clearSelection( );
+
+	    int[] indices = new int[evidence.size( )];
+	    int count = 0;
+	    for( Iterator i = evidence.iterator( ); i.hasNext( ); ) {
+		indices[count] = m.indexOf( i.next( ) );
+		count++;
+	    }
+
+	    l.setSelectedIndices( indices );
+
+	}
+
+	public void removeRemoteCreds( ) {
+// 	    System.out.println( "removing remote creds" );
+
+	    _remoteCreds.clear( );
+	}
+
+    }
+
+
+    public void setAutoRaise( boolean state ) {
+	_credentialPanel.setAutoRaise( state );
+    }
+
+    public void clearSelection( ) {
+	_credentialPanel.clearSelection( );
+    }
+
+
+    public void setRaised( boolean local ) {
+	_credentialPanel.setRaised( local );
+    }
+
+    public void setRaised( int tab ) {
+	_credentialPanel.setRaised( tab );
+    }
+
+
+    public void addCredentials( Collection evidence, boolean local ) {
+	if( evidence != null ) {
+	    _credentialPanel.addCredentials( evidence, local );
+	}
+    }
+
+    public void removeCredentials( Collection evidence, boolean local ) {
+	if( evidence != null ) {
+	    _credentialPanel.removeCredentials( evidence, local );
+	}
+    }
+
+
+    public void highlightCredentials( Collection evidence, boolean local ) {
+	if( evidence != null ) {
+	    _credentialPanel.highlightCredentials( evidence, local );
+	}
+    }
+    
+    public void addCredentials( Collection evidence, int tab ) {
+	if( evidence != null ) {
+	    _credentialPanel.addCredentials( evidence, tab );
+	}
+    }
+
+    public void removeCredentials( Collection evidence, int tab ) {
+	if( evidence != null ) {
+	    _credentialPanel.removeCredentials( evidence, tab );
+	}
+    }
+
+    public void highlightCredentials( Collection evidence, int tab ) {
+	if( evidence != null ) {
+	    _credentialPanel.highlightCredentials( evidence, tab );
+	}
+    }
+    
+
+    public VisualizationPanel( int side, Properties properties ) {
+	super( );
+
+	_side = side;
+	_properties = properties;
+	_currentCluster = null;
+	_local = true;
+	_basicProps = false;
+
+	_nodeStates = new HashMap( );
+	_bolded = new ArrayList( );
+	_remoteClusters = new HashMap( );
+	_remoteEvidence = new HashMap( );
+	_localClusters = new HashMap( );
+	_batchUpdate = new BatchGraphUpdate( );
+	_boldedNodes = new HashSet( );
+
+
+	_ignoreProcessing = (new Boolean( _properties.getProperty( IGNOREPROC_PROP, IGNOREPROC_DEFAULT ) )).booleanValue( );
+// 	System.out.println( _properties.getProperty( IGNOREPROC_PROP, IGNOREPROC_DEFAULT ) );
+// 	System.out.println( _ignoreProcessing );
+
+
+	_shadowColor = _properties.getProperty( SHADOW_PROP, SHADOW_DEFAULT );
+
+
+	Class clazz = this.getClass( );
+	_collapse = new ImageIcon( clazz.getResource( "/resources/collapse.gif" ), "collapse" );
+	_expand = new ImageIcon( clazz.getResource( "/resources/expand.gif" ), "expand" );
+
+
+	JPanel hiderPanel = new JPanel( );
+	hiderPanel.setLayout( new BoxLayout( hiderPanel, BoxLayout.X_AXIS ) );
+
+	JButton hider = new JButton( _collapse );
+	hider.setMaximumSize( new Dimension( 2000, 10 ) );
+	hider.setPreferredSize( new Dimension( 2000, 10 ) );
+	hider.setMinimumSize( new Dimension( 0, 10 ) );
+
+	hider.addActionListener( new ActionListener( ) {
+		boolean removed = false;
+		
+		public void actionPerformed( ActionEvent e ) {
+		    JButton button = (JButton)e.getSource( );
+
+		    if( ! removed ) {
+			_complete.remove( _credentialPanel );
+			button.setIcon( _expand );
+			removed = true;
+		    } else {
+			_complete.add( _credentialPanel, 2 );
+			button.setIcon( _collapse );
+			removed = false;
+		    }
+
+		    validate( );
+		    repaint( );
+		}
+
+	    } );
+
+	hiderPanel.add( hider );
+
+	_graph = new Graph( "Trust Target Graph: " + _side );
+
+	_grappaPanel = new GrappaPanel( _graph );
+	_grappaPanel.setScaleToFit( false );
+	
+// 	JScrollPane jsp = new JScrollPane( );
+// 	jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+// 	jsp.getViewport( ).setBackground( Color.white );
+// 	jsp.setViewportView( _grappaPanel );
+	
+	JScrollPane jsp = new JScrollPane( _grappaPanel );
+// 	jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	jsp.getViewport( ).setBackground( Color.white );
+// 	jsp.setViewportView( _grappaPanel );
+	
+
+	_graphPanel = new JPanel( new BorderLayout( ) );
+	PanelHelper.setBorder( _graphPanel, "Trust Target Graph" );
+	_graphPanel.add( jsp, BorderLayout.CENTER );
+
+	
+	_credentialPanel = new CredentialPanel( );
+	_credentialPanel.setMaximumSize( new Dimension( 2000, 150 ) );
+	_credentialPanel.setPreferredSize( new Dimension( 2000, 150 ) );
+	_credentialPanel.setMinimumSize( new Dimension( 0, 150 ) );
+
+	_complete = new JPanel( );
+	_complete.setLayout( new BoxLayout( _complete, BoxLayout.Y_AXIS ) );
+
+	_complete.add( _graphPanel );
+	_complete.add( hiderPanel );
+	_complete.add( _credentialPanel );
+
+
+	_grappaPanel.addGrappaListener( new TipAdapter( ) );
+
+
+	setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+	add( _complete );
+
+    }
+
+
+
+
+
+    public boolean addNodeState( NodeState ns ) {
+	if( _nodeStates.containsKey( ns.getName( ) ) ) {
+	    return false;
+	}
+
+	_nodeStates.put( ns.getName( ), ns );
+
+	return true;
+    }
+
+    public NodeState getNodeState( String name ) {
+	return (NodeState)_nodeStates.get( name );
+    }
+
+
+
+    public void reset( java.util.List updates ) {
+	_basicProps = true;
+
+	for( ListIterator i = updates.listIterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+
+	    if( u.getSide( ) == _side ) {
+		u.apply( this );
+	    }
+	}
+
+	_basicProps = false;
+	hideGraph( _graph );
+
+    }
+
+
+    public java.util.List initialize( java.util.List updates ) {
+	java.util.List filteredUpdates = new ArrayList( );
+
+	for( ListIterator i = updates.listIterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+	    if( u.getSide( ) == _side ) {
+		int changed = u.initialize( this );
+
+		// if changed == 1, processing state changed
+		//    changed == 2, satisfaction state changed
+		//    changed == 3, processing and satisfaction changed
+		//    changed == 0, no change
+
+
+		if( changed == 3 ||
+		    (!_ignoreProcessing && changed >= 1 ) ||
+		    (_ignoreProcessing && changed >= 2 ) ) {
+
+		    filteredUpdates.add( u );
+		}
+	    } else {
+		filteredUpdates.add( u );
+	    }
+	}
+
+
+	boolean isRemoteCluster = false;
+	int clusterNumber = -1;
+	HashSet remoteCluster = null;
+	Collection remoteEvidence = null;
+
+
+	for( ListIterator i = filteredUpdates.listIterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+	    if( u.getSide( ) == _side ) {
+// 		if( u instanceof NodeUpdate ) {
+// 		    System.out.println( u );
+// 		}
+
+		u.apply( this );
+
+		if( u instanceof ClusterUpdate ) {
+		    ClusterUpdate cu = (ClusterUpdate)u;
+		    if( !cu.getLocal( ) ) {
+			if( cu.getStart( ) ) {
+			    isRemoteCluster = true;
+			    clusterNumber = cu.getCluster( );
+			    remoteCluster = new HashSet( );
+			    remoteEvidence = new ArrayList( );
+			} else {
+			    isRemoteCluster = false;
+			    _remoteClusters.put( new Integer( clusterNumber ), remoteCluster );
+			    _remoteEvidence.put( new Integer( clusterNumber ), remoteEvidence );
+			}
+		    }
+		} else if( isRemoteCluster ) {
+		    remoteCluster.add( u );
+		    if( u instanceof EdgeUpdate ) {
+			Collection c = ((EdgeUpdate)u).getEvidence( );
+			remoteEvidence.addAll( c );
+		    }
+		}
+
+	    }
+	}
+
+
+	formatGraph( _graph );
+ 	hideGraph( _graph );
+	_credentialPanel.removeRemoteCreds( );
+
+
+	String scaleStr = _properties.getProperty( SCALE_PROP, SCALE_DEFAULT );
+	double scale = Double.parseDouble( scaleStr );
+
+	_grappaPanel.multiplyScaleFactor( scale );
+
+	_graph.resync( );
+	_graph.repaint( );
+
+
+	return filteredUpdates;
+    }
+
+
+
+    public PanelUpdate apply( Update u ) {
+	_batchUpdate = new BatchGraphUpdate( );
+
+	if( u.getSide( ) != _side ) {
+	    throw new RuntimeException( );
+	}
+	    
+
+	u.apply( this );	    
+
+	boolean raise = false;
+	int tab = -1;
+
+	boolean add = false;
+	boolean hl = true;
+
+	Collection c = null;
+
+	if( u instanceof ClusterUpdate ) {
+	    ClusterUpdate cu = (ClusterUpdate)u;
+	    if( !cu.getStart( ) && cu.getLocal( ) ) {
+		unSetBolded( !cu.getUndo( ), cu.getCluster( ) );
+	    } else if( cu.getStart( ) && !cu.getLocal( ) ) {
+		setShadowed( !cu.getUndo( ), cu.getCluster( ) );
+		c = (Collection) _remoteEvidence.get( new Integer( cu.getCluster( ) ) );
+		add = true;
+		hl = false;
+	    }
+	}
+
+
+	if( u.getLocal( ) ) {
+	    tab = 0;
+	    raise = true;
+	} else {
+	    tab = 1;
+	    raise = true;
+	}
+
+
+	if( u instanceof EdgeUpdate ) {
+	    EdgeUpdate eu = (EdgeUpdate)u;
+	    c = eu.getEvidence( );
+
+	    if( eu.getType( ).equals( CONTROL_EDGE ) ) {
+		if( u.getLocal( ) ) {
+		    tab = 2;
+		    raise = true;
+		}
+	    }
+	}
+
+
+	    
+	return new PanelUpdate( _batchUpdate, _side, tab, c, raise, add, hl );
+    }
+
+
+    public void update( Observable o, Object arg ) {
+	clearSelection( );
+
+	if( arg instanceof PanelUpdate ) {
+
+	    PanelUpdate u = (PanelUpdate)arg;
+	    if( u.getSide( ) != _side ) {
+ 		return;
+	    }
+
+
+// 	    if( u instanceof ClusterUpdate ) {
+// 		ClusterUpdate cu = (ClusterUpdate)u;
+// 		if( !cu.getStart( ) && cu.getLocal( ) ) {
+// 		    unSetBolded( !cu.getUndo( ), cu.getCluster( ) );
+// 		} else if( cu.getStart( ) && !cu.getLocal( ) ) {
+// 		    setShadowed( !cu.getUndo( ), cu.getCluster( ) );
+// 		}
+// 	    }
+
+	    u.apply( this );
+
+	    _graph.resync( );
+	    _graph.repaint( );
+
+	    
+// 	    if( u.getUndo( ) ) {
+// // 		System.out.println( "UNDO" );
+// 		u.undo( this );
+// 	    } else {
+// 		u.apply( this );	    
+// 	    }
+
+// 	    _graph.resync( );
+// 	    _graph.repaint( );
+
+	} else if( arg instanceof String ) {
+
+	    String s = (String)arg; 
+	    if( s.equals( "CLEAR" ) ) {
+// 		System.out.println( "CLEAR" );
+
+		hideGraph( _graph );
+// 		_credentialPanel.removeRemoteCreds( );
+	    }
+	}
+    }
+
+
+    public Graph getGraph( ) {
+	return _graph;
+    }
+
+    public Subgraph getCurrentCluster( ) {
+	return _currentCluster;
+    }
+
+    public void setCurrentCluster( Subgraph sg ) {
+	_currentCluster = sg;
+    }
+
+
+
+
+
+    private void setShadowed( boolean shadow, int clusterNum ) {
+	HashSet cluster  = (HashSet)_remoteClusters.get( new Integer( clusterNum ) );
+
+	for( Iterator i = cluster.iterator( ); i.hasNext( ); ) {
+	    Update u = (Update)i.next( );
+
+	    if( u instanceof NodeUpdate ) {
+		NodeUpdate nu = (NodeUpdate)u;
+
+		NodeState ns = getNodeState( nu.getName( ) );
+		if( ns.getHidden( ) == false ) {
+		    continue;
+		}
+
+	    }
+
+	    Element e = u.getElement( this );
+
+	    if( shadow ) {
+		setShadow( e );
+	    } else {
+		setInvis( e );
+	    }
+
+	    if( u instanceof EdgeUpdate ) {
+		EdgeUpdate eu = (EdgeUpdate)u;
+
+		NodeState ns = getNodeState( eu.getChildName( ) );
+		if( ns.getHidden( ) == false ) {
+		    continue;
+		}
+
+		e = eu.getChild( this );
+		
+		if( shadow ) {
+		    setShadow( e );
+		} else {
+		    setInvis( e );
+		}
+
+	    }
+
+
+	}
+
+
+    }
+
+
+
+    public void setShadow( Element e ) {
+	setAttribute( e, "color", _shadowColor );
+	setAttribute( e, "style", "solid" );
+	setAttribute( e, "fontcolor", _shadowColor );
+    }
+
+
+    private void unSetBolded( boolean unbold, int cluster ) {
+	_boldedNodes = new HashSet( );
+
+	if( !unbold ) {
+	    _local = true;
+	    _bolded = (java.util.List)_localClusters.get( new Integer( cluster ) );
+	}
+
+	if( unbold ) {
+	    for( Iterator i = _bolded.iterator( ); i.hasNext( ); ) {
+
+		ElementAtt e = (ElementAtt)i.next( );
+		e.apply( );
+	    }
+	} else {
+
+	    for( int i=_bolded.size()-1; i>=0;i-- ) {
+		ElementAtt e = (ElementAtt)_bolded.get(i);
+		e.undo( );
+	    }
+	}
+
+	if( !unbold ) {
+	    _local = false;
+	} else {
+	    _localClusters.put( new Integer( cluster ), _bolded );
+	    _bolded = new ArrayList( );
+	}
+
+    }
+
+
+    private class ElementAtt {
+	private Element _e;
+	private String _att;
+	private String _value;
+	private Object _undoValue;
+
+	public ElementAtt( Element e, String att, String value, String undoValue ) {
+	    _e = e;
+	    _att = att;
+	    _value = value;
+	    _undoValue = undoValue;
+	}
+
+	public void apply( ) {
+	    _undoValue = setAttribute( _e,  _att, _value );
+	}
+
+	public void undo( ) {
+	    _e.setAttribute( _att, _undoValue );
+	}
+
+
+    }
+
+
+
+
+
+    private Object setAttribute( Element e, String attr, Object value ) {
+	Object previousValue = e.setAttribute( attr, value );
+	if( _batchUpdate != null ) {
+	    _batchUpdate.add( new ElementAttribute( e, attr, value, previousValue ) );
+	}
+
+	return previousValue;
+    }
+
+
+
+    private void setNodeProps( Node n, String prefix, boolean setBold ) {
+
+	for( int i=0; i < NODE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + NODE_ATTRS_PROP[i] );
+	    if( strValue == null ) {
+		continue;
+	    }
+
+
+	    if( NODE_ATTRS_INT[i] ) {
+		setAttribute( n, NODE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		
+		if( NODE_ATTRS[i].equals( FONTSTYLE_ATTR ) && ( setBold || _boldedNodes.contains( n ) ) ) {
+		    _bolded.add( new ElementAtt( n, FONTSTYLE_ATTR, strValue,"bold" ) );
+		    strValue = "bold";
+		} 
+
+		setAttribute( n, NODE_ATTRS[i], strValue );
+
+	    }
+	}
+    }
+
+
+
+    private void setEdgeProps( Edge e, String prefix, boolean local ) {
+	for( int i=0; i < EDGE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + EDGE_ATTRS_PROP[i] );
+	    String undoValue = _properties.getProperty( prefix + EDGE_ATTRS_PROP[i] + ".bold" );
+
+	    String change = strValue;
+
+
+	    if( strValue == null ) {
+		continue;
+	    }
+	    
+	    if( local ) {
+		if( undoValue != null ) {
+		    _bolded.add( new ElementAtt( e, EDGE_ATTRS[i], strValue, undoValue ) );
+		    change = undoValue;
+		}
+
+	    }
+	    
+	    setAttribute( e, EDGE_ATTRS[i], change );
+	}
+    }
+
+    
+    public void setNodeProperties( Node n, NodeState ns, boolean local, boolean newNode ) {
+	if( ns.getHidden( ) ) {
+
+	    if( _local == false ) {
+		setShadow( n );
+	    } else {
+		setInvis( n );
+	    }
+	    return;
+	}
+
+	if( ns.getBolded( ) == false && ( local && newNode ) ) {
+	    ns.setBolded( true );
+	}
+
+	if( local&&newNode ) {
+	    _boldedNodes.add( n );
+	}
+
+	setNodeProperties( n, ns.getType( ), ns.getSatisfied( ), ns.getProcessed( ), local&&newNode );
+    }
+
+
+    private void setNodeProperties( Node n, String type, String satisfaction, String process, boolean setBold ) {
+	setNodeProps( n, DEFAULT_NODE, setBold );
+	setNodeProps( n, SYSTEM_PREFIX + "node." + type + ".", setBold );
+
+	if( _basicProps ) {
+	    return;
+	}
+
+
+	setNodeProps( n, SYSTEM_PREFIX + "node.satisfied." + satisfaction + ".", setBold );
+
+	if( !_ignoreProcessing ) {
+	    setNodeProps( n, SYSTEM_PREFIX + "node.processed." + process + ".", setBold );
+	}
+    }
+
+    public void setEdgeProperties( Edge e, String type, boolean local ) {
+	setEdgeProps( e, DEFAULT_EDGE, local );
+	setEdgeProps( e, SYSTEM_PREFIX + "edge." + type + ".", local );
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+
+    public void hideGraph( ) {
+
+	hideSubgraph( _graph );
+	_graph.resync( );
+	_graph.repaint( );
+	_credentialPanel.removeRemoteCreds( );
+    }
+
+
+    public void updateGraph( ) {
+	_graph.resync( );
+	_graph.repaint( );
+    }
+
+
+    public void hideGraph( Graph g) {
+	_credentialPanel.removeRemoteCreds( );
+
+	hideSubgraph( g );
+
+	for( Iterator i = _nodeStates.values( ).iterator( ); i.hasNext( ); ) {
+	    NodeState ns = (NodeState) i.next( );
+	    ns.clearState( );
+	}
+
+	g.resync( );
+	g.repaint( );
+
+    }
+
+    private void hideSubgraph( Subgraph sg ) {
+// 	System.out.println( "HIDING GRAPH" );
+
+	Enumeration nodes = sg.nodeElements( );
+	Enumeration edges = sg.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+    }
+
+
+    public void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+    public void setLocal( boolean local ) {
+	_local = local;
+    }
+
+    public boolean getLocal( ) {
+	return _local;
+    }
+
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizer.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizer.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizer.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,1426 @@
+package com.algomagic.atn.vis;
+import att.grappa.*;
+
+import java.util.*;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class ATNVisualizer extends JFrame 
+    implements ATNVisualizerConstants, GrappaConstants {
+
+    private Properties _properties;
+    private SidePanel[] _sides;
+
+    private Collection _updates;
+
+    private ControlPanel _controls;
+    private ProgressPanel _progressPanel;
+    private PlayBackManager _playBackManager;
+
+
+    public ATNVisualizer( String log1, String log2 ) {
+	loadProperties( );
+
+	initATNVisualizer( log1, log2 );
+	parseUpdates( log1, log2 );
+
+	_playBackManager = new PlayBackManager( );
+	_controls.addObserver( _playBackManager );
+	_playBackManager.addObserver( _progressPanel );
+
+
+	show( );
+    }
+
+
+    private void initATNVisualizer( String log1, String log2 ) {
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	_sides = new SidePanel[2];
+
+
+
+	_sides[LEFT_SIDE] = new SidePanel( LEFT_SIDE );
+	_sides[RIGHT_SIDE] = null;
+
+	JPanel main = new JPanel( );
+	main.setLayout( new BoxLayout( main, BoxLayout.X_AXIS ) );
+	main.add( _sides[LEFT_SIDE] );
+
+
+	if( log2 != null ) {
+	    _sides[RIGHT_SIDE] = new SidePanel( RIGHT_SIDE );
+	    main.add( Box.createHorizontalStrut( 10 ) );
+	    main.add( _sides[RIGHT_SIDE] );
+	}
+
+
+	JPanel bottom = new JPanel( );
+
+	bottom.setLayout( new BoxLayout( bottom, BoxLayout.X_AXIS ) );
+	bottom.add( _controls = new ControlPanel( ) );
+	bottom.add( _progressPanel = new ProgressPanel( ) );
+	
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.Y_AXIS ) );
+	contentPane.add( main );
+	contentPane.add( bottom );
+
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+	show( );
+    }
+
+
+    private void parseUpdates( String log1, String log2 ) {
+	_updates = new ArrayList( );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice", "MedSup: ReliefNet.provisioner <- Alice",
+				      IMPLICATION_EDGE ) );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+
+	if( _sides[RIGHT_SIDE] != null ) {
+
+	    _updates.add( new MessageBeginUpdate( _sides[RIGHT_SIDE], "<Message>\n<NodeOp type=\"root\">\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Credential  definedRole=\"MedSup.discount\" subject=\"ReliefNet.provisioner\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>Verifier Processed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	    // 2
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+	    
+	    // 3
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice", 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  IMPLICATION_EDGE ) );
+
+	    
+	    // 4 
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+	    
+
+	    _updates.add( new MessageEndUpdate( _sides[RIGHT_SIDE] ) );
+			  
+
+	    
+	    // 6
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice", 
+					  "MedSup: MedixFund.purchasingA <- Alice" ) );
+
+
+	    
+	    // 7
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+
+	    // 8
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedixFund.purchasingA <- Alice", 
+					  "Alice: MedixFund.cPartner <- MedSup" ) );
+
+
+
+	    // 9
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup", 
+					  "Alice: ReliefNet.member <- MedSup" ) );
+
+
+	    // 10
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+
+	}
+
+	_updates.add( new MessageBeginUpdate( _sides[LEFT_SIDE],
+					      "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"ReliefNet.provisioner\" subject=\"MedixFund.purchasingA\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n<EdgeOp type=\"control\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</EdgeOp>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"MedixFund.cPartner\" subject=\"ReliefNet.member\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n<ProcessingState>Verifier Processed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], "MedSup: ReliefNet.provisioner <- Alice", "MedSup: MedixFund.purchasingA <- Alice" ) );
+
+
+	// 7
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+
+	// 8
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedixFund.purchasingA <- Alice", 
+				      "Alice: MedixFund.cPartner <- MedSup" ) );
+
+
+	// 9
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup", 
+				      "Alice: ReliefNet.member <- MedSup" ) );
+
+
+	// 10
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	_updates.add( new MessageEndUpdate( _sides[LEFT_SIDE] ) );
+
+
+	// 12
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedSup <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      "Alice: MedSup <- MedSup" ) );
+
+
+	// 13
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	// 14
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	// 15
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      OPPONENT_PROC ) );
+	
+	
+
+	if( _sides[RIGHT_SIDE] != null ) {
+
+	    _updates.add( new MessageBeginUpdate( _sides[RIGHT_SIDE],
+						  "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedSup</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Fully Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"ReliefNet.member\" subject=\"MedSup\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	    // 13
+
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedSup <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  "Alice: MedSup <- MedSup" ) );
+
+
+	    // 14
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+	    // 15
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    // 16
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  OPPONENT_PROC ) );
+	
+
+
+	    _updates.add( new MessageEndUpdate( _sides[RIGHT_SIDE] ) );
+
+	    
+	    // 18
+
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: Alice <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedixFund.purchasingA <- Alice", 
+					  "MedSup: Alice <- Alice" ) );
+
+
+
+	    // 19
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+	    // 20
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	
+	    // 21
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  SATISFIED,
+					  FULLY_PROC ) );
+	
+
+	    // 22
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  OPPONENT_PROC ) );
+
+
+
+	}
+
+
+	_updates.add( new MessageBeginUpdate( _sides[LEFT_SIDE],
+					      "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>Alice</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Fully Processed</ProcessingState>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n</Message>") );
+
+
+
+
+	// 18
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: Alice <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedixFund.purchasingA <- Alice", 
+				      "MedSup: Alice <- Alice" ) );
+
+
+
+	// 19
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	// 20
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	
+	// 21
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      SATISFIED,
+				      FULLY_PROC ) );
+	
+
+	// 22
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new MessageEndUpdate( _sides[LEFT_SIDE] ) );
+
+
+
+ 	formatGraph( _sides[LEFT_SIDE].getGraph( ) );
+
+	if( _sides[RIGHT_SIDE] != null ) {
+ 	    formatGraph( _sides[RIGHT_SIDE].getGraph( ) );
+	}
+
+    }
+
+
+    private void hideGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+
+	g.resync( );
+	g.repaint( );
+
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+
+    
+    private void setNodeProps( Node n, String prefix ) {
+
+	for( int i=0; i < NODE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + NODE_ATTRS_PROP[i] );
+	    if( strValue == null ) {
+		continue;
+	    }
+
+	    System.out.print( prefix + NODE_ATTRS_PROP[i] );
+	    System.out.println( ":" + strValue );
+
+// 	    if( NODE_ATTRS_PROP[i].equals( "peripheries" ) ) {
+// 		n.setDefaultAttribute( NODE_ATTRS[i], new Integer( strValue ) );
+// 		continue;
+// 	    }
+	    
+
+	    if( NODE_ATTRS_INT[i] ) {
+		Attribute a = new Attribute( NODE, NODE_ATTRS[i], new Integer( strValue ) );
+		n.setAttribute( a );
+// 		n.setAttribute( NODE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		Attribute a = new Attribute( NODE, NODE_ATTRS[i], strValue );
+		n.setAttribute( a );
+// 		n.setAttribute( NODE_ATTRS[i], strValue );
+	    }
+	}
+    }
+
+    private void setEdgeProps( Edge e, String prefix ) {
+	for( int i=0; i < EDGE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + EDGE_ATTRS_PROP[i] );
+
+	    if( strValue == null ) {
+		continue;
+	    }
+	    
+	    if( EDGE_ATTRS_INT[i] ) {
+		e.setAttribute( EDGE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		e.setAttribute( EDGE_ATTRS[i], strValue );
+	    }
+	}
+    }
+
+
+
+
+    private void setNodeProperties( Node n, String type, String satisfaction, String process ) {
+	setNodeProps( n, DEFAULT_NODE );
+	setNodeProps( n, SYSTEM_PREFIX + "node." + type + "." );
+	setNodeProps( n, SYSTEM_PREFIX + "node.processed." + process + "." );
+	setNodeProps( n, SYSTEM_PREFIX + "node.satisfied." + satisfaction + "." );
+    }
+
+    private void setEdgeProperties( Edge e, String type ) {
+	setEdgeProps( e, DEFAULT_EDGE );
+	setEdgeProps( e, SYSTEM_PREFIX + "edge." + type + "." );
+    }
+
+
+
+
+    private void setSolid( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "filled" );
+ 	e.setAttribute( COLOR_ATTR, ".5,.5,.5" );
+	
+	if( e instanceof Node ) {
+	    e.setDefaultAttribute( PERIPHERIES_ATTR, new Integer( 2 ) );
+	}
+    }
+
+    private void setBold( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "bold" );
+	e.setAttribute( STYLE_ATTR, "bold" );
+    }
+
+    private void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	_properties = new Properties( );
+
+	if( file.exists( ) ) {
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( Exception e ) { }
+	}
+
+    }
+
+
+    private class SidePanel extends JPanel {
+	GrappaPanel _grappaPanel;
+	Graph _graph;
+
+	JPanel _listPanel;
+	MessagePanel _messagePanel;
+	JPanel _graphPanel;
+
+	JPanel _tallPanel;
+	JPanel _thinPanel;
+	
+	JPanel _top;
+	JPanel _complete;
+
+	int _side;
+
+	public Graph getGraph( ) {
+	    return _graph;
+	}
+
+
+	public SidePanel( int side ) {
+	    super( );
+	    Class clazz = this.getClass( );
+
+
+	    _side = side;
+
+	    _tallPanel = new JPanel( );
+	    _tallPanel.setLayout( new BoxLayout( _tallPanel, BoxLayout.Y_AXIS ) );
+
+ 	    JButton tall = new JButton( );
+	    tall.setMaximumSize( new Dimension( 10, 2000 ) );
+	    tall.setPreferredSize( new Dimension( 10, 2000 ) );
+	    tall.setMinimumSize( new Dimension( 10, 0 ) );
+
+	    tall.addActionListener( new ActionListener( ) {
+		    boolean removed = false;
+		    
+		    public void actionPerformed( ActionEvent e ) {
+			if( ! removed ) {
+			    _top.remove( _listPanel );
+			    removed = true;
+			} else {
+			    if( _side == LEFT_SIDE ) {
+				_top.add( _listPanel, 0 );
+			    } else {
+				_top.add( _listPanel, 2 );
+			    }
+
+			    removed = false;
+			}
+			
+			validate( );
+			repaint( );
+
+		    }
+
+		} );
+
+
+	    _tallPanel.add( tall );
+
+
+	    _thinPanel = new JPanel( );
+	    _thinPanel.setLayout( new BoxLayout( _thinPanel, BoxLayout.X_AXIS ) );
+
+	    JButton thin = new JButton( );
+	    thin.setMaximumSize( new Dimension( 2000, 10 ) );
+	    thin.setPreferredSize( new Dimension( 2000, 10 ) );
+	    thin.setMinimumSize( new Dimension( 0, 10 ) );
+
+	    thin.addActionListener( new ActionListener( ) {
+		    boolean removed = false;
+		    
+		    public void actionPerformed( ActionEvent e ) {
+			if( ! removed ) {
+			    _complete.remove( _messagePanel );
+			    removed = true;
+			} else {
+			    _complete.add( _messagePanel, 2 );
+			    removed = false;
+			}
+
+			validate( );
+			repaint( );
+		    }
+
+		} );
+
+
+	    _thinPanel.add( thin );
+
+	    _listPanel = new ListPanel( );
+
+	    _messagePanel = new MessagePanel( );
+
+ 	    _graphPanel = new JPanel( new BorderLayout( ) );
+
+	    setPanelBorder( _graphPanel, "Trust Negotiation Graph" );
+
+	    _listPanel.setMaximumSize( new Dimension( 150, 2000 ) );
+	    _listPanel.setPreferredSize( new Dimension( 150, 2000 ) );
+	    _listPanel.setMinimumSize( new Dimension( 150, 0 ) );
+
+	    _messagePanel.setMaximumSize( new Dimension( 2000, 150 ) );
+	    _messagePanel.setPreferredSize( new Dimension( 2000, 150 ) );
+	    _messagePanel.setMinimumSize( new Dimension( 0, 150 ) );
+
+
+	    _top = new JPanel( );
+ 	    _top.setLayout( new BoxLayout( _top, BoxLayout.X_AXIS ) );
+	    
+
+	    if( _side == LEFT_SIDE ) {
+		_top.add( _listPanel );
+		_top.add( _tallPanel );
+		_top.add( _graphPanel );
+	    } else {
+		_top.add( _graphPanel );
+		_top.add( _tallPanel );
+		_top.add( _listPanel );
+	    }
+
+
+	    _complete = new JPanel( );
+	    _complete.setLayout( new BoxLayout( _complete, BoxLayout.Y_AXIS ) );
+
+	    _complete.add( _top );
+ 	    _complete.add( _thinPanel );
+ 	    _complete.add( _messagePanel );
+
+	    _graph = new Graph( "Trust Negotiation Graph: " + _side );
+ 	    _grappaPanel = new GrappaPanel( _graph );
+	    _grappaPanel.setScaleToFit( false );
+
+ 	    JScrollPane jsp = new JScrollPane( );
+ 	    jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	    jsp.getViewport( ).setBackground( Color.white );
+ 	    jsp.setViewportView( _grappaPanel );
+	
+	    _graphPanel.add( jsp, BorderLayout.CENTER );
+
+	    setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+	    add( _complete );
+
+	}
+
+	public void setMessage( String message ) {
+	    _messagePanel.setMessage( message );
+	}
+
+    }
+
+
+    private class ControlPanel extends JPanel implements ActionListener {
+	JButton play, pause, stepForward, stepBack, rewind, fastForward, stop;
+	InternalObservable _observable;
+
+	public ControlPanel( ) {
+	    super( );
+	    
+	    _observable = new InternalObservable( );
+	    Class clazz = this.getClass( );
+
+	    play = new JButton( new ImageIcon( clazz.getResource( "/resources/Play24.gif" ), "play" ) );
+	    play.setActionCommand( "play" );
+	    play.addActionListener( this );
+	    play.setEnabled( true );
+
+	    pause = new JButton( new ImageIcon( clazz.getResource( "/resources/Pause24.gif" ), "pause" ) );
+	    pause.setActionCommand( "pause" );
+	    pause.addActionListener( this );
+	    pause.setEnabled( false );
+
+
+	    stepForward = new JButton( new ImageIcon( clazz.getResource( "/resources/StepForward24.gif" ), "step forward" ) );
+	    stepForward.setActionCommand( "stepf" );
+	    stepForward.addActionListener( this );
+	    stepForward.setEnabled( true );
+
+	    stepBack = new JButton( new ImageIcon( clazz.getResource( "/resources/StepBack24.gif" ), "step back" ) );
+	    stepBack.setActionCommand( "stepb" );
+	    stepBack.addActionListener( this );
+	    stepBack.setEnabled( true );
+
+	    rewind = new JButton( new ImageIcon( clazz.getResource( "/resources/Rewind24.gif" ), "rewind" ) );
+	    rewind.setActionCommand( "rewind" );
+	    rewind.addActionListener( this );
+	    rewind.setEnabled( true );
+
+	    fastForward = new JButton( new ImageIcon( clazz.getResource( "/resources/FastForward24.gif" ), "fast forward" ) );
+	    fastForward.setActionCommand( "ff" );
+	    fastForward.addActionListener( this );
+	    fastForward.setEnabled( true );
+
+// 	    stop = new JButton( new ImageIcon( clazz.getResource( "/resources/Stop24.gif" ), "stop" ) );
+// 	    stop.setActionCommand( "stop" );
+// 	    stop.addActionListener( this );
+
+
+	    setStyle( play );
+	    setStyle( pause );
+	    setStyle( stepForward );
+	    setStyle( stepBack );
+	    setStyle( rewind );
+	    setStyle( fastForward );
+// 	    setStyle( stop );
+
+	    setLayout( new BoxLayout( this, BoxLayout.X_AXIS ) );
+	    add( rewind );
+	    add( stepBack );
+	    add( play );
+	    add( pause );
+// 	    add( stop );
+	    add( stepForward );
+	    add( fastForward );
+
+	    JCheckBox loop = new JCheckBox( "loop", (new Boolean( _properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( ) );
+	    loop.addItemListener( new ItemListener( ) {
+		    public void itemStateChanged( ItemEvent e ) {
+			int s = e.getStateChange( );
+			Boolean state = Boolean.TRUE;
+
+			if( s == ItemEvent.DESELECTED ) {
+			    state = Boolean.FALSE;
+			}
+			
+			_observable.notify( state );
+
+		    }
+
+		} );
+
+
+	    add( Box.createHorizontalStrut( 10 ) );
+	    add( loop );
+
+	    JSpinner spinner = new JSpinner( new SpinnerNumberModel( Integer.parseInt( _properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) ), 
+								     0, 
+								     5000, 
+								     100 ) );
+
+	    JLabel spinnerLabel = new JLabel( "delay (msec)" );
+
+	    spinner.addChangeListener( new ChangeListener( ) {
+		    public void stateChanged( ChangeEvent e ) {
+			_observable.notify( e.getSource( ) );
+		    }
+		} );
+
+
+	    add( spinner );
+	    add( Box.createHorizontalStrut( 5 ) );
+	    add( spinnerLabel );
+
+	    setPanelBorder( this, "Controls" );
+	}
+
+
+	public void addObserver( Observer o ) {
+	    _observable.addObserver( o );
+	}
+
+
+	private void setStyle( JButton b ) {
+	    b.setMinimumSize( new Dimension( 24, 24 ) );
+	    b.setMaximumSize( new Dimension( 24, 24 ) );
+	    b.setPreferredSize( new Dimension( 24, 24 ) );
+	    
+	    b.setBorderPainted( false );
+	}
+
+	public void actionPerformed( ActionEvent e ) {
+	    String cmd = e.getActionCommand( );
+	    if( cmd.equals( "play" ) ) {
+		stepForward.setEnabled( false );
+		stepBack.setEnabled( false );
+		rewind.setEnabled( false );
+		fastForward.setEnabled( false );
+		play.setEnabled( false );
+		pause.setEnabled( true );
+	    }
+
+	    else if( cmd.equals( "pause" ) ) {
+		stepForward.setEnabled( true );
+		stepBack.setEnabled( true );
+		rewind.setEnabled( true );
+		fastForward.setEnabled( true );
+		play.setEnabled( true );
+		pause.setEnabled( false );
+	    }
+
+
+
+
+
+	    _observable.notify( e.getActionCommand( ) );
+	}
+
+
+	private class InternalObservable extends Observable {
+	    public void notify( Object arg ) {
+		setChanged( );
+		notifyObservers( arg );
+	    }
+
+	    
+	}
+
+    }
+
+
+    private class ListPanel extends JPanel implements Observer {
+	public ListPanel( ) {
+	    super( );
+
+	    JList oCreds = new JList( );
+	    JScrollPane oCredsJSP = new JScrollPane( oCreds );
+	    setPanelBorder( oCredsJSP, "Opponent Creds." );
+
+	    JList vCreds = new JList( );
+	    JScrollPane vCredsJSP = new JScrollPane( vCreds );
+	    setPanelBorder( vCredsJSP, "Verifier Creds." );
+
+	    JList acPolicy = new JList( );
+	    JScrollPane acPolicyJSP = new JScrollPane( acPolicy );
+	    setPanelBorder( acPolicyJSP, "AC Policies" );
+
+	    JList ackPolicy = new JList( );
+	    JScrollPane ackPolicyJSP = new JScrollPane( ackPolicy );
+	    setPanelBorder( ackPolicyJSP, "Ack Policies" );
+
+
+	    setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+
+	    JList list = new JList( );
+	    JScrollPane jsp = new JScrollPane( list );
+	    
+	    add( oCredsJSP );
+	    add( vCredsJSP );
+	    add( acPolicyJSP );
+	    add( ackPolicyJSP );
+
+
+	}
+
+
+	public void update( Observable o, Object arg ) {
+
+
+	}
+
+    }
+
+
+    private class MessagePanel extends JPanel {
+	JTextArea _message;
+
+	public MessagePanel( ) {
+	    super( );
+	    setLayout( new BorderLayout( ) );
+
+	    _message = new JTextArea( );
+	    JScrollPane jsp = new JScrollPane( _message );
+
+	    add( jsp, BorderLayout.CENTER );
+
+	    setPanelBorder( this, "Message" );
+
+	}
+
+	public void setMessage( String message ) {
+	    _message.setText( message );
+	}
+
+
+    }
+
+    
+    private class ProgressPanel extends JPanel implements Observer {
+	JProgressBar _progress;
+
+	public ProgressPanel( ) {
+	    super( );
+	    setLayout( new BorderLayout( ) );
+
+// 	    _progress = new JProgressBar( 0, _updates.size( ) );
+	    _progress = new JProgressBar( 0, 1 );
+	    _progress.setValue( 0 );
+	    _progress.setStringPainted( true );
+
+
+	    add( _progress, BorderLayout.CENTER );
+
+	    setPanelBorder( this, "Negotiation Progress" );
+	}
+
+
+	public void setMax( int n ) {
+	    _progress.setMaximum( n );
+	}
+
+	public void update( Observable o, Object arg ) {
+	    _progress.setValue( ((Integer)arg).intValue( ) );
+
+	}
+
+
+    }
+
+
+    private void setPanelBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+
+
+    private class PlayBackManager extends Observable implements Observer {
+	private int _delay = Integer.parseInt( _properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) );
+	private boolean _loop = (new Boolean( _properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( );
+	private Update[] _updateArray = (Update[]) _updates.toArray( new Update[0] );
+	private int _index = 0;
+	private boolean _clear = true;
+
+
+	private boolean _playing = false;
+
+
+	public PlayBackManager( ) {
+	    _progressPanel.setMax( _updateArray.length );
+	}
+
+	public void update( Observable o, Object arg ) {
+	    if( arg instanceof String ) {
+		String cmd = (String)arg;
+
+		if( cmd.equals( "play" ) ) {
+		    _playing = true;
+		    new Thread( new PlayThread( ) ).start( );
+		} else if( cmd.equals( "pause" ) ) {
+		    _playing = false;
+		} else if( cmd.equals( "stepf" ) ) {
+		    stepf( );
+		} else if( cmd.equals( "ff" ) ) {
+		    ff( );
+		} else if( cmd.equals( "rewind" ) ) {
+		    rewind( );
+		}
+
+	    } else if( arg instanceof JSpinner ) {
+		SpinnerNumberModel snm = (SpinnerNumberModel)((JSpinner)arg).getModel( );
+		_delay = snm.getNumber( ).intValue( );
+	    } else if (arg instanceof Boolean ) {
+		_loop = ((Boolean)arg).booleanValue( );
+	    }
+	}
+
+
+	private synchronized void stepf( ) {
+	    if( _index == 0 && _clear == false ) {
+		clearAll( );
+		_clear = true;
+
+		setChanged( );
+		notifyObservers( new Integer( _index ) );
+
+		return;
+	    }
+
+	    _clear = false;
+
+
+	    _updateArray[_index].execute( );
+	    _index++;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+
+	    
+	    if( _index == _updateArray.length ) {
+		_index = 0;
+		if( _playing == true && _loop == false ) {
+		    _playing = false;
+		}
+	    }
+
+
+	}
+
+	private synchronized void stepb( ) {
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+	}
+	
+	private synchronized void ff( ) {
+	    for( int i = _index; i < _updateArray.length; i++ ) {
+		_updateArray[i].execute( );
+	    }
+
+	    _index = 0;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+
+	}
+
+
+	private synchronized void rewind( ) {
+	    clearAll( );
+	    _index = 0;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+	}
+
+
+	private class PlayThread implements Runnable {
+	    public void run( ) {
+		while( _playing ) {
+		    try {
+			stepf( );
+			Thread.currentThread( ).sleep( _delay );
+		    } catch( InterruptedException ie ) {
+			throw new RuntimeException( ie );
+		    }
+		}
+		
+	    }
+	}
+
+
+    }
+
+
+    protected abstract class  Update {
+	public abstract void execute( );
+	public abstract void fixRef( );
+    }
+
+
+    private class TestUpdate extends Update {
+	private int _i;
+
+	public TestUpdate( int i ) {
+	    _i = i;
+	}
+
+	public void execute( ) {
+	    System.out.println( _i );
+	}
+	
+	public void fixRef( ) {
+
+	}
+
+    }
+
+    private class MessageBeginUpdate extends Update {
+	SidePanel _sp;
+	String _message;
+
+	public MessageBeginUpdate( SidePanel sp, String message ) {
+	    _sp = sp;
+	    _message = message;
+	}
+
+
+	public void execute( ) {
+	    _sp.setMessage( _message );
+	}
+	
+	public void fixRef( ) {
+
+	}
+	
+    }
+    
+    private class MessageEndUpdate extends Update {
+	SidePanel _sp;
+
+	public MessageEndUpdate( SidePanel sp ) {
+	    _sp = sp;
+	}
+
+
+	public void execute( ) {
+	    _sp.setMessage( "" );
+	}
+	
+	public void fixRef( ) {
+
+	}
+    }
+    
+	
+
+
+
+
+
+
+    private class NodeUpdate extends Update {
+	SidePanel _sp;
+	String _name;
+	Node _n;
+
+	String _type;
+	String _satisfactionState;
+	String _processingState;
+
+	public NodeUpdate( SidePanel sp, String name ) {
+	    _sp = sp;
+	    _name = name;
+
+	    Graph g = _sp.getGraph( );
+
+	    _n = g.findNodeByName( name );
+	    if( _n == null ) {
+		_n = new Node( g, name );
+		setInvis( _n );
+		g.addNode( _n );
+	    }
+
+	}
+
+	public NodeUpdate( SidePanel sp, 
+			   String name, 
+			   String type,
+			   String satisfactionState, 
+			   String processingState ) {
+	    this( sp, name );
+
+	    _type = type;
+
+
+	    _satisfactionState = satisfactionState;
+	    _processingState = processingState;
+
+
+	}
+
+	public void fixRef( ) {
+	    _n = _sp.getGraph( ).findNodeByName( _name );
+	}
+
+
+	public void execute( ) {
+	    fixRef( );
+
+	    setNodeProperties( _n, _type, _satisfactionState, _processingState );
+
+	    Graph g = _sp.getGraph( );
+
+	    g.resync( );
+	    g.repaint( );
+	}
+    }
+
+    
+    private class EdgeUpdate extends Update {
+	SidePanel _sp;
+	String _headNodeName;
+	String _tailNodeName;
+	Edge _e;
+
+	String _type;
+
+
+	public EdgeUpdate( SidePanel sp, 
+			   String headNodeName, 
+			   String tailNodeName, 
+			   String type ) {
+	    this( sp, headNodeName, tailNodeName );
+	    _type = type;
+	}
+
+
+
+	public EdgeUpdate( SidePanel sp, String headNodeName, String tailNodeName ) {
+	    _sp = sp;
+	    _headNodeName = headNodeName;
+	    _tailNodeName = tailNodeName;
+
+	    Graph g = _sp.getGraph( );
+	    Node head = g.findNodeByName( _headNodeName );
+	    Node tail = g.findNodeByName( _tailNodeName );
+
+
+	    _e = getEdgeBetween( g, head, tail );
+
+	    if( _e == null ) {
+		_e = new Edge( g, head, tail );
+		setInvis( _e );
+		g.addEdge( _e );
+	    }
+
+	}
+
+
+	public void fixRef( ) {
+	    Graph g = _sp.getGraph( );
+	    Node head = g.findNodeByName( _headNodeName );
+	    Node tail = g.findNodeByName( _tailNodeName );
+
+
+	    _e = getEdgeBetween( g, head, tail );
+	}
+
+	public void execute( ) {
+	    fixRef( );
+	    setEdgeProperties( _e, _type );
+
+	    Graph g = _sp.getGraph( );
+
+	    g.resync( );
+	    g.repaint( );
+	}
+    }
+
+
+    private void clearAll( ) {
+	for( int i = 0; i < _sides.length; i++ ) {
+	    if( _sides[i] != null ) {
+		hideGraph( _sides[i].getGraph( ) );
+	    }
+	}
+
+	
+    }
+
+    private Graph loadGraph( String dotFile ) {
+	Parser parser = null;
+	try {
+	    parser = new Parser( new FileInputStream( dotFile ) );
+	    parser.parse( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	return parser.getGraph( );
+    }
+
+
+
+    public static void main( String[] args ) {
+	ATNVisualizer atnVis = null;
+
+	if( args.length == 1 ) {
+	    atnVis = new ATNVisualizer( args[0], null );
+	} else if ( args.length == 2 ) {
+	    atnVis = new ATNVisualizer( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: ATNVisualizer <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+
+    private void printGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Node n = (Node) nodes.nextElement( );
+	    n.printAllAttributes = true;
+
+	    System.out.println( n.getName( ) );
+
+	    Enumeration e = n.getAttributePairs( );
+	    while( e.hasMoreElements( ) ) {
+		System.out.println( e.nextElement( ) );
+	    }
+
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Edge e = (Edge) edges.nextElement( );
+	    e.printAllAttributes = true;
+
+	    System.out.println( e.getName( ) );
+
+	    Enumeration en = e.getAttributePairs( );
+	    while( en.hasMoreElements( ) ) {
+		System.out.println( en.nextElement( ) );
+	    }
+	}
+
+	System.out.println( "======================================================================" );
+
+	g.printSubgraph( new PrintWriter( System.err, true ) );
+    }
+
+
+    private Edge getEdgeBetween( Graph g, Node head, Node tail ) {
+	Enumeration edges = g.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizer.java.tmp
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizer.java.tmp	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizer.java.tmp	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,525 @@
+package com.algomagic.atn.vis;
+import att.grappa.*;
+
+import java.util.Properties;
+import java.util.Enumeration;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+
+public class ATNVisualizer extends JFrame 
+    implements ATNVisualizerConstants, GrappaConstants {
+
+    private Properties _properties;
+    private GrappaPanel _grappaPanel;
+    private Graph _graph;
+
+    
+
+    public ATNVisualizer( String log1, String log2 ) {
+	initATNVisualizer( log1, log2 );
+    }
+
+
+    private void initATNVisualizer( String log1, String log2 ) {
+	loadProperties( );
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	SidePanel leftSide = new SidePanel( log1, LEFT_SIDE );
+	SidePanel rightSide = null;
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.X_AXIS ) );
+  	contentPane.add( leftSide );
+
+
+	if( log2 != null ) {
+	    rightSide = new SidePanel( log2, RIGHT_SIDE );
+	    contentPane.add( rightSide );
+	}
+
+
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+	show( );
+
+	leftSide.resetDividerLocations( );
+
+	if( log2 != null ) {
+	    rightSide.resetDividerLocations( );
+	}
+
+    }
+
+    private void hideGraph( Graph g ) {
+	Enumeration nodes = _graph.nodeElements( );
+	Enumeration edges = _graph.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+
+    }
+
+    private Graph loadGraph( String dotFile ) {
+	Parser parser = null;
+	try {
+	    parser = new Parser( new FileInputStream( dotFile ) );
+	    parser.parse( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	return parser.getGraph( );
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+    private void redrawAndPause( int millis ) {
+	_graph.resync( );
+	_graph.repaint( );
+	try { Thread.currentThread( ).sleep( millis ); }
+	catch( Exception e ) { }
+    }
+
+
+    private void setSolid( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+	e.setAttribute( STYLE_ATTR, "solid" );
+    }
+
+
+    private void setBold( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "bold" );
+	e.setAttribute( STYLE_ATTR, "bold" );
+    }
+
+    private void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+
+
+    private Edge getEdgeBetween( Node head, Node tail ) {
+	Enumeration edges = _graph.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	if( file.exists( ) ) {
+	    _properties = new Properties( );
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( FileNotFoundException fnfe ) {
+		_properties = getDefaultProperties( );
+	    } catch( IOException ioe ) {
+		_properties = getDefaultProperties( );
+	    }
+	} else {
+	    _properties = getDefaultProperties( );
+	}
+    }
+
+
+    private Properties getDefaultProperties( ) {
+	Properties p = new Properties( );
+	p.setProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT );
+	p.setProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT );
+	p.setProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT );
+
+	return p;
+    }
+
+
+    public static void main( String[] args ) {
+	ATNVisualizer atnVis = null;
+
+	if( args.length == 1 ) {
+	    atnVis = new ATNVisualizer( args[0], null );
+	} else if ( args.length == 2 ) {
+	    atnVis = new ATNVisualizer( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: ATNVisualizer <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+
+
+    private class SidePanel extends JPanel {
+	GrappaPanel _grappaPanel;
+	Graph _graph;
+
+	JPanel _listPanel;
+	JPanel _messagePanel;
+	JPanel _graphPanel;
+	JCheckBox _scaleButton;
+	
+	JSplitPane _top;
+	JSplitPane _complete;
+
+	int _side;
+	boolean _graphScaleToFit;
+	Dimension _unScaledDim;
+
+	public SidePanel( String transcriptFile, int side ) {
+	    super( );
+
+	    _side = side;
+
+	    _listPanel = new JPanel( new BorderLayout( ) );
+	    _messagePanel = new JPanel( new BorderLayout( ) );
+	    _graphPanel = new JPanel( new BorderLayout( ) );
+
+
+	    _messagePanel.setMaximumSize( new Dimension( 2000, 100 ) );
+
+
+
+// 	    _graphPanel.addComponentListener( new ComponentAdapter( ) {
+// 		    public void componentResized( ComponentEvent e ) {
+// 			if( _graphScaleToFit == true ) {
+// 			    setGraphToFit( e.getComponent( ).getSize( ) );
+// 			}
+// 		    }
+
+// 		});
+
+
+// 	    _scaleButton = new JCheckBox( "scale graph to fit" );
+// 	    _scaleButton.setSelected( true );
+// 	    _scaleButton.addItemListener( new ItemListener( ) {
+// 		    public void itemStateChanged( ItemEvent e ) {
+// 			if( e.getStateChange( ) == ItemEvent.DESELECTED ) {
+// 			    setGraphScaleToFit( false );
+// 			} else {
+// 			    setGraphScaleToFit( true );
+// 			}
+// 		    }
+// 		});
+	    
+
+	    
+	    setPanelBorder( _listPanel, "Creds and Policies" );
+	    setPanelBorder( _messagePanel, "Output Log" );
+	    setPanelBorder( _graphPanel, "Trust Negotiation Graph" );
+
+
+	    if( _side == LEFT_SIDE ) {
+		_top = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, 
+				       _listPanel, 
+				       _graphPanel );
+	    } else {
+		_top = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, 
+				       _graphPanel,
+				       _listPanel);
+		
+
+		_top.setResizeWeight( 1.0 );
+
+
+	    }
+
+	    _complete = new JSplitPane( JSplitPane.VERTICAL_SPLIT,
+					_top,
+					_messagePanel );
+
+	    _complete.setResizeWeight( 1.0 );
+
+
+	    _complete.addComponentListener( new ComponentAdapter( ) {
+		    public void componentResized( ComponentEvent e ) {
+			System.out.println( "resized: " + e.getComponent( ).getSize( ) );
+		    }
+
+		    public void componentMoved( ComponentEvent e ) {
+			System.out.println( "moved: " + e.getComponent( ).getSize( ) );
+		    }
+
+
+
+		});
+
+
+ 	    _graph = loadGraph( transcriptFile );
+ 	    formatGraph( _graph );
+
+
+ 	    _grappaPanel = new GrappaPanel( _graph );
+	    _grappaPanel.setScaleToFit( false );
+
+ 	    JScrollPane jsp = new JScrollPane( );
+ 	    jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	    jsp.getViewport( ).setBackground( Color.white );
+ 	    jsp.setViewportView( _grappaPanel );
+	
+	    _graphPanel.add( jsp, BorderLayout.CENTER );
+
+	    setLayout( new BorderLayout( ) );
+	    add( _complete, BorderLayout.CENTER );
+
+
+	    _top.setOneTouchExpandable( true );
+	    _complete.setOneTouchExpandable( true );
+	}
+
+
+	public void resetDividerLocations( ) {
+	    if( _side == LEFT_SIDE ) {
+		_top.setDividerLocation( 0.25 );
+	    } else {
+		_top.setDividerLocation( 0.75 );
+	    }
+	    _complete.setDividerLocation( 0.75 );
+
+	}
+
+	public void setGraphScaleToFit( boolean b ) {
+	    _graphScaleToFit = b;
+
+	    if( b == false ) {
+		setGraphToFit( _unScaledDim );
+	    } else {
+		setGraphToFit( _graphPanel.getSize( ) );
+	    }
+
+	}
+
+
+	public void setGraphToFit( Dimension d ) {
+
+	    d.setSize( d.getWidth( ) - 50, d.getHeight( ) - 50 );
+
+	    _grappaPanel.setScaleToSize( d );
+	    _graph.resync( );
+	    _graph.repaint( );
+
+	}
+
+
+    }
+
+
+
+    private void setPanelBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+
+
+
+
+    private void printGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Node n = (Node) nodes.nextElement( );
+	    n.printAllAttributes = true;
+
+	    System.out.println( n.getName( ) );
+
+	    Enumeration e = n.getAttributePairs( );
+	    while( e.hasMoreElements( ) ) {
+		System.out.println( e.nextElement( ) );
+	    }
+
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Edge e = (Edge) edges.nextElement( );
+	    e.printAllAttributes = true;
+
+	    System.out.println( e.getName( ) );
+
+	    Enumeration en = e.getAttributePairs( );
+	    while( en.hasMoreElements( ) ) {
+		System.out.println( en.nextElement( ) );
+	    }
+	}
+
+	System.out.println( "======================================================================" );
+
+	g.printSubgraph( new PrintWriter( System.err, true ) );
+    }
+
+
+
+    public void animate( ) {
+	Node a,b,c,d,e,f,g;
+
+	a = _graph.findNodeByName( "A" );
+	b = _graph.findNodeByName( "B" );
+	c = _graph.findNodeByName( "C" );
+	d = _graph.findNodeByName( "D" );
+	e = _graph.findNodeByName( "E" );
+	f = _graph.findNodeByName( "F" );
+	g = _graph.findNodeByName( "G" );
+
+
+	Edge ab, bc, cd, ce, ef, fg;
+
+	ab = getEdgeBetween( a,b );
+	bc = getEdgeBetween( b,c );
+	cd = getEdgeBetween( c,d );
+	ce = getEdgeBetween( c,e );
+	ef = getEdgeBetween( e,f );
+	fg = getEdgeBetween( f,g );
+	
+
+	while (true) {
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( a );
+	    redrawAndPause( 1000 );
+
+	    setBold( b );
+	    setBold( ab );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+
+	    setSolid( a );
+	    setSolid( b );
+	    setSolid( ab );
+
+	    // ----------------------------------------------------------------------
+
+	    redrawAndPause( 1000 );
+
+	    setBold( c );
+	    setBold( bc );
+
+	    redrawAndPause( 1000 );
+
+	    setBold( e );
+	    setBold( ce );
+
+	    redrawAndPause( 1000 );
+
+	    setBold( f );
+	    setBold( ef );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setSolid( c );
+	    setSolid( bc );
+	    setSolid( e );
+	    setSolid( ce );
+	    setSolid( f );
+	    setSolid( ef );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( g );
+	    setBold( fg );
+
+	    redrawAndPause( 1000 );
+	
+	    // ----------------------------------------------------------------------
+
+	    setSolid( g );
+	    setSolid( fg );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( d );
+	    setBold( cd );
+	
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setSolid( d );
+	    setSolid( cd );
+
+	    redrawAndPause( 2000 );
+
+	    // ----------------------------------------------------------------------
+
+	    hideGraph( _graph );
+
+	    redrawAndPause( 1000 );
+
+	}
+
+    }
+
+
+
+
+
+}
Index: fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizerConstants.java
===================================================================
--- fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizerConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/com/algomagic/atn/vis/ATNVisualizerConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,120 @@
+package com.algomagic.atn.vis;
+
+import att.grappa.GrappaConstants;
+
+public interface ATNVisualizerConstants extends GrappaConstants {
+    public static final String SYSTEM_PREFIX = "atnvis.";
+
+    public static final String CONFIG_FILE_PROP = SYSTEM_PREFIX + "ConfigFile";
+    public static final String WINDOW_TITLE_PROP = SYSTEM_PREFIX + "window.Title";
+    public static final String WINDOW_HEIGHT_PROP = SYSTEM_PREFIX + "window.Height";
+    public static final String WINDOW_WIDTH_PROP = SYSTEM_PREFIX + "window.Width";
+
+    public static final String DELAY_PROP = SYSTEM_PREFIX + "defaultDelay";
+    public static final String LOOP_PROP = SYSTEM_PREFIX + "loop";
+
+
+    public static final String CONFIG_FILE_DEFAULT = "atnvis.properties";
+    public static final String WINDOW_TITLE_DEFAULT = "ATN Visualization";
+    public static final String WINDOW_HEIGHT_DEFAULT = "800";
+    public static final String WINDOW_WIDTH_DEFAULT = "600";
+
+    public static final String DELAY_DEFAULT = "500";
+    public static final String LOOP_DEFAULT = "true";
+
+    public static final int LEFT_SIDE = 0;
+    public static final int RIGHT_SIDE = 1;
+
+    public static final String OPPONENT_PROC = "Opponent";
+    public static final String VERIFIER_PROC = "Verifier";
+    public static final String FULLY_PROC = "Fully";
+    public static final String NOT_PROC = "Not";
+
+    public static final String SATISFIED = "True";
+    public static final String NOT_SATISFIED = "False";
+
+    public static final String STANDARD_TARGET = "StandardTarget";
+    public static final String INTERSECTION_TARGET = "IntersectionTarget";
+    public static final String LINKING_GOAL = "LinkingGoal";
+
+    public static final String IMPLICATION_EDGE = "Implication";
+    public static final String LINKING_MONITOR_EDGE = "LinkingMonitor";
+    public static final String LINKING_SOLUTION_EDGE = "LinkingSolution";
+    public static final String LINKING_IMPLICATION_EDGE = "LinkingImplication";
+    public static final String INTERSECTION_EDGE = "Intersection";
+    public static final String CONTROL_EDGE = "Control";
+
+    public static final String DEFAULT_NODE = SYSTEM_PREFIX + "node.Default.";
+    public static final String DEFAULT_EDGE = SYSTEM_PREFIX + "edge.Default.";
+
+
+    public static final String[] NODE_ATTRS = {
+	SHAPE_ATTR,
+	SIDES_ATTR,
+	PERIPHERIES_ATTR,
+	STYLE_ATTR,
+	COLOR_ATTR,
+	FONTNAME_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR };
+
+
+
+    public static final String[] NODE_ATTRS_PROP = {
+	"shape",
+	"sides",
+	"peripheries",
+	"style",
+	"color",
+	"fontname",
+	"fontcolor",
+	"fontsize",
+	"fontstyle" };
+
+    public static final boolean[] NODE_ATTRS_INT = {
+	false,
+	true,
+	true,
+	false,
+	false,
+	false,
+	false,
+	true,
+	false };
+
+
+    public static final String[] EDGE_ATTRS = {
+	STYLE_ATTR,
+	FONTNAME_ATTR,
+	COLOR_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR,
+	DIR_ATTR };
+
+    public static final String[] EDGE_ATTRS_PROP = {
+	"style",
+	"fontname",
+	"color",
+	"fontcolor",
+	"fontsize",
+	"fontstyle", 
+	"direction"  };
+
+
+    public static final boolean[] EDGE_ATTRS_INT = {
+	false,
+	false,
+	false,
+	false,
+	true,
+	false,
+	false };
+
+    
+
+
+
+
+}
Index: fedd/abac-src/atnvis/src/resources/.xvpics/collapse.gif
===================================================================
--- fedd/abac-src/atnvis/src/resources/.xvpics/collapse.gif	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/resources/.xvpics/collapse.gif	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,5 @@
+P7 332
+#IMGINFO:64x7 Indexed (165 bytes)
+#END_OF_COMMENTS
+64 7 255
+ÿÿÿÛÿÿÚÿÿÿÛÿÿÿÚÿÿÛÿÿÿÛþÿÿÛÿÿÿÛþÿÛÿÿÿÛÿþÿÛÿÿÛÿÿþÛÿÿÿÛÿÿÚÿÿÿÛÿÿÿÚÿÿÛ¶ÚÛÚ·ÚÛÚÛ¶ÛÚÛ¶ÛÚÛÚ¶ÛÚÛ¶ÛÚÛÚ·ÚÛÚ·ÚÛÚÚ·ÚÛÚ·ÚÛÚÛ¶ÛÚÛ¶ÛÚÚÛ¶ÛÚÛ¶Ûÿÿ¶Û¶mI$I%HnÚ·ÚÛ¶Ú·Ú¶Û¶Û¶Ú·Ú¶Û¶ÚÛ¶Û¶Ú·Ú¶Û¶Ú·Ú·Ú¶Û¶ÚÛ¶m%H%IHnÚ·ÚÛ¶ÿ¶·Ú¶II$ImÛ¶¶Û¶¶Û¶¶Ú·¶Ú·¶Ú¶·Ú¶·Ú¶¶Û¶¶Ú·¶Ú·¶Ú¶·Ú¶·Ú¶¶ÛIH%HnÛ¶¶ÚÛ¶Û¶Ú¶·¶m$nÚ·µ·Ú¶·¶¶Ú·¶¶¶¶Û¶¶¶·Ú¶¶¶·Ú¶¶·¶Ú¶¶·¶Ú¶·¶¶Ú¶·¶¶m%·¶¶Ú¶ÛÛ¶¶¶¶Û¶IÚ·¶Ú¶·µ·Ú¶·¶¶Ú·¶¶¶Ú·¶¶¶·Ú¶¶¶·Ú¶¶·¶Ú¶¶·¶Ú¶·¶¶Ú¶·l·¶Û¶¶¶Û¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶
Index: fedd/abac-src/atnvis/src/resources/.xvpics/expand.gif
===================================================================
--- fedd/abac-src/atnvis/src/resources/.xvpics/expand.gif	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/resources/.xvpics/expand.gif	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,5 @@
+P7 332
+#IMGINFO:64x6 Indexed (208 bytes)
+#END_OF_COMMENTS
+64 6 255
+ÿÿÿÛÿÿÚÿÿÿÛÿÿÿÚÿÿÛÿÿÿÛþÿÿÛÿÿÿÛþÿÛÿÿÿÛÿþÿÛÿÿÛÿÿþÛÿÿÿÛÿÿÚÿÿÿÛÿÿÿÚÿÿÛ¶ÚÛÚ·mÛÚÛÚ·ÚÛÚÚ·ÚÛÚ·ÚÛÚÛ¶ÛÚÛ¶ÛÚÚÛ¶ÛÚÛ¶ÛÚÛÚ·ÚÛÚ·ÚÚÛÚ·ÚmÛÛÚ·ÚÚÿÿ¶Û¶Û¶mHnÛ¶Ú·Ú¶Û¶Ú·Ú·ÚÚ·Ú¶Û¶Ú·Ú·Ú¶Û¶Ú·ÚÚ·Ú·Ú¶Û¶Ú·Ú¶Û¶Ûl%nÚÛ¶Ú·ÿÿ¶·Ú¶II$ImÛ¶¶Û¶¶Û¶¶Ú·¶Ú·¶Ú¶·Ú¶·Ú¶¶Û¶¶Ú·¶Ú·¶Ú¶·Ú¶·Ú¶¶ÛIH%HnÛ¶¶ÚÛ¶Û¶Ú¶II%H%HnÚ·¶¶¶·Ú¶¶¶·Ú¶¶·¶Ú¶¶·¶Ú¶·¶¶Ú¶·¶¶Ú·¶¶¶Ú·¶¶¶m%H%I$¶·¶Ú¶Û¶¶¶¶Û¶¶¶·Ú¶¶¶·Ú¶¶·¶Ú¶¶·¶Ú¶·¶¶¶Ú·¶¶¶Û¶¶¶·Ù·¶¶·Ú¶¶·µÛ¶¶·¶Ú¶·¶¶Ú·
Index: fedd/abac-src/atnvis/src/resources/.xvpics/vertin.jpg
===================================================================
--- fedd/abac-src/atnvis/src/resources/.xvpics/vertin.jpg	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/resources/.xvpics/vertin.jpg	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,5 @@
+P7 332
+#IMGINFO:7x64 RGB (496 bytes)
+#END_OF_COMMENTS
+6 60 255
+ÿ»Ö»ÚÿÛÛÚ»ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶ÿ·JµÿI(¶ßiI$¶ÿ¶NDµÿ·¶M¶ÿ·º¶±ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·Úº×ÿ²×ÿÖÿÖÿÖÿÖÿÖÿÖÿÖÿÖÿ¶¶ÿ¶×ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º¶·¶ÿ·º²·ÿ·¶M¶ÿi)²ßi)Dÿi)¶ÿ·j¶ÿ·º¶¶ÿ·º¶·¶ÿ·º¶·¶ÿÛÿº×Û¶¶¶I$I$IIÛ¶I$IIÛ¶I$IIÛ¶I$IIÛ¶
Index: fedd/abac-src/atnvis/src/vis/ATNVisualizer.java
===================================================================
--- fedd/abac-src/atnvis/src/vis/ATNVisualizer.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/vis/ATNVisualizer.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,1426 @@
+package com.algomagic.atn.vis;
+import att.grappa.*;
+
+import java.util.*;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+public class ATNVisualizer extends JFrame 
+    implements ATNVisualizerConstants, GrappaConstants {
+
+    private Properties _properties;
+    private SidePanel[] _sides;
+
+    private Collection _updates;
+
+    private ControlPanel _controls;
+    private ProgressPanel _progressPanel;
+    private PlayBackManager _playBackManager;
+
+
+    public ATNVisualizer( String log1, String log2 ) {
+	loadProperties( );
+
+	initATNVisualizer( log1, log2 );
+	parseUpdates( log1, log2 );
+
+	_playBackManager = new PlayBackManager( );
+	_controls.addObserver( _playBackManager );
+	_playBackManager.addObserver( _progressPanel );
+
+
+	show( );
+    }
+
+
+    private void initATNVisualizer( String log1, String log2 ) {
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	_sides = new SidePanel[2];
+
+
+
+	_sides[LEFT_SIDE] = new SidePanel( LEFT_SIDE );
+	_sides[RIGHT_SIDE] = null;
+
+	JPanel main = new JPanel( );
+	main.setLayout( new BoxLayout( main, BoxLayout.X_AXIS ) );
+	main.add( _sides[LEFT_SIDE] );
+
+
+	if( log2 != null ) {
+	    _sides[RIGHT_SIDE] = new SidePanel( RIGHT_SIDE );
+	    main.add( Box.createHorizontalStrut( 10 ) );
+	    main.add( _sides[RIGHT_SIDE] );
+	}
+
+
+	JPanel bottom = new JPanel( );
+
+	bottom.setLayout( new BoxLayout( bottom, BoxLayout.X_AXIS ) );
+	bottom.add( _controls = new ControlPanel( ) );
+	bottom.add( _progressPanel = new ProgressPanel( ) );
+	
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.Y_AXIS ) );
+	contentPane.add( main );
+	contentPane.add( bottom );
+
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+	show( );
+    }
+
+
+    private void parseUpdates( String log1, String log2 ) {
+	_updates = new ArrayList( );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice", "MedSup: ReliefNet.provisioner <- Alice",
+				      IMPLICATION_EDGE ) );
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+
+	if( _sides[RIGHT_SIDE] != null ) {
+
+	    _updates.add( new MessageBeginUpdate( _sides[RIGHT_SIDE], "<Message>\n<NodeOp type=\"root\">\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Credential  definedRole=\"MedSup.discount\" subject=\"ReliefNet.provisioner\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedSup.discount</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>Verifier Processed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	    // 2
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+	    
+	    // 3
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice", 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  IMPLICATION_EDGE ) );
+
+	    
+	    // 4 
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+	    
+
+	    _updates.add( new MessageEndUpdate( _sides[RIGHT_SIDE] ) );
+			  
+
+	    
+	    // 6
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice", 
+					  "MedSup: MedixFund.purchasingA <- Alice" ) );
+
+
+	    
+	    // 7
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+
+	    // 8
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  OPPONENT_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedixFund.purchasingA <- Alice", 
+					  "Alice: MedixFund.cPartner <- MedSup" ) );
+
+
+
+	    // 9
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup", 
+					  "Alice: ReliefNet.member <- MedSup" ) );
+
+
+	    // 10
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  NOT_SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+
+	}
+
+	_updates.add( new MessageBeginUpdate( _sides[LEFT_SIDE],
+					      "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"ReliefNet.provisioner\" subject=\"MedixFund.purchasingA\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>ReliefNet.provisioner</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n<EdgeOp type=\"control\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</EdgeOp>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Verifier Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"MedixFund.cPartner\" subject=\"ReliefNet.member\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedixFund.cPartner</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n<ProcessingState>Verifier Processed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], "MedSup: ReliefNet.provisioner <- Alice", "MedSup: MedixFund.purchasingA <- Alice" ) );
+
+
+	// 7
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+
+	// 8
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedixFund.purchasingA <- Alice", 
+				      "Alice: MedixFund.cPartner <- MedSup" ) );
+
+
+	// 9
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup", 
+				      "Alice: ReliefNet.member <- MedSup" ) );
+
+
+	// 10
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      NOT_SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	_updates.add( new MessageEndUpdate( _sides[LEFT_SIDE] ) );
+
+
+	// 12
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedSup <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      "Alice: MedSup <- MedSup" ) );
+
+
+	// 13
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	// 14
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: MedixFund.cPartner <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	// 15
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "Alice: ReliefNet.member <- MedSup",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      OPPONENT_PROC ) );
+	
+	
+
+	if( _sides[RIGHT_SIDE] != null ) {
+
+	    _updates.add( new MessageBeginUpdate( _sides[RIGHT_SIDE],
+						  "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>MedSup</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Fully Processed</ProcessingState>\n<Evidence count=\"1\">\n<Credential  definedRole=\"ReliefNet.member\" subject=\"MedSup\"/>\n</Evidence>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>Alice</Verifier>\n	<Target>ReliefNet.member</Target>\n	<Subject>MedSup</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n</Message>" ) );
+
+
+	    // 13
+
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedSup <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  "Alice: MedSup <- MedSup" ) );
+
+
+	    // 14
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+	    // 15
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: MedixFund.cPartner <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    // 16
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "Alice: ReliefNet.member <- MedSup",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  OPPONENT_PROC ) );
+	
+
+
+	    _updates.add( new MessageEndUpdate( _sides[RIGHT_SIDE] ) );
+
+	    
+	    // 18
+
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: Alice <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	    _updates.add( new EdgeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedixFund.purchasingA <- Alice", 
+					  "MedSup: Alice <- Alice" ) );
+
+
+
+	    // 19
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  VERIFIER_PROC ) );
+
+
+	    // 20
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: ReliefNet.provisioner <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  FULLY_PROC ) );
+
+	
+	    // 21
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE], 
+					  "MedSup: MedSup.discount <- Alice",
+					  STANDARD_TARGET, 
+					  SATISFIED,
+					  FULLY_PROC ) );
+	
+
+	    // 22
+	    _updates.add( new NodeUpdate( _sides[RIGHT_SIDE],
+					  "MedSup: MedixFund.purchasingA <- Alice",
+					  STANDARD_TARGET,
+					  SATISFIED,
+					  OPPONENT_PROC ) );
+
+
+
+	}
+
+
+	_updates.add( new MessageBeginUpdate( _sides[LEFT_SIDE],
+					      "<Message>\n<EdgeOp type=\"implication\" newChild=\"true\">\n<Parent>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Parent>\n<Child>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>Alice</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n</Child>\n<ProcessingState>Fully Processed</ProcessingState>\n</EdgeOp>\n<NodeOp>\n<TrustTarget>\n	<Verifier>MedSup</Verifier>\n	<Target>MedixFund.purchasingA</Target>\n	<Subject>Alice</Subject>\n</TrustTarget>\n<ProcessingState>OpponentProcessed</ProcessingState>\n</NodeOp>\n</Message>") );
+
+
+
+
+	// 18
+
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: Alice <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	_updates.add( new EdgeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedixFund.purchasingA <- Alice", 
+				      "MedSup: Alice <- Alice" ) );
+
+
+
+	// 19
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      VERIFIER_PROC ) );
+
+
+	// 20
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: ReliefNet.provisioner <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      FULLY_PROC ) );
+
+	
+	// 21
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE], 
+				      "MedSup: MedSup.discount <- Alice",
+				      STANDARD_TARGET, 
+				      SATISFIED,
+				      FULLY_PROC ) );
+	
+
+	// 22
+	_updates.add( new NodeUpdate( _sides[LEFT_SIDE],
+				      "MedSup: MedixFund.purchasingA <- Alice",
+				      STANDARD_TARGET,
+				      SATISFIED,
+				      OPPONENT_PROC ) );
+
+	_updates.add( new MessageEndUpdate( _sides[LEFT_SIDE] ) );
+
+
+
+ 	formatGraph( _sides[LEFT_SIDE].getGraph( ) );
+
+	if( _sides[RIGHT_SIDE] != null ) {
+ 	    formatGraph( _sides[RIGHT_SIDE].getGraph( ) );
+	}
+
+    }
+
+
+    private void hideGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+
+	g.resync( );
+	g.repaint( );
+
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+
+    
+    private void setNodeProps( Node n, String prefix ) {
+
+	for( int i=0; i < NODE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + NODE_ATTRS_PROP[i] );
+	    if( strValue == null ) {
+		continue;
+	    }
+
+	    System.out.print( prefix + NODE_ATTRS_PROP[i] );
+	    System.out.println( ":" + strValue );
+
+// 	    if( NODE_ATTRS_PROP[i].equals( "peripheries" ) ) {
+// 		n.setDefaultAttribute( NODE_ATTRS[i], new Integer( strValue ) );
+// 		continue;
+// 	    }
+	    
+
+	    if( NODE_ATTRS_INT[i] ) {
+		Attribute a = new Attribute( NODE, NODE_ATTRS[i], new Integer( strValue ) );
+		n.setAttribute( a );
+// 		n.setAttribute( NODE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		Attribute a = new Attribute( NODE, NODE_ATTRS[i], strValue );
+		n.setAttribute( a );
+// 		n.setAttribute( NODE_ATTRS[i], strValue );
+	    }
+	}
+    }
+
+    private void setEdgeProps( Edge e, String prefix ) {
+	for( int i=0; i < EDGE_ATTRS.length; i++ ) {
+	    String strValue = _properties.getProperty( prefix + EDGE_ATTRS_PROP[i] );
+
+	    if( strValue == null ) {
+		continue;
+	    }
+	    
+	    if( EDGE_ATTRS_INT[i] ) {
+		e.setAttribute( EDGE_ATTRS[i], new Integer( strValue ) );
+	    } else {
+		e.setAttribute( EDGE_ATTRS[i], strValue );
+	    }
+	}
+    }
+
+
+
+
+    private void setNodeProperties( Node n, String type, String satisfaction, String process ) {
+	setNodeProps( n, DEFAULT_NODE );
+	setNodeProps( n, SYSTEM_PREFIX + "node." + type + "." );
+	setNodeProps( n, SYSTEM_PREFIX + "node.processed." + process + "." );
+	setNodeProps( n, SYSTEM_PREFIX + "node.satisfied." + satisfaction + "." );
+    }
+
+    private void setEdgeProperties( Edge e, String type ) {
+	setEdgeProps( e, DEFAULT_EDGE );
+	setEdgeProps( e, SYSTEM_PREFIX + "edge." + type + "." );
+    }
+
+
+
+
+    private void setSolid( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "filled" );
+ 	e.setAttribute( COLOR_ATTR, ".5,.5,.5" );
+	
+	if( e instanceof Node ) {
+	    e.setDefaultAttribute( PERIPHERIES_ATTR, new Integer( 2 ) );
+	}
+    }
+
+    private void setBold( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "bold" );
+	e.setAttribute( STYLE_ATTR, "bold" );
+    }
+
+    private void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+ 	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	_properties = new Properties( );
+
+	if( file.exists( ) ) {
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( Exception e ) { }
+	}
+
+    }
+
+
+    private class SidePanel extends JPanel {
+	GrappaPanel _grappaPanel;
+	Graph _graph;
+
+	JPanel _listPanel;
+	MessagePanel _messagePanel;
+	JPanel _graphPanel;
+
+	JPanel _tallPanel;
+	JPanel _thinPanel;
+	
+	JPanel _top;
+	JPanel _complete;
+
+	int _side;
+
+	public Graph getGraph( ) {
+	    return _graph;
+	}
+
+
+	public SidePanel( int side ) {
+	    super( );
+	    Class clazz = this.getClass( );
+
+
+	    _side = side;
+
+	    _tallPanel = new JPanel( );
+	    _tallPanel.setLayout( new BoxLayout( _tallPanel, BoxLayout.Y_AXIS ) );
+
+ 	    JButton tall = new JButton( );
+	    tall.setMaximumSize( new Dimension( 10, 2000 ) );
+	    tall.setPreferredSize( new Dimension( 10, 2000 ) );
+	    tall.setMinimumSize( new Dimension( 10, 0 ) );
+
+	    tall.addActionListener( new ActionListener( ) {
+		    boolean removed = false;
+		    
+		    public void actionPerformed( ActionEvent e ) {
+			if( ! removed ) {
+			    _top.remove( _listPanel );
+			    removed = true;
+			} else {
+			    if( _side == LEFT_SIDE ) {
+				_top.add( _listPanel, 0 );
+			    } else {
+				_top.add( _listPanel, 2 );
+			    }
+
+			    removed = false;
+			}
+			
+			validate( );
+			repaint( );
+
+		    }
+
+		} );
+
+
+	    _tallPanel.add( tall );
+
+
+	    _thinPanel = new JPanel( );
+	    _thinPanel.setLayout( new BoxLayout( _thinPanel, BoxLayout.X_AXIS ) );
+
+	    JButton thin = new JButton( );
+	    thin.setMaximumSize( new Dimension( 2000, 10 ) );
+	    thin.setPreferredSize( new Dimension( 2000, 10 ) );
+	    thin.setMinimumSize( new Dimension( 0, 10 ) );
+
+	    thin.addActionListener( new ActionListener( ) {
+		    boolean removed = false;
+		    
+		    public void actionPerformed( ActionEvent e ) {
+			if( ! removed ) {
+			    _complete.remove( _messagePanel );
+			    removed = true;
+			} else {
+			    _complete.add( _messagePanel, 2 );
+			    removed = false;
+			}
+
+			validate( );
+			repaint( );
+		    }
+
+		} );
+
+
+	    _thinPanel.add( thin );
+
+	    _listPanel = new ListPanel( );
+
+	    _messagePanel = new MessagePanel( );
+
+ 	    _graphPanel = new JPanel( new BorderLayout( ) );
+
+	    setPanelBorder( _graphPanel, "Trust Negotiation Graph" );
+
+	    _listPanel.setMaximumSize( new Dimension( 150, 2000 ) );
+	    _listPanel.setPreferredSize( new Dimension( 150, 2000 ) );
+	    _listPanel.setMinimumSize( new Dimension( 150, 0 ) );
+
+	    _messagePanel.setMaximumSize( new Dimension( 2000, 150 ) );
+	    _messagePanel.setPreferredSize( new Dimension( 2000, 150 ) );
+	    _messagePanel.setMinimumSize( new Dimension( 0, 150 ) );
+
+
+	    _top = new JPanel( );
+ 	    _top.setLayout( new BoxLayout( _top, BoxLayout.X_AXIS ) );
+	    
+
+	    if( _side == LEFT_SIDE ) {
+		_top.add( _listPanel );
+		_top.add( _tallPanel );
+		_top.add( _graphPanel );
+	    } else {
+		_top.add( _graphPanel );
+		_top.add( _tallPanel );
+		_top.add( _listPanel );
+	    }
+
+
+	    _complete = new JPanel( );
+	    _complete.setLayout( new BoxLayout( _complete, BoxLayout.Y_AXIS ) );
+
+	    _complete.add( _top );
+ 	    _complete.add( _thinPanel );
+ 	    _complete.add( _messagePanel );
+
+	    _graph = new Graph( "Trust Negotiation Graph: " + _side );
+ 	    _grappaPanel = new GrappaPanel( _graph );
+	    _grappaPanel.setScaleToFit( false );
+
+ 	    JScrollPane jsp = new JScrollPane( );
+ 	    jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	    jsp.getViewport( ).setBackground( Color.white );
+ 	    jsp.setViewportView( _grappaPanel );
+	
+	    _graphPanel.add( jsp, BorderLayout.CENTER );
+
+	    setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+	    add( _complete );
+
+	}
+
+	public void setMessage( String message ) {
+	    _messagePanel.setMessage( message );
+	}
+
+    }
+
+
+    private class ControlPanel extends JPanel implements ActionListener {
+	JButton play, pause, stepForward, stepBack, rewind, fastForward, stop;
+	InternalObservable _observable;
+
+	public ControlPanel( ) {
+	    super( );
+	    
+	    _observable = new InternalObservable( );
+	    Class clazz = this.getClass( );
+
+	    play = new JButton( new ImageIcon( clazz.getResource( "/resources/Play24.gif" ), "play" ) );
+	    play.setActionCommand( "play" );
+	    play.addActionListener( this );
+	    play.setEnabled( true );
+
+	    pause = new JButton( new ImageIcon( clazz.getResource( "/resources/Pause24.gif" ), "pause" ) );
+	    pause.setActionCommand( "pause" );
+	    pause.addActionListener( this );
+	    pause.setEnabled( false );
+
+
+	    stepForward = new JButton( new ImageIcon( clazz.getResource( "/resources/StepForward24.gif" ), "step forward" ) );
+	    stepForward.setActionCommand( "stepf" );
+	    stepForward.addActionListener( this );
+	    stepForward.setEnabled( true );
+
+	    stepBack = new JButton( new ImageIcon( clazz.getResource( "/resources/StepBack24.gif" ), "step back" ) );
+	    stepBack.setActionCommand( "stepb" );
+	    stepBack.addActionListener( this );
+	    stepBack.setEnabled( true );
+
+	    rewind = new JButton( new ImageIcon( clazz.getResource( "/resources/Rewind24.gif" ), "rewind" ) );
+	    rewind.setActionCommand( "rewind" );
+	    rewind.addActionListener( this );
+	    rewind.setEnabled( true );
+
+	    fastForward = new JButton( new ImageIcon( clazz.getResource( "/resources/FastForward24.gif" ), "fast forward" ) );
+	    fastForward.setActionCommand( "ff" );
+	    fastForward.addActionListener( this );
+	    fastForward.setEnabled( true );
+
+// 	    stop = new JButton( new ImageIcon( clazz.getResource( "/resources/Stop24.gif" ), "stop" ) );
+// 	    stop.setActionCommand( "stop" );
+// 	    stop.addActionListener( this );
+
+
+	    setStyle( play );
+	    setStyle( pause );
+	    setStyle( stepForward );
+	    setStyle( stepBack );
+	    setStyle( rewind );
+	    setStyle( fastForward );
+// 	    setStyle( stop );
+
+	    setLayout( new BoxLayout( this, BoxLayout.X_AXIS ) );
+	    add( rewind );
+	    add( stepBack );
+	    add( play );
+	    add( pause );
+// 	    add( stop );
+	    add( stepForward );
+	    add( fastForward );
+
+	    JCheckBox loop = new JCheckBox( "loop", (new Boolean( _properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( ) );
+	    loop.addItemListener( new ItemListener( ) {
+		    public void itemStateChanged( ItemEvent e ) {
+			int s = e.getStateChange( );
+			Boolean state = Boolean.TRUE;
+
+			if( s == ItemEvent.DESELECTED ) {
+			    state = Boolean.FALSE;
+			}
+			
+			_observable.notify( state );
+
+		    }
+
+		} );
+
+
+	    add( Box.createHorizontalStrut( 10 ) );
+	    add( loop );
+
+	    JSpinner spinner = new JSpinner( new SpinnerNumberModel( Integer.parseInt( _properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) ), 
+								     0, 
+								     5000, 
+								     100 ) );
+
+	    JLabel spinnerLabel = new JLabel( "delay (msec)" );
+
+	    spinner.addChangeListener( new ChangeListener( ) {
+		    public void stateChanged( ChangeEvent e ) {
+			_observable.notify( e.getSource( ) );
+		    }
+		} );
+
+
+	    add( spinner );
+	    add( Box.createHorizontalStrut( 5 ) );
+	    add( spinnerLabel );
+
+	    setPanelBorder( this, "Controls" );
+	}
+
+
+	public void addObserver( Observer o ) {
+	    _observable.addObserver( o );
+	}
+
+
+	private void setStyle( JButton b ) {
+	    b.setMinimumSize( new Dimension( 24, 24 ) );
+	    b.setMaximumSize( new Dimension( 24, 24 ) );
+	    b.setPreferredSize( new Dimension( 24, 24 ) );
+	    
+	    b.setBorderPainted( false );
+	}
+
+	public void actionPerformed( ActionEvent e ) {
+	    String cmd = e.getActionCommand( );
+	    if( cmd.equals( "play" ) ) {
+		stepForward.setEnabled( false );
+		stepBack.setEnabled( false );
+		rewind.setEnabled( false );
+		fastForward.setEnabled( false );
+		play.setEnabled( false );
+		pause.setEnabled( true );
+	    }
+
+	    else if( cmd.equals( "pause" ) ) {
+		stepForward.setEnabled( true );
+		stepBack.setEnabled( true );
+		rewind.setEnabled( true );
+		fastForward.setEnabled( true );
+		play.setEnabled( true );
+		pause.setEnabled( false );
+	    }
+
+
+
+
+
+	    _observable.notify( e.getActionCommand( ) );
+	}
+
+
+	private class InternalObservable extends Observable {
+	    public void notify( Object arg ) {
+		setChanged( );
+		notifyObservers( arg );
+	    }
+
+	    
+	}
+
+    }
+
+
+    private class ListPanel extends JPanel implements Observer {
+	public ListPanel( ) {
+	    super( );
+
+	    JList oCreds = new JList( );
+	    JScrollPane oCredsJSP = new JScrollPane( oCreds );
+	    setPanelBorder( oCredsJSP, "Opponent Creds." );
+
+	    JList vCreds = new JList( );
+	    JScrollPane vCredsJSP = new JScrollPane( vCreds );
+	    setPanelBorder( vCredsJSP, "Verifier Creds." );
+
+	    JList acPolicy = new JList( );
+	    JScrollPane acPolicyJSP = new JScrollPane( acPolicy );
+	    setPanelBorder( acPolicyJSP, "AC Policies" );
+
+	    JList ackPolicy = new JList( );
+	    JScrollPane ackPolicyJSP = new JScrollPane( ackPolicy );
+	    setPanelBorder( ackPolicyJSP, "Ack Policies" );
+
+
+	    setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) );
+
+	    JList list = new JList( );
+	    JScrollPane jsp = new JScrollPane( list );
+	    
+	    add( oCredsJSP );
+	    add( vCredsJSP );
+	    add( acPolicyJSP );
+	    add( ackPolicyJSP );
+
+
+	}
+
+
+	public void update( Observable o, Object arg ) {
+
+
+	}
+
+    }
+
+
+    private class MessagePanel extends JPanel {
+	JTextArea _message;
+
+	public MessagePanel( ) {
+	    super( );
+	    setLayout( new BorderLayout( ) );
+
+	    _message = new JTextArea( );
+	    JScrollPane jsp = new JScrollPane( _message );
+
+	    add( jsp, BorderLayout.CENTER );
+
+	    setPanelBorder( this, "Message" );
+
+	}
+
+	public void setMessage( String message ) {
+	    _message.setText( message );
+	}
+
+
+    }
+
+    
+    private class ProgressPanel extends JPanel implements Observer {
+	JProgressBar _progress;
+
+	public ProgressPanel( ) {
+	    super( );
+	    setLayout( new BorderLayout( ) );
+
+// 	    _progress = new JProgressBar( 0, _updates.size( ) );
+	    _progress = new JProgressBar( 0, 1 );
+	    _progress.setValue( 0 );
+	    _progress.setStringPainted( true );
+
+
+	    add( _progress, BorderLayout.CENTER );
+
+	    setPanelBorder( this, "Negotiation Progress" );
+	}
+
+
+	public void setMax( int n ) {
+	    _progress.setMaximum( n );
+	}
+
+	public void update( Observable o, Object arg ) {
+	    _progress.setValue( ((Integer)arg).intValue( ) );
+
+	}
+
+
+    }
+
+
+    private void setPanelBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+
+
+    private class PlayBackManager extends Observable implements Observer {
+	private int _delay = Integer.parseInt( _properties.getProperty( DELAY_PROP, DELAY_DEFAULT ) );
+	private boolean _loop = (new Boolean( _properties.getProperty( LOOP_PROP, LOOP_DEFAULT ) )).booleanValue( );
+	private Update[] _updateArray = (Update[]) _updates.toArray( new Update[0] );
+	private int _index = 0;
+	private boolean _clear = true;
+
+
+	private boolean _playing = false;
+
+
+	public PlayBackManager( ) {
+	    _progressPanel.setMax( _updateArray.length );
+	}
+
+	public void update( Observable o, Object arg ) {
+	    if( arg instanceof String ) {
+		String cmd = (String)arg;
+
+		if( cmd.equals( "play" ) ) {
+		    _playing = true;
+		    new Thread( new PlayThread( ) ).start( );
+		} else if( cmd.equals( "pause" ) ) {
+		    _playing = false;
+		} else if( cmd.equals( "stepf" ) ) {
+		    stepf( );
+		} else if( cmd.equals( "ff" ) ) {
+		    ff( );
+		} else if( cmd.equals( "rewind" ) ) {
+		    rewind( );
+		}
+
+	    } else if( arg instanceof JSpinner ) {
+		SpinnerNumberModel snm = (SpinnerNumberModel)((JSpinner)arg).getModel( );
+		_delay = snm.getNumber( ).intValue( );
+	    } else if (arg instanceof Boolean ) {
+		_loop = ((Boolean)arg).booleanValue( );
+	    }
+	}
+
+
+	private synchronized void stepf( ) {
+	    if( _index == 0 && _clear == false ) {
+		clearAll( );
+		_clear = true;
+
+		setChanged( );
+		notifyObservers( new Integer( _index ) );
+
+		return;
+	    }
+
+	    _clear = false;
+
+
+	    _updateArray[_index].execute( );
+	    _index++;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+
+	    
+	    if( _index == _updateArray.length ) {
+		_index = 0;
+		if( _playing == true && _loop == false ) {
+		    _playing = false;
+		}
+	    }
+
+
+	}
+
+	private synchronized void stepb( ) {
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+	}
+	
+	private synchronized void ff( ) {
+	    for( int i = _index; i < _updateArray.length; i++ ) {
+		_updateArray[i].execute( );
+	    }
+
+	    _index = 0;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+
+	}
+
+
+	private synchronized void rewind( ) {
+	    clearAll( );
+	    _index = 0;
+
+	    setChanged( );
+	    notifyObservers( new Integer( _index ) );
+	}
+
+
+	private class PlayThread implements Runnable {
+	    public void run( ) {
+		while( _playing ) {
+		    try {
+			stepf( );
+			Thread.currentThread( ).sleep( _delay );
+		    } catch( InterruptedException ie ) {
+			throw new RuntimeException( ie );
+		    }
+		}
+		
+	    }
+	}
+
+
+    }
+
+
+    protected abstract class  Update {
+	public abstract void execute( );
+	public abstract void fixRef( );
+    }
+
+
+    private class TestUpdate extends Update {
+	private int _i;
+
+	public TestUpdate( int i ) {
+	    _i = i;
+	}
+
+	public void execute( ) {
+	    System.out.println( _i );
+	}
+	
+	public void fixRef( ) {
+
+	}
+
+    }
+
+    private class MessageBeginUpdate extends Update {
+	SidePanel _sp;
+	String _message;
+
+	public MessageBeginUpdate( SidePanel sp, String message ) {
+	    _sp = sp;
+	    _message = message;
+	}
+
+
+	public void execute( ) {
+	    _sp.setMessage( _message );
+	}
+	
+	public void fixRef( ) {
+
+	}
+	
+    }
+    
+    private class MessageEndUpdate extends Update {
+	SidePanel _sp;
+
+	public MessageEndUpdate( SidePanel sp ) {
+	    _sp = sp;
+	}
+
+
+	public void execute( ) {
+	    _sp.setMessage( "" );
+	}
+	
+	public void fixRef( ) {
+
+	}
+    }
+    
+	
+
+
+
+
+
+
+    private class NodeUpdate extends Update {
+	SidePanel _sp;
+	String _name;
+	Node _n;
+
+	String _type;
+	String _satisfactionState;
+	String _processingState;
+
+	public NodeUpdate( SidePanel sp, String name ) {
+	    _sp = sp;
+	    _name = name;
+
+	    Graph g = _sp.getGraph( );
+
+	    _n = g.findNodeByName( name );
+	    if( _n == null ) {
+		_n = new Node( g, name );
+		setInvis( _n );
+		g.addNode( _n );
+	    }
+
+	}
+
+	public NodeUpdate( SidePanel sp, 
+			   String name, 
+			   String type,
+			   String satisfactionState, 
+			   String processingState ) {
+	    this( sp, name );
+
+	    _type = type;
+
+
+	    _satisfactionState = satisfactionState;
+	    _processingState = processingState;
+
+
+	}
+
+	public void fixRef( ) {
+	    _n = _sp.getGraph( ).findNodeByName( _name );
+	}
+
+
+	public void execute( ) {
+	    fixRef( );
+
+	    setNodeProperties( _n, _type, _satisfactionState, _processingState );
+
+	    Graph g = _sp.getGraph( );
+
+	    g.resync( );
+	    g.repaint( );
+	}
+    }
+
+    
+    private class EdgeUpdate extends Update {
+	SidePanel _sp;
+	String _headNodeName;
+	String _tailNodeName;
+	Edge _e;
+
+	String _type;
+
+
+	public EdgeUpdate( SidePanel sp, 
+			   String headNodeName, 
+			   String tailNodeName, 
+			   String type ) {
+	    this( sp, headNodeName, tailNodeName );
+	    _type = type;
+	}
+
+
+
+	public EdgeUpdate( SidePanel sp, String headNodeName, String tailNodeName ) {
+	    _sp = sp;
+	    _headNodeName = headNodeName;
+	    _tailNodeName = tailNodeName;
+
+	    Graph g = _sp.getGraph( );
+	    Node head = g.findNodeByName( _headNodeName );
+	    Node tail = g.findNodeByName( _tailNodeName );
+
+
+	    _e = getEdgeBetween( g, head, tail );
+
+	    if( _e == null ) {
+		_e = new Edge( g, head, tail );
+		setInvis( _e );
+		g.addEdge( _e );
+	    }
+
+	}
+
+
+	public void fixRef( ) {
+	    Graph g = _sp.getGraph( );
+	    Node head = g.findNodeByName( _headNodeName );
+	    Node tail = g.findNodeByName( _tailNodeName );
+
+
+	    _e = getEdgeBetween( g, head, tail );
+	}
+
+	public void execute( ) {
+	    fixRef( );
+	    setEdgeProperties( _e, _type );
+
+	    Graph g = _sp.getGraph( );
+
+	    g.resync( );
+	    g.repaint( );
+	}
+    }
+
+
+    private void clearAll( ) {
+	for( int i = 0; i < _sides.length; i++ ) {
+	    if( _sides[i] != null ) {
+		hideGraph( _sides[i].getGraph( ) );
+	    }
+	}
+
+	
+    }
+
+    private Graph loadGraph( String dotFile ) {
+	Parser parser = null;
+	try {
+	    parser = new Parser( new FileInputStream( dotFile ) );
+	    parser.parse( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	return parser.getGraph( );
+    }
+
+
+
+    public static void main( String[] args ) {
+	ATNVisualizer atnVis = null;
+
+	if( args.length == 1 ) {
+	    atnVis = new ATNVisualizer( args[0], null );
+	} else if ( args.length == 2 ) {
+	    atnVis = new ATNVisualizer( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: ATNVisualizer <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+
+    private void printGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Node n = (Node) nodes.nextElement( );
+	    n.printAllAttributes = true;
+
+	    System.out.println( n.getName( ) );
+
+	    Enumeration e = n.getAttributePairs( );
+	    while( e.hasMoreElements( ) ) {
+		System.out.println( e.nextElement( ) );
+	    }
+
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Edge e = (Edge) edges.nextElement( );
+	    e.printAllAttributes = true;
+
+	    System.out.println( e.getName( ) );
+
+	    Enumeration en = e.getAttributePairs( );
+	    while( en.hasMoreElements( ) ) {
+		System.out.println( en.nextElement( ) );
+	    }
+	}
+
+	System.out.println( "======================================================================" );
+
+	g.printSubgraph( new PrintWriter( System.err, true ) );
+    }
+
+
+    private Edge getEdgeBetween( Graph g, Node head, Node tail ) {
+	Enumeration edges = g.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+}
Index: fedd/abac-src/atnvis/src/vis/ATNVisualizer.java.tmp
===================================================================
--- fedd/abac-src/atnvis/src/vis/ATNVisualizer.java.tmp	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/vis/ATNVisualizer.java.tmp	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,525 @@
+package com.algomagic.atn.vis;
+import att.grappa.*;
+
+import java.util.Properties;
+import java.util.Enumeration;
+import java.io.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+
+public class ATNVisualizer extends JFrame 
+    implements ATNVisualizerConstants, GrappaConstants {
+
+    private Properties _properties;
+    private GrappaPanel _grappaPanel;
+    private Graph _graph;
+
+    
+
+    public ATNVisualizer( String log1, String log2 ) {
+	initATNVisualizer( log1, log2 );
+    }
+
+
+    private void initATNVisualizer( String log1, String log2 ) {
+	loadProperties( );
+
+	addWindowListener( new WindowAdapter( ) {
+		public void windowClosing( WindowEvent we ) {
+		    Window w = we.getWindow( );
+		    w.setVisible( false );
+		    w.dispose( );
+		    System.exit( 0 );
+		}
+	    });
+
+
+	SidePanel leftSide = new SidePanel( log1, LEFT_SIDE );
+	SidePanel rightSide = null;
+
+	Container contentPane = getContentPane( );
+	contentPane.setLayout( new BoxLayout( contentPane, BoxLayout.X_AXIS ) );
+  	contentPane.add( leftSide );
+
+
+	if( log2 != null ) {
+	    rightSide = new SidePanel( log2, RIGHT_SIDE );
+	    contentPane.add( rightSide );
+	}
+
+
+
+ 	setTitle( _properties.getProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT ) );
+ 	setSize( Integer.parseInt( _properties.getProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT ) ),
+ 		 Integer.parseInt( _properties.getProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT ) ) );
+
+	show( );
+
+	leftSide.resetDividerLocations( );
+
+	if( log2 != null ) {
+	    rightSide.resetDividerLocations( );
+	}
+
+    }
+
+    private void hideGraph( Graph g ) {
+	Enumeration nodes = _graph.nodeElements( );
+	Enumeration edges = _graph.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    Node n = (Node) nodes.nextElement( );
+	    setInvis( n );
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    setInvis( e );
+	}
+
+    }
+
+    private Graph loadGraph( String dotFile ) {
+	Parser parser = null;
+	try {
+	    parser = new Parser( new FileInputStream( dotFile ) );
+	    parser.parse( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	    System.exit( 1 );
+	}
+
+	return parser.getGraph( );
+    }
+
+
+    private void formatGraph( Graph g ) {
+	try {
+	    Process formater = Runtime.getRuntime( ).exec( "dot" );
+	    GrappaSupport.filterGraph( g, formater );
+	    formater.destroy( );
+	    
+	    g.repaint( );
+	} catch( Exception e ) {
+	    e.printStackTrace( );
+	}
+    }
+
+    private void redrawAndPause( int millis ) {
+	_graph.resync( );
+	_graph.repaint( );
+	try { Thread.currentThread( ).sleep( millis ); }
+	catch( Exception e ) { }
+    }
+
+
+    private void setSolid( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+	e.setAttribute( STYLE_ATTR, "solid" );
+    }
+
+
+    private void setBold( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "bold" );
+	e.setAttribute( STYLE_ATTR, "bold" );
+    }
+
+    private void setInvis( Element e ) {
+	e.setAttribute( FONTSTYLE_ATTR, "normal" );
+	e.setAttribute( STYLE_ATTR, "invis" );
+    }
+
+
+
+    private Edge getEdgeBetween( Node head, Node tail ) {
+	Enumeration edges = _graph.edgeElements( );
+	while( edges.hasMoreElements( ) ) {
+	    Edge e = (Edge) edges.nextElement( );
+	    Node t = e.getHead( );
+	    Node h = e.getTail( );
+	    
+	    if( h.getName( ).equals( head.getName( ) ) && t.getName( ).equals( tail.getName( ) ) ) {
+		return e;
+	    }
+	}
+
+	return null;
+    }
+
+
+
+
+    private void loadProperties( ) {
+	String propsFileName = System.getProperty( CONFIG_FILE_PROP, CONFIG_FILE_DEFAULT );
+	File file = new File( propsFileName );
+
+	if( file.exists( ) ) {
+	    _properties = new Properties( );
+	    try {
+		_properties.load( new FileInputStream( file ) );
+	    } catch( FileNotFoundException fnfe ) {
+		_properties = getDefaultProperties( );
+	    } catch( IOException ioe ) {
+		_properties = getDefaultProperties( );
+	    }
+	} else {
+	    _properties = getDefaultProperties( );
+	}
+    }
+
+
+    private Properties getDefaultProperties( ) {
+	Properties p = new Properties( );
+	p.setProperty( WINDOW_TITLE_PROP, WINDOW_TITLE_DEFAULT );
+	p.setProperty( WINDOW_HEIGHT_PROP, WINDOW_HEIGHT_DEFAULT );
+	p.setProperty( WINDOW_WIDTH_PROP, WINDOW_WIDTH_DEFAULT );
+
+	return p;
+    }
+
+
+    public static void main( String[] args ) {
+	ATNVisualizer atnVis = null;
+
+	if( args.length == 1 ) {
+	    atnVis = new ATNVisualizer( args[0], null );
+	} else if ( args.length == 2 ) {
+	    atnVis = new ATNVisualizer( args[0], args[1] );
+	} else {
+	    System.err.println( "usage: ATNVisualizer <log file> [<log file>]" );
+	    System.exit( 1 );
+	}
+
+    }
+
+
+
+
+    private class SidePanel extends JPanel {
+	GrappaPanel _grappaPanel;
+	Graph _graph;
+
+	JPanel _listPanel;
+	JPanel _messagePanel;
+	JPanel _graphPanel;
+	JCheckBox _scaleButton;
+	
+	JSplitPane _top;
+	JSplitPane _complete;
+
+	int _side;
+	boolean _graphScaleToFit;
+	Dimension _unScaledDim;
+
+	public SidePanel( String transcriptFile, int side ) {
+	    super( );
+
+	    _side = side;
+
+	    _listPanel = new JPanel( new BorderLayout( ) );
+	    _messagePanel = new JPanel( new BorderLayout( ) );
+	    _graphPanel = new JPanel( new BorderLayout( ) );
+
+
+	    _messagePanel.setMaximumSize( new Dimension( 2000, 100 ) );
+
+
+
+// 	    _graphPanel.addComponentListener( new ComponentAdapter( ) {
+// 		    public void componentResized( ComponentEvent e ) {
+// 			if( _graphScaleToFit == true ) {
+// 			    setGraphToFit( e.getComponent( ).getSize( ) );
+// 			}
+// 		    }
+
+// 		});
+
+
+// 	    _scaleButton = new JCheckBox( "scale graph to fit" );
+// 	    _scaleButton.setSelected( true );
+// 	    _scaleButton.addItemListener( new ItemListener( ) {
+// 		    public void itemStateChanged( ItemEvent e ) {
+// 			if( e.getStateChange( ) == ItemEvent.DESELECTED ) {
+// 			    setGraphScaleToFit( false );
+// 			} else {
+// 			    setGraphScaleToFit( true );
+// 			}
+// 		    }
+// 		});
+	    
+
+	    
+	    setPanelBorder( _listPanel, "Creds and Policies" );
+	    setPanelBorder( _messagePanel, "Output Log" );
+	    setPanelBorder( _graphPanel, "Trust Negotiation Graph" );
+
+
+	    if( _side == LEFT_SIDE ) {
+		_top = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, 
+				       _listPanel, 
+				       _graphPanel );
+	    } else {
+		_top = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, 
+				       _graphPanel,
+				       _listPanel);
+		
+
+		_top.setResizeWeight( 1.0 );
+
+
+	    }
+
+	    _complete = new JSplitPane( JSplitPane.VERTICAL_SPLIT,
+					_top,
+					_messagePanel );
+
+	    _complete.setResizeWeight( 1.0 );
+
+
+	    _complete.addComponentListener( new ComponentAdapter( ) {
+		    public void componentResized( ComponentEvent e ) {
+			System.out.println( "resized: " + e.getComponent( ).getSize( ) );
+		    }
+
+		    public void componentMoved( ComponentEvent e ) {
+			System.out.println( "moved: " + e.getComponent( ).getSize( ) );
+		    }
+
+
+
+		});
+
+
+ 	    _graph = loadGraph( transcriptFile );
+ 	    formatGraph( _graph );
+
+
+ 	    _grappaPanel = new GrappaPanel( _graph );
+	    _grappaPanel.setScaleToFit( false );
+
+ 	    JScrollPane jsp = new JScrollPane( );
+ 	    jsp.getViewport( ).setScrollMode( JViewport.BACKINGSTORE_SCROLL_MODE );
+ 	    jsp.getViewport( ).setBackground( Color.white );
+ 	    jsp.setViewportView( _grappaPanel );
+	
+	    _graphPanel.add( jsp, BorderLayout.CENTER );
+
+	    setLayout( new BorderLayout( ) );
+	    add( _complete, BorderLayout.CENTER );
+
+
+	    _top.setOneTouchExpandable( true );
+	    _complete.setOneTouchExpandable( true );
+	}
+
+
+	public void resetDividerLocations( ) {
+	    if( _side == LEFT_SIDE ) {
+		_top.setDividerLocation( 0.25 );
+	    } else {
+		_top.setDividerLocation( 0.75 );
+	    }
+	    _complete.setDividerLocation( 0.75 );
+
+	}
+
+	public void setGraphScaleToFit( boolean b ) {
+	    _graphScaleToFit = b;
+
+	    if( b == false ) {
+		setGraphToFit( _unScaledDim );
+	    } else {
+		setGraphToFit( _graphPanel.getSize( ) );
+	    }
+
+	}
+
+
+	public void setGraphToFit( Dimension d ) {
+
+	    d.setSize( d.getWidth( ) - 50, d.getHeight( ) - 50 );
+
+	    _grappaPanel.setScaleToSize( d );
+	    _graph.resync( );
+	    _graph.repaint( );
+
+	}
+
+
+    }
+
+
+
+    private void setPanelBorder( JComponent comp, String label ) {
+	Border empty = BorderFactory.createEmptyBorder( 0, 0, 0, 0 );
+	Border etched = BorderFactory.createEtchedBorder( );
+	
+	TitledBorder title = BorderFactory.createTitledBorder( etched, label );
+	title.setTitleJustification( TitledBorder.RIGHT );
+
+	Border compound = BorderFactory.createCompoundBorder( title, empty );
+	comp.setBorder( compound );
+    }
+
+
+
+
+    private void printGraph( Graph g ) {
+	Enumeration nodes = g.nodeElements( );
+	Enumeration edges = g.edgeElements( );
+
+	while( nodes.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Node n = (Node) nodes.nextElement( );
+	    n.printAllAttributes = true;
+
+	    System.out.println( n.getName( ) );
+
+	    Enumeration e = n.getAttributePairs( );
+	    while( e.hasMoreElements( ) ) {
+		System.out.println( e.nextElement( ) );
+	    }
+
+	}
+
+	while( edges.hasMoreElements( ) ) {
+	    System.out.println( "----------------------------------------------------------------------" );
+
+	    Edge e = (Edge) edges.nextElement( );
+	    e.printAllAttributes = true;
+
+	    System.out.println( e.getName( ) );
+
+	    Enumeration en = e.getAttributePairs( );
+	    while( en.hasMoreElements( ) ) {
+		System.out.println( en.nextElement( ) );
+	    }
+	}
+
+	System.out.println( "======================================================================" );
+
+	g.printSubgraph( new PrintWriter( System.err, true ) );
+    }
+
+
+
+    public void animate( ) {
+	Node a,b,c,d,e,f,g;
+
+	a = _graph.findNodeByName( "A" );
+	b = _graph.findNodeByName( "B" );
+	c = _graph.findNodeByName( "C" );
+	d = _graph.findNodeByName( "D" );
+	e = _graph.findNodeByName( "E" );
+	f = _graph.findNodeByName( "F" );
+	g = _graph.findNodeByName( "G" );
+
+
+	Edge ab, bc, cd, ce, ef, fg;
+
+	ab = getEdgeBetween( a,b );
+	bc = getEdgeBetween( b,c );
+	cd = getEdgeBetween( c,d );
+	ce = getEdgeBetween( c,e );
+	ef = getEdgeBetween( e,f );
+	fg = getEdgeBetween( f,g );
+	
+
+	while (true) {
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( a );
+	    redrawAndPause( 1000 );
+
+	    setBold( b );
+	    setBold( ab );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+
+	    setSolid( a );
+	    setSolid( b );
+	    setSolid( ab );
+
+	    // ----------------------------------------------------------------------
+
+	    redrawAndPause( 1000 );
+
+	    setBold( c );
+	    setBold( bc );
+
+	    redrawAndPause( 1000 );
+
+	    setBold( e );
+	    setBold( ce );
+
+	    redrawAndPause( 1000 );
+
+	    setBold( f );
+	    setBold( ef );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setSolid( c );
+	    setSolid( bc );
+	    setSolid( e );
+	    setSolid( ce );
+	    setSolid( f );
+	    setSolid( ef );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( g );
+	    setBold( fg );
+
+	    redrawAndPause( 1000 );
+	
+	    // ----------------------------------------------------------------------
+
+	    setSolid( g );
+	    setSolid( fg );
+
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setBold( d );
+	    setBold( cd );
+	
+	    redrawAndPause( 1000 );
+
+	    // ----------------------------------------------------------------------
+
+	    setSolid( d );
+	    setSolid( cd );
+
+	    redrawAndPause( 2000 );
+
+	    // ----------------------------------------------------------------------
+
+	    hideGraph( _graph );
+
+	    redrawAndPause( 1000 );
+
+	}
+
+    }
+
+
+
+
+
+}
Index: fedd/abac-src/atnvis/src/vis/ATNVisualizerConstants.java
===================================================================
--- fedd/abac-src/atnvis/src/vis/ATNVisualizerConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/atnvis/src/vis/ATNVisualizerConstants.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,120 @@
+package com.algomagic.atn.vis;
+
+import att.grappa.GrappaConstants;
+
+public interface ATNVisualizerConstants extends GrappaConstants {
+    public static final String SYSTEM_PREFIX = "atnvis.";
+
+    public static final String CONFIG_FILE_PROP = SYSTEM_PREFIX + "ConfigFile";
+    public static final String WINDOW_TITLE_PROP = SYSTEM_PREFIX + "window.Title";
+    public static final String WINDOW_HEIGHT_PROP = SYSTEM_PREFIX + "window.Height";
+    public static final String WINDOW_WIDTH_PROP = SYSTEM_PREFIX + "window.Width";
+
+    public static final String DELAY_PROP = SYSTEM_PREFIX + "defaultDelay";
+    public static final String LOOP_PROP = SYSTEM_PREFIX + "loop";
+
+
+    public static final String CONFIG_FILE_DEFAULT = "atnvis.properties";
+    public static final String WINDOW_TITLE_DEFAULT = "ATN Visualization";
+    public static final String WINDOW_HEIGHT_DEFAULT = "800";
+    public static final String WINDOW_WIDTH_DEFAULT = "600";
+
+    public static final String DELAY_DEFAULT = "500";
+    public static final String LOOP_DEFAULT = "true";
+
+    public static final int LEFT_SIDE = 0;
+    public static final int RIGHT_SIDE = 1;
+
+    public static final String OPPONENT_PROC = "Opponent";
+    public static final String VERIFIER_PROC = "Verifier";
+    public static final String FULLY_PROC = "Fully";
+    public static final String NOT_PROC = "Not";
+
+    public static final String SATISFIED = "True";
+    public static final String NOT_SATISFIED = "False";
+
+    public static final String STANDARD_TARGET = "StandardTarget";
+    public static final String INTERSECTION_TARGET = "IntersectionTarget";
+    public static final String LINKING_GOAL = "LinkingGoal";
+
+    public static final String IMPLICATION_EDGE = "Implication";
+    public static final String LINKING_MONITOR_EDGE = "LinkingMonitor";
+    public static final String LINKING_SOLUTION_EDGE = "LinkingSolution";
+    public static final String LINKING_IMPLICATION_EDGE = "LinkingImplication";
+    public static final String INTERSECTION_EDGE = "Intersection";
+    public static final String CONTROL_EDGE = "Control";
+
+    public static final String DEFAULT_NODE = SYSTEM_PREFIX + "node.Default.";
+    public static final String DEFAULT_EDGE = SYSTEM_PREFIX + "edge.Default.";
+
+
+    public static final String[] NODE_ATTRS = {
+	SHAPE_ATTR,
+	SIDES_ATTR,
+	PERIPHERIES_ATTR,
+	STYLE_ATTR,
+	COLOR_ATTR,
+	FONTNAME_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR };
+
+
+
+    public static final String[] NODE_ATTRS_PROP = {
+	"shape",
+	"sides",
+	"peripheries",
+	"style",
+	"color",
+	"fontname",
+	"fontcolor",
+	"fontsize",
+	"fontstyle" };
+
+    public static final boolean[] NODE_ATTRS_INT = {
+	false,
+	true,
+	true,
+	false,
+	false,
+	false,
+	false,
+	true,
+	false };
+
+
+    public static final String[] EDGE_ATTRS = {
+	STYLE_ATTR,
+	FONTNAME_ATTR,
+	COLOR_ATTR,
+	FONTCOLOR_ATTR,
+	FONTSIZE_ATTR,
+	FONTSTYLE_ATTR,
+	DIR_ATTR };
+
+    public static final String[] EDGE_ATTRS_PROP = {
+	"style",
+	"fontname",
+	"color",
+	"fontcolor",
+	"fontsize",
+	"fontstyle", 
+	"direction"  };
+
+
+    public static final boolean[] EDGE_ATTRS_INT = {
+	false,
+	false,
+	false,
+	false,
+	true,
+	false,
+	false };
+
+    
+
+
+
+
+}
