You are viewing a plain text version of this content. The canonical link for it is here.
Posted to alois-commits@incubator.apache.org by fl...@apache.org on 2010/11/04 18:27:42 UTC

svn commit: r1031127 [15/22] - in /incubator/alois/trunk: ./ bin/ debian/ doc/ etc/ etc/alois/ etc/alois/apache2/ etc/alois/environments/ etc/alois/prisma/ etc/cron.d/ etc/default/ etc/logrotate.d/ prisma/ prisma/bin/ prisma/conf/ prisma/conf/prisma/ p...

Added: incubator/alois/trunk/rails/java/CreateChart.java
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/java/CreateChart.java?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/java/CreateChart.java (added)
+++ incubator/alois/trunk/rails/java/CreateChart.java Thu Nov  4 18:27:22 2010
@@ -0,0 +1,663 @@
+import java.awt.*;
+import java.io.*;
+// import java.util.*;
+// import org.jfree.chart.imagemap.*;
+import org.jfree.chart.*;
+import org.jfree.chart.entity.*;
+import org.jfree.chart.plot.*;
+import org.jfree.data.category.*;
+import org.jfree.data.general.*;
+import org.jfree.util.*;
+import org.jfree.ui.TextAnchor;
+import org.jfree.chart.labels.*;
+import org.jfree.chart.renderer.xy.*;
+import org.jfree.chart.renderer.category.*;
+import org.jfree.data.xy.*;
+import org.jfree.chart.axis.*;
+// import org.jfree.chart.labels.*;
+import org.jfree.chart.urls.*;
+import java.net.URLEncoder;
+import java.awt.image.BufferedImage;
+/**
+ * Creates an HTML image map for a multiple pie chart.
+ */
+public class CreateChart {
+    
+    public class MyGenerator implements CategoryURLGenerator,
+					CategoryToolTipGenerator,
+					PieURLGenerator,
+					PieToolTipGenerator,
+					XYURLGenerator,
+					XYToolTipGenerator   {
+	private String prefix = "index.html";
+	private String seriesParameterName = "series";
+	private String categoryParameterName = "category";
+	private String rangeParameterName = "range";
+	private String rangeKey = null;
+	private CreateChart createChart = null;
+
+	private CategoryDataset theDataset = null;
+	
+	public MyGenerator(String prefix, CategoryDataset ds) {
+	    super();
+	    this.prefix = prefix;
+	    this.theDataset = ds;
+	}
+	
+	public MyGenerator(String prefix) {
+	    this.prefix = prefix;
+	}
+	public MyGenerator(String prefix, String rangeKey, CreateChart createChart) {
+	    this.prefix = prefix;
+	    this.rangeKey = rangeKey;
+	    this.createChart = createChart;
+	}
+	
+	public MyGenerator(String prefix,
+				      String seriesParameterName,
+				      String categoryParameterName) {
+	    this.prefix = prefix;
+	    this.seriesParameterName = seriesParameterName;
+	    this.categoryParameterName = categoryParameterName;
+	}
+
+	public MyGenerator(String prefix,
+				      String seriesParameterName,
+				      String categoryParameterName,
+				      String rangeParameterName,
+				      String rangeKey) {
+	    this.prefix = prefix;
+	    this.seriesParameterName = seriesParameterName;
+	    this.categoryParameterName = categoryParameterName;
+	    this.rangeParameterName = rangeParameterName;
+	    this.rangeKey = rangeKey;
+	}
+	
+	public String myGenerateURL(Comparable seriesKey, Comparable categoryKey, Comparable rangeKey) {
+	    if (categoryKey.toString().equals("<<REST>>") || 
+		seriesKey.toString().equals("<<REST>>") ||
+		(rangeKey != null && rangeKey.toString().equals("<<REST>>"))) { return "";}
+
+	    String url = this.prefix;
+	    boolean firstParameter = url.indexOf("?") == -1;
+
+	    if (categoryKey.toString().equals("rest_value")) { return "";}
+	    if (seriesKey.toString().equals("rest_serie")) { return "";}
+	    
+	    url += firstParameter ? "?" : "&";
+	    try {
+		url += this.seriesParameterName + "=" 
+		    + URLEncoder.encode(seriesKey.toString(),"UTF-8");
+		url += "&" + this.categoryParameterName + "=" 
+                + URLEncoder.encode(categoryKey.toString(),"UTF-8");
+		if (rangeKey != null) {
+		    url += "&" + this.rangeParameterName + "=" 
+			+ URLEncoder.encode(rangeKey.toString(),"UTF-8");
+		}
+	    }
+	    catch ( java.io.UnsupportedEncodingException uee ) {
+		uee.printStackTrace();
+	    }	
+	    
+	    return url;	   	    	   	    
+	}
+	
+	public String myGenerateToolTip(Comparable seriesKey, Comparable categoryKey, Comparable rangeKey, Number value) {	    
+	    String text = "";
+	    if (this.rangeKey != null && !this.rangeKey.equals("<<NULL>>")) {
+		text += this.rangeKey + ", ";
+	    }
+	    
+	    if (seriesKey != null && !seriesKey.toString().equals("<<NULL>>")) {
+		text += seriesKey.toString() + ", ";
+	    }
+
+	    text += this.createChart.xAxis + "=" + categoryKey.toString() + ", ";
+	
+	    text += "value: " + value;
+	    return text;	    
+	}
+
+	/** Pie **/
+
+	public String generateURL(PieDataset data, Comparable categoryKey, int pieIndex) {    	    
+	    Comparable seriesKey = theDataset.getRowKey(pieIndex);
+	    return myGenerateURL(seriesKey, categoryKey, null);
+ 	}
+	public String generateToolTip(PieDataset data, Comparable categoryKey) {
+	    /** not working **/
+	    Comparable seriesKey = theDataset.getRowKey(0);
+	    return myGenerateToolTip(seriesKey, categoryKey, null,999);
+	}
+
+	
+	/** Category **/
+
+	public String generateURL(CategoryDataset dataset,
+				  int series, 
+				  int category) {	    
+	    Comparable seriesKey = dataset.getRowKey(series);
+	    Comparable categoryKey = dataset.getColumnKey(category);
+
+	    return myGenerateURL(seriesKey, categoryKey, this.rangeKey);
+	}
+
+	public String generateToolTip(CategoryDataset dataset, 
+				      int series, int category) {
+	    Comparable seriesKey = dataset.getRowKey(series);
+	    Comparable categoryKey = dataset.getColumnKey(category);
+
+	    return myGenerateToolTip(seriesKey, categoryKey, this.rangeKey,dataset.getValue(seriesKey,categoryKey));
+	}
+
+	/** XY **/
+	public String generateURL(XYDataset dataset, int series, int item) {
+	    Comparable seriesKey = dataset.getSeriesKey(series);
+	    Comparable categoryKey = (Comparable)dataset.getX(series,item);
+
+	    return myGenerateURL(seriesKey, categoryKey, this.rangeKey);
+	}
+
+	public String generateToolTip(XYDataset dataset, int series, int item) {
+	    Comparable seriesKey = dataset.getSeriesKey(series);
+	    Comparable categoryKey = (Comparable)dataset.getX(series,item);
+
+	    return myGenerateToolTip(seriesKey, categoryKey, this.rangeKey,dataset.getY(series,item));
+	}
+
+
+    }
+
+
+    public static final boolean LEGEND = true;
+    public static final boolean TOOL_TIPS = true;
+    public static final boolean URLS = true;
+
+    public String filebase;
+    public JFreeChart chart;
+    public CategoryDataset[] category_datasets;
+    public XYDataset[] xy_datasets;
+    public String[] rangeNames;
+    public PieDataset pie_dataset;
+    public String htmlFile;
+    public String imageMapFile;
+    public String imageFile;
+    public String URLPrefix;
+
+    public String chartTitle;
+    public String xAxis;
+    public String yAxis;
+    public String type;
+    public boolean stacked = false;
+    public PlotOrientation orientation;
+
+    public int rangeCount = 0;
+    public int serieCount = 0;
+
+    public int width = 600;
+    public int height = 400;
+    
+    /**
+     * Default constructor.
+     */
+    public CreateChart(String filebase, String URLPrefix) {
+	super();
+	this.filebase = filebase;
+	this.htmlFile = filebase + ".html";
+	this.imageMapFile = filebase + ".map";
+	this.imageFile = filebase + ".png";
+	this.URLPrefix = URLPrefix;
+    }
+
+    public void saveFiles() {	 
+	
+	// save it to an image
+	try {
+	    ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
+	    File file1 = new File(this.imageFile);
+	    ChartUtilities.saveChartAsPNG(file1, chart, this.width, this.height, info);
+	    
+	    // write an HTML page incorporating the image with an image map
+	    File file2 = new File(this.htmlFile);
+	    OutputStream out = new BufferedOutputStream(new FileOutputStream(file2));
+	    PrintWriter writer = new PrintWriter(out);
+	    writer.println("<HEAD><TITLE>JFreeChart Image Map</TITLE></HEAD>");
+	    writer.println("<BODY>");
+	    writer.println(ChartUtilities.getImageMap("chart", info));
+	    writer.println("<IMG SRC=\"" + this.imageFile  + "\" "
+			   + "WIDTH=\"" + this.width +"\" HEIGHT=\"" + this.height + "\" BORDER=\"0\" USEMAP=\"#chart\">");
+             writer.println("</BODY>");
+             writer.println("</HTML>");
+             writer.close();
+	     
+             File file3 = new File(this.imageMapFile);
+             out = new BufferedOutputStream(new FileOutputStream(file3));
+             writer = new PrintWriter(out);
+	     writer.println(ChartUtilities.getImageMap("chart", info));
+             writer.close();
+	     
+	}
+	catch (IOException e) {
+	    System.out.println(e.toString());
+	}
+	
+    }
+
+    private Object callFunction(Object obj, String name) throws Exception {
+	return callFunction(obj,name,new Object[] {});
+    }
+    private Object callFunction(Object obj, String name, Object arg) throws Exception {
+	return callFunction(obj,name,new Object[] {arg});
+    }
+    private Object callFunction(Object obj, String name, Object[] args) throws Exception {
+	Class[] classes = new Class[args.length];
+	String classes_string = "";
+	for (int i = 0; i<args.length; i++) {
+	    classes[i] = args[i].getClass();
+	    try {
+		classes[i] = (Class)classes[i].getField("TYPE").get(classes[i]);
+	    } catch (NoSuchFieldException ex) {
+		// ok this is not a primitive type	       
+	    }
+	    classes_string += args[i].getClass().getName() + " ";
+	}
+
+	try {
+	    return callFunction(obj, name, args, classes);
+	} catch ( NoSuchMethodException e) {
+	    throw new Exception("Method " + obj.getClass().getName() + "." + name + "(" + classes_string + ") not found.");
+	}
+    }
+    
+    private Object callFunction(Object obj, String name, Object[] args, Class[] classes) throws Exception {
+	    return obj.getClass().getMethod(name,classes).invoke(obj,args);
+    }
+
+    private void configureColors(Object renderer) throws Exception {
+	Class[] pc = new Class[] {Integer.TYPE, Class.forName("java.awt.Paint")};
+	java.awt.Color secondColor = Color.white;
+	int i = 0;
+	if (false) {
+	    for (java.awt.Paint item : ChartColor.createDefaultPaintArray()) {
+		callFunction(renderer, "setSeriesPaint",
+					new java.lang.Object[] 
+		    {i,(java.awt.Paint)
+		     new GradientPaint(
+				       0.0f, 0.0f, (java.awt.Color)item, 
+				       1000, 0.0f, secondColor
+				       )},pc);
+		i += 1;
+	    }
+	} else {
+	    for (java.awt.Paint item : ChartColor.createDefaultPaintArray()) {
+		callFunction(renderer, "setSeriesPaint",
+					new java.lang.Object[] 
+		    {i, (java.awt.Paint)item },pc);
+		i += 1;
+	    }
+	}
+	
+	for (java.awt.Paint item : ChartColor.createDefaultPaintArray()) {
+	    BufferedImage bi = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB);
+	    Graphics2D big = bi.createGraphics();
+	    big.setColor((java.awt.Color)item);
+	    big.fillRect(0, 0, 1, 1);
+	    big.fillOval(1, 1, 2, 2);
+	    big.setColor(secondColor);
+	    big.fillRect(1, 0, 2, 1);
+	    big.fillOval(0, 1, 1, 2);
+	    Rectangle r = new Rectangle(0, 0, 2, 2);
+	    callFunction(renderer, "setSeriesPaint",new java.lang.Object[] {i,(java.awt.Paint) new TexturePaint(bi, r)},pc);
+	    i += 1;
+	}
+	
+	for (java.awt.Paint item : ChartColor.createDefaultPaintArray()) {
+	    BufferedImage bi = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB);
+	    Graphics2D big = bi.createGraphics();
+	    big.setColor((java.awt.Color)item);
+	    big.fillRect(0, 0, 1, 1);
+	    big.fillOval(1, 0, 2, 1);
+	    big.setColor(secondColor);
+	    big.fillRect(0, 1, 1, 2);
+	    big.fillOval(1, 1, 2, 2);
+	    Rectangle r = new Rectangle(0, 0, 2, 2);
+	    callFunction(renderer, "setSeriesPaint",new java.lang.Object[] {i, (java.awt.Paint)new TexturePaint(bi, r)},pc);
+	    i += 1;
+	}
+    }
+
+    private void correctLegend(Object plot,Object subplot) throws Exception {
+	
+	Object li = callFunction(subplot,"getLegendItems");
+	callFunction(plot,"setFixedLegendItems",new Object[] { li });
+	if (((Integer)callFunction(li,"getItemCount")) == 1 && 
+	    ((String)callFunction(callFunction(li,"get",0),"getLabel")).equals("<<NULL>>")) {
+	    callFunction(plot,"setFixedLegendItems",new LegendItemCollection());
+	}
+    }
+    
+     
+    
+    private XYItemRenderer createLineRenderer() throws Exception {
+	XYItemRenderer renderer;
+	if (this.stacked)
+	    renderer = new StackedXYAreaRenderer2();
+	else
+	    renderer = new StandardXYItemRenderer( StandardXYItemRenderer.SHAPES_AND_LINES);
+	configureColors(renderer);
+	return renderer;
+    }
+    private BarRenderer createBarRenderer() throws Exception {
+	// RENDERER	
+        BarRenderer renderer;
+	if (this.stacked)
+	    renderer = new StackedBarRenderer();
+	else
+	    renderer = new BarRenderer();
+	
+	ItemLabelPosition position1 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER);
+	ItemLabelPosition position2 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER);
+	renderer.setPositiveItemLabelPosition(position1);
+	renderer.setNegativeItemLabelPosition(position2);	
+	renderer.setDrawBarOutline(false);
+	configureColors(renderer);
+	return renderer;
+    }
+
+
+
+    /**
+     * Creates a sample chart with the given dataset.
+      * 
+      * @param dataset  the dataset.
+      * 
+      * @return A sample chart.
+      */
+    private void createPieChart() throws Exception {
+	this.chart = ChartFactory.createMultiplePieChart(
+							       this.chartTitle,  // chart title
+							       this.category_datasets[0],               // dataset
+							       TableOrder.BY_ROW,
+							       CreateChart.LEGEND,                  // include legend
+							       CreateChart.TOOL_TIPS,
+							       CreateChart.URLS
+							       );       
+	MultiplePiePlot plot = (MultiplePiePlot) this.chart.getPlot();	
+	JFreeChart subchart = plot.getPieChart();
+	
+	PiePlot p = (PiePlot) subchart.getPlot();
+	 /*         p.setLabelGenerator(new StandardPieItemLabelGenerator("{0}"));*/
+	p.setLabelFont(new Font("SansSerif", Font.PLAIN, 8));
+	p.setInteriorGap(0.30);
+	MyGenerator generator = new MyGenerator(this.URLPrefix,this.category_datasets[0]);
+	p.setURLGenerator(generator);
+	// p.setToolTipGenerator(generator);
+    }
+        
+    public void createLineChart() throws Exception {
+	// parent plot...
+	final NumberAxis domainAxis = new NumberAxis(this.xAxis);
+	domainAxis.setAutoRangeIncludesZero(false);
+	domainAxis.setAutoRangeStickyZero(false);
+	domainAxis.setAutoRange(true);
+
+	final CombinedDomainXYPlot plot = new CombinedDomainXYPlot(domainAxis);
+	
+	//plot.setGap(10.0);
+	for (int range = 0; range<rangeCount; range++) {	    
+
+	    NumberAxis rangeAxis = new NumberAxis(this.rangeNames[range] + " " + this.yAxis);
+	    if (this.rangeNames[range] == null) {
+		rangeAxis = new NumberAxis(this.yAxis);
+	    }
+	    rangeAxis.setAutoRangeIncludesZero(true);
+	    rangeAxis.setAutoRangeStickyZero(true);
+	    rangeAxis.setAutoRange(true);
+
+	    XYItemRenderer my_renderer = createLineRenderer();
+	    MyGenerator generator = new MyGenerator(this.URLPrefix, this.rangeNames[range], this);
+	    my_renderer.setURLGenerator(generator);
+	    my_renderer.setBaseToolTipGenerator(generator);
+
+
+	    final XYPlot subplot = new XYPlot(this.xy_datasets[range],
+					      null, rangeAxis, my_renderer);
+
+	    subplot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
+	    plot.add(subplot, 1);
+
+	    correctLegend(plot, subplot);
+
+	    plot.setOrientation(this.orientation);
+	}
+	
+	
+	// return a new chart containing the overlaid plot...
+	this.chart =  new JFreeChart(this.chartTitle,
+			      JFreeChart.DEFAULT_TITLE_FONT, plot, true);	
+    }
+    
+    public void createBarChart() throws Exception {
+	// create the chart...
+	
+	CategoryAxis categoryAxis = new CategoryAxis(this.xAxis);
+	//	categoryAxis = null;
+	
+	
+	CombinedDomainCategoryPlot plot = new CombinedDomainCategoryPlot(categoryAxis);
+	
+	for (int range = 0; range<rangeCount; range++) {
+	    BarRenderer my_renderer = createBarRenderer();
+	    MyGenerator generator = new MyGenerator(this.URLPrefix, this.rangeNames[range], this);
+	    my_renderer.setBaseItemURLGenerator(generator);
+	    my_renderer.setBaseToolTipGenerator(generator);
+
+	    ValueAxis valueAxis = new NumberAxis(this.rangeNames[range] + " " + this.yAxis);
+	    
+	    if (this.rangeNames[range] == null) {
+		valueAxis = new NumberAxis(this.yAxis);
+	    }
+
+	    CategoryPlot subplot = new CategoryPlot(this.category_datasets[range], categoryAxis, valueAxis,
+						    my_renderer);
+
+	    plot.add(subplot, 1);
+
+	    // Correct Legend
+	    correctLegend(plot,subplot);
+
+	    subplot.setOrientation(this.orientation);
+
+	}
+     
+
+	// NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
+	this.chart = new JFreeChart(this.chartTitle, JFreeChart.DEFAULT_TITLE_FONT,
+				    plot, true);
+	
+	chart.setBackgroundPaint(Color.white);
+	plot.setBackgroundPaint(Color.lightGray);
+	plot.setDomainGridlinePaint(Color.white);
+	plot.setRangeGridlinePaint(Color.white);
+        
+	//	plot.clearDomainAxes();
+	final CategoryAxis domainAxis = plot.getDomainAxis();
+	domainAxis.setCategoryLabelPositions(
+					     CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0)
+					     );
+	// OPTIONAL CUSTOMISATION COMPLETED.         
+    }
+    
+    
+    public void createXYChart() throws Exception {
+        // create the chart...
+        this.chart = ChartFactory.createXYLineChart(
+						    this.chartTitle,      // chart title
+						    this.xAxis,                      // x axis label
+						    this.yAxis,                      // y axis label
+						    this.xy_datasets[0],                  // data
+						    this.orientation,
+						    CreateChart.LEGEND,                     // include legend
+						    CreateChart.TOOL_TIPS,                     // tooltips
+						    CreateChart.URLS                     // urls
+						    );
+	
+        // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
+        chart.setBackgroundPaint(Color.white);
+        // get a reference to the plot for further customisation...
+        XYPlot plot = chart.getXYPlot();
+        plot.setBackgroundPaint(Color.lightGray);
+        //    plot.setAxisOffset(new Spacer(Spacer.ABSOLUTE, 5.0, 5.0, 5.0, 5.0));
+        plot.setDomainGridlinePaint(Color.white);
+        plot.setRangeGridlinePaint(Color.white);
+	
+        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
+	//       renderer.setSeriesLinesVisible(1, false);
+	//        renderer.setSeriesShapesVisible(1, false);
+        plot.setRenderer(renderer);
+	
+        // change the auto tick unit selection to integer units only...
+        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
+        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
+        // OPTIONAL CUSTOMISATION COMPLETED.
+        // save the image to an appropriate location : The images folder in your Instant Rails application
+    }
+    
+    
+    public void createCategory1TestData() throws Exception {
+         double[][] data = new double[][] {
+             {3.0, 4.0, 3.0, 5.0},
+             {5.0, 7.0, 6.0, 8.0},
+             {5.0, 7.0, 3.0, 8.0},
+             {1.0, 2.0, 3.0, 4.0},
+             {2.0, 3.0, 2.0, 3.0}
+         };
+	 CategoryDataset cd = DatasetUtilities.createCategoryDataset(
+								     "Region ",
+								     "Sales/Q",
+								     data				
+								     );
+	 this.category_datasets = new CategoryDataset[1];
+         this.category_datasets[0] = cd; 
+    }
+    
+    
+
+    
+    public void loadDataFromStdIn() throws IOException {	
+	java.io.BufferedReader stdin = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
+	
+	//	System.out.println("Chart title?");
+	this.chartTitle = stdin.readLine();
+
+	//	System.out.println("Width?");
+	this.width = Integer.parseInt(stdin.readLine());
+	//	System.out.println("Height?");
+	this.height = Integer.parseInt(stdin.readLine());
+
+	//	System.out.println("X-Axis?");
+	this.xAxis = stdin.readLine();
+	
+	//	System.out.println("Y-Axis?");
+	this.yAxis = stdin.readLine();
+
+	//	System.out.println("Series count?");
+	serieCount = Integer.parseInt(stdin.readLine());
+
+	//	System.out.println("Range count?");
+	rangeCount = Integer.parseInt(stdin.readLine());
+	
+	this.category_datasets = new CategoryDataset[rangeCount];
+	this.xy_datasets = new CategoryTableXYDataset[rangeCount];
+	this.rangeNames = new String[rangeCount];
+	    
+	for (int range = 0; range<rangeCount; range++) {
+	    rangeNames[range] = stdin.readLine();
+	    if (rangeNames[range].equals("<<NULL>>")) {
+		rangeNames[range] = null;
+	    }
+		
+	    CategoryDataset category_dataset = new DefaultCategoryDataset();
+	    category_datasets[range] = category_dataset;
+
+	    //XYSeriesCollection xy_serie = new XYSeriesCollection();
+	    CategoryTableXYDataset xy_dataset = new CategoryTableXYDataset();
+	    xy_datasets[range] = xy_dataset;
+
+	    for (int serie = 0; serie<serieCount; serie++) {
+		//	    System.out.println("Serie name?");
+		String serieName =  stdin.readLine();
+
+		int rowCount = Integer.parseInt(stdin.readLine());
+		int columnCount = Integer.parseInt(stdin.readLine());
+
+		//final XYSeries xy_serie = new XYSeries(serieName);
+		
+		for (int row = 0; row<rowCount; row++) {
+		    //		System.out.println("Category name?");
+		    String categoryName = stdin.readLine();		    
+		    for (int col = 0; col<columnCount; col++) {
+			String val = stdin.readLine();
+			//		    System.out.println(val + ":" + serieName + ":" + categoryName + "\n");
+			
+			((DefaultCategoryDataset)category_dataset).addValue(
+									    Integer.parseInt(val),
+									    serieName,
+									    categoryName);
+			if (type.equals("line") || type.equals("lines")) {
+			    //xy_serie.add(Float.parseFloat(categoryName), Float.parseFloat(val));
+			    xy_dataset.add(Float.parseFloat(categoryName), Float.parseFloat(val), serieName);
+			}
+
+		    }
+		}
+		//		xy_serie.addSeries(xy_serie);
+	    }
+	}
+    }
+    
+    /**
+     * Starting point for the chart.
+     *
+     * @param args  ignored.
+      */
+    public static void main(String[] args) {
+	try {	    
+	    CreateChart chart = new CreateChart(args[0],args[1]);
+	    chart.type = args[2];
+	    chart.stacked = Boolean.parseBoolean(args[3]);
+	    if (Boolean.parseBoolean(args[4]))
+		chart.orientation = PlotOrientation.HORIZONTAL;
+	    else
+		chart.orientation = PlotOrientation.VERTICAL;
+		
+	    chart.loadDataFromStdIn(); //	chart.createCategoryTestData();	   	    	    
+	    //chart.createCategory2TestData();
+	    
+	    if (chart.type.equals("bar"))
+		chart.createBarChart();
+	    else if (chart.type.equals("pie"))
+		chart.createPieChart();
+	    else if (chart.type.equals("line"))
+		chart.createLineChart();
+	    else
+		throw new Exception("Unknown type '" + chart.type + "'");
+	    
+	    chart.saveFiles();
+	    System.exit(0);
+	} catch (Exception ex) {
+	    StringWriter sw = new StringWriter();
+	    PrintWriter pw = new PrintWriter(sw, true);
+	    ex.printStackTrace(pw);
+	    pw.flush();
+	    sw.flush();
+	    
+	    System.out.print(sw.toString());
+	    
+	    System.out.println(ex.toString());
+	    System.exit(1);
+	}
+	
+    }
+}
+

