Commit in lcsim/src/org/lcsim/job on MAIN
IParameterConverter.java+26added 1.1
ParameterConverters.java+444added 1.1
JobControlManager.java+44-1931.27 -> 1.28
+514-193
2 added + 1 modified, total 3 files
separate conversion code into separate class to cleanup JobControlManager

lcsim/src/org/lcsim/job
IParameterConverter.java added at 1.1
diff -N IParameterConverter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ IParameterConverter.java	5 Oct 2009 20:34:20 -0000	1.1
@@ -0,0 +1,26 @@
+package org.lcsim.job;
+
+import org.jdom.Element;
+import org.lcsim.util.xml.JDOMExpressionFactory;
+
+/**
+ * Interface for converting from XML to typed objects for input to LCSim Drivers.
+ * @author jeremym
+ */
+public interface IParameterConverter 
+{
+	/**
+	 * This method returns true if the converter can handle the given type.
+	 * @param propertyType The class of the parameter.
+	 * @return True if converter handles the given type; False if no.
+	 */
+	public boolean handles(Class propertyType);	
+	
+	/**
+	 * Convert an XML element parameter to a specific type and return as an Object.
+	 * @param factory The expression factory to be used for variable evaluation.
+	 * @param parameterElement The XML parameter data.
+	 * @return Parameter converted to specific type.  Returned as generic object.
+	 */
+	public Object convert(JDOMExpressionFactory factory, Element parameterElement);
+}

