diff --git a/.gitattributes b/.gitattributes
index efe3262f890dfd7a9d48dc45578a711a65391ae0..b1f4400dce038d50e82bb093784207d24c657685 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -39,6 +39,11 @@ testfont binary
 /lib/modules/Debug.pmod/werror.pmod foreign_ident
 /lib/modules/Filesystem.pmod/Tar.pmod foreign_ident
 /lib/modules/GLU.pmod foreign_ident
+/lib/modules/Graphics.pmod/Graph.pmod/create_bars.pike foreign_ident
+/lib/modules/Graphics.pmod/Graph.pmod/create_graph.pike foreign_ident
+/lib/modules/Graphics.pmod/Graph.pmod/create_pie.pike foreign_ident
+/lib/modules/Graphics.pmod/Graph.pmod/graph.h foreign_ident
+/lib/modules/Graphics.pmod/Graph.pmod/polyline.pike foreign_ident
 /lib/modules/LR.pmod/Grammar_parser.pmod foreign_ident
 /lib/modules/LR.pmod/item.pike foreign_ident
 /lib/modules/LR.pmod/lr.pike foreign_ident
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/create_bars.pike b/lib/modules/Graphics.pmod/Graph.pmod/create_bars.pike
new file mode 100755
index 0000000000000000000000000000000000000000..b143252dba56c3301d5eccb51cb197c8402165c3
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/create_bars.pike
@@ -0,0 +1,821 @@
+#!NOMODULE
+
+#include "graph.h"
+
+import Image;
+import Array;
+import Stdio;
+
+inherit "polyline.pike";
+inherit "create_graph.pike";
+
+constant cvs_version = "$Id: create_bars.pike,v 1.1 1999/09/30 13:03:56 hedda Exp $";
+
+/*
+ * name = "BG: Create bars";
+ * doc = "Business Graphics sub-module for drawing bars.";
+ */
+
+/*
+These functions were written by Henrik "Hedda" Wallin (hedda@idonex.se)
+Create_bars can draw normal bars, sumbars and normalized sumbars.
+*/ 
+
+mapping(string:mixed) create_bars(mapping(string:mixed) diagram_data)
+{
+
+#ifdef BG_DEBUG
+  mapping bg_timers = ([]);
+#endif
+
+  //Supports only xsize>=100
+
+  int si=diagram_data["fontsize"];
+ 
+  //Fix defaultcolors!
+  setinitcolors(diagram_data);
+
+
+  string where_is_ax;
+
+  object(image) barsdiagram;
+
+#ifdef BG_DEBUG
+  bg_timers->init_bg = gauge {
+#endif
+  init_bg(diagram_data);
+#ifdef BG_DEBUG
+  };
+#endif
+  barsdiagram=diagram_data["image"];
+
+#ifdef BG_DEBUG
+  bg_timers->set_legend_size = gauge {
+#endif
+  set_legend_size(diagram_data);
+#ifdef BG_DEBUG
+  };
+#endif
+  //write("ysize:"+diagram_data["ysize"]+"\n");
+  diagram_data["ysize"]-=diagram_data["legend_size"];
+  //write("ysize:"+diagram_data["ysize"]+"\n");
+  
+#ifdef BG_DEBUG
+  bg_timers->init = gauge {
+#endif
+
+  //Calculate biggest and smallest datavalues
+  init(diagram_data);
+#ifdef BG_DEBUG
+  };
+#endif
+
+  //Calculate how many and how big the texts are.
+#ifdef BG_DEBUG
+  bg_timers->space = gauge {
+#endif
+  if (!(diagram_data["xspace"]))
+  {
+    //Initiate the distance between the texts on the x-axis (Or X-axis?)
+    float range=(diagram_data["xmaxvalue"]-
+		 diagram_data["xminvalue"]);
+    float space=pow(10.0, floor(log(range/3.0)/log(10.0)));
+    if (range/space>5.0)
+    {
+      if(range/(2.0*space)>5.0)
+      {
+	space=space*5.0;
+      }
+      else
+	space=space*2.0;
+    }
+    else
+      if (range/space<2.5)
+	space*=0.5;
+    diagram_data["xspace"]=space;      
+  }
+  if (!(diagram_data["yspace"]))
+  {
+    //Initiate the distance between the texts on the y-axis (Or X-axis?)
+    float range=(diagram_data["ymaxvalue"]-
+		 diagram_data["yminvalue"]);
+    float space=pow(10.0, floor(log(range/3.0)/log(10.0)));
+    if (range/space>5.0)
+    {
+      if(range/(2.0*space)>5.0)
+	space *= 5.0;
+      else
+	space *= 2.0;
+    }
+    else
+      if (range/space<2.5)
+	space *= 0.5;
+    diagram_data["yspace"]=space;      
+  }
+ 
+#ifdef BG_DEBUG
+  };
+#endif
+
+
+#ifdef BG_DEBUG
+  bg_timers->text = gauge {
+#endif
+    
+    
+  float start;
+  start=diagram_data["xminvalue"]+diagram_data["xspace"]/2.0;
+  diagram_data["values_for_xnames"]=allocate(sizeof(diagram_data["xnames"]));
+  for(int i=0; i<sizeof(diagram_data["xnames"]); i++)
+    diagram_data["values_for_xnames"][i]=start+start*2*i;
+
+  if (!(diagram_data["values_for_ynames"]))
+  {
+    if ((diagram_data["yspace"]<LITET)
+	&& (diagram_data["yspace"]>-LITET))
+      throw( ({"Very bad error because yspace is zero!\n",
+	       backtrace()}));
+    float start;
+    start=diagram_data["yminvalue"];
+    start=diagram_data["yspace"]*ceil((start)/diagram_data["yspace"]);
+    diagram_data["values_for_ynames"]=({start});
+    while(diagram_data["values_for_ynames"][-1]<=
+	  diagram_data["ymaxvalue"]-diagram_data["yspace"])
+      diagram_data["values_for_ynames"]+=({start+=diagram_data["yspace"]});
+  }
+  
+  function fun;
+  if (diagram_data["eng"])
+    fun=diagram_eng;
+  else
+    fun=diagram_neng;
+  
+  //Draw the text if it does not exist
+  if (!(diagram_data["ynames"]))
+    if (diagram_data["eng"]||diagram_data["neng"])
+    {
+      diagram_data["ynames"]=
+	allocate(sizeof(diagram_data["values_for_ynames"]));
+      array(mixed) v=diagram_data["values_for_ynames"];
+      mixed m=diagram_data["ymaxvalue"];
+      mixed mi=diagram_data["yminvalue"];
+      for(int i=0; i<sizeof(v); i++)
+	if (abs(v[i]*1000)<max(m, abs(mi)))
+	  diagram_data["ynames"][i]="0";
+	else	
+	  diagram_data["ynames"][i]=
+	    fun((float)(v[i]));
+    }
+    else
+    {
+      diagram_data["ynames"]=
+	allocate(sizeof(diagram_data["values_for_ynames"]));
+      
+      for(int i=0; i<sizeof(diagram_data["values_for_ynames"]); i++)
+	diagram_data["ynames"][i]=
+	  no_end_zeros((string)(diagram_data["values_for_ynames"][i]));
+    }
+  
+  
+  if (!(diagram_data["xnames"]))
+  {
+    diagram_data["xnames"]=
+      allocate(sizeof(diagram_data["values_for_xnames"]));
+      
+    for(int i=0; i<sizeof(diagram_data["values_for_xnames"]); i++)
+      diagram_data["xnames"][i]=
+	no_end_zeros((string)(diagram_data["values_for_xnames"][i]));
+  }
+
+
+  //Draw the text-images
+  //calculate xmaxynames, ymaxynames xmaxxnames ymaxxnames
+  create_text(diagram_data);
+  si=diagram_data["fontsize"];
+
+#ifdef BG_DEBUG
+  };
+#endif
+
+  //Create the label-texts for the X-axis
+  object labelimg;
+  string label;
+  int labelx=0;
+  int labely=0;
+  if (diagram_data["labels"])
+  {
+    if (diagram_data["labels"][2] && sizeof(diagram_data["labels"][2]))
+      label=diagram_data["labels"][0]+" ["+diagram_data["labels"][2]+"]"; //Xstorhet
+    else
+      label=diagram_data["labels"][0];
+
+    GETFONT(xaxisfont);
+    if ((label!="")&&(label!=0))
+      labelimg=notext
+	->write(UNICODE(label,diagram_data["encoding"]))
+	->scale(0,diagram_data["labelsize"]);
+    else
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+
+    if (labelimg->xsize()<1)
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+
+    if (labelimg->xsize()>
+	diagram_data["xsize"]/2)
+      labelimg=labelimg->scale(diagram_data["xsize"]/2, 0);
+
+    labely=diagram_data["labelsize"];
+    labelx=labelimg->xsize();
+  }
+  else
+    diagram_data["labelsize"]=0;
+
+  labely+=write_name(diagram_data);
+
+  int ypos_for_xaxis; //Distance from bottom
+  int xpos_for_yaxis; //Distance from right
+
+  //Decide where the graph can be drawn
+  diagram_data["ystart"]=(int)ceil(diagram_data["linewidth"]);
+  diagram_data["ystop"]=diagram_data["ysize"]-
+    (int)ceil(diagram_data["linewidth"]+si)-labely;
+  if (((float)diagram_data["yminvalue"]>-LITET)&&
+      ((float)diagram_data["yminvalue"]<LITET))
+    diagram_data["yminvalue"]=0.0;
+
+  if (diagram_data["yminvalue"]<0)
+  {
+    //Calculate position for the x-axis. 
+    //If this doesn't work: Draw the y-axis at right or left
+    // and recalculate diagram_data["ystart"]
+    ypos_for_xaxis=((-diagram_data["yminvalue"])
+		    * (diagram_data["ystop"] - diagram_data["ystart"]))
+      /	(diagram_data["ymaxvalue"]-diagram_data["yminvalue"])
+      + diagram_data["ystart"];
+      
+    int minpos;
+    minpos=max(labely, diagram_data["ymaxxnames"])+si/2;
+    if (minpos>ypos_for_xaxis)
+    {
+      ypos_for_xaxis=minpos;
+      diagram_data["ystart"]=ypos_for_xaxis+
+	diagram_data["yminvalue"]*(diagram_data["ystop"]-ypos_for_xaxis)/
+	(diagram_data["ymaxvalue"]);
+    }
+    else
+    {
+      int maxpos;
+      maxpos=diagram_data["ysize"]-
+	(int)ceil(diagram_data["linewidth"]+si*2)
+	- labely;
+      if (maxpos<ypos_for_xaxis)
+      {
+	ypos_for_xaxis=maxpos;
+	diagram_data["ystop"]=ypos_for_xaxis
+	  + diagram_data["ymaxvalue"]*(ypos_for_xaxis-diagram_data["ystart"])
+	  / (0-diagram_data["yminvalue"]);
+      }
+    }
+  }
+  else
+    if (diagram_data["yminvalue"]==0.0)
+    {
+      // Place the x-axis and diagram_data["ystart"] at bottom.  
+      diagram_data["ystop"]=diagram_data["ysize"]
+	- (int)ceil(diagram_data["linewidth"]+si)-labely;
+      ypos_for_xaxis=max(labely, diagram_data["ymaxxnames"])+si/2;
+      diagram_data["ystart"]=ypos_for_xaxis;
+    }
+    else
+    {
+      //Place the x-axis at bottom and diagram_data["ystart"] a
+      //Little bit higher
+      diagram_data["ystop"]=diagram_data["ysize"]
+	- (int)ceil(diagram_data["linewidth"]+si)-labely;
+      ypos_for_xaxis=max(labely, diagram_data["ymaxxnames"])+si/2;
+      diagram_data["ystart"]=ypos_for_xaxis+si*2;
+    }
+
+  //Calculate position for the y-axis
+  diagram_data["xstart"]=(int)ceil(diagram_data["linewidth"]);
+  diagram_data["xstop"]=diagram_data["xsize"]-
+    (int)ceil(diagram_data["linewidth"])-max(si,labelx+si/2)-
+    diagram_data["xmaxxnames"]/2;
+  if (((float)diagram_data["xminvalue"]>-LITET)&&
+      ((float)diagram_data["xminvalue"]<LITET))
+    diagram_data["xminvalue"]=0.0;
+  
+  if (diagram_data["xminvalue"]<0)
+  {
+    //Calculate position for the y-axis. 
+    //If this doesn't work: Draw the y-axis at right or left
+    // and recalculate diagram_data["xstart"]
+    xpos_for_yaxis=((-diagram_data["xminvalue"])
+		    * (diagram_data["xstop"]-diagram_data["xstart"]))
+      /	(diagram_data["xmaxvalue"]-diagram_data["xminvalue"])
+      + diagram_data["xstart"];
+      
+    int minpos;
+    minpos=diagram_data["xmaxynames"]+si/2;
+    if (minpos>xpos_for_yaxis)
+    {
+      xpos_for_yaxis=minpos;
+      diagram_data["xstart"]=xpos_for_yaxis+
+	diagram_data["xminvalue"]*(diagram_data["xstop"]-xpos_for_yaxis)/
+	(diagram_data["ymaxvalue"]);
+    }
+    else
+    {
+      int maxpos;
+      maxpos=diagram_data["xsize"]-
+	(int)ceil((float)diagram_data["linewidth"]+si*2+labelx);
+      if (maxpos<xpos_for_yaxis)
+      {
+	xpos_for_yaxis=maxpos;
+	diagram_data["xstop"]=xpos_for_yaxis+
+	  diagram_data["xmaxvalue"]*(xpos_for_yaxis-diagram_data["xstart"])/
+	  (0-diagram_data["xminvalue"]);
+      }
+    }
+  }
+  else
+    if (diagram_data["xminvalue"]==0.0)
+    {
+      //Place the y-axis at left (?) and diagram_data["xstart"] at
+      // the same place
+      diagram_data["xstop"]=diagram_data["xsize"]-
+	(int)ceil(diagram_data["linewidth"])-max(si,labelx+si/2)-
+	diagram_data["xmaxxnames"]/2;
+      xpos_for_yaxis=diagram_data["xmaxynames"]+si/2+2;
+      diagram_data["xstart"]=xpos_for_yaxis+si/2;
+    }
+    else
+    {
+      //Place the y-axis at left (?) and diagram_data["xstart"] a
+      // little bit more right (?)
+      diagram_data["xstop"]=diagram_data["xsize"]-
+	(int)ceil(diagram_data["linewidth"])-max(si,labelx+si/2)-
+	diagram_data["xmaxxnames"]/2;
+      xpos_for_yaxis=diagram_data["xmaxynames"]+si/2;
+      diagram_data["xstart"]=xpos_for_yaxis+si*2;
+    }
+
+  //Calculate some shit
+  float xstart=(float)diagram_data["xstart"];
+  float xmore=(-xstart+diagram_data["xstop"])/
+    (diagram_data["xmaxvalue"]-diagram_data["xminvalue"]);
+  float ystart=(float)diagram_data["ystart"];
+  float ymore=(-ystart+diagram_data["ystop"])/
+    (diagram_data["ymaxvalue"]-diagram_data["yminvalue"]);
+  
+#ifdef BG_DEBUG
+  bg_timers->draw_grid = gauge {
+#endif
+
+  draw_grid(diagram_data, xpos_for_yaxis, ypos_for_xaxis, 
+	     xmore, ymore, xstart, ystart, (float) si);
+  
+#ifdef BG_DEBUG
+  };
+#endif
+
+
+  //???
+  int farg=0;
+
+ 
+#ifdef BG_DEBUG
+  bg_timers->draw_values = gauge {
+#endif
+
+  if (diagram_data["type"]=="sumbars")
+  {
+    int s=diagram_data["datasize"];
+    float barw=diagram_data["xspace"]*xmore/3.0;
+    for(int i=0; i<s; i++)
+    {
+      int j=0;
+      float x,y;
+      x=xstart+(diagram_data["xspace"]/2.0+diagram_data["xspace"]*i)*
+	xmore;
+      
+      y=-(-diagram_data["yminvalue"])*ymore+
+	diagram_data["ysize"]-ystart;	 
+      float start=y;
+      
+      foreach(column(diagram_data["data"], i), float|string d)
+      {
+	if (d==VOIDSYMBOL)
+	  d=0.0;
+	y-=d*ymore;
+	
+	barsdiagram->setcolor(@(diagram_data["datacolors"][j++]));
+	
+	barsdiagram->polygone(
+			      ({x-barw, y 
+				, x+barw, y, 
+				x+barw, start
+				, x-barw, start
+			      }));  
+	/*   barsdiagram->setcolor(0,0,0);
+	     draw(barsdiagram, 0.5, 
+	     ({
+	     x-barw, start,
+	     x-barw, y 
+	     , x+barw, y, 
+	     x+barw, start
+	     
+	     })
+	     );
+	*/
+	start=y;
+      }
+    }
+  }
+  else
+  if (diagram_data["subtype"]=="line")
+    if (diagram_data["drawtype"]=="linear")
+      foreach(diagram_data["data"], array(float|string) d)
+      {
+	array(float|string) l=allocate(sizeof(d)*2);
+	for(int i=0; i<sizeof(d); i++)
+	  if (d[i]==VOIDSYMBOL)
+	  {
+	    l[i*2]=VOIDSYMBOL;
+	    l[i*2+1]=VOIDSYMBOL;
+	  }
+	  else
+	  {
+	    l[i*2]=xstart+(diagram_data["xspace"]/2.0+
+			   diagram_data["xspace"]*i)
+	      * xmore;
+	    l[i*2+1]=-(d[i]-diagram_data["yminvalue"])*ymore+
+	      diagram_data["ysize"]-ystart;	  
+	  }
+	  
+	  //Draw Ugly outlines
+	  if ((diagram_data["backdatacolors"])&&
+	      (diagram_data["backlinewidth"]))
+	  {
+	    barsdiagram->setcolor(@(diagram_data["backdatacolors"][farg]));
+	    draw(barsdiagram, diagram_data["backlinewidth"],l,
+		 diagram_data["xspace"] );
+	  }
+
+	  barsdiagram->setcolor(@(diagram_data["datacolors"][farg++]));
+	  draw(barsdiagram, diagram_data["graphlinewidth"],l);
+      }
+    else
+      throw( ({"\""+diagram_data["drawtype"]
+	       + "\" is an unknown bars-diagram drawtype!\n",
+	       backtrace()}));
+  else
+    if (diagram_data["subtype"]=="box")
+      if (diagram_data["drawtype"]=="2D")
+      {
+	int s=sizeof(diagram_data["data"]);
+	float barw=diagram_data["xspace"]*xmore/1.5;
+	float dnr=-barw/2.0+ barw/s/2.0;
+	barw/=s;
+	barw/=2.0;
+	farg=-1;
+	float yfoo=(float)(diagram_data["ysize"]-ypos_for_xaxis);
+	//"draw_values":3580,
+	foreach(diagram_data["data"], array(float|string) d)
+	{
+	  farg++;
+	  
+	  for(int i=0; i<sizeof(d); i++)
+	    if (d[i]!=VOIDSYMBOL)
+	    {
+	      float x,y;
+	      x=xstart+(diagram_data["xspace"]/2.0+diagram_data["xspace"]*i)*
+		xmore;
+	      y=-(d[i]-diagram_data["yminvalue"])*ymore+
+		diagram_data["ysize"]-ystart;	 
+	      barsdiagram->setcolor(@(diagram_data["datacolors"][farg]));
+	      
+	      barsdiagram->polygone(
+				    ({x-barw+dnr, y 
+				      , x+barw+dnr, y, 
+				      x+barw+dnr, yfoo
+				      , x-barw+dnr, yfoo
+				    })); 
+	      /*  barsdiagram->setcolor(0,0,0);		  
+		  draw(barsdiagram, 0.5, 
+		  ({x-barw+dnr, y 
+		  , x+barw+dnr, y, 
+		  x+barw+dnr, diagram_data["ysize"]-ypos_for_xaxis
+		  , x-barw+dnr,diagram_data["ysize"]- ypos_for_xaxis,
+		  x-barw+dnr, y 
+		  }));*/
+	    }
+	  dnr+=barw*2.0;
+	}   
+      }
+      else
+	throw( ({"\""+diagram_data["drawtype"]
+		 + "\" is an unknown bars-diagram drawtype!\n", backtrace()}));
+    else
+      throw( ({"\""+diagram_data["subtype"]
+	       +"\" is an unknown bars-diagram subtype!\n", backtrace()}));
+
+#ifdef BG_DEBUG
+  };
+#endif
+  
+  //Draw X and Y-axis
+  barsdiagram->setcolor(@(diagram_data["axcolor"]));
+  
+
+  //Draw the X-axis
+  if ((diagram_data["xminvalue"]<=LITET)&&
+      (diagram_data["xmaxvalue"]>=-LITET))
+    barsdiagram->
+      polygone(make_polygon_from_line(diagram_data["linewidth"], 
+				      ({
+					xpos_for_yaxis,
+					diagram_data["ysize"]- ypos_for_xaxis,
+					diagram_data["xsize"]-
+					diagram_data["linewidth"]-labelx/2,  
+					diagram_data["ysize"]-ypos_for_xaxis
+				      }), 
+				      1, 1)[0]);
+  else
+    if (diagram_data["xmaxvalue"]<-LITET)
+    {
+      barsdiagram
+	->polygone(make_polygon_from_line(
+                     diagram_data["linewidth"], 
+		     ({
+		       xpos_for_yaxis,
+		       diagram_data["ysize"]-ypos_for_xaxis,
+		       
+		       xpos_for_yaxis-4.0/3.0*si, 
+		       diagram_data["ysize"]-ypos_for_xaxis,
+		       
+		       xpos_for_yaxis-si, 
+		       diagram_data["ysize"]-ypos_for_xaxis-si/2.0,
+		       xpos_for_yaxis-si/1.5,
+		       diagram_data["ysize"]-ypos_for_xaxis+si/2.0,
+		       
+		       xpos_for_yaxis-si/3.0,
+		       diagram_data["ysize"]-ypos_for_xaxis,
+		       
+		       diagram_data["xsize"]-diagram_data["linewidth"]
+		       - labelx/2, 
+		       diagram_data["ysize"]-ypos_for_xaxis
+		     }), 1, 1)[0]);
+    }
+    else
+      if (diagram_data["xminvalue"]>LITET)
+	{
+	barsdiagram
+	  ->polygone(make_polygon_from_line(
+                       diagram_data["linewidth"], 
+		       ({
+			 xpos_for_yaxis,
+			 diagram_data["ysize"]- ypos_for_xaxis,
+			 
+			 xpos_for_yaxis+si/3.0, 
+			 diagram_data["ysize"]-ypos_for_xaxis,
+			 
+			 xpos_for_yaxis+si/1.5, 
+			 diagram_data["ysize"]-ypos_for_xaxis-si/2.0,
+			 xpos_for_yaxis+si, 
+			 diagram_data["ysize"]-ypos_for_xaxis+si/2.0,
+			 
+			 xpos_for_yaxis+4.0/3.0*si, 
+			 diagram_data["ysize"]-ypos_for_xaxis,
+			 
+			 diagram_data["xsize"]-diagram_data["linewidth"]
+			 - labelx/2, 
+			 diagram_data["ysize"]-ypos_for_xaxis
+		       }), 1, 1)[0]);
+      }
+  
+  //Draw arrow on the X-axis
+  if (diagram_data["subtype"]=="line")
+    barsdiagram->polygone( ({
+      diagram_data["xsize"]-diagram_data["linewidth"]/2-(float)si-labelx/2,
+      diagram_data["ysize"]-ypos_for_xaxis-(float)si/4.0,
+      
+      diagram_data["xsize"]-diagram_data["linewidth"]/2-labelx/2,
+      diagram_data["ysize"]-ypos_for_xaxis,
+      
+      diagram_data["xsize"]-diagram_data["linewidth"]/2-(float)si-labelx/2,
+      diagram_data["ysize"]-ypos_for_xaxis+(float)si/4.0
+    })
+			   );  
+  
+  //Draw Y-axis
+  if ((diagram_data["yminvalue"]<=LITET)&&
+      (diagram_data["ymaxvalue"]>=-LITET))
+  {
+    if  ((diagram_data["yminvalue"]<=LITET)&&
+	 (diagram_data["yminvalue"]>=-LITET)) 
+      barsdiagram->
+	polygone(make_polygon_from_line(diagram_data["linewidth"], 
+					({
+					  xpos_for_yaxis,
+					  diagram_data["ysize"]-ypos_for_xaxis,
+					  xpos_for_yaxis,
+					  si+labely
+					  }), 1, 1)[0]);
+    else
+      barsdiagram->
+	polygone(make_polygon_from_line(diagram_data["linewidth"], 
+					({
+					  xpos_for_yaxis,
+					  diagram_data["ysize"]
+					  - diagram_data["linewidth"],
+					  
+					  xpos_for_yaxis,
+					  si+labely
+					  }), 1, 1)[0]);
+    
+  }
+  else
+    if (diagram_data["ymaxvalue"]<-LITET)
+    {
+      barsdiagram->
+	polygone(make_polygon_from_line(
+                   diagram_data["linewidth"], 
+		   ({
+		     xpos_for_yaxis,
+		     diagram_data["ysize"]-diagram_data["linewidth"],
+		     
+		     xpos_for_yaxis,
+		     diagram_data["ysize"]-ypos_for_xaxis+si*4.0/3.0,
+		     
+		     xpos_for_yaxis-si/2.0,
+		     diagram_data["ysize"]-ypos_for_xaxis+si,
+		     
+		     xpos_for_yaxis+si/2.0,
+		     diagram_data["ysize"]-ypos_for_xaxis+si/1.5,
+		     
+		     xpos_for_yaxis,
+		     diagram_data["ysize"]-ypos_for_xaxis+si/3.0,
+		     
+		     xpos_for_yaxis,
+		     si+labely
+		   }), 1, 1)[0]);
+    }
+    else
+      if (diagram_data["yminvalue"]>LITET)
+      {
+	barsdiagram->
+	  polygone(make_polygon_from_line(
+		     diagram_data["linewidth"], 
+		     ({
+		       xpos_for_yaxis,
+		       diagram_data["ysize"]-diagram_data["linewidth"],
+		       
+		       xpos_for_yaxis,
+		       diagram_data["ysize"]-ypos_for_xaxis-si/3.0,
+		       
+		       xpos_for_yaxis-si/2.0,
+		       diagram_data["ysize"]-ypos_for_xaxis-si/1.5,
+		       
+		       xpos_for_yaxis+si/2.0,
+		       diagram_data["ysize"]-ypos_for_xaxis-si,
+		       
+		       xpos_for_yaxis,
+		       diagram_data["ysize"]-ypos_for_xaxis-si*4.0/3.0,
+		       
+		       xpos_for_yaxis,
+		       si+labely
+		     }), 1, 1)[0]);
+      }
+    
+  //Draw arrow
+  barsdiagram->
+    polygone( ({
+      xpos_for_yaxis-(float)si/4.0,
+      diagram_data["linewidth"]/2.0+(float)si+labely,
+				      
+      xpos_for_yaxis,
+      diagram_data["linewidth"]/2.0+labely,
+	
+      xpos_for_yaxis+(float)si/4.0,
+      diagram_data["linewidth"]/2.0+(float)si+labely
+    }) ); 
+
+  //Write the text on the X-axis
+  int s=sizeof(diagram_data["xnamesimg"]);
+
+
+ 
+#ifdef BG_DEBUG
+  bg_timers->text_on_axis = gauge {
+#endif
+
+  for(int i=0; i<s; i++)
+    if ((diagram_data["values_for_xnames"][i]<diagram_data["xmaxvalue"])&&
+	(diagram_data["values_for_xnames"][i]>diagram_data["xminvalue"]))
+    {
+      barsdiagram->paste_alpha_color(
+                    diagram_data["xnamesimg"][i], 
+		    @(diagram_data["textcolor"]), 
+		    (int)floor((diagram_data["values_for_xnames"][i]
+				- diagram_data["xminvalue"])*xmore+xstart
+			       - diagram_data["xnamesimg"][i]->xsize()/2), 
+		    (int)floor(diagram_data["ysize"]-ypos_for_xaxis+si/4.0));
+    }
+
+  //Write the text on the Y-axis
+  s=min(sizeof(diagram_data["ynamesimg"]), 
+	sizeof(diagram_data["values_for_ynames"]));
+  for(int i=0; i<s; i++)
+    if ((diagram_data["values_for_ynames"][i]<=diagram_data["ymaxvalue"])&&
+	(diagram_data["values_for_ynames"][i]>=diagram_data["yminvalue"]))
+    {
+      barsdiagram->setcolor(@diagram_data["textcolor"]);
+      barsdiagram->paste_alpha_color(
+                     diagram_data["ynamesimg"][i], 
+		     @(diagram_data["textcolor"]), 
+		     (int)floor(xpos_for_yaxis-
+				si/4.0-diagram_data["linewidth"]-
+				diagram_data["ynamesimg"][i]->xsize()),
+		     (int)floor(-(diagram_data["values_for_ynames"][i]-
+				  diagram_data["yminvalue"])
+				*ymore+diagram_data["ysize"]-ystart
+				-
+				diagram_data["ymaxynames"]/2));
+      
+      barsdiagram->setcolor(@diagram_data["axcolor"]);
+      barsdiagram->
+	polygone(make_polygon_from_line(
+                   diagram_data["linewidth"], 
+		   ({
+		     xpos_for_yaxis-si/4,
+		     (-(diagram_data["values_for_ynames"][i]
+			- diagram_data["yminvalue"])*ymore
+		      + diagram_data["ysize"]-ystart),
+		     
+		     xpos_for_yaxis+si/4,
+		     (-(diagram_data["values_for_ynames"][i]
+			- diagram_data["yminvalue"])*ymore
+		      + diagram_data["ysize"]-ystart)
+		   }), 1, 1)[0]);
+    }
+
+
+  //Write labels ({xstorhet, ystorhet, xenhet, yenhet})
+  if (diagram_data["labelsize"])
+  {
+    barsdiagram
+      ->paste_alpha_color(labelimg, 
+			  @(diagram_data["labelcolor"]), 
+			  diagram_data["xsize"]-labelx
+			  - (int)ceil((float)diagram_data["linewidth"]),
+			  diagram_data["ysize"]
+			  - (int)ceil((float)(ypos_for_xaxis-si/2)));
+      
+    string label;
+    int x;
+    int y;
+
+    if (diagram_data["labels"][3] && sizeof(diagram_data["labels"][3]))
+      label=diagram_data["labels"][1]+" ["+diagram_data["labels"][3]+"]"; //Yquantity
+    else
+      label=diagram_data["labels"][1];
+    GETFONT(yaxisfont);
+    if ((label!="")&&(label!=0))
+      labelimg=notext
+	->write(label)->scale(0,diagram_data["labelsize"]);
+    else
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+    
+    if (labelimg->xsize()<1)
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+    
+    if (labelimg->xsize()>
+	diagram_data["xsize"])
+      labelimg=labelimg->scale(diagram_data["xsize"], 0);
+      
+    x=max(2,((int)floor((float)xpos_for_yaxis)-labelimg->xsize()/2));
+    x=min(x, barsdiagram->xsize()-labelimg->xsize());
+      
+    y=0; 
+      
+    if (label && sizeof(label))
+      barsdiagram->paste_alpha_color(labelimg, 
+				     @(diagram_data["labelcolor"]), 
+				     x,
+				     2+labely-labelimg->ysize());
+  }
+
+ 
+#ifdef BG_DEBUG
+  };
+#endif
+
+  diagram_data["ysize"]-=diagram_data["legend_size"];
+  diagram_data["image"]=barsdiagram;
+
+#ifdef BG_DEBUG
+  diagram_data->bg_timers=bg_timers;
+#endif
+  return diagram_data;
+}
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/create_graph.pike b/lib/modules/Graphics.pmod/Graph.pmod/create_graph.pike
new file mode 100755
index 0000000000000000000000000000000000000000..cfec894114cd8e2d0a595767e67f500efbf65b16
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/create_graph.pike
@@ -0,0 +1,1613 @@
+#!NOMODULE
+
+#include "graph.h"
+
+import Image;
+import Array;
+import Stdio;
+
+inherit "polyline.pike";
+
+constant cvs_version = "$Id: create_graph.pike,v 1.1 1999/09/30 13:04:01 hedda Exp $";
+
+/*
+ * name = "BG: Create graphs";
+ * doc = "Business Graphics sub-module for drawing graphs.";
+ */
+
+/*
+These functions were written by Henrik "Hedda" Wallin (hedda@idonex.se)
+Create_graph draws a graph but there are also some other functions
+used by create_pie and create_bars.
+
+This was orginally a part of the Roxen module Business Graphics.
+*/ 
+
+
+object tileimage(object img, int xs, int ys)
+{
+  //written by js@idonex.se
+
+  object dest=image(xs,ys);
+  int srcx=img->xsize();
+  int srcy=img->ysize();
+  if(srcx <= 0 || srcy <= 0)
+    return dest;
+  
+  for(int x=0; x<=xs; x+=srcx)
+    for(int y=0; y<=ys; y+=srcy)
+      dest->paste(img,x,y);
+
+  return dest;
+}
+
+//Key word eng:
+//This function writes a float like on an engineer-format
+string diagram_eng(float a)
+{
+  string foo="";
+  if (a<0.0)
+  {
+    foo="-";
+    a=-a;
+  }
+  array(string) pfix = ({ "a", "f", "p", "n", "µ", "m", "",
+			  "k", "M", "G", "T", "P", "E" });
+  if (a == 0.0) return "0";
+  float p = log(a)/log(1000.0);
+  if (p < -6.0) p = 0.0;
+  if (p >= 7.0) p = 0.0;
+  int i = (int) floor(p+0.000001);
+  string s;
+  sscanf(sprintf("%g%s", a*exp(-i*log(1000.0)), pfix[6+i]), "%*[ ]%s", s);
+  return foo+s;
+}
+
+//Key word neng:
+//This function writes a float like on an engineer-format
+//Exept for 0.1<a<1.0 
+// "neng" is a short for Noring's eng by the way :-) 
+string diagram_neng(float a)
+{
+  string foo="";
+  if (a<0.0)
+  {
+    foo="-";
+    a=-a;
+  }
+  array(string) pfix;
+  pfix = ({ "a", "f", "p", "n", "µ", "m", "",
+	    "k", "M", "G", "T", "P", "E" });
+  if (a == 0.0) return "0";
+  float p = log(a)/log(1000.0);
+  if (p < -6.0) p = 0.0;
+  if (p >= 7.0) p = 0.0;
+  int i = (int) floor(p+0.000001);
+  if ((a<1.0)&&(a>=0.0999999))
+    i=0;
+  string s; 
+  sscanf(sprintf("%g%s", a*exp(-i*log(1000.0)), pfix[6+i]), "%*[ ]%s", s);
+  return foo+s;
+}
+
+void draw(object(image) img, float h, array(float|string) coords,
+	  void|int|float zerolength)
+{
+  if ((sizeof(coords)==2)||
+      (sizeof(coords)==3))
+  {
+    array(float) foo=({(float)coords[0]-(float)zerolength,
+		       (float)coords[1],
+		       (float)coords[0]+(float)zerolength,
+		       (float)coords[1]
+    });
+    img->polygone(make_polygon_from_line(h, foo,1, 1)[0]);
+  }
+  else
+    for(int i=0; i<sizeof(coords)-3; i+=2)
+    {
+      if (coords[i]!=VOIDSYMBOL)
+	if (coords[i+2]!=VOIDSYMBOL)
+	  img->polygone( make_polygon_from_line(h, coords[i..i+3], 1, 1)[0] );
+	  else
+	    if ( ((i>0)&&(coords[i-2]==VOIDSYMBOL))||(i==0) )
+	      img->polygone( make_polygon_from_line(h, coords[i..i+1],
+						    1, 1)[0] );
+      }
+}
+
+mapping(string:mixed) setinitcolors(mapping(string:mixed) diagram_data)
+{
+  foreach(diagram_data["data"], mixed* fo)
+    if (sizeof(fo)>diagram_data["datasize"])
+      diagram_data["datasize"]=sizeof(fo);
+  
+  if (diagram_data["type"]=="sumbars")
+    for(int i; i<sizeof(diagram_data["data"]); i++)
+      diagram_data["data"][i]=diagram_data["data"][i]+
+	allocate(diagram_data["datasize"]-sizeof(diagram_data["data"][i]));
+
+
+  if ((diagram_data["type"]=="sumbars")||
+      (diagram_data["type"]=="bars"))
+    if (diagram_data["xdatanames"])
+      if (sizeof(diagram_data["datasize"])<
+	  sizeof(diagram_data["xdatanames"]))
+	diagram_data["xdatanames"]=diagram_data["xdatanames"]
+	  [..sizeof(diagram_data["datasize"])-1];
+
+  object piediagram=diagram_data["image"];
+
+  if (diagram_data["datacolors"])
+  {
+    int cnum;
+    if (diagram_data["type"]=="pie")
+      cnum=diagram_data["datasize"];
+    else
+      cnum=sizeof(diagram_data["data"]);
+    if (sizeof(diagram_data["datacolors"])<cnum)
+      diagram_data["datacolors"]=0;
+    else
+      foreach(diagram_data["datacolors"], mixed color)
+	if (sizeof(color)!=3)
+	  diagram_data["datacolors"]=0;
+  }
+
+  if (!(diagram_data["datacolors"]))
+  {
+    int numbers;
+    if (diagram_data["type"]=="pie")
+      numbers=diagram_data["datasize"];
+    else
+      numbers=sizeof(diagram_data["data"]);
+    
+    int** carr=allocate(numbers);
+    int steg=128+128/(numbers);
+
+    switch( numbers ) {
+     case 1:
+       carr=({({19,200,102})});
+       break;
+     case 2:
+       carr=({({190, 180, 0}), ({19, 19, 200})});
+       break;
+     case 3:
+       carr=({({200, 19, 19}), ({19, 19, 200}), ({42, 200, 19})});
+       break;
+     case 4:
+       carr=({({200, 19, 19}), ({19, 66, 200}), ({180, 180, 0}), ({19, 220, 102})});
+       break;
+     case 5:
+       carr= ({({200, 19, 19}), ({19, 85, 200}), ({180, 180, 0}), ({129, 19, 200}), ({19, 200, 80})});
+       break;
+     case 6:
+       carr= ({({200, 19, 19}), ({19, 85, 200}), ({180, 180, 0}), ({74, 220, 19}), ({100, 19, 200}), ({19, 200, 102})});
+       break;
+     case 7:
+       carr= ({({200, 19, 19}), ({19, 85, 200}), ({180, 180, 0}), ({72, 19, 200}), ({74, 200, 19}), ({200, 19, 140}), ({19, 200, 102})});
+       break;
+     case 8:
+       carr=({({200, 19, 19}), ({19, 110, 200}), ({180, 180, 0}), ({55, 19, 200}), ({96, 220, 19}), ({142, 19, 200}), ({19, 220, 69}), ({80, 19, 200})}) ;
+       break;
+     case 9:
+       carr= ({({200, 19, 19}), ({19, 115, 200}), ({200, 115, 19}), ({19, 19, 200}), ({118, 200, 19}), ({115, 19, 200}), ({42, 220, 19}), ({200, 19, 118}), ({19, 200, 112})});
+       break;
+     case 10:
+       carr=({({200, 19, 19}), ({19, 121, 200}), ({200, 104, 19}), ({19, 55, 200}), ({140, 200, 19}), ({88, 19, 200}), ({74, 220, 19}), ({130, 24, 130}), ({19, 220, 69}), ({180, 180, 0})}) ;
+       break;
+     case 11:
+       carr=({({200, 19, 19}), ({19, 123, 200}), ({200, 99, 19}), ({19, 63, 200}), ({150, 200, 19}), ({74, 19, 200}), ({91, 220, 19}), ({134, 19, 200}), ({19, 200, 47}), ({200, 19, 115}), ({19, 200, 107})}) ;
+       break;
+     case 12:
+       carr=({({200, 19, 19}), ({19, 126, 200}), ({200, 93, 19}), ({19, 72, 200}), ({200, 148, 19}), ({61, 19, 200}), ({107, 200, 19}), ({115, 19, 200}), ({53, 220, 19}), ({200, 109, 140}), ({19, 220, 80}), ({200, 19, 185})}) ;
+       break;
+     default:
+	  //No colours given!
+	  //Now we have the %-numbers in pnumbers
+	  //Lets create a colourarray carr
+	  for(int i=0; i<numbers; i++)
+	      carr[i]=Colors.hsv_to_rgb((i*steg)%256,190,200);
+    }
+
+    if (diagram_data["bw"])
+      for(int i=0; i<numbers; i++)
+	carr[i]=({ (i*steg)%256,
+		   (i*steg)%256, 
+		   (i*steg)%256 });
+      
+      diagram_data["datacolors"]=carr;
+    }
+
+  diagram_data["image"]=piediagram;
+  return diagram_data["image"];
+}
+
+
+
+mapping(string:mixed) init(mapping(string:mixed) diagram_data)
+{
+  float xminvalue=0.0, xmaxvalue=-STORT, yminvalue=0.0, ymaxvalue=-STORT;
+  
+  if (diagram_data["xmin"])
+    xminvalue=STORT;
+  if (diagram_data["ymin"])
+    yminvalue=STORT;
+  
+  if (diagram_data["labelcolor"]==0)
+    diagram_data["labelcolor"]=diagram_data["textcolor"];
+  if (diagram_data["labelcolor"] && sizeof(diagram_data["labelcolor"])!=3)
+    diagram_data["labelcolor"]=diagram_data["textcolor"];
+  diagram_data["linewidth"]=(float)diagram_data["linewidth"];
+  if ( diagram_data["linewidth"]< 0.01)
+     diagram_data["linewidth"]=1.0;
+
+  //Oulinecolors
+  if ((diagram_data["backdatacolors"]==0)&&
+      (diagram_data["backlinewidth"]))
+  {
+    int dcs=sizeof(diagram_data["datacolors"]);
+    diagram_data["backdatacolors"]=allocate(dcs);
+    for(int i=0; i<dcs; i++)
+      diagram_data["backdatacolors"][i]=({255-diagram_data["datacolors"][i][0],
+					  255-diagram_data["datacolors"][i][1],
+					  255-diagram_data["datacolors"][i][2]
+      });
+      
+    }
+  //diagram_data["backlinewidth"]=diagram_data["linewidth"]+1.0;
+  
+  if (!(diagram_data["legendcolor"]))
+    diagram_data["legendcolor"]=diagram_data["bgcolor"];
+  
+  if (diagram_data["type"]=="graph")
+    diagram_data["subtype"]="line";
+  
+  if (diagram_data["type"]=="bars")
+    diagram_data["xminvalue"]=0;
+
+  if (diagram_data["type"]=="sumbars")
+  {
+    diagram_data["xminvalue"]=0;
+    if (diagram_data["subtype"]=="norm")
+    {
+      diagram_data["yminvalue"]=0;
+      if (!(diagram_data["labels"]))
+	diagram_data["labels"]=({"", "%", "", ""});
+    }
+  }
+  if ((diagram_data["subtype"]==0) ||
+      (diagram_data["subtype"]==""))
+    diagram_data["subtype"]="line";
+
+  if (diagram_data["subtype"]=="line")
+    if ((!(diagram_data["drawtype"])) ||
+	(diagram_data["drawtype"]==""))
+      diagram_data["drawtype"]="linear";
+
+  if (diagram_data["subtype"]=="box")
+    if ((!(diagram_data["drawtype"])) ||
+	(diagram_data["drawtype"]==""))
+      diagram_data["drawtype"]="2D";
+
+  if (diagram_data["type"]=="sumbars")
+  {
+    diagram_data["data"]=Array.map(diagram_data["data"], replace,
+				   VOIDSYMBOL, 0.0);
+    
+    int j=sizeof(diagram_data["data"]);
+    float k;
+    if (diagram_data["subtype"]=="norm")
+    {
+      int j2=diagram_data["datasize"];
+      for(int i=0; i<j2; i++)
+      {
+	k=`+(@column(diagram_data["data"], i));
+	if (k<LITET)
+	  k=LITET;
+	else
+	  k=100.0/k;
+	for(int i2=0; i2<j; i2++)
+	  diagram_data["data"][i2][i]*=k;
+      }
+      yminvalue=0.0;
+      ymaxvalue=100.0;
+      
+    }
+    else
+      for(int i=0; i<diagram_data["datasize"]; i++)
+      {
+	if (yminvalue>(k=`+(@column(diagram_data["data"], i))))
+	  yminvalue=k;
+	if (ymaxvalue<(k))
+	  ymaxvalue=k;
+      }
+    xminvalue=0.0;
+    xmaxvalue=10.0;
+      
+  }
+  else
+    foreach(diagram_data["data"], array(float|string) d)
+    {
+      int j=sizeof(d);
+	
+      if (diagram_data["type"]=="graph")
+      {
+	d-=({VOIDSYMBOL});
+	j=sizeof(d)-1;
+	for(int i=0; i<j; i++)
+	{
+	  float k;
+	  if (xminvalue>(k=d[i]))
+	    xminvalue=k;
+	  if (xmaxvalue<(k))
+	    xmaxvalue=k;
+	  if (yminvalue>(k=d[++i]))
+	    yminvalue=k;
+	  if (ymaxvalue<(k))
+	    ymaxvalue=k;
+	}
+      }
+      else
+	if (diagram_data["type"]=="bars")
+	{
+	  for(int i; i<j; i++)
+	    if (floatp(d[i]))
+	    {
+	      float k; 
+	      if (yminvalue>(k=d[i]))
+		yminvalue=k;
+	      if (ymaxvalue<(k))
+		ymaxvalue=k;
+	    }
+	  xminvalue=0.0;
+	  xmaxvalue=10.0;
+	}
+	else
+	  if (diagram_data["type"]=="pie")
+	  {
+	    for(int i; i<j; i++)
+	    {
+	      if (!floatp(d[i]))
+		d[i]=0;
+	      
+	      float k; 
+	      if (yminvalue>(k=d[i]))
+		yminvalue=k;
+	      if (ymaxvalue<(k))
+		ymaxvalue=k;
+	    }
+	    xminvalue=0.0;
+	    xmaxvalue=10.0;
+	  }
+	  else
+	    throw( ({"\""+diagram_data["type"]
+		     + "\" is an unknown graph type!\n", backtrace()}));
+    }
+
+  if (diagram_data["type"]=="sumbars")
+    diagram_data["box"]=0;
+
+  if (diagram_data["type"]=="pie")
+  {
+    diagram_data["vertgrid"]=0;
+    diagram_data["horgrid"]=0;
+  }
+
+  xmaxvalue=max(xmaxvalue, xminvalue+STORTLITET);
+  ymaxvalue=max(ymaxvalue, yminvalue+STORTLITET);
+
+
+  if (!(diagram_data["xminvalue"]))
+    diagram_data["xminvalue"]=xminvalue;
+  if ((!(diagram_data["xmaxvalue"])) ||
+      (diagram_data["xmaxvalue"]<xmaxvalue))
+    if (xmaxvalue<0.0)
+      diagram_data["xmaxvalue"]=0.0;
+    else
+      diagram_data["xmaxvalue"]=xmaxvalue;
+  if (!(diagram_data["yminvalue"]))
+    diagram_data["yminvalue"]=yminvalue;
+  if ((!(diagram_data["ymaxvalue"])) ||
+      (diagram_data["ymaxvalue"]<ymaxvalue))
+    if (ymaxvalue<0.0)
+      diagram_data["ymaxvalue"]=0.0;
+    else
+      diagram_data["ymaxvalue"]=ymaxvalue;
+
+  //Create empty names on xnames if the names don't exist.
+  if ((diagram_data["type"]=="bars")||(diagram_data["type"]=="sumbars"))
+  {
+    if (!(diagram_data["xnames"]))
+      diagram_data["xnames"]=allocate(diagram_data["datasize"]);
+  }
+
+  //If xnames exist, set xspace if values_for_xnames don't exist
+  if (diagram_data["xnames"] && sizeof(diagram_data["xnames"])==0)
+    diagram_data["xnames"]=0;
+  if (diagram_data["type"]!="graph")
+    if (diagram_data["xnames"])
+      diagram_data["xspace"]=max((diagram_data["xmaxvalue"]-
+				  diagram_data["xminvalue"])
+				 /(float)(max(sizeof(diagram_data["xnames"]), 
+					      diagram_data["datasize"])),
+				 LITET*20);
+  
+  //If ynames exist, set yspace
+  if (diagram_data["ynames"])
+  {
+    diagram_data["ynames"]=({" "})+diagram_data["ynames"];
+    diagram_data["yspace"]=(diagram_data["ymaxvalue"]-
+			    diagram_data["yminvalue"])
+      /(float)sizeof(diagram_data["ynames"]);
+  }
+  //Check if labelsize is to big:
+  if (diagram_data["labelsize"]>diagram_data["ysize"]/5)
+    diagram_data["labelsize"]=diagram_data["ysize"]/5;
+  
+  return diagram_data;
+};
+
+/*
+#ifndef ROXEN
+object get_font(string j, int p, int t, int h, string fdg, int s, int hd)
+{
+  return font()->load("avant_garde");
+};
+#endif
+*/
+
+//Paste the text into the graph
+//calculate xmaxynames, ymaxynames xmaxxnames ymaxxnames
+mapping(string:mixed) create_text(mapping(string:mixed) diagram_data)
+{
+  int tobig=1;
+  int xmaxynames=0, ymaxynames=0, xmaxxnames=0, ymaxxnames=0;
+  int r=0;
+  while(tobig)
+  {
+    r++;
+    if (r>9)
+      throw( ({"Very bad error while trying to resize the textfont!\n",
+	       backtrace()}));
+      
+    GETFONT(xnamesfont);
+    int j;
+    diagram_data["xnamesimg"]=allocate(j=sizeof(diagram_data["xnames"]));
+    for(int i=0; i<j; i++)
+    {
+      if ( ((diagram_data["values_for_xnames"][i]>LITET)
+	    || (diagram_data["values_for_xnames"][i]<-LITET))
+	   && ((diagram_data["xnames"][i])
+	       && sizeof(diagram_data["xnames"][i])))
+	diagram_data["xnamesimg"][i]=notext
+	  ->write(UNICODE(diagram_data["xnames"][i],diagram_data["encoding"]))
+	  ->scale(0,diagram_data["fontsize"]);
+      else
+	diagram_data["xnamesimg"][i]=
+	  image(diagram_data["fontsize"],diagram_data["fontsize"]);
+      
+      if (diagram_data["xnamesimg"][i]->xsize()<1)
+	diagram_data["xnamesimg"][i]=image(diagram_data["fontsize"],
+					   diagram_data["fontsize"]);
+    }
+      
+    GETFONT(ynamesfont);
+
+    diagram_data["ynamesimg"]=allocate(j=sizeof(diagram_data["ynames"]));
+    if ((diagram_data["type"]=="bars")||
+	(diagram_data["type"]=="sumbars"))
+      for(int i=0; i<j; i++)
+      {
+	if ((diagram_data["ynames"][i]) && (sizeof(diagram_data["ynames"][i])))
+	{
+	  if (diagram_data["ynames"][i]=="-0")
+	    diagram_data["ynames"][i]="0";
+	  diagram_data["ynamesimg"][i]=notext
+	    ->write(UNICODE(diagram_data["ynames"][i],
+			    diagram_data["encoding"]))
+	    ->scale(0,diagram_data["fontsize"]);
+	}
+	else
+	  diagram_data["ynamesimg"][i]=
+	    image(diagram_data["fontsize"],diagram_data["fontsize"]);
+	
+	if (diagram_data["ynamesimg"][i]->xsize()<1)
+	  diagram_data["ynamesimg"][i]=image(diagram_data["fontsize"],
+					     diagram_data["fontsize"]);
+      }
+    else
+      for(int i=0; i<j; i++)
+      {
+	if (((diagram_data["values_for_ynames"][i]>LITET)
+	     || (diagram_data["values_for_ynames"][i]<-LITET))
+	    && ((diagram_data["ynames"][i])
+		&& (sizeof(diagram_data["ynames"][i]))))
+	  diagram_data["ynamesimg"][i]=notext
+	    ->write(UNICODE(diagram_data["ynames"][i],
+			    diagram_data["encoding"]))
+	    ->scale(0,diagram_data["fontsize"]);
+	else
+	  diagram_data["ynamesimg"][i]=
+	    image(diagram_data["fontsize"],diagram_data["fontsize"]);
+	
+	if (diagram_data["ynamesimg"][i]->xsize()<1)
+	  diagram_data["ynamesimg"][i]=image(diagram_data["fontsize"],
+					     diagram_data["fontsize"]);
+      }
+      
+      if (diagram_data["orient"]=="vert")
+	for(int i; i<sizeof(diagram_data["xnamesimg"]); i++)
+	  diagram_data["xnamesimg"][i]=diagram_data["xnamesimg"][i]
+	    ->rotate_ccw();
+      
+      
+      xmaxynames=0, ymaxynames=0, xmaxxnames=0, ymaxxnames=0;
+      
+      foreach(diagram_data["xnamesimg"], object img)
+	if (img->ysize()>ymaxxnames) 
+	  ymaxxnames=img->ysize();
+      
+      foreach(diagram_data["xnamesimg"], object img)
+	if (img->xsize()>xmaxxnames) 
+	  xmaxxnames=img->xsize();
+      
+      foreach(diagram_data["ynamesimg"], object img)
+	if (img->ysize()>ymaxynames) 
+	  ymaxynames=img->ysize();
+      
+      foreach(diagram_data["ynamesimg"], object img)
+	if (img->xsize()>xmaxynames) 
+	  xmaxynames=img->xsize();
+      
+      diagram_data["ymaxxnames"]=ymaxxnames;
+      diagram_data["xmaxxnames"]=xmaxxnames;
+      diagram_data["ymaxynames"]=ymaxynames;
+      diagram_data["xmaxynames"]=xmaxynames;
+      
+      if (ymaxxnames+xmaxynames>diagram_data["ysize"]/2)
+      {
+	tobig+=2;
+	diagram_data["fontsize"]=diagram_data["fontsize"]
+	  * diagram_data["ysize"]/2/(ymaxxnames+xmaxynames);
+      }
+      
+      if (ymaxynames>diagram_data["ysize"]/3)
+      {
+	tobig+=2;
+	diagram_data["fontsize"]=diagram_data["fontsize"]
+	  * diagram_data["ysize"]/3/ymaxynames;
+      }
+      
+      if (xmaxynames>diagram_data["xsize"]/2)
+      {
+	tobig+=2;
+	diagram_data["fontsize"]=diagram_data["fontsize"]
+	  * diagram_data["xsize"]/2/xmaxynames;
+      }
+      
+      if (xmaxxnames>diagram_data["xsize"]/3)
+      {
+	tobig+=2;
+	diagram_data["fontsize"]=diagram_data["fontsize"]
+	  * diagram_data["xsize"]/3/xmaxxnames;
+      }
+      
+      if (tobig==1)
+	tobig=0;
+      else
+	tobig--;
+      
+  } 
+}
+
+//Remove ending zeros. 
+//The Swedish is some insults between the programmers
+string no_end_zeros(string f)
+{
+  if (search(f, ".")!=-1)
+  {
+    int j;
+    /* FIXME  Vad i Hvte gör du här?! */
+    //Jag vet vad jag gör! Idi! :-)
+    for(j=sizeof(f)-1; f[j]=='0'; j--)
+    {}
+    if (f[j]=='.')
+      return f[..--j];
+    else
+      return f[..j];
+  }
+  return f;
+}
+
+//This functions just happen to draw the grid...
+mapping draw_grid(mapping diagram_data, int|float xpos_for_yaxis,
+		   int|float ypos_for_xaxis, float xmore, float ymore, 
+		   float xstart, float ystart, float si)
+{
+  //Draw the vertical grid (vertgrid)
+  int s=sizeof(diagram_data["xnames"]);
+  object graph=diagram_data["image"];
+  if (!diagram_data["gridwidth"])
+    diagram_data["gridwidth"]=diagram_data["linewidth"]/4.0;
+
+  graph->setcolor(@diagram_data["gridcolor"]);
+  float gw=(float)diagram_data["gridwidth"];
+  if ((diagram_data["vertgrid"])&&
+      (gw>LITET))
+    {
+      mixed vfx=diagram_data["values_for_xnames"];
+      float ystop=(float)(diagram_data["ysize"]-diagram_data["ystop"]);
+      float ystart=(float)(diagram_data["ysize"]-ystart);
+      float gw2=gw/2.0;
+      float xmin=(float)diagram_data["xminvalue"];
+      float xmax=(float)diagram_data["xmaxvalue"];
+      for(int i=0; i<s; i++)
+	if ((vfx[i]>xmin)&&
+	    (vfx[i]<xmax))
+	  {
+	    float temp;
+	    graph->
+	      polygone(({ 
+		(temp=(vfx[i]- diagram_data["xminvalue"])* xmore+xstart)-gw2,
+		ystart,
+		
+		temp+gw2,
+		ystart,
+
+		temp+gw2,
+		ystop,
+
+		temp-gw2,
+		  ystop}));
+	    /*
+	      //make_polygon_from_line() can't handle close edges
+	    make_polygon_from_line(
+					      gw,
+					      ({
+						((diagram_data["values_for_xnames"][i]
+						  - diagram_data["xminvalue"])
+						 * xmore+xstart),
+						diagram_data["ysize"]-ystart,
+						
+						((diagram_data["values_for_xnames"][i]
+						  - diagram_data["xminvalue"])
+						 * xmore+xstart),
+						diagram_data["ysize"]
+						- diagram_data["ystop"]
+					      }), 
+					      1, 1)[0]);
+	    */
+      }
+    }
+  //Draw the horisontal grid (the horgrid)
+  s=sizeof(diagram_data["values_for_ynames"]);
+  if ((diagram_data["horgrid"])
+      && (gw>LITET))
+    for(int i=0; i<s; i++)
+      if ((diagram_data["values_for_ynames"][i]>diagram_data["yminvalue"])&&
+	  (diagram_data["values_for_ynames"][i]<diagram_data["ymaxvalue"]))
+      {
+	graph->
+	  polygone(make_polygon_from_line(
+		     gw,
+		     ({
+		       xstart,
+		       (-(diagram_data["values_for_ynames"][i]-
+			  diagram_data["yminvalue"])
+			*ymore+diagram_data["ysize"]-ystart),
+		       
+		       diagram_data["xstop"],
+		       (-(diagram_data["values_for_ynames"][i]-
+			  diagram_data["yminvalue"])
+			*ymore+diagram_data["ysize"]-
+			ystart)
+		     }), 
+		     1, 1)[0]);
+      }
+}
+
+//This function also paste the info in the legend.
+mapping set_legend_size(mapping diagram_data)
+{
+  if (!(diagram_data["legendfontsize"]))
+    diagram_data["legendfontsize"]=diagram_data["fontsize"];
+  int raws;
+  //Check if the font is to big:
+  int tobig=1;
+  int j=0;
+  int xmax=0, ymax=0;
+  int b;
+  int columnnr;
+  array(object(image)) texts;
+  array(mixed) plupps; //This is the stuff that is draw before the texts
+  object notext;
+
+
+  if (diagram_data["legend_texts"])
+  {
+    if (sizeof(diagram_data["legend_texts"])>
+	sizeof(diagram_data["datacolors"]))
+      diagram_data["legend_texts"]=diagram_data["legend_texts"]
+	[..sizeof(diagram_data["datacolors"])-1];
+    
+    int r=0;
+    while(tobig)
+    {
+      r++;
+      if (r>3)
+	throw( ({"Very bad error while trying to resize the legendfonts!\n",
+		 backtrace()}));
+      {
+	texts=allocate(sizeof(diagram_data["legend_texts"]));
+	plupps=allocate(sizeof(diagram_data["legend_texts"]));
+	
+	GETFONT(legendfont);
+	
+	j=sizeof(texts);
+	if (!diagram_data["legendcolor"])
+	  diagram_data["legendcolor"]=diagram_data["bgcolor"];
+	for(int i=0; i<j; i++)
+	{
+	  if (diagram_data["legend_texts"][i]
+	      && (sizeof(diagram_data["legend_texts"][i])))
+	    texts[i]=notext
+	      ->write(UNICODE(diagram_data["legend_texts"][i],
+			      diagram_data["encoding"]))
+	      ->scale(0,diagram_data["legendfontsize"]);
+	  else
+	    texts[i]=
+	      image(diagram_data["legendfontsize"],
+		    diagram_data["legendfontsize"]);
+		
+	  if (texts[i]->xsize()<1)
+	    texts[i]=image(diagram_data["legendfontsize"],
+			   diagram_data["legendfontsize"]);
+	}
+	    
+	xmax=0, ymax=0;
+	
+	foreach(texts, object img)
+	  if (img->ysize()>ymax) 
+	    ymax=img->ysize();
+
+	foreach(texts, object img)
+	  if (img->xsize()>xmax) 
+	    xmax=img->xsize(); 
+	  
+	//Draw the line for Graph / the box for bars
+	if ((diagram_data["type"]=="graph") ||
+	    (diagram_data["type"]=="bars") ||
+	    (diagram_data["type"]=="sumbars") ||
+	    (diagram_data["type"]=="pie"))
+	  for(int i=0; i<j; i++)
+	  {
+	    plupps[i]=image(diagram_data["legendfontsize"],
+			    diagram_data["legendfontsize"]);
+		
+	    plupps[i]->setcolor(255,255,255);
+	    if ( (diagram_data["linewidth"]*1.5
+		  < (float)diagram_data["legendfontsize"])
+		 && (diagram_data["subtype"]=="line")
+		 && (diagram_data["drawtype"]!="level") )
+	      plupps[i]->polygone(make_polygon_from_line(
+				   diagram_data["linewidth"], 
+				   ({
+				     (float)(diagram_data["linewidth"]/2+1),
+				     (float)(plupps[i]->ysize()-
+					     diagram_data["linewidth"]/2-2),
+				     (float)(plupps[i]->xsize()-
+					     diagram_data["linewidth"]/2-2),
+				     (float)(diagram_data["linewidth"]/2+1)
+				   }), 
+				   1, 1)[0]);
+	    else
+	      plupps[i]->box( 1, 1, plupps[i]->xsize()-2,
+			      plupps[i]->ysize()-2 );
+	  }
+	else
+	  throw( ({"\""+diagram_data["type"]+"\" is an unknown graph type!\n",
+		   backtrace()}));
+	  
+	//Calculate how many colomns it can be
+	b;
+	columnnr=(diagram_data["image"]->xsize()-4)/
+	  (b=xmax+2*diagram_data["legendfontsize"]);
+	  
+	if (columnnr==0)
+	{
+	  int m=((diagram_data["image"]->xsize()-4)-2*diagram_data["legendfontsize"]);
+	  if (m<4) m=4;
+	  for(int i=0; i<sizeof(texts); i++)
+	    if (texts[i]->xsize()>m)
+	    {
+	      texts[i]=
+		texts[i]->scale((int)m,0);
+	      //write("x: "+texts[i]->xsize()+"\n");
+	      //write("y: "+texts[i]->ysize()+"\n");
+	    }
+	  columnnr=1;
+	}
+	
+	raws=(j+columnnr-1)/columnnr;
+	diagram_data["legend_size"]=raws*diagram_data["legendfontsize"];
+	
+	
+	if (diagram_data["image"]->ysize()/2>=raws
+	    * diagram_data["legendfontsize"])
+	  tobig=0;
+	else
+	{
+	  tobig++;
+	  if (tobig==2)
+	    diagram_data["legendfontsize"]=diagram_data["image"]->ysize()/raws;
+	  else
+	    diagram_data["legendfontsize"]=diagram_data["image"]
+	      -> ysize()/2/raws;
+	}
+      }
+      
+    }
+  }
+
+  //Place images and texts
+  
+  if (diagram_data["legend_texts"])
+  {
+    for(int i=0; i<j; i++)
+    {
+      diagram_data["image"]
+	->paste_alpha_color(plupps[i], 
+			    @(diagram_data["datacolors"][i]), 
+			    (i/raws)*b,
+			    (i%raws)*diagram_data["legendfontsize"]
+			    +diagram_data["image"]
+			    ->ysize()-diagram_data["legend_size"] );
+      diagram_data["image"]->setcolor(0,0,0);
+      draw( diagram_data["image"], 0.5,
+	    ({(i/raws)*b, (i%raws)*diagram_data["legendfontsize"]+
+	      diagram_data["image"]->ysize()-diagram_data["legend_size"]+1,
+	      (i/raws)*b+plupps[i]->xsize()-1.0,
+	      (i%raws)*diagram_data["legendfontsize"]
+	      + diagram_data["image"]->ysize()-diagram_data["legend_size"]+1, 
+	      (i/raws)*b+plupps[i]->xsize()-1.0,
+	      (i%raws)*diagram_data["legendfontsize"]
+	      + diagram_data["image"]->ysize()-diagram_data["legend_size"]
+	      + plupps[i]->ysize()-1,
+	      (i/raws)*b+1,
+	      (i%raws)*diagram_data["legendfontsize"] + diagram_data["image"]
+	      -> ysize()-diagram_data["legend_size"]+plupps[i]->ysize()-1,
+	      (i/raws)*b, (i%raws)*diagram_data["legendfontsize"]
+	      + diagram_data["image"]->ysize()-diagram_data["legend_size"]+1
+	    })); 
+      
+      
+      diagram_data["image"]
+	->paste_alpha_color(texts[i], 
+			    @(diagram_data["textcolor"]), 
+			    (i/raws)*b+1+diagram_data["legendfontsize"],
+			    (i%raws)*diagram_data["legendfontsize"]+
+			    diagram_data["image"]->ysize()
+			    - diagram_data["legend_size"] );
+    }
+  }
+  else
+    diagram_data["legend_size"]=0;
+}
+
+mapping(string:mixed) init_bg(mapping diagram_data)
+{
+  if (diagram_data["bgcolor"])
+    diagram_data["image"]=image(diagram_data["xsize"],diagram_data["ysize"],
+				@(diagram_data["bgcolor"]));
+  else
+    if ((diagram_data["xsize"]==0)||(0==diagram_data["ysize"]))
+    {
+      diagram_data["xsize"]=diagram_data["image"]->xsize();
+      diagram_data["ysize"]=diagram_data["image"]->ysize();
+    }
+    else
+      if (diagram_data["image"]&&(diagram_data["image"]->xsize()>4)&&
+	  (diagram_data["image"]->ysize()>4))
+	diagram_data["image"]=tileimage(diagram_data["image"], 
+					diagram_data["xsize"], 
+					diagram_data["ysize"]);
+      else
+	diagram_data["image"]=image(diagram_data["xsize"],
+				    diagram_data["ysize"],
+				    255,255,255);
+}
+
+int write_name(mapping diagram_data)
+{
+  if (!diagram_data["name"])
+    return 0;
+  GETFONT(namefont);
+
+  object text;
+  int y,x;
+  if (diagram_data["namesize"])
+    y=diagram_data["namesize"];
+  else
+    y=diagram_data["fontsize"];
+  
+  text=notext->write(UNICODE(diagram_data["name"],diagram_data["encoding"]))
+    ->scale(0,y);
+
+  if (text->xsize()>=diagram_data["xsize"])
+    text->scale(diagram_data["xsize"]-1,0);
+  
+  array color;
+  if (diagram_data["namecolor"])
+    color=diagram_data["namecolor"];
+  else
+    color=diagram_data["textcolor"];
+  
+
+  diagram_data["image"]
+    -> paste_alpha_color( text, @(color),
+			  diagram_data["xsize"]/2-text->xsize()/2, 2 );
+	  
+  return text->ysize()+2;
+}
+
+mapping(string:mixed) create_graph(mapping diagram_data)
+{
+  //Supports only xsize>=100
+  int si=diagram_data["fontsize"];
+  
+  string where_is_ax;
+  
+  //No uneven data
+  
+  for(int i=0; i<sizeof(diagram_data["data"]); i++)
+    if (sizeof(diagram_data["data"][i])%2)
+      diagram_data["data"][i]
+	= diagram_data["data"][i][..sizeof(diagram_data["data"][i])-2];
+
+  //Fix defaultcolors!
+  setinitcolors(diagram_data);
+
+  object(image) graph;
+  init_bg(diagram_data);
+  graph=diagram_data["image"];
+
+  set_legend_size(diagram_data);
+
+  diagram_data["ysize"]-=diagram_data["legend_size"];
+  
+  //Get biggest and smallest data-value
+  init(diagram_data);
+
+  //Find out how many and how big the textimages are
+  if (!(diagram_data["xspace"]))
+    if (diagram_data["xnames"])
+    {
+      diagram_data["xnames"]=({" "})+diagram_data["xnames"];
+      diagram_data["xspace"]=(diagram_data["xmaxvalue"]
+			      - diagram_data["xminvalue"])/
+	(LITET+sizeof(diagram_data["xnames"]));
+    }
+    else
+      {
+	//Initiate how long it is between
+	float range=(diagram_data["xmaxvalue"]
+		     - diagram_data["xminvalue"]);
+	if ((range>-LITET)&&
+	    (range<LITET))
+	  range=LITET*10.0;
+	
+	float space=pow(10.0, floor(log(range/3.0)/log(10.0)));
+	if ( range/space > 5.0 )
+	{
+	  if(range/(2.0*space)>5.0)
+	    space *= 5.0;
+	  else
+	    space *= 2.0;
+	}
+	else
+	  if (range/space<2.5)
+	    space *= 0.5;
+	diagram_data["xspace"]=space;
+      }
+  if (!(diagram_data["yspace"]))
+  {
+    //Initiate how long it is between
+      
+    float range=(diagram_data["ymaxvalue"]
+		 - diagram_data["yminvalue"]);
+    if ((range>-LITET)&&
+	(range<LITET))
+      range=LITET*10.0;
+
+    float space=pow(10.0, floor(log(range/3.0)/log(10.0)));
+    if (range/space>5.0)
+      if(range/(2.0*space)>5.0)
+	space *= 5.0;
+      else
+	space *= 2.0;
+    else
+      if (range/space<2.5)
+	space *= 0.5;
+    diagram_data["yspace"]=space;      
+  }
+ 
+  if (!(diagram_data["values_for_xnames"]))
+  {
+    if ((diagram_data["xspace"]<LITET)&&
+	(diagram_data["xspace"]>-LITET))
+      throw( ({"Very bad error because xspace is zero!\n", backtrace()}));
+    float start;
+    start=diagram_data["xminvalue"];
+    start=diagram_data["xspace"]*ceil((start)/diagram_data["xspace"]);
+    diagram_data["values_for_xnames"]=({start});
+    while(diagram_data["values_for_xnames"][-1]
+	  <= diagram_data["xmaxvalue"]-diagram_data["xspace"])
+      diagram_data["values_for_xnames"]+=({start+=diagram_data["xspace"]});
+  }
+  if (!(diagram_data["values_for_ynames"]))
+  {
+    if ((diagram_data["yspace"]<LITET)&&
+	(diagram_data["yspace"]>-LITET))
+      throw( ({"Very bad error because yspace is zero!\n", backtrace()}));
+    
+    float start;
+    start=diagram_data["yminvalue"];
+    start=diagram_data["yspace"]*ceil((start)/diagram_data["yspace"]);
+    diagram_data["values_for_ynames"]=({start});
+    while(diagram_data["values_for_ynames"][-1]
+	  <= diagram_data["ymaxvalue"]-diagram_data["yspace"])
+      diagram_data["values_for_ynames"]+=({start+=diagram_data["yspace"]});
+  }
+  
+  //Generate the texten if it doesn't exist
+  if (!(diagram_data["ynames"]))
+    if (diagram_data["eng"])
+      {
+	diagram_data["ynames"]=
+	  allocate(sizeof(diagram_data["values_for_ynames"]));
+	
+	for(int i=0; i<sizeof(diagram_data["values_for_ynames"]); i++)
+	  diagram_data["ynames"][i]=
+	    diagram_eng((float)(diagram_data["values_for_ynames"][i]));
+      } 
+    else if (diagram_data["neng"])
+      {
+	diagram_data["ynames"]=
+	  allocate(sizeof(diagram_data["values_for_ynames"]));
+	
+	for(int i=0; i<sizeof(diagram_data["values_for_ynames"]); i++)
+	  diagram_data["ynames"][i]=
+	    diagram_neng((float)(diagram_data["values_for_ynames"][i]));
+      } else {
+	diagram_data["ynames"]=
+	  allocate(sizeof(diagram_data["values_for_ynames"]));
+	
+	for(int i=0; i<sizeof(diagram_data["values_for_ynames"]); i++)
+	  diagram_data["ynames"][i]=
+	    no_end_zeros((string)(diagram_data["values_for_ynames"][i]));
+      }
+  
+
+    
+  if (!(diagram_data["xnames"]))
+    if (diagram_data["eng"])
+    {
+      diagram_data["xnames"]=
+	allocate(sizeof(diagram_data["values_for_xnames"]));
+      
+      for(int i=0; i<sizeof(diagram_data["values_for_xnames"]); i++)
+	diagram_data["xnames"][i]=
+	  diagram_eng((float)(diagram_data["values_for_xnames"][i]));
+    }
+    else if (diagram_data["neng"])
+    {
+      diagram_data["xnames"]=
+	allocate(sizeof(diagram_data["values_for_xnames"]));
+      
+      for(int i=0; i<sizeof(diagram_data["values_for_xnames"]); i++)
+	diagram_data["xnames"][i]=
+	  diagram_neng((float)(diagram_data["values_for_xnames"][i]));
+    }
+    else
+    {
+      diagram_data["xnames"]=
+	allocate(sizeof(diagram_data["values_for_xnames"]));
+      
+      for(int i=0; i<sizeof(diagram_data["values_for_xnames"]); i++)
+	diagram_data["xnames"][i]=
+	  no_end_zeros((string)(diagram_data["values_for_xnames"][i]));
+    }
+  
+
+  //Draw images with the texts
+  //calculate xmaxynames, ymaxynames xmaxxnames ymaxxnames
+  create_text(diagram_data);
+  si=diagram_data["fontsize"];
+
+  //Create the labeltext for the xaxis
+  object labelimg;
+  string label;
+  int labelx=0;
+  int labely=0;
+
+  GETFONT(xaxisfont);
+
+  if (diagram_data["labels"])
+  {
+    if (diagram_data["labels"][2] && sizeof(diagram_data["labels"][2]))
+      label=diagram_data["labels"][0]+" ["+diagram_data["labels"][2]+"]"; //Xstorhet
+    else
+      label=diagram_data["labels"][0];
+    if ((label!="")&&(label!=0))
+      labelimg=notext
+	-> write(label)->scale(0,diagram_data["labelsize"]);
+    else
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+      
+    if (labelimg->xsize()<1)
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+
+    if (labelimg->xsize()>
+	diagram_data["xsize"]/2)
+      labelimg=labelimg->scale(diagram_data["xsize"]/2,0);
+
+    labely=diagram_data["labelsize"];
+    labelx=labelimg->xsize();
+  }
+  
+  labely+=write_name(diagram_data);
+
+  int ypos_for_xaxis; //Distance from below
+  int xpos_for_yaxis; //Distanse from right
+  //Calculate where in the image a graph should be drawn
+  diagram_data["ystart"]=(int)ceil(diagram_data["linewidth"]);
+  diagram_data["ystop"]=diagram_data["ysize"]
+    - (int)ceil((float)diagram_data["linewidth"]+si)-labely;
+  if (((float)diagram_data["yminvalue"]>-LITET)&&
+      ((float)diagram_data["yminvalue"]<LITET))
+    diagram_data["yminvalue"]=0.0;
+  
+  if (diagram_data["yminvalue"]<0)
+  {
+    //Calculate position for the x-axis. 
+    //If this doesn't work: Draw the x-axis at bottom or top
+    // and recalculate diagram_data["ystart"]
+    ypos_for_xaxis=((-diagram_data["yminvalue"])*(diagram_data["ystop"]-diagram_data["ystart"]))/
+      (diagram_data["ymaxvalue"]-diagram_data["yminvalue"])+diagram_data["ystart"];
+      
+    int minpos;
+    minpos=max(labely, diagram_data["ymaxxnames"])+si/2;
+    if (minpos>ypos_for_xaxis)
+    {
+      ypos_for_xaxis=minpos;
+      diagram_data["ystart"]=ypos_for_xaxis+
+	diagram_data["yminvalue"]*(diagram_data["ystop"]-ypos_for_xaxis)/
+	(diagram_data["ymaxvalue"]);
+    } else {
+      int maxpos;
+      maxpos=diagram_data["ysize"]-
+	(int)ceil(diagram_data["linewidth"]+si*2)-
+	labely;
+      if (maxpos<ypos_for_xaxis)
+      {
+	ypos_for_xaxis=maxpos;
+	diagram_data["ystop"]=ypos_for_xaxis+
+	  diagram_data["ymaxvalue"]*(ypos_for_xaxis-diagram_data["ystart"])/
+	  (0-diagram_data["yminvalue"]);
+      }
+    }
+  }
+  else
+    if (diagram_data["yminvalue"]==0.0)
+    {
+      // Place the x-axis and diagram_data["ystart"] at bottom.  
+      diagram_data["ystop"]=diagram_data["ysize"]-
+	(int)ceil(diagram_data["linewidth"]+si)-labely;
+      ypos_for_xaxis=max(labely, diagram_data["ymaxxnames"])+si/2;
+      diagram_data["ystart"]=ypos_for_xaxis;
+    }
+    else
+    {
+      //Place the x-axis at bottom and diagram_data["ystart"] a
+      //Little bit higher
+      diagram_data["ystop"]=diagram_data["ysize"]-
+	(int)ceil(diagram_data["linewidth"]+si)-labely;
+      ypos_for_xaxis=max(labely, diagram_data["ymaxxnames"])+si/2;
+      diagram_data["ystart"]=ypos_for_xaxis+si*2;
+    }
+  
+  //Calculate position for the y-axis
+  diagram_data["xstart"]=(int)ceil(diagram_data["linewidth"]);
+  diagram_data["xstop"]=diagram_data["xsize"]-
+    (int)ceil(diagram_data["linewidth"])-max(si,labelx+si/2)
+    - diagram_data["xmaxxnames"]/2;
+  if (((float)diagram_data["xminvalue"]>-LITET)&&
+      ((float)diagram_data["xminvalue"]<LITET))
+    diagram_data["xminvalue"]=0.0;
+  
+  if (diagram_data["xminvalue"]<0.0)
+  {
+    //Calculate position for the y-axis. 
+    //If this doesn't work: Draw the y-axis at right or left
+    // and recalculate diagram_data["xstart"]
+    xpos_for_yaxis=((-diagram_data["xminvalue"])*(diagram_data["xstop"]
+						  - diagram_data["xstart"]))/
+      (diagram_data["xmaxvalue"]-diagram_data["xminvalue"])
+      + diagram_data["xstart"];
+      
+    int minpos;
+    minpos=diagram_data["xmaxynames"]+si/2+
+      diagram_data["linewidth"]+2;
+    if (minpos>xpos_for_yaxis)
+    {
+      xpos_for_yaxis=minpos;
+      diagram_data["xstart"]=xpos_for_yaxis+
+	diagram_data["xminvalue"]*(diagram_data["xstop"]-xpos_for_yaxis)/
+	(diagram_data["ymaxvalue"]);
+    } else {
+      int maxpos;
+      maxpos=diagram_data["xsize"]-
+	(int)ceil(diagram_data["linewidth"])-si*2-labelx;
+      if (maxpos<xpos_for_yaxis)
+      {
+	xpos_for_yaxis=maxpos;
+	diagram_data["xstop"]=xpos_for_yaxis+
+	  diagram_data["xmaxvalue"]*(xpos_for_yaxis-diagram_data["xstart"])/
+	  (0-diagram_data["xminvalue"]);
+      }
+    }
+  }
+  else
+    if (diagram_data["xminvalue"]==0.0)
+    {
+      //Place the y-axis at left (?) and diagram_data["xstart"] at
+      // the same place
+      diagram_data["xstop"]=diagram_data["xsize"]
+	- (int)ceil(diagram_data["linewidth"])-max(si,labelx+si/2)-diagram_data["xmaxxnames"]/2;
+      xpos_for_yaxis=diagram_data["xmaxynames"]+si/2+
+	diagram_data["linewidth"]+2;
+      diagram_data["xstart"]=xpos_for_yaxis;
+    } else {
+      //Place the y-axis at left (?) and diagram_data["xstart"] a
+      // little bit more right.
+      diagram_data["xstop"]=diagram_data["xsize"]-
+	(int)ceil(diagram_data["linewidth"])-max(si,labelx+si/2)
+	- diagram_data["xmaxxnames"]/2;
+      xpos_for_yaxis=diagram_data["xmaxynames"]+si/2+
+	diagram_data["linewidth"]+2;
+      diagram_data["xstart"]=xpos_for_yaxis+si*2;
+    }
+
+  //draw the axises.
+  graph->setcolor(@(diagram_data["axcolor"]));
+  
+  //Draw the x-axis
+  if ((diagram_data["xminvalue"]<=LITET)&&
+      (diagram_data["xmaxvalue"]>=-LITET))
+    graph->
+      polygone(make_polygon_from_line(diagram_data["linewidth"], 
+				      ({
+					diagram_data["linewidth"],
+					diagram_data["ysize"]- ypos_for_xaxis,
+					diagram_data["xsize"]-
+					si-labelx/2, 
+					diagram_data["ysize"]-ypos_for_xaxis
+				      }), 
+				      1, 1)[0]);
+  else
+    if (diagram_data["xmaxvalue"]<-LITET)
+    {
+      graph->
+	polygone(make_polygon_from_line(
+		   diagram_data["linewidth"], 
+		   ({
+		     diagram_data["linewidth"],
+		     diagram_data["ysize"]- ypos_for_xaxis,
+		     
+		     xpos_for_yaxis-4.0/3.0*si, 
+		     diagram_data["ysize"]-ypos_for_xaxis,
+		     
+		     xpos_for_yaxis-si, 
+		     diagram_data["ysize"]-ypos_for_xaxis-
+		     si/2.0,
+		     xpos_for_yaxis-si/1.5, 
+		     diagram_data["ysize"]-ypos_for_xaxis+
+		     si/2.0,
+		     
+		     xpos_for_yaxis-si/3.0, 
+		     diagram_data["ysize"]-ypos_for_xaxis,
+		     
+		     diagram_data["xsize"]-si-labelx/2, 
+		     diagram_data["ysize"]-ypos_for_xaxis
+		     
+		   }), 
+		   1, 1)[0]);
+    }
+    else
+      if (diagram_data["xminvalue"]>LITET)
+      {
+	graph->
+	  polygone(make_polygon_from_line(
+		     diagram_data["linewidth"], 
+		     ({
+		       diagram_data["linewidth"],
+		       diagram_data["ysize"]- ypos_for_xaxis,
+		       
+		       xpos_for_yaxis+si/3.0, 
+		       diagram_data["ysize"]-ypos_for_xaxis,
+		       
+		       xpos_for_yaxis+si/1.5, 
+		       diagram_data["ysize"]-ypos_for_xaxis-
+		       si/2.0,
+		       xpos_for_yaxis+si, 
+		       diagram_data["ysize"]-ypos_for_xaxis+
+		       si/2.0,
+		       
+		       xpos_for_yaxis+4.0/3.0*si, 
+		       diagram_data["ysize"]-ypos_for_xaxis,
+		       
+		       diagram_data["xsize"]-si-labelx/2, 
+		       diagram_data["ysize"]-ypos_for_xaxis
+		       
+		     }), 
+		     1, 1)[0]);
+	
+      }
+  
+  graph->polygone(
+		  ({
+		    diagram_data["xsize"]-
+		    diagram_data["linewidth"]/2-
+		    (float)si-labelx/2, 
+		    diagram_data["ysize"]-ypos_for_xaxis-
+		    (float)si/4.0,
+		    
+		    diagram_data["xsize"]-
+		    diagram_data["linewidth"]/2-labelx/2, 
+		    diagram_data["ysize"]-ypos_for_xaxis,
+		    
+		    diagram_data["xsize"]-
+		    diagram_data["linewidth"]/2-
+		    (float)si-labelx/2, 
+		    diagram_data["ysize"]-ypos_for_xaxis+
+		    (float)si/4.0
+		  })
+		  );
+  
+
+  //Draw the Y-axis
+  if ((diagram_data["yminvalue"]<=LITET)&&
+      (diagram_data["ymaxvalue"]>=-LITET))
+    graph->
+      polygone(make_polygon_from_line(
+                 diagram_data["linewidth"], 
+		 ({
+		   xpos_for_yaxis,
+		   diagram_data["ysize"]-diagram_data["linewidth"],
+		   xpos_for_yaxis,
+		   si+labely
+		 }), 
+		 1, 1)[0]);
+  else
+    if (diagram_data["ymaxvalue"]<-LITET)
+    {
+      graph->
+	polygone(make_polygon_from_line(
+                   diagram_data["linewidth"], 
+		   ({
+		     xpos_for_yaxis,
+		     diagram_data["ysize"]-diagram_data["linewidth"],
+		     
+		     xpos_for_yaxis,
+		     diagram_data["ysize"]-ypos_for_xaxis+si*4.0/3.0,
+		     
+		     xpos_for_yaxis-si/2.0,
+		     diagram_data["ysize"]-ypos_for_xaxis+si,
+		     
+		     xpos_for_yaxis+si/2.0,
+		     diagram_data["ysize"]-ypos_for_xaxis+si/1.5,
+		     
+		     xpos_for_yaxis,
+		     diagram_data["ysize"]-ypos_for_xaxis+si/3.0,
+		     
+		     xpos_for_yaxis,
+		     si+labely
+		   }), 
+		   1, 1)[0]);
+    }
+    else
+      if (diagram_data["yminvalue"]>LITET)
+      {
+	graph->
+	  polygone(make_polygon_from_line(
+		     diagram_data["linewidth"], 
+		     ({
+		       xpos_for_yaxis,
+		       diagram_data["ysize"]-diagram_data["linewidth"],
+		       
+		       xpos_for_yaxis,
+		       diagram_data["ysize"]-ypos_for_xaxis-si/3.0,
+		       
+		       xpos_for_yaxis-si/2.0,
+		       diagram_data["ysize"]-ypos_for_xaxis-si/1.5,
+		       
+		       xpos_for_yaxis+si/2.0,
+		       diagram_data["ysize"]-ypos_for_xaxis-si,
+		       
+		       xpos_for_yaxis,
+		       diagram_data["ysize"]-ypos_for_xaxis-si*4.0/3.0,
+		       
+		       xpos_for_yaxis,
+		       si+labely
+		     }), 
+		     1, 1)[0]);
+      }
+    
+  //Draw arrow
+  graph->
+    polygone(
+	     ({
+	       xpos_for_yaxis-
+	       (float)si/4.0,
+	       diagram_data["linewidth"]/2.0+
+	       (float)si+
+	       labely,
+				      
+	       xpos_for_yaxis,
+	       diagram_data["linewidth"]/2.0+
+	       labely,
+	
+	       xpos_for_yaxis+
+	       (float)si/4.0,
+	       diagram_data["linewidth"]/2.0+
+	       (float)si+
+	       labely
+	     })); 
+  
+  //Calculate some shit
+  float xstart=(float)diagram_data["xstart"];
+  float xmore=(-xstart+diagram_data["xstop"])/
+    (diagram_data["xmaxvalue"]-diagram_data["xminvalue"]);
+  float ystart=(float)diagram_data["ystart"];
+  float ymore=(-ystart+diagram_data["ystop"])/
+    (diagram_data["ymaxvalue"]-diagram_data["yminvalue"]);
+  
+  draw_grid(diagram_data, xpos_for_yaxis, ypos_for_xaxis, 
+	    xmore, ymore, xstart, ystart, (float) si);
+  
+  //Paste the texts on the X-axis
+  int s=sizeof(diagram_data["xnamesimg"]);
+  for(int i=0; i<s; i++)
+    if ((diagram_data["values_for_xnames"][i]<diagram_data["xmaxvalue"])&&
+	(diagram_data["values_for_xnames"][i]>diagram_data["xminvalue"]))
+    {
+      graph->setcolor(@diagram_data["textcolor"]);
+      graph->paste_alpha_color(diagram_data["xnamesimg"][i], 
+			       @(diagram_data["textcolor"]), 
+			       (int)floor((diagram_data["values_for_xnames"][i]
+					   - diagram_data["xminvalue"])
+					  * xmore+xstart
+					  - diagram_data["xnamesimg"][i]
+					  -> xsize()/2), 
+			       (int)floor(diagram_data["ysize"]-ypos_for_xaxis
+					  + si/2.0));
+      graph->setcolor(@diagram_data["axcolor"]);
+      graph->
+	polygone(make_polygon_from_line(
+		   diagram_data["linewidth"], 
+		   ({
+		     ((diagram_data["values_for_xnames"][i]
+		       - diagram_data["xminvalue"]) * xmore+xstart),
+		     diagram_data["ysize"]-ypos_for_xaxis+si/4,
+		     ((diagram_data["values_for_xnames"][i]-
+		       diagram_data["xminvalue"])
+		      *xmore+xstart),
+		     diagram_data["ysize"]-ypos_for_xaxis-si/4
+		   }), 
+		   1, 1)[0]);
+    }
+
+  //Paste the tests on the Y-axis
+  s=sizeof(diagram_data["ynamesimg"]);
+  for(int i=0; i<s; i++)
+    if ((diagram_data["values_for_ynames"][i]<diagram_data["ymaxvalue"])&&
+	(diagram_data["values_for_ynames"][i]>diagram_data["yminvalue"]))
+    {
+      graph->setcolor(@diagram_data["textcolor"]);
+      graph->paste_alpha_color(
+               diagram_data["ynamesimg"][i], 
+	       @(diagram_data["textcolor"]), 
+	       (int)floor(xpos_for_yaxis-
+			  si/4.0-diagram_data["linewidth"]-
+			  diagram_data["ynamesimg"][i]->xsize()),
+	       (int)floor(-(diagram_data["values_for_ynames"][i]-
+			    diagram_data["yminvalue"])
+			  *ymore+diagram_data["ysize"]-ystart
+			  - diagram_data["ymaxynames"]/2));
+      graph->setcolor(@diagram_data["axcolor"]);
+      graph->
+	polygone(make_polygon_from_line(
+          diagram_data["linewidth"], 
+	  ({
+	    xpos_for_yaxis - si/4,
+	    (-(diagram_data["values_for_ynames"][i]
+	       - diagram_data["yminvalue"])
+	     *ymore+diagram_data["ysize"]-ystart),
+	    
+	    xpos_for_yaxis+
+	    si/4,
+	    (-(diagram_data["values_for_ynames"][i]-
+	       diagram_data["yminvalue"])
+	     *ymore+diagram_data["ysize"]-ystart)
+	  }), 
+	  1, 1)[0]);
+    }
+
+
+  //Paste labels ({xquantity, yquantity, xunit, yunit})
+  if (diagram_data["labelsize"])
+  {
+    graph->paste_alpha_color(labelimg, 
+			     @(diagram_data["labelcolor"]), 
+			     diagram_data["xsize"]-labelx
+			     - (int)ceil((float)diagram_data["linewidth"]),
+			     diagram_data["ysize"]
+			     - (int)ceil((float)(ypos_for_xaxis-si/2)));
+    
+    string label;
+    int x;
+    int y;
+    GETFONT(yaxisfont);
+    if (diagram_data["labels"][3] && sizeof(diagram_data["labels"][3]))
+      label=diagram_data["labels"][1]+" ["+diagram_data["labels"][3]+"]"; //Ystorhet
+    else
+      label=diagram_data["labels"][1];
+    if ((label!="")&&(label!=0))
+      labelimg=notext->write(UNICODE(label,diagram_data["encoding"]))
+	-> scale(0,diagram_data["labelsize"]);
+    else
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+    
+    if (labelimg->xsize()<1)
+      labelimg=image(diagram_data["labelsize"],diagram_data["labelsize"]);
+    
+    if (labelimg->xsize()>
+	diagram_data["xsize"])
+      labelimg=labelimg->scale(diagram_data["xsize"], 0);
+    
+    
+    x=max(2,((int)floor((float)xpos_for_yaxis)-labelimg->xsize()/2));
+    x=min(x, graph->xsize()-labelimg->xsize());
+      
+    y=0; 
+
+    if (label && sizeof(label))
+      graph->paste_alpha_color(labelimg, 
+			       @(diagram_data["labelcolor"]), x,
+			       2+labely-labelimg->ysize());
+      
+  }
+
+  //Draw the data
+  int farg=0;
+  
+  foreach(diagram_data["data"], array(float) d)
+  {
+    d-=({VOIDSYMBOL});
+    for(int i=0; i<sizeof(d)-1; i++)
+    {
+      d[i]=(d[i]-diagram_data["xminvalue"])*xmore+xstart;
+      i++;
+      d[i]=-(d[i]-diagram_data["yminvalue"])*ymore+diagram_data["ysize"]
+	- ystart;	  
+    }
+
+    graph->setcolor(@(diagram_data["datacolors"][farg++]));
+    
+    draw(graph, diagram_data["linewidth"],d);
+  }
+  
+  diagram_data["ysize"]-=diagram_data["legend_size"];
+  diagram_data["image"]=graph;
+  return diagram_data;
+}
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/create_pie.pike b/lib/modules/Graphics.pmod/Graph.pmod/create_pie.pike
new file mode 100644
index 0000000000000000000000000000000000000000..bd7d191b0621a9722999f39c0cfae9107b62172d
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/create_pie.pike
@@ -0,0 +1,502 @@
+#!NOMODULE
+
+#include "graph.h"
+
+// import Image;
+import Array;
+import Stdio;
+
+inherit "polyline.pike";
+inherit "create_graph.pike";
+inherit "create_bars.pike";
+
+constant cvs_version = "$Id: create_pie.pike,v 1.1 1999/09/30 13:04:05 hedda Exp $";
+
+/*
+ * name = "BG: Create pies";
+ * doc = "Business Graphics sub-module for drawing pie-charts.";
+ */
+
+/*
+These functions were written by Henrik "Hedda" Wallin (hedda@idonex.se)
+Create_pie can draw pie charts in different forms.
+
+The data is taken from the diagram_data-mapping which is described in 
+ doc/diagram_internals.txt
+
+
+*/ 
+
+
+mapping(string:mixed) create_pie(mapping(string:mixed) diagram_data)
+{
+  //Only tested with xsize>=100
+  int si=diagram_data["fontsize"];
+
+  string where_is_ax;
+
+  object(Image.image) piediagram;
+
+  init_bg(diagram_data);
+  piediagram=diagram_data["image"];
+  setinitcolors(diagram_data);
+
+  set_legend_size(diagram_data);
+
+  diagram_data["ysize"]-=diagram_data["legend_size"];
+  
+  //Do the standard init (The init function is in create_graph)
+  init(diagram_data);
+
+  //Initiate values
+  int|void  size=diagram_data["xsize"];
+  array(int|float) numbers=diagram_data["data"][0];
+  void | array(string) names=diagram_data["xnames"];
+  void|int twoD=diagram_data["drawtype"]=="2D";
+  void|array(array(int)) colors=diagram_data["datacolors"];
+  array(int)bg=diagram_data["bgcolor"];
+  array(int)fg=diagram_data["textcolor"];
+  int tone=diagram_data["tone"];
+
+  for(int i; i<sizeof(numbers); i++)
+    if ((float)numbers[i]<0.0)
+      numbers[i]*=-1.0;
+  
+
+
+
+  //////////////////////
+
+
+
+  
+  object* text;
+  object notext;
+  int ymaxtext;
+  int xmaxtext;
+
+  int imysize;
+  int imxsize;
+  float *arr=allocate(802);
+  float *arr2=allocate(802);
+  float *arr3=allocate(802);
+  float *arrplus=allocate(802);
+  float *arrpp=allocate(802);
+
+  int yc;
+  int xc;
+  int xr;
+  int yr;
+
+  mixed sum;
+  int sum2;
+
+  int* pnumbers=allocate(sizeof(numbers));
+  int* order=indices(numbers);
+
+  int edge_nr=0;
+
+
+
+  //create the text objects
+  if (names)
+    text=allocate(sizeof(names));
+   
+  if (diagram_data["3Ddepth"]>diagram_data["ysize"]/5)
+    diagram_data["3Ddepth"]=diagram_data["ysize"]/5;
+  
+  GETFONT(xnamesfont);
+  if (names)
+    if (notext)
+      for(int i=0; i<sizeof(names); i++)
+	{
+	  if ((names[i]!=0) && (names[i]!=""))
+	    text[i]=notext
+	      ->write(UNICODE((string)(names[i]),diagram_data["encoding"]))
+	      ->scale(0,diagram_data["fontsize"]);
+	  else
+	    text[i]=Image.image(diagram_data["fontsize"],
+				diagram_data["fontsize"]);
+
+	  if (text[i]->xsize()<1)
+	    text[i]=Image.image(diagram_data["fontsize"],
+				diagram_data["fontsize"]);
+
+	  if (text[i]->xsize()>diagram_data["xsize"]/5+diagram_data["3Ddepth"])
+	    text[i]=text[i]->scale((int)diagram_data["xsize"]/5, 0);
+
+	  if (text[i]->ysize()>diagram_data["ysize"]/5-diagram_data["3Ddepth"])
+	    text[i]=text[i]->scale(0, (int)diagram_data["ysize"]/5-
+				   diagram_data["3Ddepth"]);
+	  
+	  if (xmaxtext<(text[i]->xsize()))
+	    xmaxtext=text[i]->xsize();
+	  if (ymaxtext<(text[i]->ysize()))
+	    ymaxtext=text[i]->ysize();
+	  
+	}
+    else
+       throw(({"Missing font or similar error!\n", backtrace() }));
+
+  int nameheight=write_name(diagram_data);
+
+  //Some calculations
+  if (twoD)
+    {
+      xc=diagram_data["xsize"]/2;
+      yc=diagram_data["ysize"]/2+nameheight/2;
+      xr=(int)min(xc-xmaxtext-ymaxtext-1-diagram_data["linewidth"], 
+		  yc-2*ymaxtext-
+		  1-diagram_data["linewidth"]-nameheight);
+      yr=xr;
+    }
+  else
+    {
+      xc=diagram_data["xsize"]/2;
+      yc=diagram_data["ysize"]/2-diagram_data["3Ddepth"]/2+nameheight/2;
+      yr=(int)(min(xc-xmaxtext-ymaxtext-1-diagram_data["3Ddepth"]/2, 
+		   yc-2*ymaxtext-1-nameheight)
+	       -diagram_data["linewidth"]);
+      xr=(int)(min(xc-xmaxtext-ymaxtext-1, 
+		   yc+diagram_data["3Ddepth"]/2-
+		   2*ymaxtext-1-nameheight)-
+	       diagram_data["linewidth"]);
+    }
+  float w=diagram_data["linewidth"];
+
+  if (xr<2)
+    throw(({"Image to small for this pie-diagram.\n"
+	    "Try smaller font or bigger image!\n", backtrace() }));
+
+  //initiate the 0.25*% for different numbers:
+  //Ex: If numbers is ({3,3}) pnumbers will be ({200, 200}) 
+  sum=`+(@ numbers);
+  int i;
+
+  if (sum>LITET)
+    {
+      for(int i=0; i<sizeof(numbers); i++)
+	{
+	  float t=(float)(numbers[i]*400)/sum;
+	  pnumbers[i]=(int)floor(t);
+	  numbers[i]=t-floor(t);
+	}
+      
+      
+      //Now the rests are in the numbers-array
+      //We now make sure that the sum of pnumbers is 400.
+      sort(numbers, order);
+      sum2=`+(@ pnumbers);
+      i=sizeof(pnumbers);
+      while(sum2<400)
+	{
+	  pnumbers[order[--i]]++;
+	  sum2++;
+	}  
+    }
+  else
+    if (sizeof(numbers)>1)
+      {
+	for(int i=0; i<sizeof(numbers); i++)
+	  pnumbers[i]=(int)floor(400.0/(float)sizeof(numbers));
+	int j=400-`+(@pnumbers);
+	for(int i=0; i<j; i++)
+	  pnumbers[i]++;
+      }
+    else
+      pnumbers=({400});
+  
+  //Initiate the piediagram!
+  float FI=0;
+  if (diagram_data["center"])
+    {
+      //If to great center integer is given, module is used. 
+      // Center should not be greater than sizeof(data[0]).
+      diagram_data["center"]%=(1+sizeof(numbers));
+      FI=(400-`+(0,@pnumbers[0..diagram_data["center"]-2])
+	-pnumbers[diagram_data["center"]-1]*0.5)*2.0*PI/400.0;
+    }
+  else
+    if (diagram_data["rotate"])
+      FI=((float)(diagram_data["rotate"])*2.0*PI/360.0)%(2*PI);
+  float most_down=yc+yr+w;
+  float most_right=xc+xr+w;
+  float most_left=xc-xr-w;
+
+  for(int i=0; i<401; i++)
+    {
+      arr[2*i]=xc+xr*sin((i*2.0*PI/400.0)+FI);
+      arr[1+2*i]=yc+yr*sin(-PI/2+i*2.0*PI/400.0+FI);
+      arr2[2*i]=xc+(xr+w)*sin((i*2.0*PI/400.0));
+      arr2[2*i+1]=yc+(w+yr)*sin(-PI/2+i*2.0*PI/400.0);
+      arr3[2*i]=xc+(xr+w)*sin((-i*2.0*PI/400.0+FI));
+      arr3[2*i+1]=yc+(w+yr)*sin(-PI/2-i*2.0*PI/400.0+FI);
+    }
+
+  //Draw the slices
+  if (sizeof(diagram_data["datacolors"])>
+      sizeof(diagram_data["data"][0]))
+    diagram_data["datacolors"]=diagram_data["datacolors"]
+      [0..sizeof(diagram_data["data"][0])-1];
+  
+  int t=sizeof(diagram_data["datacolors"]);
+
+  float miniwxr;
+  float miniwyr;
+
+  if (!twoD)
+    {
+      array arrfoo=copy_value(arr2);
+      miniwxr=max((w+xr)/2,(w+xr)-diagram_data["3Ddepth"]/10);
+      miniwyr=max((w+yr)/2,(w+yr)-diagram_data["3Ddepth"]/10);
+      for(int i=200; i<604; i+=2)
+	{
+	  arrfoo[i]=xc+miniwxr*sin((i*PI/400.0));
+	  arrfoo[i+1]=yc+miniwyr*sin(-PI/2+i*PI/400.0)+
+	    diagram_data["3Ddepth"];
+	}
+      //arrfoo[i]=arr2[i]+diagram_data["3Ddepth"];
+      for(int i=0; i<401; i++)
+	{
+	  arrplus[2*i]=xc+(xr+w)*sin((i*2.0*PI/400.0)+FI);
+	  arrplus[1+2*i]=yc+(w+yr)*sin(-PI/2+i*2.0*PI/400.0+FI);
+	  arrpp[2*i]=xc+miniwxr*sin((-i*2.0*PI/400.0)+FI);
+	  arrpp[1+2*i]=yc+miniwyr*sin(-PI/2-i*2.0*PI/400.0+FI)+
+	    diagram_data["3Ddepth"];
+	}
+      object skugg;
+      skugg=Image.image(piediagram->xsize(),piediagram->ysize(), 255,255,255);
+      object foo;
+      foo=Image.image(piediagram->xsize(),piediagram->ysize(), 255,255,255);
+      skugg->tuned_box(xc,yc-yr-1,xc+xr+1,1+yc+yr+diagram_data["3Ddepth"],  
+		       ({			 
+			 ({255,255,255}),
+			 ({100,100,100}),
+			 ({255,255,255}),
+			 ({100,100,100})		      
+		       }));
+      skugg->tuned_box(xc-xr-1,yc-yr-1,xc,1+yc+yr+diagram_data["3Ddepth"],  
+		       ({			 
+			 ({100,100,100}),
+			 ({255,255,255}),
+			 ({100,100,100}),
+			 ({255,255,255})
+		       }));
+      skugg->polyfill(arr2[600..801]+({xc,0,0,0}));
+      skugg->polyfill(
+		      arr2[..201]
+		      +
+		      ({piediagram->xsize()-1,0,xc,0})
+		      );
+      skugg->polyfill(
+		      arr2[200..201]+
+		      arrfoo[200..401]
+		      +
+		      ({xc,piediagram->ysize()-1,
+			piediagram->xsize()-1,piediagram->ysize()-1})
+		      );
+      skugg->polyfill(
+		      arrfoo[400..601]+
+		      arr2[600..601]+
+		      ({0,piediagram->ysize()-1,xc,piediagram->ysize()-1
+		      })
+		      );
+      
+      edge_nr=0;
+      for(i=0; i<t; i++)
+	{
+	  piediagram->setcolor(
+			       @diagram_data["datacolors"][i]
+			       );
+	  
+	  if (pnumbers[i])
+	    {
+	      piediagram->
+		polygone(
+			 (arrplus[2*edge_nr..2*(edge_nr+pnumbers[i]+2)+1]
+			  +
+			   arrpp[800-2*(edge_nr+pnumbers[i]+2)..
+				801-2*edge_nr])
+			 );
+	    }
+	  edge_nr+=pnumbers[i];
+	}
+      piediagram=piediagram*skugg;
+
+      piediagram->setcolor(0,0,0);
+      piediagram->polyfill(
+			   make_polygon_from_line(diagram_data["linewidth"],
+						  ({
+						    xc+(xr+w/2.0), 
+						    yc})+
+						  arrfoo[200..
+							601]+
+						  ({xc-(xr+w/2.0), 
+						    yc}),
+						  0,1)[0]);
+    }
+    
+  edge_nr=0;
+  for(i=0; i<t; i++)
+    {
+      piediagram=piediagram->setcolor(@diagram_data["datacolors"][i]);
+      if (pnumbers[i])
+	piediagram=piediagram->polyfill(({(float)xc,(float)yc})+
+					arr[2*edge_nr..2*(edge_nr+pnumbers[i]+2)+1]);
+      edge_nr+=pnumbers[i];
+    }
+  
+
+
+  edge_nr=pnumbers[0];
+
+  //black borders
+  if (diagram_data["linewidth"]>LITET)
+    {
+      piediagram->setcolor(@diagram_data["axcolor"]);
+      piediagram->polygone(
+				      make_polygon_from_line(diagram_data["linewidth"],
+							     ({
+							       xc,
+							       yc,
+							       arr[0],
+							       arr[1]
+							     })
+							     ,
+							     0, 1)[0]
+				      );
+
+      for(int i=1; i<sizeof(pnumbers); i++)
+	{
+	  piediagram->
+	    polygone(
+		     make_polygon_from_line(diagram_data["linewidth"],
+					    ({xc
+					      ,yc,
+					      arr[2*(edge_nr)],
+					      arr[2*(edge_nr)+1]
+					    })
+					    ,
+					    0, 1)[0]
+		     );
+	  
+	  edge_nr+=pnumbers[i];
+	}
+      piediagram->polygone(arr[..401]
+			   +arr3[400..]);
+      piediagram->polygone(arr[400..]
+			   +arr3[..401]);
+    }
+  
+  piediagram->setcolor(255,255,255);
+  
+  //And now some shading!
+  if (!twoD)
+    {
+      object below;
+      int *b=({70,70,70});
+      int *a=({0,0,0});
+      
+      
+      object tbild;
+
+      int imxsize=piediagram->xsize(); //diagram_data["xsize"];
+      int imysize=piediagram->ysize(); //diagram_data["ysize"]+diagram_data["legendsize"];
+
+      if(tone)
+	{
+	  
+	  
+	  tbild=Image.image(imxsize, imysize, 255, 255, 255)->
+	    tuned_box(0, 0 , 1, imysize,
+		      ({a,a,b,b}));
+	  tbild=tbild->paste(tbild->copy(0,0,0, imysize), 1, 0);
+	  tbild=tbild->paste(tbild->copy(0,0,1, imysize), 2, 0);
+	  tbild=tbild->paste(tbild->copy(0,0,3, imysize), 4, 0);
+	  tbild=tbild->paste(tbild->copy(0,0,7, imysize), 8, 0);
+	  tbild=tbild->paste(tbild->copy(0,0,15, imysize), 16, 0);
+	  if (imxsize>32)
+	    tbild=tbild->paste(tbild->copy(0,0,31, imysize), 32, 0);
+      
+	  if (imxsize>64)
+	    tbild->
+	      paste(tbild->copy(0,0,63, imysize), 64, 0);
+	  if (imxsize>128)
+	    tbild=tbild->paste(tbild->copy(0,0,128, imysize), 128, 0);
+	  if (imxsize>256)
+	    tbild=tbild->paste(tbild->copy(0,0,256, imysize), 256, 0);
+	  if (imxsize>512)
+	    tbild=tbild->paste(tbild->copy(0,0,512, imysize), 512, 0);
+	  piediagram+=tbild;
+	}
+
+      //Vertical lines below
+      edge_nr=(int)(FI*200.0/PI+0.5);
+      piediagram->setcolor(0,0,0);
+      for(int i=0; i<sizeof(pnumbers); i++)
+	{
+	  if (sin(-PI/2+edge_nr*2.0*PI/400.0)>0)
+	    {
+	      
+	      float x1=xc+(xr+w/2.0)*sin((edge_nr*2.0*PI/400.0));
+	      float y1=yc+(w/2.0+yr)*sin(-PI/2+edge_nr*2.0*PI/400.0);
+	      float x2=xc+(miniwxr-w/2.0)*sin((edge_nr*2.0*PI/400.0));
+	      float y2=yc+diagram_data["3Ddepth"]
+		+(miniwyr-w/2.0)*sin(-PI/2+edge_nr*2.0*PI/400.0);
+	      piediagram=piediagram->
+		polygone(
+			 make_polygon_from_line(diagram_data["linewidth"],
+						({
+						  x1,y1,
+						  x2,y2
+						})
+						,
+						0, 1)[0]
+			 );
+	      
+	    }
+	  edge_nr+=pnumbers[i];
+	}
+      
+    }
+
+  
+  //write the text!
+  int|float place;
+  sum=0;
+  if (names)
+    for(int i=0; i<min(sizeof(pnumbers), sizeof(text)); i++)
+      {
+	int t;
+	sum+=pnumbers[i];
+	place=sum-pnumbers[i]/2;
+	if (FI)
+	  {
+	    place=place+FI*400.0/(2.0*PI);
+	    if (place>400)
+	      place=place%400;
+	  }
+	piediagram=piediagram->setcolor(255,0, 0);
+
+	
+	t=(place<202)?0:-text[i]->xsize();
+	int yt=0;
+	if (((place>100)&&(place<300))&&
+	    (!twoD))
+	  yt=diagram_data["3Ddepth"];
+	
+	int ex=text[i]->ysize();
+	int x=(int)(xc +t+ (xr+ex)*sin(place*PI*2.0/400.0+0.0001));
+	int y=(int)(-text[i]->ysize()/2+yc +yt+ 
+		    (yr+ex)*sin(-PI/2.0+place*PI*2.0/400.0+0.0001));
+      
+	piediagram=piediagram->paste_alpha_color(text[i], @fg, x, y);
+      }
+
+  diagram_data["ysize"]-=diagram_data["legend_size"];
+  diagram_data["image"]=piediagram;
+  return diagram_data;
+
+
+
+}
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/doc.txt b/lib/modules/Graphics.pmod/Graph.pmod/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c71521ea938832717ab66ddecf0e6c90f56ebc34
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/doc.txt
@@ -0,0 +1,299 @@
+Graph-doc
+
+Methods
+Image.Image Graphics.Graph.pie(mapping(string:mixed) graphdata)
+Image.Image Graphics.Graph.bars(mapping(string:mixed) graphdata)
+Image.Image Graphics.Graph.sumbars(mapping(string:mixed) graphdata)
+Image.Image Graphics.Graph.line(mapping(string:mixed) graphdata)
+Image.Image Graphics.Graph.norm(mapping(string:mixed) graphdata)
+Image.Image Graphics.Graph.graph(mapping(string:mixed) graphdata)
+
+The mapping graphdata can contain the following (all arguments can be
+left out):
+
+Note: type and subtype is left out.
+
+drawtype   Only "linear" works for now.
+tone       If present a Pie-chart will be toned.
+3Ddepth    How much 3D-depth a graph will have in pixels Default is 10.
+data       An array of arrays. Each array describing a data-set.
+           The graph-function however should be fed with an array
+           of arrays with X,Y-pairs.
+labels     An array(string) with four elements
+           ({xquantity, yquantity, xunit, yunit}). The strings will
+           be written on the axis.
+xnames     An array(string) with the text that will be written under
+           the X-axis. This should be the same size as sizeof(data).
+ynames     An array(string) with the text that will be written to
+           the left of the Y-axis. 
+fontsize   The size of the text. Default is 10.
+labelsize  The size of the text for labels. Default is fontsize.
+legendfontsize The size of the text for the legend. Default is fontsize.
+legend_texts   The texts that will be written the legend. 
+values_for_xnames An array(float) that describes where the ynames should 
+                  be placed. The numbers are like the data-numbers.
+                  Default is equally distributed.
+values_for_ynames An array(float) that describes where the ynames should 
+                  be placed. The numbers are like the data-numbers.
+                  Default is equally distributed.
+xsize      X-size of the graph in pixels. Default is 100.
+ysize      Y-size of the graph in pixels. Default is 100.
+image      An image that the graph will be drawn on.
+legendcolor    The color of the text in the legend. Default is?
+legendimage    I have no idea.
+bgcolor        The bakground-color. If the the background is a image
+               this color is used for antialias the texts.
+gbimage    Some sort of image...
+axcolor    The color of the axis.
+datacolors An array of colors for the datasets. 
+backdatacolors An array of color that do something...
+textcolor  Color of the text. Defualt is black.
+labelcolor Color of the labeltexts.
+orient     Can be "hor" or "vert". 
+linewidth  Width of the lines.
+backlinewidth Width of the outline-lines. Defualt is 0.
+vertgrid   If the vertical grid should be present.
+horgrid    If the horizontal grid should be present.
+gridwidth  Width of the grid. Defualt is linewidth/4.
+rotate     How much a the Pie in a Pie-shart should be rotated in degrees. 
+center     Makes the first Pie-slice be centered.
+bw         Draws the grapf black and white.
+eng        Writes the numbers in eng format.
+neng       Writes the numbers in engformat except for 0.1 < x < 1.0
+xmin       Where the X-axis should start. This will be overrided 
+           by datavalues.
+ymin       Where the Y-axis should start. This will be overrided 
+           by datavalues.
+name       A string with the name of the graph that will be written
+           at top of the graph.
+namecolor  The color of the name.
+font       The font that will be used. Default is Image.Font().
+gridcolor  The color of the grid. Default is black.
+
+
+
+
+
+Diagram info:
+
+Huvud-funktioner:
+create_graph(mapping diagram_data);
+create_bars(mapping diagram_data);
+create_sumbars(mapping diagram_data);
+create_pie(mapping diagram_data);
+
+
+Graphs: 
+Graphs är punkter eller punkter med linjer mellan sig. Punkterna anges
+med x, y.
+Indata på formen x, y, y, y omvandlas av inläsningsfunktionen.
+
+Bars:
+Barsdata består av en lista av listor med värden i. Värdena skrivs
+ut som staplar eller negativa staplar.
+
+Data lagras i ett data-mapping:
+diagram_data
+
+
+string type;
+//Är lika med "graph", "bars", "sumbars", "pie";
+
+string subtype;
+//Är alltid "line" för graph-er. Tänkbara för bars är "line", "dot", "box"  
+//Är "pie" för tårtor?
+//Sumbars: "norm" ger alla staplar lika höga.
+
+//Följande gäller för bars-line och graph-diagram
+string drawtype;
+ "level"; //Om !=0 så är bars-diagrammet bara vågräta streck 
+ "linear"; //Om !=0 så är bars/graph-diagrammet linjärt spline (default)
+ "quadratic"; //Om !=0 så är bars/graph-diagrammet kvadratiskt spline
+ "cubic";//Om !=0 så är bars/graph-diagrammet kubiskt spline 
+ //För bars-box och pie:
+ "2D" - ritar 2D boxar/kakor
+ "3D" - flash!!!
+
+int tone;
+  //Anger om skuggning ska ske
+ 
+float|int 3Ddepth;
+//Anger hur djup 3D ska vara i pixel
+
+array(array(float|string)) data; 
+//Innehåller för graph 
+ // en array med arrayer av typ x-pos1, y-pos1, x-pos2, ...
+//För Bars:
+ // x-data1, x-data2, ...
+//För pie:
+ // value1, value2, ... 
+//Om ett dataelement är lika med "\n" så betyder det VOID
+
+
+array(string) labels;
+//Innehåller en array med ({xstorhet, ystorhet, xenhet, yenhet})
+// För bars kan används inte xenhet
+//Om ett dataelement är lika med "\n" så betyder det VOiD
+
+array(string) xnames;
+//Innehåller en array med olika namn som ska stå längs x-axeln 
+//(t ex jan, feb).
+//Om ett dataelement är lika med "\n" så betyder det VOiD
+
+
+array(string) ynames;
+//Innehåller en array med olika namn som ska stå längs y-axeln (t ex
+//lite, mycket).
+// Dessa namn skrivs i diagrammet av create_pie.
+//Om ett dataelement är lika med "\n" så betyder det VOiD
+
+
+array(object(image)) xnamesimg;
+array(object(image)) ynamesimg;
+//bilderna på x- och ynames.
+
+int xmaxxnames;
+int ymaxxnames;
+int xmaxynames;
+int ymaxynames;
+//Anger max-storleken på text-bilderna.
+
+int fontsize;
+//anger med vilken storlek texten ska skrivas
+
+int labelsize;
+// anger med vilken storlek texten för labels ska skrivas
+// Denna ska sättas till 0 om det inte finns några labels!!!
+
+int legendfontsize;
+//Anger storleken på legend-texten.
+// (Default fontsize)
+//Om den är för stor minskas den. 
+
+int legend_size;
+//Storleken på legenden.
+
+array(string) legend_texts;
+// innehåller texten som ska stå i Legenden.
+// Det ska vara en text per data
+// Är 0 om ingen text ska skrivas ut.
+array(froat) values_for_xnames;
+//Innehåller en array med nivåerna som ska förknippas med vissa xnames.
+//Om dessa inte anges kan de sättas ut jämt.
+//Bars sätter denna själv
+// Dessa namn är de som används av pie-diagramet för legenden.
+//Om ett dataelement är lika med "\n" så betyder det VOID
+
+
+array(froat) values_for_ynames;
+//Innehåller en array med nivåerna som ska förknippas med vissa ynames.
+//Om dessa inte anges kan de sättas ut jämt.
+
+float xmaxvalue, xminvalue, ymaxvalue, yminvalue;
+//anger inom vilka områden man ska förvänta sig data. Minvalue sätts
+//i normala fall till min(0, minsta_värde) och maxvalue till 
+//max(0, största_värde).
+
+
+float xspace, float yspace, 
+//anger hur lång det ska vara mellan utskrifterna av nuffror/xnames/ynames
+
+int xsize, ysize;
+//anger hur stor bild man ska generera.
+
+"image":image-object,
+// Denna kan sättas till bakgrundsbilden innan create_XXX anropas.
+// OBS om den ska användas så måste bgcolor vara 0!!!
+ 
+"xstart": var_i_bilden_vi_kan_börja_rita_data-int, //från höger
+"ystart": var_i_bilden_vi_kan_börja_rita_data-int, //Nerifrån!
+"xstop":int, //från höger
+"ystop":int //Nerifrån!
+
+"legendcolor":({int r, int g, int b}) 
+//bgfärgen på bakgrunden i legenden
+//Om legendcolor är 0 så är det bilden:
+
+"legendimage": object(image) 
+// som ska användas som bakgrundsbild.
+
+"bgcolor":({int r, int g, int b}) 
+//färgen på bakgrunden i bilden
+//Om bgcolor är 0 så är det bilden:
+
+"bgimage": object(image) 
+// som ska användas som bakgrundsbild.
+
+"axcolor":({int r, int g, int b}) 
+//Färgen på axlarna och på outlines i pie
+
+"datacolors":({({int r, int g, int b}), ... }) 
+//Färgen på linjerna/barsen/slicerna
+//För grapher och bars måste de vara av samma antal som antalet 
+//uppsättningar data
+
+"backdatacolors":({({int r, int g, int b}), ... }) 
+//Färgen på kontueren kring linjerna/barsen/slicerna
+//För grapher och bars måste de vara av samma antal som antalet 
+//uppsättningar data
+
+"textcolor":({int r, int g, int b})
+// färgen på texten
+
+"labelcolor":({int r, int g, int b})
+// färgen på labelstexten (default är textcolor):({int r, int g, int b})
+
+"orient":"hor" eller "vert"
+//Anger om skriften på x-axel ska skrivas horizontelt eller vertikalt.
+//hor är default.
+
+"linewidth":float bredd på alla linjer
+
+"backlinewidth":float bredd på alla linjer
+
+"grindwidth":float bredd på alla linjer i grinden
+
+"vertgrind": int om denna är så blir det vertikala grind
+
+"horgrind": int om denna är så blir det horizontella grind
+
+"image":object(image)
+//bilden som grafen ritas i.
+
+"rotate": int|float 
+//How much the pie should be rotated in degres (0-360).
+
+"center": int
+//If center==0 no centration takes place.
+//Else the slice number center-1 will be in the topp.
+
+"datasize": int
+//how many datas there are in the biggest dataset
+
+"bw": int
+//If this is != 0 the graphs are drawn in black and white.
+//The black and white colors are set to be as different as possible
+//If colors are given, bw is ignored
+//the bgpicture or bg is not affected.
+
+"eng": mixed
+//If this is != 0 the information on the axis are presented in
+//engineer-format (120k, 34u (LPC?)) 
+
+"neng": mixed
+//If this is != 0 the information on the axis are presented in
+//Norings engineer-format (120k, 34u, and 0.434) 
+
+"xmin": int
+//If this is !=0 the xaxis starts at the minumum value. 
+"ymin": int
+//If this is !=0 the yaxis starts at the minumum value. 
+
+"name":string
+//The name of the diagram that will be written at the top of the diagram
+
+"namesize":int
+//The size of the name. If it is 0, "fontsize" is used instead.
+
+"namecolor":int
+//The color of the name. If it is 0, "textcolor" is used instead.
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/graph.h b/lib/modules/Graphics.pmod/Graph.pmod/graph.h
new file mode 100644
index 0000000000000000000000000000000000000000..2876beb03151f8f16cd2e48af9eff1caa8814448
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/graph.h
@@ -0,0 +1,30 @@
+/*
+ * name = "BG: diagram.h";
+ * doc = "Business Graphics common things. You must upgrade this component to use newer versions of BG.";
+ *
+ * string cvs_version="$Id: graph.h,v 1.1 1999/09/30 13:04:11 hedda Exp $";
+ */
+
+
+#define max(i, j) (((i)>(j)) ? (i) : (j))
+#define min(i, j) (((i)<(j)) ? (i) : (j))
+// #define abs(arg) ((arg)*(1-2*((arg)<0)))   // Don't do it this way! /grubba
+#define abs(arg) (((arg)<0) ? -(arg) : (arg))
+
+#define PI 3.14159265358979
+#define VOIDSYMBOL "\n"
+#define SEP "\t"
+#define UNICODE(TEXT,ENCODING) Locale.Charset.decoder(ENCODING)->feed(TEXT)->drain()
+
+private constant LITET = 1.0e-38;
+private constant STORTLITET = 1.0e-30;
+private constant STORT = 1.0e30;
+
+
+//This is used in Roxen. Don't work with only Pike
+//#define GETFONT(WHATFONT) object notext=resolve_font(diagram_data->WHATFONT||diagram_data->font);
+#define GETFONT(WHATFONT) object notext=diagram_data->font;
+
+//#define BG_DEBUG 1
+#define error(X) throw( ({ (X), backtrace()[0..sizeof(backtrace())-2] }) )
+
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/module.pmod b/lib/modules/Graphics.pmod/Graph.pmod/module.pmod
new file mode 100644
index 0000000000000000000000000000000000000000..d2cc297d6e41b1b50f723b64ed936ede8f9302b1
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/module.pmod
@@ -0,0 +1,147 @@
+
+#include "graph.h"
+
+import Array;
+import Stdio;
+
+private inherit "polyline.pike";
+private inherit "create_graph.pike";
+private inherit "create_bars.pike";
+private inherit "create_pie.pike";
+private inherit "create_graph.pike";
+
+//This function sets all unset objects in diagram_data and
+//checks some other stuff.
+mapping(string:mixed) check_mapping(mapping(string:mixed) diagram_data, 
+				    string type)
+{
+  mapping m=diagram_data;
+
+  
+  //This maps from mapping entry to defaulvalue
+  //This may be optimized, but I don't think the zeros mather. 
+  //I just wanted all indices to be here. But this will not be
+  //Updated so it is a bad idea in the long run.
+  mapping md=
+    ([
+      "type":1, //This is already checked
+      "subtype":1, //This is already checked
+      "drawtype":"linear", //Will be set to "2D" for pie below
+      "tone":0,
+      "3Ddepth":10,
+      "data":({({1.0}), ({2.0}), 
+	       ({4.0})}), //Will be set to something else with graph
+      "labels":0, //array(string) ({xquantity, yquantity, xunit, yunit})
+      "xnames":0, //array(string) ?
+      "ynames":0, //array(string) ?
+      "fontsize":10,
+      "labelsize":0, //Default is set somewhere else
+      "legendfontsize":0,
+      "legend_texts":0,
+      "values_for_xnames":0,
+      "values_for_ynames":0,
+      //xmaxvalue, xminvalue, ymaxvalue, yminvalue;
+      "xsize":100,
+      "ysize":100,
+      "image":0,
+      "legendcolor":0,
+      "legendimage":0,
+      "bgcolor":0,
+      "gbimage":0,
+      "axcolor":({0,0,0}),
+      "datacolors":0,
+      "backdatacolors":0,
+      "textcolor":({0,0,0}),
+      "labelcolor":0,
+      "orient":"hor",
+      "linewidth":0,
+      "backlinewidth":0,
+      "vertgrid":0,
+      "horgrid":0,
+      "gridwidth":0,
+      "rotate":0,
+      "center":0,
+      "bw":0,
+      "eng":0,
+      "neng":0,
+      "xmin":0,
+      "ymin":0,
+      "name":0,
+      "namecolor":0,
+      "font":Image.Font(),
+      "gridcolor":({0,0,0})
+    ]);
+    foreach(indices(md), string i)
+      if (!m[i]) m[i]=md[i];
+    
+
+    switch(type)
+    {
+    case "pie":  
+      m->type = "pie";
+      m->subtype="pie";
+      md->drawtype="2D";
+      break;
+   case "bars":
+     m->type = "bars";
+     m->subtype = "box";
+     m_delete( m, "drawtype" );
+     break;
+   case "line":
+     m->type = "bars";
+     m->subtype = "line";
+     break;
+   case "norm":
+     m->type = "sumbars";
+     m->subtype = "norm";
+     break;
+   case "graph":
+     m->type = "graph";
+     m->subtype = "line";
+    md->data=({({1.0,1.0}),({2.0,1.0}),({2.0,2.0}),({1.5,1.5})});
+     break;
+   case "sumbars":
+     m->type = "sumbars";
+     break;
+   default:
+     error("This error will never happen error in Diagram.pmod.\n");
+    }
+
+
+  return diagram_data;
+}
+
+Image.Image pie(mapping(string:mixed) diagram_data)
+{
+  check_mapping(diagram_data, "pie");
+  return create_pie(diagram_data)->image;
+} 
+
+Image.Image bars(mapping(string:mixed) diagram_data)
+{
+  check_mapping(diagram_data, "bars");
+  return create_bars(diagram_data)->image;
+} 
+
+Image.Image sumbars(mapping(string:mixed) diagram_data)
+{
+  check_mapping(diagram_data, "sumbars");
+  return create_bars(diagram_data)->image;
+} 
+Image.Image line(mapping(string:mixed) diagram_data)
+{
+  check_mapping(diagram_data, "line");
+  return create_bars(diagram_data)->image;
+} 
+
+Image.Image norm(mapping(string:mixed) diagram_data)
+{
+  check_mapping(diagram_data, "norm");
+  return create_bars(diagram_data)->image;
+} 
+
+Image.Image graph(mapping(string:mixed) diagram_data)
+{
+  check_mapping(diagram_data, "graph");
+  return create_graph(diagram_data)->image;
+} 
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/polyline.pike b/lib/modules/Graphics.pmod/Graph.pmod/polyline.pike
new file mode 100644
index 0000000000000000000000000000000000000000..3033b772f459146ad733a3f77f9b47e4c58ed3d8
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/polyline.pike
@@ -0,0 +1,218 @@
+#!NOMODULE
+/*
+ * name = "BG: Create pies";
+ * doc = "Business Graphics sub-module providing draw functions.";
+ * $Id: polyline.pike,v 1.1 1999/09/30 13:04:17 hedda Exp $
+ */
+
+#define CAP_BUTT       0
+#define CAP_ROUND      1
+#define CAP_PROJECTING 2
+
+#define JOIN_MITER     0
+#define JOIN_ROUND     1
+#define JOIN_BEVEL     2
+
+
+#define CAPSTEPS  10
+#define JOINSTEPS 5
+
+
+constant PI = 3.1415926535897932384626433832795080;
+
+/*
+ * Some optimizations for the cappings.
+ *
+ * /grubba (who got tired of BG beeing so slow)
+ */
+
+static array(float) init_cap_sin_table()
+{
+  array(float) s_t = allocate(CAPSTEPS);
+
+  for (int i = 0; i < CAPSTEPS; i++) {
+    s_t[i] = sin(PI*i/(CAPSTEPS-1));
+  }
+  return(s_t);
+}
+
+static array(float) cap_sin_table = init_cap_sin_table();
+
+static array(float) init_cap_cos_table()
+{
+  array(float) c_t = allocate(CAPSTEPS);
+
+  for (int i = 0; i < CAPSTEPS; i++) {
+    c_t[i] = cos(PI*i/(CAPSTEPS-1));
+  }
+  return(c_t);
+}
+
+static array(float) cap_cos_table = init_cap_cos_table();
+
+
+
+static private array(float) xyreverse(array(float) a)
+{
+  array(float) r = reverse(a);
+  int n = sizeof(r)/2;
+  while(n--) {
+    float t = r[n<<1];
+    r[n<<1] = r[(n<<1)+1];
+    r[(n<<1)+1] = t;
+  }
+  return r;
+}
+
+array(array(float)) make_polygon_from_line(float h, array(float) coords,
+				   int|void cap_style, int|void join_style)
+{
+  int points = sizeof(coords)/2;
+  int closed = points>2 &&
+    coords[0] == coords[(points-1)<<1] &&
+    coords[1] == coords[((points-1)<<1)+1];
+  if(closed)
+    --points;
+  int point;
+  float sx = h/2, sy = 0.0;
+  array(float) left = ({ }), right = ({ });
+
+  for(point=0; point<points; point++) {
+
+    float ox = coords[point<<1], oy = coords[(point<<1)+1];
+    int t = (point==points-1 ? (closed? 0 : point) : point+1);
+    float tx = coords[t<<1], ty = coords[(t<<1)+1];
+    float dx = tx - ox, dy = ty - oy, dd = sqrt(dx*dx + dy*dy);
+    if(dd > 0.0) {
+      sx = (-dy*h) / (dd*2);
+      sy = (dx*h) / (dd*2);
+    }
+
+    if(point == 0 && !closed) {
+
+      /* Initial cap */
+
+      switch(cap_style) {
+      case CAP_BUTT:
+	left += ({ ox+sx, oy+sy });
+	right += ({ ox-sx, oy-sy });
+	break;
+      case CAP_PROJECTING:
+	left += ({ ox+sx-sy, oy+sy+sx });
+	right += ({ ox-sx-sy, oy-sy+sx });
+	break;
+      case CAP_ROUND:
+	array(float) initial_cap = allocate(CAPSTEPS*2);
+	
+	int j=0;
+	for(int i=0; i<CAPSTEPS; i++) {
+	  initial_cap[j++] = ox + sx*cap_cos_table[i] - sy*cap_sin_table[i];
+	  initial_cap[j++] = oy + sy*cap_cos_table[i] + sx*cap_sin_table[i];
+	}
+	right += initial_cap;
+	break;
+      }
+
+    }
+
+    if(closed || point<points-1) {
+
+      /* Interconnecting segment and join */
+
+      if(point == points-2 && !closed)
+	/* Let the final cap generate the segment */
+	continue;
+
+      int t2 = (t==points-1 ? 0 : t+1);
+      float t2x = coords[t2<<1], t2y = coords[(t2<<1)+1];
+      float d2x = t2x - tx, d2y = t2y - ty, d2d = sqrt(d2x*d2x + d2y*d2y);
+      float s2x, s2y;
+      if(d2d > 0.0) {
+	s2x = (-d2y*h) / (d2d*2);
+	s2y = (d2x*h) / (d2d*2);
+      } else {
+	s2x = sx;
+	s2y = sy;
+      }
+
+      float mdiv = (sx*s2y-sy*s2x); 
+      if(mdiv == 0.0) {
+	left += ({ tx+sx, ty+sy, tx+s2x, ty+s2y });
+	right += ({ tx-sx, ty-sy, tx-s2x, ty-s2y });
+      } else {
+	float m = (s2y*(sy-s2y)+s2x*(sx-s2x))/mdiv;
+
+	/* Left join */
+
+	switch(mdiv<0.0 && join_style) {
+	case JOIN_MITER:
+	  left += ({ tx+sx+sy*m, ty+sy-sx*m });
+	  break;
+	case JOIN_BEVEL:
+	  left += ({ tx+sx, ty+sy, tx+s2x, ty+s2y });
+	  break;
+	case JOIN_ROUND:
+	  float theta0 = acos((sx*s2x+sy*s2y)/(sx*sx+sy*sy));
+	  for(int i=0; i<JOINSTEPS; i++) {
+	    float theta = theta0*i/(JOINSTEPS-1);
+	    float sint = sin(theta), cost = cos(theta);
+	    left += ({ tx+sx*cost+sy*sint, ty+sy*cost-sx*sint });
+	  }
+	  break;
+	}
+
+	/* Right join */
+
+	switch(mdiv>0.0 && join_style) {
+	case JOIN_MITER:
+	  right += ({ tx-sx-sy*m, ty-sy+sx*m });
+	  break;
+	case JOIN_BEVEL:
+	  right += ({ tx-sx, ty-sy, tx-s2x, ty-s2y });
+	  break;
+	case JOIN_ROUND:
+	  float theta0 = -acos((sx*s2x+sy*s2y)/(sx*sx+sy*sy));
+	  for(int i=0; i<JOINSTEPS; i++) {
+	    float theta = theta0*i/(JOINSTEPS-1);
+	    float sint = sin(theta), cost = cos(theta);
+	    right += ({ tx-sx*cost-sy*sint, ty-sy*cost+sx*sint });
+	  }
+	  break;
+	}
+      }
+
+    } else {
+
+      /* Final cap */
+
+      switch(cap_style) {
+      case CAP_BUTT:
+	left += ({ ox+sx, oy+sy });
+	right += ({ ox-sx, oy-sy });
+	break;
+      case CAP_PROJECTING:
+	left += ({ ox+sx+sy, oy+sy-sx });
+	right += ({ ox-sx+sy, oy-sy-sx });
+	break;
+      case CAP_ROUND:
+	array(float) end_cap = allocate(CAPSTEPS*2);
+	
+	int j=0;
+	for(int i=0; i<CAPSTEPS; i++) {
+	  end_cap[j++] = ox - sx*cap_cos_table[i] + sy*cap_sin_table[i];
+	  end_cap[j++] = oy - sy*cap_cos_table[i] - sx*cap_sin_table[i];
+	}
+	right += end_cap;
+	break;
+      }
+
+    }
+
+  }
+
+  if(closed)
+    return ({ left, right });
+  else
+    return ({ left + xyreverse(right) });
+
+}
diff --git a/lib/modules/Graphics.pmod/Graph.pmod/test.pike b/lib/modules/Graphics.pmod/Graph.pmod/test.pike
new file mode 100755
index 0000000000000000000000000000000000000000..f09eba3c80f30268a3479caa198bc233e66c9ee7
--- /dev/null
+++ b/lib/modules/Graphics.pmod/Graph.pmod/test.pike
@@ -0,0 +1,10 @@
+#!/usr/local/bin/pike-hubbe
+
+//This should not be a part of this module?
+import ".";
+
+void main()
+{
+  Image.Image image=Diagram.bars((["data":({({1.0,2.0,1.0,2.0})})]));
+  Stdio.write_file("dia.gif", Image.GIF.encode(image));
+}