Added: incubator/alois/trunk/rails/lib/action_mailer-patch.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/action_mailer-patch.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/action_mailer-patch.rb (added)
+++ incubator/alois/trunk/rails/lib/action_mailer-patch.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,78 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module ActionMailer
+  # Represents a subpart of an email message. It shares many similar
+  # attributes of ActionMailer::Base.  Although you can create parts manually
+  # and add them to the +parts+ list of the mailer, it is easier
+  # to use the helper methods in ActionMailer::PartContainer.
+  class Part
+    # Convert the part to a mail object which can be included in the parts
+    # list of another mail object.
+    def to_mail(defaults)
+      part = TMail::Mail.new
+
+      real_content_type, ctype_attrs = parse_content_type(defaults)
+
+      if @parts.empty?
+        part.content_transfer_encoding = transfer_encoding || "quoted-printable"
+        case (transfer_encoding || "").downcase
+          when "base64" then
+            part.body = TMail::Base64.folding_encode(body)
+          when "quoted-printable"
+            part.body = [normalize_new_lines(body)].pack("M*")
+          else
+            part.body = body
+        end
+
+        # Always set the content_type after setting the body and or parts!
+        if content_disposition == "attachment"
+          ctype_attrs.delete "charset"
+	end
+
+        # Also don't set filename and name when there is none (like in
+        # non-attachment parts)
+	if filename
+          ctype_attrs.delete "charset"
+          part.set_content_type(real_content_type, nil,
+            squish("name" => filename).merge(ctype_attrs))
+          part.set_content_disposition(content_disposition,
+            squish("filename" => filename).merge(ctype_attrs))
+        else
+          part.set_content_type(real_content_type, nil, ctype_attrs)
+          part.set_content_disposition(content_disposition)
+        end
+      else
+        if String === body
+          @parts.unshift Part.new(:charset => charset, :body => @body, :content_type => 'text/plain')
+          @body = nil
+        end
+          
+        @parts.each do |p|
+          prt = (TMail::Mail === p ? p : p.to_mail(defaults))
+          part.parts << prt
+        end
+        
+        if real_content_type =~ /multipart/
+          ctype_attrs.delete 'charset'
+          part.set_content_type(real_content_type, nil, ctype_attrs)
+        end
+      end
+
+      headers.each { |k,v| part[k] = v }
+
+      part
+    end
+  end
+end