lcsim/src/org/lcsim/job
ParameterConverters.java added at 1.1
diff -N ParameterConverters.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ParameterConverters.java	5 Oct 2009 20:34:20 -0000	1.1
@@ -0,0 +1,444 @@
+package org.lcsim.job;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.jdom.Element;
+import org.lcsim.util.xml.JDOMExpressionFactory;
+
+/**
+ * Converter utilities for making Java Beans arguments from LCSim XML Driver parameters,
+ * using a JDOM factory to do expression evaluation.
+ * @author jeremym
+ */
+public class ParameterConverters 
+{	
+	List<IParameterConverter> converters = new ArrayList<IParameterConverter>();
+	JDOMExpressionFactory factory;
+	
+	public ParameterConverters(JDOMExpressionFactory factory)	
+	{
+		this.factory = factory;
+		
+		add(new IntegerConverter());
+		add(new StringConverter());
+		add(new DoubleConverter());
+		add(new FloatConverter());
+		add(new BooleanConverter());
+		add(new Hep3VectorConverter());
+		add(new DoubleArray1DConverter());
+		add(new IntegerArray1DConverter());
+		add(new FloatArray1DConverter());
+		add(new StringArray1DConverter());
+		add(new BooleanArray1DConverter());
+		add(new FileConverter());
+		add(new URLConverter());
+		add(new IntegerArray2DConverter());
+		add(new DoubleArray2DConverter());
+	}
+	
+	public Object convert(Class propertyType, Element parameterElement)
+	{
+		IParameterConverter p = getConverterForType(propertyType);
+		if (p != null)
+		{
+			return p.convert(factory, parameterElement);
+		}
+		else 
+		{
+			return null;
+		}
+	}
+	
+	protected void add(IParameterConverter converter)
+	{		
+		converters.add(converter);
+	}
+	
+	public List<IParameterConverter> getConverters()
+	{
+		return converters;
+	}
+	
+	public IParameterConverter getConverterForType(Class propertyType)
+	{
+		for (IParameterConverter p : converters)
+		{
+			if (p.handles(propertyType))
+				return p;
+		}		
+		return null;
+	}
+	
+	public class IntegerConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(int.class);
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			return Integer.valueOf((int)factory.computeDouble(parameterElement.getValue()));
+		}
+	}
+	
+	public class StringConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(String.class);
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			return parameterElement.getValue();
+		}
+	}
+	
+	public class DoubleConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(double.class);			
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			return Double.valueOf(factory.computeDouble(parameterElement.getValue()));
+		}
+	}
+	
+	public class FloatConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(float.class);			
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			return Float.valueOf(factory.computeFloat(parameterElement.getValue()));
+		}
+	}	
+	
+	public class BooleanConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(boolean.class);			
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			return Boolean.valueOf(parameterElement.getValue());
+		}
+	}	
+	
+	public class Hep3VectorConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(Hep3Vector.class);			
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue());
+			double x = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
+			double y = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
+			double z = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
+			return new BasicHep3Vector(x, y, z);
+		}
+	}		
+	
+	public class DoubleArray1DConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.getName().equals("[D");			
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue());
+			int size = tokenize.countTokens();
+			double da[] = new double[size];
+			int i = 0;
+			while (tokenize.hasMoreTokens())
+			{
+				da[i] = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
+				++i;
+			}
+			return da;
+		}
+	}
+	
+	public class IntegerArray1DConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.getName().equals("[I");
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue());
+			int size = tokenize.countTokens();
+			int ia[] = new int[size];
+			int i = 0;
+			while (tokenize.hasMoreTokens())
+			{
+				ia[i] = Integer.valueOf((int)factory.computeDouble(tokenize.nextToken()));
+				++i;
+			}
+			return ia;
+		}
+	}
+	
+	public class FloatArray1DConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.getName().equals("[F");
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue());		
+			int size = tokenize.countTokens();
+			float fa[] = new float[size];
+			int i = 0;
+			while (tokenize.hasMoreTokens())
+			{
+				fa[i] = Float.valueOf(factory.computeFloat(tokenize.nextToken()));
+				++i;
+			}
+			return fa;
+		}
+	}
+	
+	public class StringArray1DConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.getName().equals("[Ljava.lang.String;");
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue());
+			int size = tokenize.countTokens();
+			String sa[] = new String[size];
+			int i = 0;
+			while (tokenize.hasMoreTokens())
+			{
+				sa[i] = tokenize.nextToken();
+				++i;
+			}
+			return sa;
+		}
+	}
+	
+	public class BooleanArray1DConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.getName().equals("[Z");
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue());
+			int size = tokenize.countTokens();
+			boolean ba[] = new boolean[size];
+			int i = 0;
+			while (tokenize.hasMoreTokens())
+			{
+				ba[i] = Boolean.valueOf(tokenize.nextToken());
+				++i;
+			}
+			return ba;
+		}	
+	}
+	
+	public class FileConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(File.class);
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			return new File(parameterElement.getValue());
+		}
+	}
+	
+	public class URLConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(URL.class);
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			try 
+			{
+				return new URL(parameterElement.getValue());
+			}
+			catch (MalformedURLException x)
+			{
+				throw new RuntimeException("Bad URL " + parameterElement.getValue() + " in XML job description.",x);
+			}
+		}
+	}
+	public class DoubleArray2DConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{	
+			return propertyType.getName().equals("[[D");
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			// Parse into a list of list of doubles.
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue(), ";");
+			int length = tokenize.countTokens();
+			int ir = 0;
+			List<List<Double>> rows = new ArrayList<List<Double>>(length);
+			while (tokenize.hasMoreTokens())
+			{
+				String rowStr = tokenize.nextToken();
+				StringTokenizer tokenize2 = new StringTokenizer(rowStr);
+				rows.add(new ArrayList<Double>());
+				List<Double> row = rows.get(ir);
+				while (tokenize2.hasMoreTokens())
+				{
+					String entry = tokenize2.nextToken();
+					Double d = factory.computeDouble(entry);
+					row.add(d);
+				}
+				++ir;				
+			}		
+			
+			// Convert list of doubles into 2D array, checking for wrong sized rows.
+			double arr[][] = new double[rows.size()][rows.get(0).size()];				
+			int jcheck = rows.get(0).size() - 1;
+			int i=0;
+			int j=0;
+			for (List<Double> aa : rows)
+			{			
+				for (Double a : aa)
+				{
+					if (j > jcheck)
+					{
+						throw new RuntimeException(
+								"Row " + j + " of array " + 
+								parameterElement.getName() + 
+								"with length " + aa.size() +
+								" is too long.");
+					}
+					arr[i][j] = a;
+					++j;
+				}
+				if (j < jcheck)
+				{
+					throw new RuntimeException(
+							"Row " + j + " of array " + 
+							parameterElement.getName() + 
+							"with length " + aa.size() +
+							"is too short.");
+				}
+				j=0;
+				++i;				
+			}
+			return arr;
+		}
+	}
+	
+	public class IntegerArray2DConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.getName().equals("[[I");
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			// Parse into a list of list of doubles.
+			StringTokenizer tokenize = new StringTokenizer(parameterElement.getValue(), ";");
+			int length = tokenize.countTokens();
+			int ir = 0;
+			List<List<Integer>> rows = new ArrayList<List<Integer>>(length);
+			while (tokenize.hasMoreTokens())
+			{
+				String rowStr = tokenize.nextToken();
+				StringTokenizer tokenize2 = new StringTokenizer(rowStr);
+				rows.add(new ArrayList<Integer>());
+				List<Integer> row = rows.get(ir);
+				while (tokenize2.hasMoreTokens())
+				{
+					String entry = tokenize2.nextToken();
+					Integer d = Integer.valueOf(entry);
+					row.add(d);
+				}
+				++ir;				
+			}		
+			
+			// Convert list of doubles into 2D array, checking for wrong sized rows.
+			int arr[][] = new int[rows.size()][rows.get(0).size()];				
+			int jcheck = rows.get(0).size() - 1;
+			int i=0;
+			int j=0;
+			for (List<Integer> aa : rows)
+			{			
+				for (Integer a : aa)
+				{
+					if (j > jcheck)
+					{
+						throw new RuntimeException(
+								"Row " + j + " of array " + 
+								parameterElement.getName() + 
+								"with length " + aa.size() +
+								" is too long.");
+					}
+					arr[i][j] = a;					
+					++j;
+				}
+				if (j < jcheck)
+				{
+					throw new RuntimeException(
+							"Row " + j + " of array " + 
+							parameterElement.getName() + 
+							"with length " + aa.size() +
+							"is too short.");
+				}
+				j=0;
+				++i;				
+			}
+			return arr;		
+		}		
+	}	
+	
+	public class ElementConverter implements IParameterConverter
+	{
+		public boolean handles(Class propertyType)
+		{
+			return propertyType.equals(Element.class);
+		}
+		
+		public Object convert(JDOMExpressionFactory factory, Element parameterElement)
+		{
+			return parameterElement;
+		}
+	}
+}
\ No newline at end of file

lcsim/src/org/lcsim/job
JobControlManager.java 1.27 -> 1.28
diff -u -r1.27 -r1.28
--- JobControlManager.java	15 Sep 2009 23:43:28 -0000	1.27
+++ JobControlManager.java	5 Oct 2009 20:34:20 -0000	1.28
@@ -1,8 +1,5 @@
 package org.lcsim.job;
 
-import hep.physics.vec.BasicHep3Vector;
-import hep.physics.vec.Hep3Vector;
-
 import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.MethodDescriptor;
@@ -25,7 +22,6 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.StringTokenizer;
 import java.util.Map.Entry;
 
 import org.freehep.application.studio.Studio;
@@ -50,12 +46,11 @@
  * @verbose $id: $
  */
 //TODO: additional parameter types (SymmetricMatrix, etc.)
-//TODO: 2d parameter arrays
 //TODO: example XML steering file generation (e.g. like Marlin)
-//TODO: basic command line arg support (no args then expect steering file loc):
+//TODO: basic command line arg support:
 //      -s steeringFile
 //      -e exampleSteeringOutput.xml
-//      -d # debug only; don't actually run job.
+//      -d # debug only; don't actually run the job.
 //      etc.
 public class JobControlManager
 {
@@ -79,15 +74,14 @@
 	LCSimLoop loop;
 	Element root;
 	Map<String,Double> constants = new HashMap<String,Double>();
-	JDOMExpressionFactory factory;	
+	JDOMExpressionFactory factory;
+	private static ParameterConverters paramConverter;
 
 	/**
 	 * Default no-argument constructor.
 	 */
 	public JobControlManager()
-	{
-		//findAvailableDrivers();
-	}
+	{}
 	
 	/**
 	 * Simple frontend method taking the name of the XML steering file.
@@ -149,7 +143,7 @@
 			if (skipEvents != -1)
 			{
 				if (verbose)
-					logStream.println("Skipping " + skipEvents + " events");
+					logStream.println("Skipping " + skipEvents + " events.");
 				loop.skip(skipEvents);
 			}
 			
@@ -220,8 +214,10 @@
 	 */
 	public void setup(InputStream in)
 	{
-		SAXBuilder builder = new SAXBuilder();		
+		SAXBuilder builder = new SAXBuilder();
 		factory = new JDOMExpressionFactory();
+		if (paramConverter == null)
+			paramConverter = new ParameterConverters(factory);
 		builder.setFactory(factory);
 		
 		Document doc = null;
@@ -294,6 +290,7 @@
 		printSystemProperties = false;
 		printUserClassPath = false;
 		printDriversDetailed = false;
+		printVersion = false;
 		verbose = false;
 		wasSetup = false;
 		logStream = System.out;
@@ -315,27 +312,6 @@
 		driverMap.put(name, driver);
 	}
 
-	/**
-	 * Setup a list of available Drivers if a services file exists.
-	 */
-/*
-	private void findAvailableDrivers()
-	{
-		InputStream in = JobControlManager.class.getResourceAsStream("/META-INF/services/org.lcsim.util.Driver");
-		if (in == null)
-		{			
-			return;
-		}
-		Scanner scan = new Scanner(in);
-		while (scan.hasNext())
-		{
-			String fullName = scan.nextLine().trim();
-			String shortName = fullName.substring(fullName.lastIndexOf(".") + 1);
-			availableDrivers.put(shortName, fullName);
-		}
-	}
-*/
-
 	private void printSystemProperties(PrintStream ps)
 	{
 		logStream.println("--- System Properties ---");
@@ -608,7 +584,8 @@
 				try
 				{
 					urlList.add((new File(jarElement.getText()).toURL()));
-				} catch (Exception x)
+				} 
+				catch (Exception x)
 				{
 					throw new RuntimeException("Bad jar location: " + jarElement.getText());
 				}
@@ -806,9 +783,16 @@
 					setter = methList.get(0).getMethod();
 					propertyType = setter.getParameterTypes()[0];
 				}														