Added: incubator/alois/trunk/rails/lib/alois/config.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/alois/config.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/alois/config.rb (added)
+++ incubator/alois/trunk/rails/lib/alois/config.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,97 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'yaml'
+
+if defined?(RAILS_ROOT)
+  ALOIS_DEFAULT_CONFIG = "#{RAILS_ROOT}/config/alois.conf" unless defined?(ALOIS_DEFAULT_CONFIG)
+else
+  ALOIS_DEFAULT_CONFIG = "/etc/alois/alois.conf" unless defined?(ALOIS_DEFAULT_CONFIG)
+end
+
+def get_replacements(configfile)
+  # prepare regexps
+  replacements = {}
+  configs = read_config(configfile, false)
+  for (configname,config) in configs
+    for (valuename,value) in config
+      replacements["{{#{configname}.#{valuename}}}"] = value
+    end if not config == nil
+  end
+  return replacements
+end
+
+def replace_configurations(replacements, value)
+  def str_sub(replacements, value)
+    for (reg,val) in replacements
+      value = value.gsub(reg.to_s,val.to_s)
+    end
+    print "WARNING: Not replaced:#{value}" if value =~ /\{\{/ or value =~ /\}\}/
+    return value
+  end
+
+  case value.class.to_s
+  when "String"
+    return str_sub(replacements, value)
+  when "Array"
+    return value.map { |v| replace_configurations(replacements, v)}
+  else
+    return value
+  end
+end
+
+
+def read_config(configfile = nil, with_replace = true)
+  configfile = ALOIS_DEFAULT_CONFIG unless configfile
+  return $current_config if $current_config_file == configfile and $current_replacement == with_replace
+
+  configfile = ALOIS_DEFAULT_CONFIG unless configfile
+  tree = YAML::parse(File.open(configfile))
+
+  configurations = tree["/configs/*"]
+  configurations = tree.select("/configs")[0].transform
+
+  for (name, configname) in configurations
+    c = tree.select("/#{configname}")[0]
+    c = c.transform if not c == nil
+    configurations[name] = c
+  end
+
+  if with_replace
+    replacements = get_replacements(configfile)
+
+    for (service, host) in configurations
+      throw "#{host} configuration not found!" unless host
+      for (name, value) in host
+        host[name] = replace_configurations(replacements, value)
+      end
+    end
+  end
+
+  $current_config_file = configfile
+  $current_config = configurations
+  $current_replacement = with_replace
+  throw "Configuration could not be loaded." unless configurations
+  return configurations
+end
+
+def get_config(name, property, default_value = nil)
+  v = read_config
+  return default_value unless v
+  v = v[name]
+  return default_value unless v
+  v = v[property]
+  return default_value unless v
+  return v
+end

Added: incubator/alois/trunk/rails/lib/alois/date_time_enhance.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/alois/date_time_enhance.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/alois/date_time_enhance.rb (added)
+++ incubator/alois/trunk/rails/lib/alois/date_time_enhance.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,185 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Time
+
+  def beginning_of_minute
+    change(:sec => 0)
+  end
+
+  def beginning_of_hour
+    change(:min => 0).beginning_of_minute
+  end
+
+
+  def end_of_minute
+    change(:sec => 59)
+  end
+
+  def end_of_hour
+    change(:min => 59).end_of_minute
+  end
+  
+  # day and month already included
+  
+  def end_of_week
+    6.days.from_now(beginning_of_week).end_of_day
+  end
+  
+  def end_of_year
+    change(:month => 12).end_of_month
+  end
+
+  def self.suggest(text, with_range = true)
+    text = text.strip
+
+    case text
+    when nil, ""
+      ret = ["beginning","end","last","this","today","yesterday","NUMBER"]
+      ret.push("from") if with_range 
+      ret
+    when /^(beginning *)$/, /^(end *)$/
+      ret = ["last","this","today","yesterday","NUMBER"]
+      ret.push("from") if with_range 
+      ret.map{|v| "#{$1} #{v}"}
+    when /^(from .* until)(.*)/
+      self.suggest($2,false).map{|v| "#{$1} #{v}"}
+    when /^(from)(.*)/
+      ret = self.suggest($2,false).map {|v| "#{$1} #{v}"}
+      if (($2 or "").strip.to_time rescue false)
+	ret.push("#{text} until")
+      end
+      ret
+    when /^(from .* )(-|to|until|till|up to) (.*)/
+      self.suggest($3).map {|v| "#{$1}#{$2} #{v}"}
+    when /^(beginning|end)? ?(\d+|this|last) *$/
+      ["day","days","week","weeks","year","years","hour","hours","month","months"].map {|v| "#{text} #{v}"}
+    when /^(\d+|from|this|last) (beginning|end)? ?(day|days|week|weeks|year|years|hour|hours) *$/
+      ["ago","from now"].map {|v| "#{text} #{v}"}
+    else
+      []
+    end
+  end
+  
+end
+
+class String
+
+  alias_method :orig_to_time, :to_time
+  def to_time(from = Time.now)
+    if self =~ /(from )?(the )?(.*) (-|to|until|till|up to) (the )?(.*)/
+      first = $3.to_time(from)
+      second_str = $6
+      if second_str =~ /^(.*) later$/
+	return first.."#{$1} from now".to_time(first)
+      else
+	return first..second_str.to_time(from)
+      end
+    end
+    
+    correction = :none
+
+    case self
+    when /^(at )?begin(ning)? (of )?(.*)$/
+      correction = :beginning
+      str = $4
+    when /^(at )?end(ing)? (of )?(.*)$/
+      correction = :end
+      str = $4
+    else
+      str = self
+    end
+   
+    time = nil
+
+    case str
+    when "today"
+      num = 0
+      span = "day"
+      direction = "ago"
+    when "yesterday"
+      num = 1
+      span = "day"
+      direction = "ago"
+    when /^(\d+|last|this|the)? ?(day|days|week|weeks|year|years|month|months|hour|hours) ?(ago|from now)?$/
+      direction = ($3 or "ago")
+      direction = "from_now" if direction == "from now"
+      span = $2.singularize      
+
+      case $1
+      when "last"
+	raise "'#{$3}' does not make sense with 'last'." if $3
+	num = 1
+      when "this","the"
+	raise "'#{$3}' does not make sense with 'this'." if $3
+	num = 0
+      when nil
+	num = 0
+      else
+	raise "Please add a direction 'ago' or 'from now' to the end #{$3}." unless $3	
+	num = $1.to_i
+      end
+    else
+      begin
+	time = orig_to_time
+	case time.strftime("%T")
+	when /00:00:00$/
+	  span = "day"
+	when /00:00$/
+	  span = "hour"
+	else
+	  span = "minute"
+	end
+      rescue ArgumentError
+	raise "Date not recognized '#{self}' ."
+      end
+    end
+
+    time = num.send(span).send(direction,from.to_time) unless time
+
+    case correction
+    when :beginning
+      time.send("beginning_of_#{span}")
+    when :end
+      time.send("end_of_#{span}")
+    else
+      time
+    end
+  end
+
+  def to_time_range(from = Time.now)
+    v = self.to_time(from)
+    if v.class == Range
+      v
+    else
+      "beginning of #{self} until end of #{self}".to_time(from)
+    end
+  end
+
+  def to_time_range_str(from = Time.now)
+    res = self.to_time_range(from)
+    res.first.strftime("%F %T")..res.last.strftime("%F %T")
+  end
+
+  def to_time_str(from = Time.now)
+    res = to_time(from)
+    if res.class.name == "Range"
+      res.first.strftime("%F %T")..res.last.strftime("%F %T")
+    else
+      res.strftime("%F %T")
+    end
+  end
+    
+end
+    