-				
-				// Create an Object for next Driver parameter using the conversion method.
-				Object nextParameter = convertParameter(parameterElement, propertyType);
+								
+				IParameterConverter converter = paramConverter.getConverterForType(propertyType);
+				if (converter == null)
+				{
+					throw new RuntimeException(
+							"No converter found for parameter " + 
+							parameterElement.getName() + 
+							" with type " + propertyType.getName() + ".");
+				}
+				Object nextParameter = converter.convert(factory, parameterElement);
 								
 				// Invoke the setter.
 				Object pargs[] = new Object[1];
@@ -821,7 +805,7 @@
 				} 
 				catch (Exception x)
 				{
-					throw new RuntimeException(x);
+					throw new RuntimeException("Problem processing parameter " + parameterElement.getName() + ".",x);
 				}									
 			} // parameter loop
 			addDriver(name, newDriver);
@@ -844,161 +828,7 @@
 				throw new RuntimeException("Driver " + driverName + " was not found.");
 		}
 	}
-	
-	/**
-	 * Converts a String <code>value</code> to a Java class specified by <code>propertyType</code>.
-	 * @param value The string value from the XML parameter.
-	 * @param propertyType The type of the parameter.
-	 * @return The value of <code>value</code> as Class <code>propertyType</code>.
-	 */
-	private Object convertParameter(Element parameterElement, Class propertyType)
-	{
-		// The Object that will be returned and passed to the Driver's setter.
-		Object o = null;
 		
-		// The contents of the parameter's XML element.  
-		String value = parameterElement.getText();
-
-		// Single int.
-		// Evaluate expression.
-		if (propertyType.equals(int.class))
-		{
-			o = Integer.valueOf((int)factory.computeDouble(value));
-		}
-		// Single String.
-		// No expression.
-		else if (propertyType.equals(String.class))
-		{
-			o = value;
-		}
-		// Single double.
-		// Evaluate expression.
-		else if (propertyType.equals(double.class))
-		{
-			o = Double.valueOf(factory.computeDouble(value));
-		}
-		// Single float.
-		// Evaluate expression.
-		else if (propertyType.equals(float.class))
-		{
-			o = Float.valueOf(factory.computeFloat(value));
-		}
-		// Single boolean.
-		// No expression.
-		else if (propertyType.equals(boolean.class))
-		{
-			o = Boolean.valueOf(value);
-		}
-		// Single Hep3Vector type.
-		else if (propertyType.equals(Hep3Vector.class))
-		{
-			StringTokenizer tokenize = new StringTokenizer(value);
-			double x = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
-			double y = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
-			double z = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
-			o = new BasicHep3Vector(x, y, z);
-		}
-		// 1d array of doubles.
-		// Each token is evaluated.
-		else if (propertyType.getName().equals("[D"))
-		{
-			StringTokenizer tokenize = new StringTokenizer(value);
-			int size = tokenize.countTokens();
-			double da[] = new double[size];
-			int i = 0;
-			while (tokenize.hasMoreTokens())
-			{
-				da[i] = Double.valueOf(factory.computeDouble(tokenize.nextToken()));
-				++i;
-			}
-			o = da;
-		}
-		// 1d array of ints.
-		// Each token is evaluated.
-		else if (propertyType.getName().equals("[I"))
-		{
-			StringTokenizer tokenize = new StringTokenizer(value);
-			int size = tokenize.countTokens();
-			int ia[] = new int[size];
-			int i = 0;
-			while (tokenize.hasMoreTokens())
-			{
-				ia[i] = Integer.valueOf((int)factory.computeDouble(tokenize.nextToken()));
-				++i;
-			}
-			o = ia;
-		}
-		// 1d array of floats.
-		// Each token is evaluated.
-		else if (propertyType.getName().equals("[F"))
-		{
-			StringTokenizer tokenize = new StringTokenizer(value);
-			int size = tokenize.countTokens();
-			float fa[] = new float[size];
-			int i = 0;
-			while (tokenize.hasMoreTokens())
-			{
-				fa[i] = Float.valueOf(factory.computeFloat(tokenize.nextToken()));
-				++i;
-			}
-			o = fa;
-		}
-		// 1d array of strings.
-		// No expressions.
-		else if (propertyType.getName().equals("[Ljava.lang.String;"))
-		{
-			StringTokenizer tokenize = new StringTokenizer(value);
-			int size = tokenize.countTokens();
-			String sa[] = new String[size];
-			int i = 0;
-			while (tokenize.hasMoreTokens())
-			{
-				sa[i] = tokenize.nextToken();
-				++i;
-			}
-			o = sa;
-		}
-		// 1d array of booleans.
-		// No expressions.
-		else if (propertyType.getName().equals("[Z"))
-		{
-			StringTokenizer tokenize = new StringTokenizer(value);
-			int size = tokenize.countTokens();
-			boolean ba[] = new boolean[size];
-			int i = 0;
-			while (tokenize.hasMoreTokens())
-			{
-				ba[i] = Boolean.valueOf(tokenize.nextToken());
-				++i;
-			}
-			o = ba;
-		}
-		// Single File type.
-		else if (propertyType.equals(File.class))
-		{
-			o = new File(value);
-		}
-		// Single URL type.
-		else if (propertyType.equals(URL.class))
-		{
-			try 
-			{
-				o = new URL(value);
-			}
-			catch (MalformedURLException x)
-			{
-				throw new RuntimeException("Bad URL " + value + " in XML job description.",x);
-			}
-		}
-		// Element to be processed by user's setter method.
-		else if (propertyType.equals(Element.class))
-		{
-			o = parameterElement;
-		}
-
-		return o;
-	}
-	
 	private void processConstants()
 	{
 		Element define = root.getChild("define");		
@@ -1038,3 +868,24 @@
 		return null;
 	}	
 }
+
+/**
+ * Setup a list of available Drivers if a services file exists.
+ */
+/*
+private void findAvailableDrivers()
+{
+	InputStream in = JobControlManager.class.getResourceAsStream("/META-INF/services/org.lcsim.util.Driver");
+	if (in == null)
+	{			
+		return;
+	}
+	Scanner scan = new Scanner(in);
+	while (scan.hasNext())
+	{
+		String fullName = scan.nextLine().trim();
+		String shortName = fullName.substring(fullName.lastIndexOf(".") + 1);
+		availableDrivers.put(shortName, fullName);
+	}
+}
+*/
\ No newline at end of file
CVSspam 0.2.8