Added: incubator/alois/trunk/rails/lib/alois/utils.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/alois/utils.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/alois/utils.rb (added)
+++ incubator/alois/trunk/rails/lib/alois/utils.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,282 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "yaml"
+require "zlib"
+begin
+  require "mysql"
+rescue LoadError
+  print "Unable to load mysql library #{$!}\n"
+end
+
+def question_continue
+  unless defined?(LIBISI)
+    print "Do you want to continue? Press ENTER, CTRL-C to abort\n"
+    STDIN.readline
+  else
+    exit 1 unless $ui.question("Do you want to continue?", :default => false)
+  end
+end
+
+def get_password(name)  
+  return ENV["db_#{name}_password".upcase] if ENV["db_#{name}_password".upcase]
+  raise "Libisi not available, cannot get password for #{name}" unless $ui
+  $ui.password("Please enter #{name} password")
+end
+
+def check_mysql_password
+
+  # try to make a connetion on the localhost trough root without a pw
+  begin
+    dbh = connect_mysql_local_real(nil)
+
+    # if we reach here, this is bad, 
+    # no password is defined for root
+    # ask user...
+
+    raise "Mysql has no root password defined, will not continue" unless
+      defined?(LIBISI)
+    raise "No mysql root password set" unless 
+      $ui.question("No password for root user defined!!\nYou must define one to continue.\nDo you want to define one now?")
+    password = set_mysql_password("ALL", "*", "root@localhost")  
+  rescue
+    raise if not $!.to_s =~ /Access denied for user/
+    $log.debug("OK there is a root pw!") if $log
+  end
+end
+
+
+def set_mysql_password(privileges, object, person, password = nil)  
+  raise "Libisi not available, cannot set new password." unless $ui
+  if password == nil then    
+    print 
+    password = $ui.password("Set #{privileges} for #{object} to #{person}...\nPlease enter new password")
+    password2 = $ui.password("Please reenter new password")
+    raise "Password did not match!" if not password2 == password
+    raise "No password entered!" if password == "" or password == nil
+    raise "Do not use '\"'!" if (password =~ /\"/)
+  end
+
+  query = "GRANT #{privileges} PRIVILEGES ON #{object} TO #{person} IDENTIFIED BY \"#{password}\""
+  $log.info("Executing #{query.inspect}")
+  connect_mysql_local_real(nil).query(query)
+  password
+end
+
+# redirect to libisis host_name
+def hostname; host_name; end
+
+def db_root_password
+  check_mysql_password
+  # get the rootpassword 
+  @password ||= (ENV["DB_ROOT_PASSWORD"] or get_password("root"))
+  @password
+end
+
+def connect_activerecord_local(db = "mysql")
+  ActiveRecord::Base.establish_connection({
+					    :adapter => "mysql",
+					    :database => db,
+					    :host => "localhost",
+					    :username => "root",
+					    :port => 3306,
+					    :password => db_root_password
+					  })
+end
+
+def connect_mysql_local_real(pw, db = "mysql")
+  Mysql.real_connect("localhost", "root", pw, db)
+end
+
+def connect_mysql_local(database = "mysql")
+  conn = connect_mysql_local_real(db_root_password, database)  
+end
+
+
+class Object
+  # computes a hash of a yaml serialization
+  # sort the lines first to get the same result
+  # even if attribute order changed.
+  def Object.yaml_hash(yaml)
+    yaml.split("\n").sort.join("\n").hash
+  end
+  
+  # Load object from yaml
+  def Object.from_yaml(yaml)
+    ret = YAML.parse(yaml).transform
+    # fix, otherwise attributes_methods:160 will complain nil.[] on cached methods
+    ret.instance_eval("@attributes_cache ||= {}")
+    ret
+  end
+
+  # Load object from zipped yaml
+  def Object.from_zip(zip)
+    i = Zlib::Inflate.new()
+    i.inflate("x\234")
+    return from_yaml(i.inflate(Base64.decode64(zip)))
+  end
+
+  # Serialize object to zipped yaml
+  def Object.to_zip(obj)
+    d = Zlib::Deflate.new()
+    d.deflate(obj.to_yaml)
+    return Base64.encode64(d.deflate(nil))
+  end
+  # Calls Objects to_zip function
+  def to_zip
+    Object.to_zip(self)
+  end
+
+  # Helper function for loading ipranges from a file. Executes Class.create for each entry.
+  def Object.load_from_yaml(filename)
+    yaml_string = ""
+    yaml_string << IO.read(filename)
+    yaml = YAML::load(yaml_string)    
+    yaml.each {|vals|
+      self.create(vals[1])
+    }
+  end
+  
+  # Use from_yaml function of prisma for loading classes
+  def from_yaml(yaml)
+    self.class.from_yaml(yaml.strip)
+  end
+
+  # returns prisma yaml_hash
+  def yaml_hash
+    yaml = self.to_yaml
+    return Object.yaml_hash(yaml)
+  end
+
+  # TODO: describe this, is this still needed?
+  def load_from_yaml(filename)
+    yaml_string = ""
+    yaml_string << IO.read(filename)
+    yaml = YAML::load(yaml_string)    
+    yaml.keys.sort.select {|name|
+      !self.respond_to?(:name) or !self.find_by_name(yaml[name]["name"])
+    }.map {|name|
+      self.create(yaml[name]) rescue $!.to_s
+    }
+  end
+  
+  # Use from_zip of prisma
+  def from_zip(zip)
+    self.class.from_zip(zip)
+  end
+  
+  alias_method :orig_to_yaml, :to_yaml
+  # This instance variables may not be serialized
+  # this constant is only used for yaml serialization
+  BAD_INSTANCE_VARIABLES = ["@datasource","@attributes_cache",
+                            "@source_table_class","@table","@view","@report_template",
+                            "@sentinel"] unless defined?(BAD_INSTANCE_VARIABLES)
+
+  # Removes BAD_INSTANCE_VARIABLES and yields
+  # a block. Instancevariables are set again
+  # afterwards.
+  def remove_bad_instance_variables(&block)
+    tmp = {}      
+    BAD_INSTANCE_VARIABLES.each {|var|
+      tmp[var] = remove_instance_variable(var) if
+      instance_variable_defined?(var)
+    }
+    if block
+      ret = yield
+      tmp.each {|var,val| instance_variable_set(var,val)}
+      ret
+    end
+  end
+  
+
+  # New to_yaml function that removes BAD_INSTANCE_VARIABLES
+  # before serializing. Original to_yaml function can be
+  # called with orig_to_yaml, but will probably not work.
+  def to_yaml( opts = {})
+    remove_bad_instance_variables {
+      self.orig_to_yaml(opts)
+    }
+  end
+           
+end
+
+class ActiveRecord::Base
+  def self.description(val=nil); return @desc unless val; @desc = val;end
+
+  def self.connection_approx_count(connection, table_name)
+    case connection.class.name
+    when /Mysql/
+      res = connection.execute("SHOW TABLE STATUS LIKE '#{table_name}'")
+      res = res.fetch_hash
+      return nil unless res
+      a_count = res['Rows'].to_i
+    else
+      $log.warn("Approx count not implemented for #{connection.class.name}")
+      return nil
+    end
+  rescue ActiveRecord::Transactions::TransactionError
+    raise $!
+  end
+
+  def self.approx_count
+    if self.respond_to?(:alois_connection) and conn = self.alois_connection      
+      val = connection_approx_count(conn, self.table_name)
+      return val if val and val > 20000
+    end
+
+    return count
+  end
+
+  def self.connection_auto_increment(connection, table_name)
+    case connection.class.name
+    when /Mysql/
+      res = connection.execute("SHOW TABLE STATUS LIKE '#{table_name}'") 	
+      res.fetch_hash['Auto_increment'].to_i
+    when /SQLite/
+      res = connection.execute("select * from SQLITE_SEQUENCE WHERE name = '#{table_name}'")
+      return(0) if res == []
+      res[0]["seq"].to_i
+    else
+      raise "Autoincrement not implemented for #{connection.class.name}"
+    end    
+  rescue ActiveRecord::Transactions::TransactionError
+    raise $!
+  end
+
+  def self.auto_increment
+    if self.respond_to?(:alois_connection) and conn = self.alois_connection      
+      return connection_auto_increment(conn, table_name)
+    else
+      raise "Autoincrement not implemented"
+    end
+  end
+
+
+  def self.alois_connection
+    self.connection
+  end
+
+  # Clone, remove bad instancevariables
+  def full_clone
+    res = self.clone
+    res.remove_bad_instance_variables
+    if self.id
+      attrs = res.send :instance_variable_get, '@attributes'
+      attrs[self.class.primary_key] = self[self.class.primary_key]
+    end
+    res.instance_eval("@attributes_cache ||= {}")
+    res
+  end
+
+end

Added: incubator/alois/trunk/rails/lib/awesome_email_fix.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/awesome_email_fix.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/awesome_email_fix.rb (added)
+++ incubator/alois/trunk/rails/lib/awesome_email_fix.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,37 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# with this the css files can be found in the public/stylesheet director
+# multiple css can be defined with "css ['sheet1','sheet2']"
+module ActionMailer
+  module InlineStyles
+    module InstanceMethods
+      def parse_css_doc(file_name)
+        sac = CSS::SAC::Parser.new
+	@css = [@css] if !@css.is_a?(Array)
+	sac.parse(@css.map {|css|
+		    css = "#{css}.css" unless css =~ /\.css^/
+		    file = File.join(RAILS_ROOT, 'public', 'stylesheets', css)	  
+		    File.read(file)
+		  }.join("\n"))
+	
+      end
+    end
+    
+    def self.included(receiver)
+      receiver.send :include, InstanceMethods
+    end
+  end
+end
+      

Added: incubator/alois/trunk/rails/lib/dummy_class_extension.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/dummy_class_extension.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/dummy_class_extension.rb (added)
+++ incubator/alois/trunk/rails/lib/dummy_class_extension.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,25 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# otherwise an exception occurs here
+# when building mails in console
+# /var/local/share/home/fpellanda/logintas/alois/alois-1.0/rails/vendor/rails/actionpack/lib/action_view/base.rb:419:in `template_format'
+class DummyClass
+  def parameters
+    {}
+  end
+  def protocol
+    "dummyprotocol"
+  end
+end

Added: incubator/alois/trunk/rails/lib/fix_activerecrod_base_inspect_bug.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/fix_activerecrod_base_inspect_bug.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/fix_activerecrod_base_inspect_bug.rb (added)
+++ incubator/alois/trunk/rails/lib/fix_activerecrod_base_inspect_bug.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,35 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# this seems not to work
+# essential is the "rescue false"
+
+# /usr/share/alois/www/vendor/rails/activerecord/lib/active_record/base.rb:1153
+module ActiveRecord
+  class Base
+    # Returns a string like 'Post id:integer, title:string, body:text'
+    def self.inspect
+      if self == Base
+	super
+      elsif abstract_class?
+	"#{super}(abstract)"
+      elsif (table_exists? rescue false)
+	attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
+	"#{super}(#{attr_list})"
+      else
+	"#{super}(Table doesn't exist or no connection)"
+      end
+    end
+  end
+end

Added: incubator/alois/trunk/rails/lib/ip_address.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/ip_address.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/ip_address.rb (added)
+++ incubator/alois/trunk/rails/lib/ip_address.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,165 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# code from http://www.prfsa.com/post.rhtml?title=ruby-ip-address-class-part-2
+# example code:
+#
+# ip = IpAddress.new("10.0.0.1")
+# puts "Address: #{ip} (version #{ip.version})"
+#  => Address: 10.0.0.1 (version 4)
+#
+# ip = IpAddress.new(156763422792541232312137643, 6)
+# puts "Address: #{ip} (version #{ip.version})"
+#  => Address: 0000:0000:0081:abf2:2d8a:a5bf:cf88:b7ab (version 6)
+
+class IpAddress
+  IP_MAX = {4 => (1 << 32) - 1, 6 => (1 << 128) - 1}
+  IP_BITS = {4 => 32, 6 => 128}
+
+  # Takes an Integer or a String representation of an IP Address and coerces it
+  # to a representation of the requested type (:integer / :string). If the
+  # version (4/6) is not specified then it will be guessed with guess_version.
+  def self.coerce(value, to_type, version = nil)
+    raise "unknown type #{to_type.inspect} requested" unless
+      [:integer, :string].include?(to_type)
+    version ||= guess_version(value)
+    
+    case value
+    when Integer
+      if to_type == :integer then value
+      elsif version == 4
+        [24, 16, 8, 0].map { |shift| (value >> shift) & 255 }.join(".")
+      else sprintf("%.32x", value).scan(/.{4}/).join(":")
+      end
+    when String
+      if to_type == :string then value
+      elsif version == 4
+        value.split(".").inject(0) { |total, octet| (total << 8) + octet.to_i }
+      else value.delete(":").to_i(16)
+      end
+    end
+  end
+
+  # Takes an Integer or a String and guesses whether it represents an IPv4 or
+  # IPv6 address. For an Integer, IPv4 is assumed unless the value is greater
+  # than IP_MAX[4]. For a String, IPv6 is assumed if it contains at least one
+  # colon (:).
+  def self.guess_version(value)
+    case value
+    when Integer then value > IP_MAX[4] ? 6 : 4
+    when String then value =~ /:/ ? 6 : 4
+    end
+  end
+
+  attr_reader :integer, :string, :version
+
+  # Takes an Integer or a String representation of an IP Address and creates a
+  # new IpAddress object with it. If the version (4/6) is not specified then it
+  # will be guessed with guess_version.
+  def initialize(value, version = nil)
+    @version = version || IpAddress.guess_version(value)
+    @integer = IpAddress.coerce(value, :integer, @version)
+    @string = IpAddress.coerce(value, :string, @version)
+  end
+
+  def to_i; @integer; end
+
+  def to_s; @string; end
+
+  # Adds the specified Integer value to that of the IpAddress and returns a new
+  # IpAddress based on the sum.
+  def +(value)
+    IpAddress.new(@integer + value, @version)
+  end
+  
+  # Subtracts the specified Integer value from that of the IpAddress and returns
+  # a new IpAddress based on the difference.
+  def -(value)
+    IpAddress.new(@integer - value, @version)
+  end
+  
+  # Returns the next IpAddress after this one.
+  def succ
+    self + 1
+  end
+  
+  include Comparable      
+  
+  # Compares one IpAddress with another based on the Integer representation of
+  # their values.
+  def <=>(other)
+    @integer <=> other.integer
+  end
+  
+  # Takes an Integer or a String representation of a network mask and returns
+  # the range of IpAddresses in that network.
+  def mask(value)
+    base_int = @integer & IpAddress.coerce(value, :integer, @version)
+    Range.new(IpAddress.new(base_int, @version),
+	      IpAddress.new(base_int + IpAddress.mask_size(value, @version) - 1))
+  end
+  
+  
+  # Takes an Integer or a String representation of a network mask and returns the
+  # number of addresses it encodes. If the version (4/6) is not specified then it
+  # will be guessed with guess_version.
+  def self.mask_size(value, version = nil)
+    version ||= guess_version(value)
+    (coerce(value, :integer, version) ^ IP_MAX[version]) + 1
+  end
+  
+  # Takes an Integer bitcount (bits) and returns an appropriate masking Integer.
+  # For example, a /24 network (in IPv4) corresponds to a mask of 255.255.255.0 
+  # or the number 4294967040. If the version (4/6) is not specified then it will
+  # be assumed to be 4 unless bits > 32.
+  def self.mask_from_slash_bits(bits, version = nil)
+    raise "bits > 128" if bits > 128
+    version ||= bits > 32 ? 6 : 4
+    
+    max = IP_MAX[version]
+    left_shift = IP_BITS[version] - bits
+    (max << left_shift) & max
+  end
+  
+  # Returns the range of IpAddresses in the specified /bits network. Basically a
+  # convenience wrapper around mask.
+  def /(bits)
+    mask(IpAddress.mask_from_slash_bits(bits, @version))
+  end
+  
+  def dig
+    open("|/usr/bin/dig -x #{self.to_s} +short") {|f| f.readlines.join("\n") }
+  end
+end
+
+class Integer
+  def to_ip(version = nil)
+    IpAddress.new(self, version)
+  end
+end
+
+class String
+  def to_ip(version = nil)
+    if self =~ /^([\da-f]{4}\:){7}[\da-f]{4}$/ or self =~ /^([\d]{1,3}\.){3}[\d]{1,3}$/ 
+      return IpAddress.new(self, version)
+    end
+    #    if self =~ /^([\da-f]{4}\:){7}[\da-f]{4}$/ 
+    # todo for ipv6    
+    #    end
+    if self =~ /^(([\d]{1,3}\.){3}[\d]{1,3})\/(\d{1,2})$/ 
+      return IpAddress.new($1) / $3.to_i
+    end
+    raise "'#{self}' is not an IP address."
+  end
+end

Added: incubator/alois/trunk/rails/lib/mysql_adapter_extensions.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/mysql_adapter_extensions.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/mysql_adapter_extensions.rb (added)
+++ incubator/alois/trunk/rails/lib/mysql_adapter_extensions.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,72 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module ActiveRecord
+  module ConnectionAdapters
+    class MysqlAdapter
+
+      def auto_increment(table_name)
+	begin
+	  res = execute("SHOW TABLE STATUS LIKE '#{table_name}'") 	
+	  res.fetch_hash['Auto_increment'].to_i
+	rescue ActiveRecord::Transactions::TransactionError
+	  raise $!
+	end
+      end
+      
+      def flush_tables
+	execute("flush tables")
+      end
+      
+      def approx_count(table_name)
+	begin
+	  res = execute("SHOW TABLE STATUS LIKE '#{table_name}'")
+	  res = res.fetch_hash
+	  return nil unless res
+	  a_count = res['Rows'].to_i
+	rescue ActiveRecord::Transactions::TransactionError
+	  raise $!
+	end
+      end
+      
+      def current_queries
+	ret = []
+	res = execute("SHOW FULL PROCESSLIST")
+	while col = res.fetch_hash
+	  ret.push(col)
+	end
+	return ret
+      end
+
+      def kill(query_id)
+	execute("KILL #{query_id.to_i}")
+      end
+
+      def innodb_status
+	execute("SHOW INNODB STATUS").fetch_hash["Status"]
+      end
+      
+      def variables_text
+	hash = {}
+	res = execute("SHOW VARIABLES")
+	while col = res.fetch_hash
+	  hash[col["Variable_name"]] = col["Value"]
+	end
+	ml = hash.keys.map {|k| k.length}.max
+	
+	hash.keys.sort.map {|key| key.ljust(ml," ") + ": " + hash[key].to_s }.join("\n")
+      end
+    end
+  end
+end

Added: incubator/alois/trunk/rails/lib/tasks/alois.rake
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/lib/tasks/alois.rake?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/lib/tasks/alois.rake (added)
+++ incubator/alois/trunk/rails/lib/tasks/alois.rake Thu Nov  4 18:27:22 2010
@@ -0,0 +1,118 @@
+namespace "alois" do
+
+  desc "Freeze all gems"
+  task :freeze => :environment do
+    Rails.configuration.gems.each {|g| 
+	ENV["GEM"] = g.name
+	Rake::Task["gems:freeze"].execute
+	Rake::Task["gems:link"].execute
+    }
+  end
+
+  namespace :db do
+
+    desc "Dumps the schema version."
+    task :dump_schema_version => :environment do
+	DefaultSchemaMigration.dump_schema_version
+    end
+
+    desc "Check schema version."
+    task :print_schema_version => :environment do
+	begin 
+	  config = Rails::Configuration.new.database_configuration[RAILS_ENV]
+	  DefaultSchemaMigration.check_schma_version!(config['database'])
+	  print "VERSION: #{DefaultSchemaMigration.version}\n"	  	  
+	rescue
+	  print "#{$!}\n"
+	  case $!.to_s 
+	  when /mismatch/
+	    exit 2
+	  when /Unknown database/
+	    exit 3
+	  when /'mysql.schema_migrations' doesn't exist/
+	    exit 4
+	  else	    
+	    exit 1
+	  end
+	end
+    end
+    
+    desc "Creates the database only. (no structure)"
+    task :create => :environment do
+	config = Rails::Configuration.new.database_configuration[RAILS_ENV]
+        connection = connect_mysql_local
+	connection.query("CREATE DATABASE #{config['database']}")
+    end
+
+    desc "Drops the database"
+    task :drop => :environment do
+	config = Rails::Configuration.new.database_configuration[RAILS_ENV]
+	print "Will drop database '#{config['database']}' on '#{config['host']}'."
+	[3,2,1,0].each { |n|
+	  print(" #{n} ")
+	  STDOUT.flush
+	  sleep(1)
+	}
+	print "\n"
+        connection = connect_mysql_local
+	connection.query("DROP DATABASE #{config['database']}")
+    end
+
+    desc "Prints out the current selected default database."
+    task :print_database => :environment do
+	config = Rails::Configuration.new.database_configuration[RAILS_ENV]
+	print "The current connection is: '#{config['database']}' on '#{config['host']}'\n"
+    end
+
+    desc "Removes the default databse - no rails database tasks can be performed anymore."
+    task :undefine_db do
+      File.delete('db') if File.symlink?('db')
+      File.delete('test/fixtures') if File.symlink?('test/fixtures') 
+    end
+
+    desc "Defines that the default connection points to the pumpy database."
+    task :set_pumpy_db => :undefine_db do
+      File.symlink('db_pumpy','db')
+      File.symlink('fixtures_pumpy','test/fixtures') if File.directory?('test')
+    end
+
+    desc "Defines that the default connection points to the alois database."
+    task :set_alois_db => :undefine_db do
+      File.symlink('db_alois','db')
+      File.symlink('fixtures_alois','test/fixtures') if File.directory?('test')
+    end
+
+    desc "Compares the current database schema to the 'should be' schema."
+    task :compare_schema => :environment do
+      # dump the actual schema to
+      File.copy("db/expected_schema.rb","db/schema.rb") if File.exist?("db/expected_schema.rb")
+      ENV['SCHEMA'] = "db/current_schema.rb"
+      Rake::Task["db:schema:dump"].invoke
+	
+      difference = false
+
+      # compare the 
+      open("|/usr/bin/diff -w -u db/schema.rb db/current_schema.rb").each { |line|
+	print line
+        difference = true
+      }		
+
+      # remove dumped schema file
+      File.delete("db/current_schema.rb")
+     
+      throw "Current db has not the proper schema." if difference
+    end
+
+    desc "Creates the schema dump file from the migration scripts."
+    task :create_schema do
+	ENV['RAILS_ENV'] = 'test'
+	RAILS_ENV = 'test'
+        Rake::Task["environment"].invoke
+        Rake::Task["db:test:purge"].invoke
+	ActiveRecord::Base.connection.reconnect!
+        Rake::Task["db:migrate"].invoke
+        Rake::Task["db:schema:dump"].invoke
+    end
+
+  end
+end
\ No newline at end of file

Added: incubator/alois/trunk/rails/public/404.html
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/404.html?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/public/404.html (added)
+++ incubator/alois/trunk/rails/public/404.html Thu Nov  4 18:27:22 2010
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body>
+  <h1>File not found</h1>
+  <p>Change this error message for pages not found in public/404.html</p>
+</body>
+</html>
\ No newline at end of file

Added: incubator/alois/trunk/rails/public/500.html
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/500.html?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/public/500.html (added)
+++ incubator/alois/trunk/rails/public/500.html Thu Nov  4 18:27:22 2010
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body>
+  <h1>Application error</h1>
+  <p>Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html</p>
+</body>
+</html>
\ No newline at end of file

Added: incubator/alois/trunk/rails/public/dispatch.cgi
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/dispatch.cgi?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/public/dispatch.cgi (added)
+++ incubator/alois/trunk/rails/public/dispatch.cgi Thu Nov  4 18:27:22 2010
@@ -0,0 +1,10 @@
+#!/usr/bin/ruby1.8
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+require "dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch
\ No newline at end of file

Added: incubator/alois/trunk/rails/public/dispatch.fcgi
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/dispatch.fcgi?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/public/dispatch.fcgi (added)
+++ incubator/alois/trunk/rails/public/dispatch.fcgi Thu Nov  4 18:27:22 2010
@@ -0,0 +1,24 @@
+#!/usr/bin/ruby1.8
+#
+# You may specify the path to the FastCGI crash log (a log of unhandled
+# exceptions which forced the FastCGI instance to exit, great for debugging)
+# and the number of requests to process before running garbage collection.
+#
+# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
+# and the GC period is nil (turned off).  A reasonable number of requests
+# could range from 10-100 depending on the memory footprint of your app.
+#
+# Example:
+#   # Default log path, normal GC behavior.
+#   RailsFCGIHandler.process!
+#
+#   # Default log path, 50 requests between GC.
+#   RailsFCGIHandler.process! nil, 50
+#
+#   # Custom log path, normal GC behavior.
+#   RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
+#
+require File.dirname(__FILE__) + "/../config/environment"
+require 'fcgi_handler'
+
+RailsFCGIHandler.process!

Added: incubator/alois/trunk/rails/public/dispatch.rb
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/dispatch.rb?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/public/dispatch.rb (added)
+++ incubator/alois/trunk/rails/public/dispatch.rb Thu Nov  4 18:27:22 2010
@@ -0,0 +1,24 @@
+# Copyright 2010 The Apache Software Foundation.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#!/usr/bin/ruby1.8
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+require "dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch
\ No newline at end of file

Added: incubator/alois/trunk/rails/public/favicon.ico
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/favicon.ico?rev=1031127&view=auto
==============================================================================
    (empty)

Added: incubator/alois/trunk/rails/public/help.html
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/help.html?rev=1031127&view=auto
==============================================================================
--- incubator/alois/trunk/rails/public/help.html (added)
+++ incubator/alois/trunk/rails/public/help.html Thu Nov  4 18:27:22 2010
@@ -0,0 +1,404 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>Alois Help</title>
+  </head>
+
+  <body>
+    <h1>Alois Help</h1>
+    <h2>Logverarbeitung Übersicht</h2>
+    <table>
+	<tr>
+	  <th>Logs</th>
+	  <th><a href="#database">Pumpy</a></th>
+	  <th>Prisma</th>
+	  <th><a href="#database">Dobby</a></th>
+	  <th><a href="#view">View</a></th>
+	  <th><a href="#filter">Filter</a></th>
+	</tr>
+	<tr>
+	  <td style="text-align:center"><img src="images/flat-theme/text_block.png"/></td>
+	  <td style="text-align:center"><img src="images/flat-theme/inserttable.png"/></td>
+	  <td style="text-align:center"><img src="images/flat-theme/tab_right.png"/></td>
+	  <td style="text-align:center"><img src="images/flat-theme/matrix.png"/></td>
+	  <td style="text-align:center"><img src="images/flat-theme/data.png"/></td>
+	  <td style="text-align:center"><img src="images/flat-theme/filter.png"/></td>
+	</tr>
+	<tr>
+	  <td>Logs werden per Syslog verschickt.</td>	  
+	  <td>"Raw" gespeicherte Logs in Tabellen auf Insink.</td>	  
+	  <td>Log informationen werden von Pumpy geholt und auseinandergenommen.</td>	  
+	  <td>Aufgesplittete Logmeldungen in Dobby-Datenbank.</td>	  
+	  <td style="border-left: solid 2px black;">Mit SQL generierte Ansichten der Log-Tabellen.</td>	  
+	  <td style="border-right: solid 2px black;">Hilfswerkzeug zum Filtern bestehender Ansichten.</td>
+	</tr>
+	<tr>
+	  <th colspan="4"></th>
+	  <th colspan="2" style="border-top: solid 2px black;">Daten Sets für Reporting</th>
+	</tr>
+	<tr>
+	  <td colspan="4"></td>
+	  <td colspan="2" style="text-align:center;"><img src="images/flat-theme/smallcal.png"/></td>
+	</tr>
+    </table>
+    <h2>Reporting Übersicht</h2>
+    <table>
+	<tr>
+	  <th rowspan="2">Daten Set</th>
+	  <th rowspan="2"><a href="#sentinel">Sentinel</a></th>
+	  <th><img src="images/flat-theme/tab_right.png" height="20"/></th>
+	  <th><a href="#alarm">Alarm</a></th>
+	</tr>
+	<tr>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td style="text-align:center"><img src="images/flat-theme/bell.png"/></td>
+	</tr>
+	<tr>
+	  <td rowspan="2" style="text-align:center"><img src="images/flat-theme/smallcal.png"/></td>
+	  <td rowspan="2" style="text-align:center"><img src="images/police_man_ganson.png" width="60" /></td>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td>Von Sentinel generierte Alarme.</td>
+	</tr>
+	<tr>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <th><a href="#report_generate">Report</a></th>
+	</tr>
+	<tr>
+	  <td rowspan="2">Zusammengesetzt aus Views + Filter.</td>
+	  <td rowspan="2">Periodisch ausgeführter Wächter.</td>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td style="text-align:center"><img src="images/flat-theme/gkrellm.png"/></td>
+	</tr>
+	<tr>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td>Periodisch von Sentinel generierte Reporte.</td>
+	</tr>
+    </table>
+
+    <h2><a name="view"><img src="images/flat-theme/data.png"/> View</a></h2>
+    <h3>Anzeigen</h3>
+    <p>Gewünschte View auswählen. Aus Menu:</p>
+    <p><img src="images/help/open_view1.jpg"/></p>
+    <p>oder aus <a href="views">View Liste</a>:</p>
+    <p><img src="images/help/open_view2.jpg"/></p>
+    <p>Es erscheint dann eine Tabellenansicht der gewählten View.</p>
+    <p><a href="images/help/survey_table.jpg"><img src="images/help/survey_table.jpg" width="610"/></a></p>
+    <p>Beschreibung der Elemente:</p>
+    <ol>
+      <li>Hier kann durch die Datensätze navigiert werden.</li>
+      <li>Dies ist der Aktuelle aktive Filter. Hier kann die Zeitspanne in Worten eingegeben werden.</li>
+      <li>Wenn mit der Maus über eine Tabellenzelle gefahren wird erscheint dieses Menu. Hier können neue Bedingungen eingefügt werden. Die neuen Bedingungen werden dann bei 2. aufgeführt.<br>
+	<img src="images/add.png"/> Es werden nur noch Zeilen angezeigt welche in dieser Spalte diesen Wert haben.<br>
+	<img src="images/remove.png"/> Es werden alle Zeilen ausgeschlossen welche diesen Wert haben.</li>
+      <li>Wenn mit der Maus über einen Tabellkopf gefahren wird erscheint dieses Menu. <br>
+	<img src="images/up.png"/>,<img src="images/down.png"/> Datensätze auf- oder absteigend sortieren.<br>
+	<img src="images/pie-chart.png"/> <img src="images/bar-chart.png"/> Pie- oder Barchart mit der Verteilung der Werten dieser Spalte.<br>
+	<img src="images/line-chart.png"/> Wenn der Typ der Spalte numerisch ist, oder ein Datum/Zeit enthält, können auch Liniengrafiken dargestellt werden.</li>
+    </ol>
+            
+    <h2><a name="filter"><img src="images/flat-theme/filter.png"/> Filter</a></h2>
+    <h3>Erstellen</h3>
+    <p>Entweder den aktuellen Filter aus der View-Azeige speicher:</p>
+    <p><img src="images/help/create_filter1.jpg"/></p>
+    <p>Oder den Menupunkt Reporting -> Filters -> <a href="filters/new">New...</a> wählen:</p>
+    <p><img src="images/help/create_filter2.jpg"/></p>
+    <p>Es erscheint dann folgende Maske:</p>
+    <p><img src="images/help/filter_edit.jpg"/></p>
+    <ol>
+      <li>Hier können Bedingungen entfernt werden.</li>
+      <li>Hier können die Bedingungen bearbeitet werden.</li>
+      <li>Die Beschreibung des Filters</li>
+      <li>Hier kann ein Filter aus in Zip-Form geladen werden. (Wird nur zum hin- und herkopieren zwischen verschiedenen Servern verwendet)</li>
+    </ol>
+    
+    
+    <h2><a name="chart">Chart</a></h2>
+    <h3>Erstellen</h3>
+    <p>Über den Tabellenkopf in der View-Ansicht.</p>
+    <p><img src="images/help/create_chart1.jpg"/></p>
+    <p>Oder über den Knopf "Chart" in der View-Ansicht.</p>
+    <p><img src="images/help/create_chart2.jpg"/></p>
+    <h3>Bearbeiten in View-Ansicht</h3>
+    <p><a href="images/help/modify_chart.jpg"><img width="592" src="images/help/modify_chart.jpg"/></a></p>
+    <ol>
+      <li>Indem auf die Grafik geklickt wird können die Werte weiter eingegrenzt werden. Es werden dann die Tabelleneinträge angezeigt welche das ausgewählte Element repräsentieren.</li>
+      <li>Hier kann angegeben werden aufgrund welcher Spalten die Grafik erstellt werden soll.</li>
+      <li>Hier kann die Sortierung bestimmt werden.</li>
+      <li>Hier kann der Grafiktyp gewählt werden. vlnr: Bar-Chart, Line-Chart, Pie-Chart. Einschränkungen: Line-Charts können nur für X-Achsen mit numerischen Typen oder Datum/Zeit gewählt werden. Die Multichart Spalte kann nicht für Pie Charts gewählt werden.</li>
+      <li>Nachdem änderungen in der Maske vorgenommen wurden, kann die Grafik mit dem Update-Knopf aktualisiert werden.</li>
+      <li>Unter der Grafik erscheint die Erstellungszeit der Grafik. Zum Teil werden die Daten zwischengespeichert. Um die Daten und die Grafik neu zu generieren, den Reload Knopf verwenden.</li>
+    </ol>
+    <h3>Chart Typen Übersicht</h3>
+
+    <table border=1>
+	<tr>
+	  <th>Typ</th>
+	  <th>2 Dim.</th>
+	  <th>3 Dim.</th>
+	  <th>4 Dim.</th>
+	</tr>
+	<tr>
+	  <th>Spalten</th>
+	  <td>date</td>
+	  <td>date,level</td>
+	  <td>date,level,facility</td>
+	</tr>
+	<tr>
+	  <td>Pie</td>	  
+	  <td><a href="images/help/pie-chart-1.png"><img width="300" src="images/help/pie-chart-1.png"/></a>
+	  <td><a href="images/help/pie-chart-2.png"><img width="300" src="images/help/pie-chart-2.png"/></a>
+	  <td>-</a>
+	</tr>
+	<tr>
+	  <td>Bar</td>	  
+	  <td><a href="images/help/bar-chart-1.png"><img width="300" src="images/help/bar-chart-1.png"/></a>
+	  <td><a href="images/help/bar-chart-2.png"><img width="300" src="images/help/bar-chart-2.png"/></a>
+	  <td><a href="images/help/bar-chart-3.png"><img width="300" src="images/help/bar-chart-3.png"/></a>
+	</tr>
+	<tr>
+	  <td>Line</td>	  
+	  <td><a href="images/help/line-chart-1.png"><img width="300" src="images/help/line-chart-1.png"/></a>
+	  <td><a href="images/help/line-chart-2.png"><img width="300" src="images/help/line-chart-2.png"/></a>
+	  <td><a href="images/help/line-chart-3.png"><img width="300" src="images/help/line-chart-3.png"/></a>
+	</tr>
+	<tr>
+	  <td>Bar Stacked</td>	  
+	  <td>-</a>
+	  <td><a href="images/help/bar-stacked-chart-2.png"><img width="300" src="images/help/bar-stacked-chart-2.png"/></a>
+	  <td><a href="images/help/bar-stacked-chart-3.png"><img width="300" src="images/help/bar-stacked-chart-3.png"/></a>
+	</tr>
+	<tr>
+	  <td>Line Stacked</td>	  
+	  <td>-</a>
+	  <td><a href="images/help/line-stacked-chart-2.png"><img width="300" src="images/help/line-stacked-chart-2.png"/></a>
+	  <td><a href="images/help/line-stacked-chart-3.png"><img width="300" src="images/help/line-stacked-chart-3.png"/></a>
+	</tr>
+    </table>
+
+    <p></p>
+    <h2><a name="report_template"><img src="images/flat-theme/edit.png"/> Report Template</a></h2>
+    <h3>Erstellen</h3>
+    <p>Im Menu Reporting -> Report Template -> <a href="report_templates/new">New...</a></p>
+    <p><img src="images/help/new_report_template.jpg"></p>
+    <p>Es erscheint folgende Maske:</p>
+    <p><img src="images/help/new_report_template_maske.jpg"></p>
+    <ol>
+      <li>Hier kann der Report beschrieben werden. Bei Title kann der Name angegeben werden welcher in den Emails als Subject erscheinen soll.</li>
+      <li>Hier wird das eigentliche Template in HTML eingegeben. Die Werte, welche unten am Textfeld angegeben sind, werden beim Report erstellen ersetzt.</li>
+      <li>View hat keinen Einfluss auf die Erstellung eines Reports. Sie wird nur für Plausibilitäts-Prüfungen verwendet und kann auch leer sein. Wenn ein Wert eingefügt ist, dann können nur Charts und Tables ausgewählt werden, welche auf die angegebene View anwendbar sind.</li>
+      <li>Charts und Tables können erst hinzugefügt werden wenn das ReportTemplate einmal gespeichert wurde.</li>      
+    </ol>
+    
+    <h3>Hinzufügen von Charts und Tables</h3>
+    <p>Bei der Ansicht eines Report-Templates können nun die Charts angegeben werden.</p>
+    <p><img src="images/help/show_report_template.jpg"/></p>
+    <ol>
+      <li>Hier kann ein Chart ausgewählt und hinzugefügt werden.</li>
+      <li>Hier kann eine Voransicht mit Zufällig generierten Daten angezeigt werden.</li>
+      <li>Hier kann eine Voransicht mit Daten aus der oberhalb angegebenen Datasource und Time Range erstellt werden.</li>
+      <li>Hier kann ein Report mit Daten aus der oberhalb angegebenen Datasource und Time Range erstellt werden. Der Report wird dann gespeichert und erscheint unter <a href="reports">Reports</a></li>
+    </ol>
+
+    <h2><a name="report"><img src="images/flat-theme/gkrellm.png"/> Report</a></h2>
+    <h3>Manuell erstellen</h3>
+    <table>
+	<tr>
+	  <th>Data Set</th>
+	  <th></th>
+	  <th>Report Template</th>
+	  <th></th>
+	  <th>Report</th>
+	</tr>
+	
+	<tr>
+	  <td style="text-align:center;"><img src="images/flat-theme/smallcal.png"/></td>
+	  <td><img src="images/flat-theme/edit_add.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/flat-theme/edit.png"/></td>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/flat-theme/gkrellm.png"/></td>
+	</tr>
+    </table>
+    <p>Das gewünschte ReportTemplate aus Menu auswählen:</p>
+    <p><img src="images/help/select_report_template.jpg"/></p>
+    <p>Es erscheint die Detailansicht des Report-Templates mit folgender Maske:</p>
+    <p><img src="images/help/render_report_template.jpg"/></p>
+    <ol>
+      <li>Die View für das Data-Set auswählen.</li>
+      <li>Die Zeitspanne für das Data-Set eingeben.</li>
+      <li>Knopf "Save as Report" betätigen.</li>
+    </ol>
+    <p>Es sollte dann nach einiger Zeit der Report angezeigt werden. Wenn wieder die Detail-Anzeige des Report-Templates erscheint, Fehlermeldung beachten.</p>
+
+
+
+    <h2><a name="sentinel"><img src="images/police_man_ganson.png" width="60" /> Sentinel</a></h2>
+    <p>Sentinel Editieren</p>
+    <p><img src="images/help/edit_sentinel.jpg"></p>
+    <ol>
+      <li>Hier kann angegeben, was bei der Ausführung dieses Sentinels generiert werden soll. Der Sentinel ist ausgeschaltet wenn hier disabled gewählt wird.</li>
+      <li>Hier wird angegeben in welchen Intervallen dieser Sentinel ausgeführt wird. Bitte konsultieren Sie die Online-Hilfe für mehr Details: <img src="images/help/help_button.jpg"> dann <img src="images/help/cron_interval_help.jpg"></li>
+      <li>Hier kann die Email-Versendung ein oder ausgeschaltet werden. Das Email wird an die in Mail to definerte Adresse versendet.</li>
+      <li>Geben sie hier die "Schwelle" an, ab wann die in 1. ausgewählte Aktion ausgelöst werden soll. D.h. wenn die Anzahl Zeilen den angegebenen Wert übersteigt, wird ein Report und/oder Alarm generiert und ggf. eine Email verschickt.</li>
+      <li>Hier wird die View für das Daten Set definiert.</li>
+      <li>Hier wird die Zeitspanne für die zu selektierenden Daten angegeben.</li>
+      <li>Hier werden die anzuwendenden Filter für die View angegeben. (Kommaseparierte Liste)</li>
+      <li>Hier wird das Alarm-Level angegeben, wenn ein Alarm generiert werden soll.</li>
+      <li>Hier wird das Report-Template angegeben, wenn ein Report generiert werden soll.</li>
+    </ol>
+    
+
+    <h3><a name="report_generate">Periodische Reporte generieren</a></h3>
+    <table>
+	<tr>
+	  <th>Data Set</th>
+	  <th></th>
+	  <th>Report Template</th>
+	  <th></th>
+	  <th>Sentinel</th>
+	  <th></th>
+	  <th>Report</th>
+	</tr>
+	
+	<tr>
+	  <td style="text-align:center;"><img src="images/flat-theme/smallcal.png"/></td>
+	  <td><img src="images/flat-theme/edit_add.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/flat-theme/edit.png"/></td>
+	  <td><img src="images/flat-theme/edit_add.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/police_man_ganson.png" width="60" /></td>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/flat-theme/gkrellm.png"/></td>
+	</tr>
+    </table>
+    
+    <p>Damit periodisch ein Report generiert wird, muss ein Sentinel mit folgenden Angaben erstellt werden (vgl. Sentinel Erstellen):</p>
+    <ul>
+      <li>Bei 1: Action = report</li>
+      <li>Bei 2: Cron interval = GEWÜNSCHTES INTERVAL<br>
+	Zum Beispiel einmal täglich um 17:15 Uhr: 15 17 * * *</li>
+      <li>Bei 4: Threshold = GEWÜNSCHTEN WERT<br>
+	Normalerweise 0</li>
+      <li>Bei 5,6,7: Gewünschte View, Time Range und Filter auswählen</li>
+      <li>Bei 9: Das Report Template auswählen</li>
+    </ul>
+    
+    <h3><a name="alarm_generate">Alarme generieren</a></h3>
+    <table>
+	<tr>
+	  <th>Data Set</th>
+	  <th></th>
+	  <th>Sentinel</th>
+	  <th></th>
+	  <th>Alarm</th>
+	</tr>
+	
+	<tr>
+	  <td style="text-align:center;"><img src="images/flat-theme/smallcal.png"/></td>
+	  <td><img src="images/flat-theme/edit_add.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/police_man_ganson.png" width="60" /></td>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/flat-theme/bell.png"/></td>
+	</tr>
+    </table>
+
+    <p>Damit periodisch Alarme generiert wird, muss ein Sentinel mit folgenden Angaben erstellt werden (vgl. Sentinel Erstellen):</p>
+    <ul>
+      <li>Bei 1: Action = alarm</li>
+      <li>Bei 2: Cron interval = GEWÜNSCHTES INTERVAL<br>
+	Zum Beispiel einmal täglich um 17:15 Uhr: 15 17 * * *</li>
+      <li>Bei 4: Threshold = GEWÜNSCHTEN WERT<br>
+	Normalerweise 0</li>
+      <li>Bei 5,6,7: Gewünschte View, Time Range und Filter auswählen</li>
+      <li>Bei 8: Alarm Level auswählen</li>
+    </ul>
+    
+    <h3>Alarm mit Report generieren</h3>
+    <table>
+	<tr>
+	  <th>Data Set</th>
+	  <th></th>
+	  <th>Report Template</th>
+	  <th></th>
+	  <th>Sentinel</th>
+	  <th></th>
+	  <th>Alarm mit Report</th>
+	</tr>
+	
+	<tr>
+	  <td style="text-align:center;"><img src="images/flat-theme/smallcal.png"/></td>
+	  <td><img src="images/flat-theme/edit_add.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/flat-theme/edit.png"/></td>
+	  <td><img src="images/flat-theme/edit_add.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/police_man_ganson.png" width="60" /></td>
+	  <td><img src="images/flat-theme/tab_right.png" height="20"/></td>
+	  <td style="text-align:center;"><img src="images/flat-theme/bell.png"/><img src="images/flat-theme/gkrellm.png"/></td>
+	</tr>
+    </table>
+    
+    <p>Damit periodisch Alarme generiert wird, muss ein Sentinel mit folgenden Angaben erstellt werden (vgl. Sentinel Erstellen):</p>
+    <ul>
+      <li>Bei 1: Action = alarm_and_report</li>
+      <li>Bei 2: Cron interval = GEWÜNSCHTES INTERVAL<br>
+	Zum Beispiel einmal täglich um 17:15 Uhr: 15 17 * * *</li>
+      <li>Bei 4: Threshold = GEWÜNSCHTEN WERT<br>
+	Normalerweise 0</li>
+      <li>Bei 5,6,7: Gewünschte View, Time Range und Filter auswählen</li>
+      <li>Bei 8: Alarm Level auswählen</li>
+      <li>Bei 9: Das Report Template auswählen</li>
+    </ul>
+
+    <h2><a name="alarm">Alarm</a></h2>
+    <h3>Ampel</h3>
+    <p><img src="images/help/ampel.jpg"/></p>    
+    <ul>
+      <li>Grün: Es gibt keine zu bearbeitenden Alarme.</li>
+      <li>Orange: Es gibt zu bearbeitende Alarme mit Level error oder warning.</li>
+      <li>Rot: Es gitb zu bearbeitende Alarme mit Level emergency, alert oder critical.</li>
+    </ul>
+    <h3>Alarm Liste</h3>
+    <p>Auf <a href="prisma/overview">Overview</a> Seite oder im Header auf die Ampel klicken.</p>
+    <p><img src="images/help/ampel.jpg"/></p>
+    <p>Es erscheint folgende Seite:</p>
+    <p><img src="images/help/alarm_list.jpg"></p>
+    <ol>
+      <li>Hier sind die aktuellen (zu bearbeitenden) Alarme sortiert nach Level Zeit.</li>
+      <li>Hier sind die zuletzt bestätigten alarme.</li>
+      <li>Hier sind die aktuellen Alarme welche nur zu Informationszwecken eingerichtet wurden. (Alarm Level &lt;= 5: notice)</li>
+    </ol>
+
+    <h3>Details</h3>
+    <p><img src="images/help/alarm_detail.jpg"/></p>
+    <ul>
+      <li>Created at: Wann der Alarm ausgelöst wurde.</li>
+      <li>Data: Die Datensätze welche den Alarm ausgelöst haben in Textform.</li>
+      <li>Report: Falls vorhanden, Link auf zugehörigen Report.</li>
+      <li>Sentinel: Falls vorhanden, Sentinel welcher den Alarm ausgelöst hat. Hier ist auch die Beschreibung des Alarmes und allfällig auszulösende Massnahmen enthalten.</li>
+    </ul>
+    <h3>Acknowlege</h3>
+    <p>In der Alarmliste auf edit klicken:</p>
+    <p><img src="images/help/alarm_edit_click.jpg"></p>
+    <p>Es erscheint folgende Maske:</p>
+    <p><img src="images/help/alarm_edit.jpg"></p>
+    <ul>
+      <li>Kommentar einfügen, warum der Alarm ausgelöst wurde und weshalb der Alarm acknowledged werden kann.</li>
+      <li>Acknowledge checkbox betätigen.</li>
+      <li>Update drücken.</li>
+    </ul>
+
+    <h2><a name="database">Database</a></h2>
+    <h3>Datenbank Details anzeigen</h3>
+    <p><img src="images/help/database_status.jpg"/></p>
+    <h3>Unnötige (zu lange laufende) Queries abbrechen.</h3>
+    <p><img src="images/help/database_detail.jpg"/></p>
+    <ol>
+      <li>Mit "Kill" kann die angezeigte Query abgebrochen werden.</li>
+    </ol>
+    
+
+    <hr>
+    <address><a href="mailto:flavio.pellanda@logintas.ch">Flavio Pellanda</a></address>
+<!-- Created: Mon Jul  7 13:56:19 CEST 2008 -->
+<!-- hhmts start -->
+Last modified: Tue Jul  8 01:02:53 CEST 2008
+<!-- hhmts end -->
+  </body>
+</html>

Added: incubator/alois/trunk/rails/public/images/add.png
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/images/add.png?rev=1031127&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/alois/trunk/rails/public/images/add.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/alois/trunk/rails/public/images/bar-chart.png
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/images/bar-chart.png?rev=1031127&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/alois/trunk/rails/public/images/bar-chart.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/alois/trunk/rails/public/images/bookmark_add.png
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/images/bookmark_add.png?rev=1031127&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/alois/trunk/rails/public/images/bookmark_add.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/alois/trunk/rails/public/images/close.png
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/images/close.png?rev=1031127&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/alois/trunk/rails/public/images/close.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/alois/trunk/rails/public/images/delete.png
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/images/delete.png?rev=1031127&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/alois/trunk/rails/public/images/delete.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/alois/trunk/rails/public/images/dot.gif
URL: http://svn.apache.org/viewvc/incubator/alois/trunk/rails/public/images/dot.gif?rev=1031127&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/alois/trunk/rails/public/images/dot.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream