Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/CHANGELOG
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/CHANGELOG	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/CHANGELOG	(revision 17735)
@@ -0,0 +1,18 @@
+
+Version 0.0.2
+- DEL: ods->setPath2OdsFiles().
+- ADD: Date cell, time cell and datetime cell
+- ADD: Merge cell
+- ADD: Formula
+- ADD: fonts
+- ADD: examples
+
+Version 0.0.1.
+- First version
+- GPL V3
+- Create and insert Cell
+- Color, bold, ...
+- UTF-8
+- Multi table
+- Table split
+- ...
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/COPYING
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/COPYING	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/COPYING	(revision 17735)
@@ -0,0 +1,165 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/VERSION
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/VERSION	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/VERSION	(revision 17735)
@@ -0,0 +1,1 @@
+0.0.2
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsFontFace.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsFontFace.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsFontFace.php	(revision 17735)
@@ -0,0 +1,37 @@
+<?php
+/*-
+ * Copyright (c) 2009 Laurent VUIBERT
+ * License : GNU Lesser General Public License v3
+ */
+
+class odsFontFace {
+	private $fontName; // = "Nimbus Sans L";
+	private $fontFamilyGeneric;
+	private $fontPitch;
+	
+	public function __construct($fontName, $fontFamilyGeneric = null, $fontPitch = 'variable') {
+		$this->fontName          = $fontName;
+		$this->fontFamilyGeneric = $fontFamilyGeneric;
+		$this->fontPitch         = $fontPitch;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$style_font_face = $dom->createElement('style:font-face');
+			$style_font_face->setAttribute("style:name", $this->fontName);
+			$style_font_face->setAttribute("svg:font-family", "'".$this->fontName."'");
+			$style_font_face->setAttribute("style:font-family-generic", $this->fontFamilyGeneric);
+			$style_font_face->setAttribute("style:font-pitch", $this->fontPitch);
+		return $style_font_face;
+	}
+	
+	public function getFontName() {
+		return $this->fontName;
+	}
+	
+	public function getStyles(ods $ods, DOMDocument $dom) {
+		return $this->getContent($ods,$dom);
+	}
+}
+
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsStyle.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsStyle.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsStyle.php	(revision 17735)
@@ -0,0 +1,1365 @@
+<?php
+/*-
+ * Copyright (c) 2009 Laurent VUIBERT
+ * License : GNU Lesser General Public License v3
+ */
+
+abstract class odsStyle {
+	protected $name;
+	protected $family; // table-column, table-row, table, table-cell
+	
+	protected function __construct($name, $family) {
+		if($name == null) $name = $this->getType().'-'.$this->randString();
+		
+		$this->name   = $name;
+		$this->family = $family;
+	}
+	
+	protected function getContent(ods $ods, DOMDocument $dom) {
+		$style_style = $dom->createElement('style:style');
+			$style_style->setAttribute("style:name", $this->name);
+			$style_style->setAttribute("style:family", $this->family);
+		return $style_style;
+	} 
+
+	public function getName() {
+		return $this->name;
+	}
+	
+	public function __clone() {
+		$this->name = 'clone-'.$this->name.'-'.rand(0,99999999999);
+	}
+	
+	public function setName($name) {
+		$this->name = $name;
+	}
+	
+	abstract protected function getType();
+	
+	protected function randString() {
+		return md5(time().rand().$this->getType());
+	}
+	
+}
+
+class odsStyleTableColumn extends odsStyle {
+	private $breakBefore;         // auto
+	private $columnWidth;         // 2.267cm
+	
+	public function __construct($name = null) {
+		parent::__construct($name, "table-column");
+		$this->breakBefore = "auto";
+		$this->columnWidth = "2.267cm";
+	}
+	
+	public function getContent(ods $ods,DOMDocument $dom) {
+		$style_style = parent::getContent($ods,$dom);
+			
+			// style:table-column-properties
+			$style_table_column_properties = $dom->createElement('style:table-column-properties');
+				$style_table_column_properties->setAttribute("fo:break-before", $this->breakBefore);
+				$style_table_column_properties->setAttribute("style:column-width", $this->columnWidth);
+				$style_style->appendChild($style_table_column_properties);
+
+		return $style_style;
+	}
+	
+	public function getType() {
+		return 'odsStyleTableColumn';
+	}
+	
+	public function setColumnWidth($columnWidth) {
+		$this->columnWidth = $columnWidth;
+	}
+	
+	public function setBreakBefore($breakBefore) {
+		$this->breakBefore = $breakBefore;
+	}
+}
+
+class odsStyleTable extends odsStyle {
+	private $masterPageName;      // Default
+	private $display;             // true
+	private $writingMode;         // lr-tb
+
+	public function __construct($name = null) {
+		parent::__construct($name, "table");
+		$this->masterPageName = "Default";
+		$this->display        = "true";
+		$this->writingMode    = "lr-tb";
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$style_style = parent::getContent($ods,$dom);
+			$style_style->setAttribute("style:master-page-name", $this->masterPageName);
+			
+			// style:table-properties
+			$style_table_properties = $dom->createElement('style:table-properties');
+				$style_table_properties->setAttribute("table:display", $this->display);
+				$style_table_properties->setAttribute("style:writing-mode", $this->writingMode);
+				$style_style->appendChild($style_table_properties);
+		return $style_style;
+	}
+	
+	public function getType() {
+		return 'odsStyleTable';
+	}
+}
+
+class odsStyleTableRow extends odsStyle {
+	private $rowHeight;           // 0.52cm
+	private $breakBefore;         // auto
+	private $useOptimalRowHeight; // true, false
+	
+	public function __construct($name = null) {
+		parent::__construct($name, "table-row");
+		$this->rowHeight           = "0.52cm";
+		$this->breakBefore         = "auto";
+		$this->useOptimalRowHeight = "true";
+	}
+
+	public function setRowHeight($rowHeight) {
+		$this->rowHeight = $rowHeight;
+	}
+
+	public function setBreakBefore($breakBefore) {
+		$this->breakBefore = $breakBefore;
+	}
+
+	public function setUseOptimalRowHeight($useOptimalRowHeight) {
+		$this->useOptimalRowHeight = $useOptimalRowHeight;
+	}
+
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$style_style = parent::getContent($ods,$dom);
+			
+			// style:table-row-properties
+			$style_table_row_properties = $dom->createElement('style:table-row-properties');
+				$style_table_row_properties->setAttribute("style:row-height", $this->rowHeight);
+				$style_table_row_properties->setAttribute("fo:break-before", $this->breakBefore);
+				$style_table_row_properties->setAttribute("style:use-optimal-row-height", $this->useOptimalRowHeight);
+				$style_style->appendChild($style_table_row_properties);
+				
+		return $style_style; 
+	}
+	
+	public function getType() {
+		return 'odsStyleTableRow';
+	}
+}
+
+class odsStyleTableCell extends odsStyle {
+	private $parentStyleName;     // Default
+	private $textAlignSource;     // fix
+	private $repeatContent;       // true, false
+	private $color;               // opt: #ffffff
+	private $backgroundColor;     // opt: #ffffff
+	private $border;              // opt: 0.002cm solid #000000
+	private $textAlign;           // opt: center
+	private $marginLeft;          // opt: 0cm
+	private $fontWeight;          // opt: bold
+	private $fontSize;            // opt: 18pt;
+	private $fontStyle;           // opt: italic, normal
+	private $underline;           // opt: font-color, #000000, null
+	private $fontFace;            // opt: fontFace
+	private $styleDataName;       // opt: interne
+	
+	public function __construct($name = null) {
+		parent::__construct($name, "table-cell");
+		$this->parentStyleName     = "Default";
+		$this->textAlignSource     = "fix";
+		$this->repeatContent       = "false";
+		$this->color               = false;
+		$this->backgroundColor     = false;
+		$this->border              = false;
+		$this->textAlign           = false;
+		$this->marginLeft          = false;
+		$this->fontWeight          = false;
+		$this->fontSize            = false;
+		$this->fontStyle           = false;
+		$this->underline           = false;
+		$this->fontFace            = false;
+		$this->styleDataName       = false;
+	}
+	
+	public function setColor($color) {
+		$this->color = $color;
+	}
+	
+	public function setBackgroundColor($color) {
+		$this->backgroundColor = $color;
+	}
+
+	public function setBorder($border) {
+		$this->border = $border;
+	}
+	
+	public function setTextAlign($textAlign) {
+		$this->textAlign = $textAlign;
+	}
+	
+	public function setFontWeight($weight) {
+		$this->fontWeight = $weight;
+	}
+	
+	public function setFontStyle($fontStyle) {
+		$this->fontStyle = $fontStyle;
+	}
+	
+	public function setUnderline($underline) {
+		$this->underline = $underline;
+	}
+	
+	public function setStyleDataName($styleDataName) {
+		$this->styleDataName = $styleDataName;
+	}
+	
+	public function setFontSize($fontSize) {
+		$this->fontSize = $fontSize;
+	}
+	
+	public function setFontFace(odsFontFace $fontFace) {
+		$this->fontFace = $fontFace;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		// style:style
+		$style_style = parent::getContent($ods,$dom);
+			$style_style->setAttribute("style:parent-style-name", $this->parentStyleName);
+			if($this->styleDataName)
+				$style_style->setAttribute("style:data-style-name", $this->styleDataName);
+			
+			// style:table-cell-properties
+			$style_table_cell_properties = $dom->createElement('style:table-cell-properties');
+				$style_table_cell_properties->setAttribute("style:text-align-source", $this->textAlignSource);
+				$style_table_cell_properties->setAttribute("style:repeat-content", $this->repeatContent);
+				
+				if($this->backgroundColor)
+					$style_table_cell_properties->setAttribute("fo:background-color", $this->backgroundColor);
+					
+				if($this->border)
+					$style_table_cell_properties->setAttribute("fo:border", $this->border);
+				
+				$style_style->appendChild($style_table_cell_properties);
+
+				if($this->textAlign) {
+					// style:paragraph-properties
+					$style_paragraph_properties = $dom->createElement('style:paragraph-properties');
+						$style_paragraph_properties->setAttribute("fo:text-align", $this->textAlign);
+						$style_paragraph_properties->setAttribute("fo:margin-left", "0cm");
+						$style_style->appendChild($style_paragraph_properties);
+				}
+				
+				if($this->color OR $this->fontWeight OR $this->fontStyle OR $this->underline OR $this->fontSize OR $this->fontFace) {
+					// style:text-properties
+					$style_text_properties = $dom->createElement('style:text-properties');
+					
+						if($this->color)
+							$style_text_properties->setAttribute("fo:color", $this->color);
+							
+						if($this->fontWeight) {
+							$style_text_properties->setAttribute("fo:font-weight", $this->fontWeight);
+							$style_text_properties->setAttribute("style:font-weight-asian", $this->fontWeight);
+							$style_text_properties->setAttribute("style:font-weight-complex", $this->fontWeight);
+						}
+						
+						if($this->fontStyle) {
+							$style_text_properties->setAttribute("fo:font-style", $this->fontStyle);
+							$style_text_properties->setAttribute("fo:font-style-asian", $this->fontStyle);
+							$style_text_properties->setAttribute("fo:font-style-complex", $this->fontStyle);
+						}
+						
+						if($this->underline) {
+							$style_text_properties->setAttribute("style:text-underline-style", 'solid');
+							$style_text_properties->setAttribute("style:text-underline-width", 'auto');
+							$style_text_properties->setAttribute("style:text-underline-color", $this->underline);
+						}
+						
+						if($this->fontSize) {
+							$style_text_properties->setAttribute("fo:font-size", $this->fontSize);
+							$style_text_properties->setAttribute("style:font-size-asian", $this->fontSize);
+							$style_text_properties->setAttribute("style:font-size-complex", $this->fontSize);
+						}
+						
+						if($this->fontFace) {
+							$style_text_properties->setAttribute("style:font-name", $this->fontFace->getFontName());
+						}
+						
+						$style_style->appendChild($style_text_properties);
+				}
+				
+				
+		return $style_style;
+	}
+	 
+	public function getType() {
+		return 'odsStyleTableCell';
+	}
+}
+
+class odsStyleGraphic extends odsStyle {
+	private $stroke;    // none
+	private $fill;      // none
+ 	private $luminance; // 0%
+ 	private $contrast;  // 0%
+ 	private $gamma;     // 100%
+ 	private $red;       // 0%
+ 	private $green;     // 0%
+ 	private $blue;      // 0%  
+ 	private $opacity;   // 100%
+
+	public function __construct($name = null) {
+		parent::__construct($name, "graphic");
+		$this->stroke    = "none";
+		$this->fill      = "none";
+		$this->luminance = "0%";
+		$this->contrast  = "0%";
+		$this->gamma     = "100%";
+		$this->red       = "0%";
+		$this->green     = "0%";
+		$this->blue      = "0%";
+		$this->opacity   = "100%";
+	}
+	
+	public function setStroke($stroke) {
+		$this->stroke = $stroke;
+	}
+	
+	public function setFill($fill) {
+		$this->fill = $fill;
+	}
+	
+	public function setLuminance($luminance) {
+		$this->luminance = $luminance;
+	}
+	
+	public function setContrast($contrast) {
+		$this->contrast = $contrast;
+	}
+	
+	public function setGamma($gamma) {
+		$this->gamma = $gamma;
+	}
+	
+	public function setRed($red) {
+		$this->red = $red;
+	}
+	
+	public function setGreen($green) {
+		$this->green = $green;
+	}
+	
+	public function setBlue($blue) {
+		$this->blue = $blue;
+	}
+	
+	public function setOpacity($opacity) {
+		$this->opacity = $opacity;
+	}
+	
+	public function getContent(ods $ods,DOMDocument $dom) {
+		$style_style = parent::getContent($ods,$dom);
+		
+			// style:table-row-properties
+			$style_graphic_properties = $dom->createElement('style:graphic-properties');
+				$style_graphic_properties->setAttribute("draw:stroke",        $this->stroke);
+				$style_graphic_properties->setAttribute("draw:fill",          $this->fill);
+				$style_graphic_properties->setAttribute("draw:textarea-horizontal-align", "center");
+				$style_graphic_properties->setAttribute("draw:textarea-vertical-align", "middle");
+				$style_graphic_properties->setAttribute("draw:color-mode", "standard");
+				$style_graphic_properties->setAttribute("draw:luminance",     $this->luminance);
+				$style_graphic_properties->setAttribute("draw:contrast",      $this->contrast);
+				$style_graphic_properties->setAttribute("draw:gamma",         $this->gamma);
+				$style_graphic_properties->setAttribute("draw:red",           $this->red);
+				$style_graphic_properties->setAttribute("draw:green",         $this->green);
+				$style_graphic_properties->setAttribute("draw:blue",          $this->blue);
+				$style_graphic_properties->setAttribute("fo:clip", "rect(0cm, 0cm, 0cm, 0cm)");
+				$style_graphic_properties->setAttribute("draw:image-opacity", $this->opacity);
+				$style_graphic_properties->setAttribute("style:mirror", "none");
+				$style_style->appendChild($style_graphic_properties);
+				
+		return $style_style;
+	}
+
+	public function getType() {
+		return 'odsStyleGraphic';
+	}
+	
+}
+
+
+abstract class odsStyleMoney extends odsStyle {
+	//abstract protected function __construct();
+	//abstract protected function getContent();
+	//abstract protected function getType();
+}
+
+
+class odsStyleMoneyEUR extends odsStyleMoney {
+	
+	public function __construct() {
+		$this->name='NCur-EUR-P0';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_currency_style = $dom->createElement('number:currency-style');
+			$number_currency_style->setAttribute("style:name", "NCur-EUR-P0");
+			$number_currency_style->setAttribute("style:volatile", "true");
+		
+			$number_number = $dom->createElement('number:number');
+				$number_number->setAttribute("number:decimal-places", "2");
+				$number_number->setAttribute("number:min-integer-digits", "1");
+				$number_number->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_number);
+				
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_currency_style->appendChild($number_text);
+		
+			$number_currency_symbol = $dom->createElement('number:currency-symbol', '€');
+				$number_currency_symbol->setAttribute("number:language", "fr");
+				$number_currency_symbol->setAttribute("number:country", "FR");
+				$number_number->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_currency_symbol);
+		return $number_currency_style;
+	}
+	
+	public function getType() {
+		return 'odsStyleMoneyEUR';
+	}
+}
+
+class odsStyleMoneyEURNeg extends odsStyleMoney {
+	
+	public function __construct() {
+		$this->name='NCur-EUR';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+	
+		$number_currency_style = $dom->createElement('number:currency-style');
+			$number_currency_style->setAttribute("style:name", "NCur-EUR");
+	
+			$style_text_properties = $dom->createElement('style:text-properties');
+				$style_text_properties->setAttribute("fo:color", "#ff0000");
+				$number_currency_style->appendChild($style_text_properties);
+	
+			$number_text = $dom->createElement('number:text', '-');
+				$number_currency_style->appendChild($number_text);
+		
+			$number_number = $dom->createElement('number:number');
+				$number_number->setAttribute("number:decimal-places", "2");
+				$number_number->setAttribute("number:min-integer-digits", "1");
+				$number_number->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_number);
+				
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_currency_style->appendChild($number_text);
+		
+			$number_currency_symbol = $dom->createElement('number:currency-symbol', '€');
+				$number_currency_symbol->setAttribute("number:language", "fr");
+				$number_currency_symbol->setAttribute("number:country", "FR");
+				$number_currency_style->appendChild($number_currency_symbol);
+		
+			$style_map = $dom->createElement('style:map');
+				$style_map->setAttribute("style:condition", "value()>=0");
+				$style_map->setAttribute("style:apply-style-name", "NCur-EUR-P0");
+				$number_currency_style->appendChild($style_map);
+
+		return $number_currency_style;
+	}
+
+	public function getType() {
+		return 'odsStyleMoneyEURNeg';
+	}
+}
+
+class odsStyleMoneyUSD extends odsStyleMoney {
+	
+	public function __construct() {
+		$this->name='NCur-USD-P0';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_currency_style = $dom->createElement('number:currency-style');
+			$number_currency_style->setAttribute("style:name", "NCur-USD-P0");
+			$number_currency_style->setAttribute("style:volatile", "true");
+
+			$number_currency_symbol = $dom->createElement('number:currency-symbol', '$');
+				$number_currency_symbol->setAttribute("number:language", "en");
+				$number_currency_symbol->setAttribute("number:country", "US");
+				$number_currency_symbol->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_currency_symbol);
+		
+			$number_number = $dom->createElement('number:number');
+				$number_number->setAttribute("number:decimal-places", "2");
+				$number_number->setAttribute("number:min-integer-digits", "1");
+				$number_number->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_number);
+		return $number_currency_style;
+		
+	}
+	
+	public function getType() {
+		return 'odsStyleMoneyUSD';
+	}
+}
+
+class odsStyleMoneyUSDNeg extends odsStyleMoney {
+	
+	public function __construct(){
+		$this->name='NCur-USD';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_currency_style = $dom->createElement('number:currency-style');
+			$number_currency_style->setAttribute("style:name", "NCur-USD");
+
+			$style_text_properties = $dom->createElement('style:text-properties');
+				$style_text_properties->setAttribute("fo:color", "#ff0000");
+				$number_currency_style->appendChild($style_text_properties);
+
+			$number_text = $dom->createElement('number:text', '-');
+				$number_currency_style->appendChild($number_text);
+		
+			$number_currency_symbol = $dom->createElement('number:currency-symbol', '$');
+				$number_currency_symbol->setAttribute("number:language", "en");
+				$number_currency_symbol->setAttribute("number:country", "US");
+				$number_currency_style->appendChild($number_currency_symbol);
+		
+			$number_number = $dom->createElement('number:number');
+				$number_number->setAttribute("number:decimal-places", "2");
+				$number_number->setAttribute("number:min-integer-digits", "1");
+				$number_number->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_number);
+								
+			$style_map = $dom->createElement('style:map');
+				$style_map->setAttribute("style:condition", "value()>=0");
+				$style_map->setAttribute("style:apply-style-name", "NCur-USD-P0");
+				$number_currency_style->appendChild($style_map);
+		return $number_currency_style;
+	}
+	
+	public function getType() {
+		return 'odsStyleMoneyUSDNeg';
+	}
+}
+
+class odsStyleMoneyGBP extends odsStyleMoney {
+	
+	public function __construct() {
+		$this->name='NCur-GBP-P0';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_currency_style = $dom->createElement('number:currency-style');
+			$number_currency_style->setAttribute("style:name", "NCur-GBP-P0");
+			$number_currency_style->setAttribute("style:volatile", "true");
+
+			$number_currency_symbol = $dom->createElement('number:currency-symbol', '£');
+				$number_currency_symbol->setAttribute("number:language", "en");
+				$number_currency_symbol->setAttribute("number:country", "GB");
+				$number_currency_style->appendChild($number_currency_symbol);
+		
+			$number_number = $dom->createElement('number:number');
+				$number_number->setAttribute("number:decimal-places", "2");
+				$number_number->setAttribute("number:min-integer-digits", "1");
+				$number_number->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_number);
+		return $number_currency_style;
+	}
+	
+	public function getType() {
+		return 'odsStyleMoneyGBP';
+	}
+}
+
+class odsStyleMoneyGBPNeg extends odsStyleMoney {
+	
+	public function __construct() {
+		$this->name='NCur-GBP';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_currency_style = $dom->createElement('number:currency-style');
+			$number_currency_style->setAttribute("style:name", "NCur-GBP");
+
+			$style_text_properties = $dom->createElement('style:text-properties');
+				$style_text_properties->setAttribute("fo:color", "#ff0000");
+				$number_currency_style->appendChild($style_text_properties);
+
+			$number_text = $dom->createElement('number:text', '-');
+				$number_currency_style->appendChild($number_text);
+		
+			$number_currency_symbol = $dom->createElement('number:currency-symbol', '£');
+				$number_currency_symbol->setAttribute("number:language", "en");
+				$number_currency_symbol->setAttribute("number:country", "GB");
+				$number_currency_style->appendChild($number_currency_symbol);
+		
+			$number_number = $dom->createElement('number:number');
+				$number_number->setAttribute("number:decimal-places", "2");
+				$number_number->setAttribute("number:min-integer-digits", "1");
+				$number_number->setAttribute("number:grouping", "true");
+				$number_currency_style->appendChild($number_number);
+								
+			$style_map = $dom->createElement('style:map');
+				$style_map->setAttribute("style:condition", "value()>=0");
+				$style_map->setAttribute("style:apply-style-name", "NCur-GBP-P0");
+				$number_currency_style->appendChild($style_map);
+		return $number_currency_style;
+	}
+	
+	public function getType() {
+		return 'odsStyleMoneyGBPNeg';
+	}
+}
+
+abstract class odsStyleDate extends odsStyle {
+	protected $language;
+	
+	protected function setLanguage($number_date_style) {
+		if(!isset($this->language)) return;
+		$number_date_style->setAttribute("number:language", $this->language);
+		$number_date_style->setAttribute("number:country", $this->language);
+	}
+}
+
+class odsStyleDateMMDDYYYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-MMDDYYYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_day = $dom->createElement('number:day');
+				$number_day->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_year->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateMMDDYYYY';
+	}
+}
+
+class odsStyleDateMMDDYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-MMDDYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_day = $dom->createElement('number:day');
+				$number_day->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateMMDDYY';
+	}
+}
+
+class odsStyleDateDDMMYYYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-DDMMYYYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_day->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+	
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_year->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDDMMYYYY';
+	}
+}
+
+class odsStyleDateDDMMYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-DDMMYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_day->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+	
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDDMMYY';
+	}
+}
+
+class odsStyleDateDMMMYYYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-DMMMYYYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+	
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:textual", "true");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_year->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDMMMYYYY';
+	}
+}
+
+class odsStyleDateDMMMYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-DMMMYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+	
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:textual", "true");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDMMMYY';
+	}
+}
+
+class odsStyleDateDMMMMYYYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-DMMMMYYYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+	
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:textual", "true");
+				$number_month->setAttribute(" number:style", "long");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_year->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDMMMMYYYY';
+	}
+}
+
+class odsStyleDateDMMMMYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-DMMMMYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+	
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:textual", "true");
+				$number_month->setAttribute(" number:style", "long");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDMMMMYY';
+	}
+}
+
+class odsStyleDateMMMDYYYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-MMMDYYYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:textual", "true");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);	
+
+			$number_text = $dom->createElement('number:text', ', ');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_year->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDMMMMYY';
+	}
+}
+
+class odsStyleDateMMMDYY extends odsStyleDate {
+	public function __construct($language) {
+		$this->name='Date-MMMDYY';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_month->setAttribute("number:textual", "true");
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);	
+
+			$number_text = $dom->createElement('number:text', ', ');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateDMMMM';
+	}
+}
+
+abstract class odsStyleTime extends odsStyle {
+}
+
+class odsStyleTimeHHMMSS extends odsStyleTime {
+	public function __construct() {
+		$this->name='Time-HHMMSS';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_time_style = $dom->createElement('number:time-style');
+			$number_time_style->setAttribute("style:name", $this->name);
+			
+			$number_hours = $dom->createElement('number:hours');
+				$number_hours->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_time_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+				$number_minutes->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_minutes);	
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_time_style->appendChild($number_text);
+
+			$number_seconds = $dom->createElement('number:seconds');
+				$number_seconds->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_seconds);	
+			
+		return $number_time_style;
+	}
+
+	public function getType() {
+		return 'odsStyleTimeHHMMSS';
+	}
+}
+
+class odsStyleTimeHHMM extends odsStyleTime {
+	public function __construct() {
+		$this->name='Time-HHMM';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_time_style = $dom->createElement('number:time-style');
+			$number_time_style->setAttribute("style:name", $this->name);
+			
+			$number_hours = $dom->createElement('number:hours');
+				$number_hours->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_time_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+				$number_minutes->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_minutes);	
+			
+		return $number_time_style;
+	}
+
+	public function getType() {
+		return 'odsStyleTimeHHMM';
+	}
+}
+
+class odsStyleTimeHHMMSSAMPM extends odsStyleTime {
+	public function __construct() {
+		$this->name='Time-HHMMSSAMPM';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_time_style = $dom->createElement('number:time-style');
+			$number_time_style->setAttribute("style:name", $this->name);
+			
+			$number_hours = $dom->createElement('number:hours');
+				$number_hours->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_time_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+				$number_minutes->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_minutes);	
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_time_style->appendChild($number_text);
+
+			$number_seconds = $dom->createElement('number:seconds');
+				$number_seconds->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_seconds);	
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_time_style->appendChild($number_text);
+
+			$number_am_pm = $dom->createElement('number:am-pm');
+				$number_am_pm->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_am_pm);	
+			
+		return $number_time_style;
+	}
+
+	public function getType() {
+		return 'odsStyleTimeHHMMSSAMPM';
+	}
+}
+
+class odsStyleTimeHHMMAMPM extends odsStyleTime {
+	public function __construct() {
+		$this->name='Time-HHMMAMPM';
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_time_style = $dom->createElement('number:time-style');
+			$number_time_style->setAttribute("style:name", $this->name);
+			
+			$number_hours = $dom->createElement('number:hours');
+				$number_hours->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_time_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+				$number_minutes->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_minutes);	
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_time_style->appendChild($number_text);
+			
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_am_pm = $dom->createElement('number:am-pm');
+				$number_am_pm->setAttribute("number:style", "long");
+				$number_time_style->appendChild($number_am_pm);	
+			
+		return $number_time_style;
+	}
+
+	public function getType() {
+		return 'odsStyleTimeHHMMAMPM';
+	}
+}
+
+abstract class odsStyleDateTime extends odsStyleDate {
+}
+
+class odsStyleDateTimeMMDDYYHHMMSSAMPM extends odsStyleDateTime {
+	public function __construct($language) {
+		$this->name='DateTime-MMDDYYHHMMSSAMPM';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);	
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_hours = $dom->createElement('number:hours');
+			$number_hours->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_date_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+			$number_minutes->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_minutes);
+				
+			$number_text = $dom->createElement('number:text', ':');
+				$number_date_style->appendChild($number_text);
+
+			$number_seconds = $dom->createElement('number:seconds');
+				$number_seconds->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_seconds);
+				
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+			
+			$number_am_pm = $dom->createElement('number:am-pm');
+				$number_date_style->appendChild($number_am_pm);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateTimeMMDDYYHHMMSSAMPM';
+	}
+}
+
+class odsStyleDateTimeMMDDYYHHMMAMPM extends odsStyleDateTime {
+	public function __construct($language) {
+		$this->name='DateTime-MMDDYYHHMMAMPM';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);	
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_hours = $dom->createElement('number:hours');
+			$number_hours->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_date_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+			$number_minutes->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_minutes);
+			
+			$number_am_pm = $dom->createElement('number:am-pm');
+				$number_date_style->appendChild($number_am_pm);
+			
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateTimeMMDDYYHHMMAMPM';
+	}
+}
+
+class odsStyleDateTimeDDMMYYHHMMSS extends odsStyleDateTime {
+	public function __construct($language) {
+		$this->name='DateTime-DDMMYYHHMMSS';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);	
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_hours = $dom->createElement('number:hours');
+			$number_hours->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_date_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+			$number_minutes->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_minutes);
+				
+			$number_text = $dom->createElement('number:text', ':');
+				$number_date_style->appendChild($number_text);
+
+			$number_seconds = $dom->createElement('number:seconds');
+				$number_seconds->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_seconds);
+				
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateTimeDDMMYYHHMMSS';
+	}
+}
+
+class odsStyleDateTimeDDMMYYHHMM extends odsStyleDateTime {
+	public function __construct($language) {
+		$this->name='DateTime-DDMMYYHHMM';
+		$this->language = $language;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$number_date_style = $dom->createElement('number:date-style');
+			$number_date_style->setAttribute("style:name", $this->name);
+			$number_date_style->setAttribute("number:automatic-order", "true");
+			$this->setLanguage($number_date_style);
+			
+			$number_day = $dom->createElement('number:day');
+				$number_date_style->appendChild($number_day);	
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+			
+			$number_month = $dom->createElement('number:month');
+				$number_date_style->appendChild($number_month);
+
+			$number_text = $dom->createElement('number:text', '/');
+				$number_date_style->appendChild($number_text);
+
+			$number_year = $dom->createElement('number:year');
+				$number_date_style->appendChild($number_year);
+
+			$number_text = $dom->createElement('number:text', ' ');
+				$number_date_style->appendChild($number_text);
+
+			$number_hours = $dom->createElement('number:hours');
+			$number_hours->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_hours);
+
+			$number_text = $dom->createElement('number:text', ':');
+				$number_date_style->appendChild($number_text);
+
+			$number_minutes = $dom->createElement('number:minutes');
+			$number_minutes->setAttribute("number:style", "long");
+				$number_date_style->appendChild($number_minutes);
+				
+		return $number_date_style;
+	}
+
+	public function getType() {
+		return 'odsStyleDateTimeDDMMYYHHMM';
+	}
+}
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTable.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTable.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTable.php	(revision 17735)
@@ -0,0 +1,221 @@
+<?php
+/*-
+ * Copyright (c) 2009 Laurent VUIBERT
+ * License : GNU Lesser General Public License v3
+ */
+
+class odsTable {
+	private $name;
+	private $styleName;
+	private $print;
+	
+	private $cursorPositionX;
+	private $cursorPositionY;
+	private $horizontalSplitMode;
+	private $verticalSplitMode;
+	private $horizontalSplitPosition;
+	private $verticalSplitPosition;
+	private	$positionLeft;
+	private	$positionRight;
+	private	$positionTop;
+	private	$positionBottom;
+	
+	
+	private $tableColumns;
+	private $rows;
+	
+	public function __construct($name, $odsStyleTable = null) {
+		$this->name                         = $name;
+		if($odsStyleTable) $this->styleName = $odsStyleTable->getName;
+		else               $this->styleName = "ta1";
+		$this->print                        = "false";
+		
+		$this->cursorPositionX              = 0;
+		$this->cursorPositionY              = 0;
+		$this->horizontalSplitMode          = 0;
+		$this->verticalSplitMode            = 0;
+		$this->horizontalSplitPosition      = 0;
+		$this->verticalSplitPosition        = 0;
+		$this->positionLeft                 = 0;
+		$this->positionRight                = 0;
+		$this->positionTop                  = 0;
+		$this->positionBottom               = 0;
+		
+		$this->tableColumns                 = array();
+		$this->rows                         = array();
+	}
+	
+	public function getName() {
+		return $this->name;
+	}
+	
+	public function setHorizontalSplit($colones = 1) {
+		$this->setHorizontalSplitMode(2);
+		$this->setHorizontalSplitPosition($colones);
+		$this->setPositionRight($colones);
+	}
+	
+	public function setVerticalSplit($lines = 1) {
+		$this->setVerticalSplitMode(2);
+		$this->setVerticalSplitPosition($lines);
+		$this->setPositionBottom($lines);
+	}
+	
+	public function addRow($odsTableRow) {
+		array_push($this->rows,$odsTableRow);
+	}
+	
+	public function addTableColumn($odsTableColumn) {
+		array_push($this->tableColumns, $odsTableColumn);
+	}
+	
+	public function setCursorPositionX($cursorPositionX) {
+		$this->cursorPositionX = $cursorPositionX;
+	}
+
+	public function setCursorPositionY($cursorPositionY) {
+		$this->cursorPositionY = $cursorPositionY;
+	}
+	
+	public function setHorizontalSplitMode($horizontalSplitMode) {
+		$this->horizontalSplitMode = $horizontalSplitMode;
+	}
+
+	public function setVerticalSplitMode($verticalSplitMode) {
+		$this->verticalSplitMode = $verticalSplitMode; 
+	}
+	
+	public function setHorizontalSplitPosition($horizontalSplitPosition) {
+		$this->horizontalSplitPosition = $horizontalSplitPosition;
+	}
+	
+	public function setVerticalSplitPosition($verticalSplitPosition) {
+		$this->verticalSplitPosition = $verticalSplitPosition;
+	}
+	
+	public function setPositionLeft($positionLeft) {
+		$this->positionLeft = $positionLeft;
+	}
+	
+	public function setPositionRight($positionRight) {
+		$this->positionRight = $positionRight;
+	}
+	
+	public function setPositionTop($positionTop) {
+		$this->positionTop = $positionTop;
+	}
+	
+	public function setPositionBottom($positionBottom) {
+		$this->positionBottom = $positionBottom;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$table_table = $dom->createElement('table:table');
+			$table_table->setAttribute("table:name", $this->name);
+			$table_table->setAttribute("table:style-name", $this->styleName);
+			$table_table->setAttribute("table:print", $this->print);
+			
+			if(count($this->tableColumns)) {
+				foreach($this->tableColumns as $tableColumn) 
+					$table_table->appendChild($tableColumn->getContent($ods,$dom));
+			} else {
+				$column = new odsTableColumn($ods->getStyleByName('co1'));
+				$table_table->appendChild($column->getContent($ods,$dom));
+			}
+
+			if(count($this->rows)) {
+				foreach($this->rows as $row) 
+					$table_table->appendChild($row->getContent($ods,$dom));
+			} else {
+				$row = new odsTableRow();
+				$table_table->appendChild($row->getContent($ods,$dom));
+			}
+				
+		return $table_table;
+	}
+	
+	public function getSettings(ods $ods, DOMDocument $dom) {
+		$config_config_item_map_entry2 = $dom->createElement('config:config-item-map-entry');
+			$config_config_item_map_entry2->setAttribute("config:name", $this->name);
+			//$config_config_item_map_named->appendChild($config_config_item_map_entry2);
+			
+			$config_config_item = $dom->createElement('config:config-item',$this->cursorPositionX);
+				$config_config_item->setAttribute("config:name", "CursorPositionX");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+			
+			$config_config_item = $dom->createElement('config:config-item',$this->cursorPositionY);
+				$config_config_item->setAttribute("config:name", "CursorPositionY");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+	
+			$config_config_item = $dom->createElement('config:config-item',$this->horizontalSplitMode);
+				$config_config_item->setAttribute("config:name", "HorizontalSplitMode");
+				$config_config_item->setAttribute("config:type", "short");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item', $this->verticalSplitMode);
+				$config_config_item->setAttribute("config:name", "VerticalSplitMode");
+				$config_config_item->setAttribute("config:type", "short");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',$this->horizontalSplitPosition);
+				$config_config_item->setAttribute("config:name", "HorizontalSplitPosition");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+		
+			$config_config_item = $dom->createElement('config:config-item',$this->verticalSplitPosition);
+				$config_config_item->setAttribute("config:name", "VerticalSplitPosition");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',2);
+				$config_config_item->setAttribute("config:name", "ActiveSplitRange");
+				$config_config_item->setAttribute("config:type", "short");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',$this->positionLeft);
+				$config_config_item->setAttribute("config:name", "PositionLeft");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',$this->positionRight);
+				$config_config_item->setAttribute("config:name", "PositionRight");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',$this->positionTop);
+				$config_config_item->setAttribute("config:name", "PositionTop");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',$this->positionBottom);
+				$config_config_item->setAttribute("config:name", "PositionBottom");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',0);
+				$config_config_item->setAttribute("config:name", "ZoomType");
+				$config_config_item->setAttribute("config:type", "short");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',100);
+				$config_config_item->setAttribute("config:name", "ZoomValue");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',60);
+				$config_config_item->setAttribute("config:name", "PageViewZoomValue");
+				$config_config_item->setAttribute("config:type", "int");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+
+			$config_config_item = $dom->createElement('config:config-item',"true");
+				$config_config_item->setAttribute("config:name", "ShowGrid");
+				$config_config_item->setAttribute("config:type", "boolean");
+				$config_config_item_map_entry2->appendChild($config_config_item);
+		
+		return $config_config_item_map_entry2;
+	}
+}
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableCell.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableCell.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableCell.php	(revision 17735)
@@ -0,0 +1,503 @@
+<?php
+/*-
+ * Copyright (c) 2009 Laurent VUIBERT
+ * License : GNU Lesser General Public License v3
+ */
+
+abstract class odsTableCell {
+	protected $styleName;
+	protected $numberColumnsSpanned;
+	protected $numberRowsSpanned;
+	protected $formula;
+	protected $numberColumnsRepeated;
+	
+	abstract protected function __construct();
+	
+	protected function getContent(ods $ods, DOMDocument $dom) {
+		$table_table_cell = $dom->createElement('table:table-cell');
+		if( $this->styleName ) {
+			$ods->addTmpStyles($this->styleName);
+			$table_table_cell->setAttribute("table:style-name", $this->styleName->getName());
+		}
+		$this->cellOpts($table_table_cell);
+		return $table_table_cell;
+	}
+	
+	protected function cellOpts( $table_table_cell ) {
+		if($this->numberColumnsSpanned)
+			$table_table_cell->setAttribute("table:number-columns-spanned", $this->numberColumnsSpanned);
+		if($this->numberRowsSpanned)
+			$table_table_cell->setAttribute("table:number-rows-spanned", $this->numberRowsSpanned);
+		if($this->formula)
+			$table_table_cell->setAttribute("table:formula", "of:=".$this->formula);
+		if($this->numberColumnsRepeated)
+			$table_table_cell->setAttribute("table:number-columns-repeated", $this->numberColumnsRepeated);
+	}
+	
+	public function setNumberColumnsSpanned($numberColumnsSpanned) {
+		$this->numberColumnsSpanned = $numberColumnsSpanned;
+	}
+	
+	public function getNumberColumnsSpanned() {
+		if(!$this->numberColumnsSpanned) return 1;
+		return $this->numberColumnsSpanned;
+	}
+	
+	public function setNumberRowsSpanned($numberRowsSpanned) {
+		$this->numberRowsSpanned = $numberRowsSpanned;
+	}
+	
+	public function setFormula($formula) {
+		$this->formula = $formula;
+	}
+	
+	public function setNumberColumnsRepeated($numberColumnsRepeated) {
+		$this->numberColumnsRepeated = $numberColumnsRepeated;
+	}
+	
+}
+
+class odsTableCellEmpty extends odsTableCell {
+	
+	public function __construct(odsStyleTableCell $odsStyleTableCell = null) {
+		$this->styleName = $odsStyleTableCell;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		return odsTableCell::getContent($ods,$dom);
+	}
+}
+
+class odsCoveredTableCell extends odsTableCell {
+	public function __construct() {}
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$table_table_cell = $dom->createElement('table:covered-table-cell');
+		$this->cellOpts($table_table_cell); 
+		return $table_table_cell;
+	}
+}
+
+class odsTableCellStringHttp extends odsTableCell {
+	public $value;
+	public $styleName;
+	
+	public function __construct($value,odsStyleTableCell $odsStyleTableCell = null) {
+		$this->value = $value;
+		$this->styleName = $odsStyleTableCell;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$table_table_cell = odsTableCell::getContent($ods,$dom);
+			$table_table_cell->setAttribute("office:value-type", "string");
+			
+			// text:p
+			$text_p = $dom->createElement('text:p',$this->value);
+				$table_table_cell->appendChild($text_p);
+		return $table_table_cell;
+	}
+}
+
+class odsTableCellString extends odsTableCellStringHttp {
+	public function __construct($value,odsStyleTableCell $odsStyleTableCell = null) {
+		$this->value = str_replace('&', '&amp;', $value);
+		$this->styleName = $odsStyleTableCell;
+	}
+}
+
+class odsTableCellStringEmail extends odsTableCellString {
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$table_table_cell = odsTableCell::getContent($ods,$dom);
+			$table_table_cell->setAttribute("office:value-type", "string");
+			
+			// text:p
+			$text_p = $dom->createElement('text:p');
+				$table_table_cell->appendChild($text_p);
+				
+				// text:a
+				$text_a = $dom->createElement('text:a',$this->value);
+					$text_a->setAttribute("xlink:href", "mailto:".$this->value);
+					$text_p->appendChild($text_a);
+		return $table_table_cell;
+	}
+}
+
+class odsTableCellStringUrl extends odsTableCellString {
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$table_table_cell = odsTableCell::getContent($ods,$dom);
+			$table_table_cell->setAttribute("office:value-type", "string");
+			
+			// text:p
+			$text_p = $dom->createElement('text:p');
+				$table_table_cell->appendChild($text_p);
+				
+				// text:a
+				$text_a = $dom->createElement('text:a',$this->value);
+					$text_a->setAttribute("xlink:href", (substr($this->value,0,7)=="http://"?'':"http://").$this->value);
+					$text_p->appendChild($text_a);
+		return $table_table_cell;
+	}
+}
+
+
+
+class odsTableCellFloat extends odsTableCell {
+	public $value;
+	public $styleName;
+	
+	public function __construct($value,odsStyleTableCell $odsStyleTableCell = null) {
+		$this->value = $value;
+		$this->styleName = $odsStyleTableCell;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$table_table_cell = odsTableCell::getContent($ods,$dom);
+			$table_table_cell->setAttribute("office:value-type", "float");
+			$table_table_cell->setAttribute("office:value", $this->value);
+			
+			// text:p
+			$text_p = $dom->createElement('text:p',$this->value);
+				$table_table_cell->appendChild($text_p);
+		return $table_table_cell;
+	}
+}
+
+class odsTableCellCurrency extends odsTableCell {
+	public $value;
+	public $styleName;
+	public $currency;
+	
+	public function __construct($value, $currency, $odsStyleTableCell = null) {
+		$this->value    = $value;
+		$this->currency = $currency;
+		$this->styleName = $odsStyleTableCell;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		switch($this->currency) {
+		case 'EUR':
+			$ods->addTmpStyles(new odsStyleMoneyEUR());
+			$ods->addTmpStyles(new odsStyleMoneyEURNeg());
+			break;
+		case 'USD':
+			$ods->addTmpStyles(new odsStyleMoneyUSD());
+			$ods->addTmpStyles(new odsStyleMoneyUSDNeg());
+			break;
+		case 'GBP':
+			$ods->addTmpStyles(new odsStyleMoneyGBP());
+			$ods->addTmpStyles(new odsStyleMoneyGBPNeg());
+			break;
+		default:
+			//FIXME: send error;
+		}
+
+		$table_table_cell = $dom->createElement('table:table-cell');
+		$this->cellOpts($table_table_cell);
+			if( $this->styleName ) {
+				$style = $ods->getStyleByName($this->styleName->getName()."-".$this->currency);
+				if(!$style) {
+					$style = clone $this->styleName;
+					$style->setName($this->styleName->getName()."-".$this->currency);
+					$style->setStyleDataName('NCur-'.$this->currency);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			} else {
+				$style = $ods->getStyleByName("ce1-".$this->currency);
+				if(!$style) {
+					$style = clone $ods->getStyleByName("ce1");
+					$style->setName("ce1-".$this->currency);
+					$style->setStyleDataName('NCur-'.$this->currency);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			}
+			
+			$table_table_cell->setAttribute("office:value-type", "currency");
+			$table_table_cell->setAttribute("office:currency", $this->currency);
+			$table_table_cell->setAttribute("office:value", $this->value);
+			
+			// text:p
+			$text_p = $dom->createElement('text:p');
+				$table_table_cell->appendChild($text_p);
+			
+		return $table_table_cell;
+	}
+}
+
+class odsTableCellDate extends odsTableCell {
+	private $date;
+	private $format;
+	private $language;
+	
+	public function __construct($date,  $format="MMDDYYYY", $language=null, odsStyleGraphic $odsStyleCellDate = null) {
+		$this->date = $date;
+		$this->format = $format;
+		$this->language = $language;
+		$this->styleName = $odsStyleCellDate;
+	}
+		
+	public function getContent(ods $ods, DOMDocument $dom) {
+		switch($this->format) {
+		case 'DDMMYYYY':
+			$ods->addTmpStyles(new odsStyleDateDDMMYYYY($this->language));
+			break;
+		case 'DDMMYY':
+			$ods->addTmpStyles($style = new odsStyleDateDDMMYY($this->language));
+			break;
+		case 'MMDDYYYY':
+			$ods->addTmpStyles($style = new odsStyleDateMMDDYYYY($this->language));
+			break;
+		case 'MMDDYY':
+			$ods->addTmpStyles($style = new odsStyleDateMMDDYY($this->language));
+			break;
+		case 'DMMMYYYY':
+			$ods->addTmpStyles($style = new odsStyleDateDMMMYYYY($this->language));
+			break;
+		case 'DMMMYY':
+			$ods->addTmpStyles($style = new odsStyleDateDMMMYY($this->language));
+			break;
+		case 'DMMMMYYYY':
+			$ods->addTmpStyles($style = new odsStyleDateDMMMMYYYY($this->language));
+			break;
+		case 'DMMMMYY':
+			$ods->addTmpStyles($style = new odsStyleDateDMMMMYY($this->language));
+			break;
+		case 'MMMDYYYY':
+			$ods->addTmpStyles($style = new odsStyleDateMMMDYYYY($this->language));
+			break;
+		case 'MMMDYY':
+			$ods->addTmpStyles($style = new odsStyleDateMMMDYY($this->language));
+			break;
+		default:
+			//FIXME: send error;
+		}
+		
+		$table_table_cell = $dom->createElement('table:table-cell');
+		$this->cellOpts($table_table_cell);
+		
+		if( $this->styleName ) {
+				$style = $ods->getStyleByName($this->styleName->getName()."-".$this->format);
+				if(!$style) {
+					$style = clone $this->styleName;
+					$style->setName($this->styleName->getName()."-".$this->format);
+					$style->setStyleDataName('Date-'.$this->format);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			} else {
+				$style = $ods->getStyleByName("ce1-".$this->format);
+				if(!$style) {
+					$style = clone $ods->getStyleByName("ce1");
+					$style->setName("ce1-".$this->format);
+					$style->setStyleDataName('Date-'.$this->format);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			}
+		
+		$table_table_cell->setAttribute("office:value-type","date");
+		$table_table_cell->setAttribute("office:date-value",$this->date);
+		return $table_table_cell;
+	}
+	
+}
+
+class odsTableCellTime extends odsTableCell {
+	private $time;
+	private $format;
+	
+	public function __construct($time, $format="HHMM", odsStyleGraphic $odsStyleCellDate = null) {
+		$this->time = $time;
+		$this->format = $format;
+		$this->styleName = $odsStyleCellDate;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		switch($this->format) {
+		case 'HHMMSS':
+			$ods->addTmpStyles(new odsStyleTimeHHMMSS());
+			break;
+		case 'HHMM':
+			$ods->addTmpStyles(new odsStyleTimeHHMM());
+			break;
+		case 'HHMMSSAMPM':
+			$ods->addTmpStyles(new odsStyleTimeHHMMSSAMPM());
+			break;
+		case 'HHMMAMPM':
+			$ods->addTmpStyles(new odsStyleTimeHHMMAMPM());
+			break;
+		default:
+			//FIXME: send error;
+		}
+		
+		$table_table_cell = $dom->createElement('table:table-cell');
+		$this->cellOpts($table_table_cell);
+		
+		if( $this->styleName ) {
+				$style = $ods->getStyleByName($this->styleName->getName()."-".$this->format);
+				if(!$style) {
+					$style = clone $this->styleName;
+					$style->setName($this->styleName->getName()."-".$this->format);
+					$style->setStyleDataName('Time-'.$this->format);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			} else {
+				$style = $ods->getStyleByName("ce1-".$this->format);
+				if(!$style) {
+					$style = clone $ods->getStyleByName("ce1");
+					$style->setName("ce1-".$this->format);
+					$style->setStyleDataName('Time-'.$this->format);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			}
+		
+		$table_table_cell->setAttribute("office:value-type","time");
+		$table_table_cell->setAttribute("office:time-value",$this->time);
+		return $table_table_cell;
+	}
+}
+
+class odsTableCellDateTime extends odsTableCell {
+	private $dateTime;
+	private $format;
+	
+	public function __construct($dateTime, $format="MMDDYYHHMMAMPM", $language=null, odsStyleGraphic $odsStyleCellDate = null) {
+		$this->dateTime = $dateTime;
+		$this->format = $format;
+		$this->language = $language;
+		$this->styleName = $odsStyleCellDate;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		switch($this->format) {
+		case 'MMDDYYHHMMSSAMPM':
+			$ods->addTmpStyles(new odsStyleDateTimeMMDDYYHHMMSSAMPM($this->language));
+			break;
+		case 'MMDDYYHHMMAMPM':
+			$ods->addTmpStyles(new odsStyleDateTimeMMDDYYHHMMAMPM($this->language));
+			break;
+		case 'DDMMYYHHMMSS':
+			$ods->addTmpStyles(new odsStyleDateTimeDDMMYYHHMMSS($this->language));
+			break;
+		case 'DDMMYYHHMM':
+			$ods->addTmpStyles(new odsStyleDateTimeDDMMYYHHMM($this->language));
+			break;
+		default:
+			//FIXME: send error;
+		}
+		
+		$table_table_cell = $dom->createElement('table:table-cell');
+		$this->cellOpts($table_table_cell);
+		
+		if( $this->styleName ) {
+				$style = $ods->getStyleByName($this->styleName->getName()."-".$this->format);
+				if(!$style) {
+					$style = clone $this->styleName;
+					$style->setName($this->styleName->getName()."-".$this->format);
+					$style->setStyleDataName('DateTime-'.$this->format);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			} else {
+				$style = $ods->getStyleByName("ce1-".$this->format);
+				if(!$style) {
+					$style = clone $ods->getStyleByName("ce1");
+					$style->setName("ce1-".$this->format);
+					$style->setStyleDataName('DateTime-'.$this->format);
+					$ods->addTmpStyles($style);
+				}
+				$table_table_cell->setAttribute("table:style-name", $style->getName());
+			}
+		
+		$table_table_cell->setAttribute("office:value-type","date");
+		$table_table_cell->setAttribute("office:date-value",$this->dateTime);
+		return $table_table_cell;
+	}
+}
+
+class odsTableCellImage extends odsTableCell {
+	private $file;
+	private $width;
+	private $heigth;
+	
+	private $zIndex;
+	private $x;
+	private $y;
+	
+	public function __construct($file, odsStyleGraphic $odsStyleGraphic = null) {
+		$this->styleName = $odsStyleGraphic;
+		$this->file      = $file;
+		$im = imagecreatefromstring( file_get_contents( $file )); 
+		$this->width  = (imagesx($im)*0.035276875)."cm";
+		$this->height = (imagesy($im)*0.035276875)."cm";
+		imagedestroy($im);
+		
+		$this->zIndex = "0";
+		$this->x      = "0cm";
+		$this->y      = "0cm";
+	}
+	
+	public function setWidth($width) {
+		$this->width = $width;
+	}
+	
+	public function setHeight($heigth) {
+		$this->heigth = $heigth;
+	}
+	
+	public function setZIndex($zIndex) {
+		$this->zIndex = $zIndex;
+	}
+	
+	public function setX($x) {
+		$this->$x = $x;
+	}
+	
+	public function setY($y) {
+		$this->$y = $y;
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		if($this->styleName)
+			$style = $this->styleName;
+		else 
+			$style = new odsStyleGraphic("gr1");
+			
+		$ods->addTmpStyles($style);
+		
+		$table_table_cell = $dom->createElement('table:table-cell');
+		$this->cellOpts($table_table_cell);
+
+			$draw_frame = $dom->createElement('draw:frame');
+				//$draw_frame->setAttribute("table:end-cell-address", "Feuille1.AA85");
+				//$draw_frame->setAttribute("table:end-x", "1.27cm");
+				//$draw_frame->setAttribute("table:end-y", "0.472cm");
+				$draw_frame->setAttribute("draw:z-index", $this->zIndex);
+				$draw_frame->setAttribute("draw:name", "Images ".md5(time().rand()));
+				$draw_frame->setAttribute("draw:style-name", $style->getName());
+				$draw_frame->setAttribute("draw:text-style-name", "P1");
+				$draw_frame->setAttribute("svg:width", $this->width);
+				$draw_frame->setAttribute("svg:height", $this->height);
+				$draw_frame->setAttribute("svg:x", $this->x);
+				$draw_frame->setAttribute("svg:y", $this->y);
+				$table_table_cell->appendChild($draw_frame);
+				
+				$draw_image = $dom->createElement('draw:image');
+					$draw_image->setAttribute("xlink:href", $ods->addTmpPictures($this->file));
+					$draw_image->setAttribute("xlink:type", "simple");
+					$draw_image->setAttribute("xlink:show", "embed");
+					$draw_image->setAttribute("xlink:actuate", "onLoad");
+					$draw_frame->appendChild($draw_image);
+					
+					$text_p = $dom->createElement('text:p');
+						$draw_image->appendChild($text_p);
+						
+		return $table_table_cell;
+	}
+}
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableColumn.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableColumn.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableColumn.php	(revision 17735)
@@ -0,0 +1,47 @@
+<?php
+
+/*-
+ * Copyright (c) 2009 Laurent VUIBERT
+ * License : GNU Lesser General Public License v3
+ */
+
+class odsTableColumn {
+	//private $styleName;
+	private $repeated;
+	private $odsStyleTableColumn;
+	
+	public function __construct(odsStyleTableColumn $odsStyleTableColumn) {
+		$this->odsStyleTableColumn = $odsStyleTableColumn;
+		$this->repeated = null;
+	}
+	
+	public function getContent(ods $ods,DOMDocument $dom) {
+		if(!$ods->getStyleByName($this->odsStyleTableColumn->getName()))
+			$ods->addTmpStyles($this->odsStyleTableColumn);
+		
+		$table_table_column = $dom->createElement('table:table-column');
+			$table_table_column->setAttribute("table:style-name", $this->odsStyleTableColumn->getName());
+			if($this->repeated)
+				$table_table_column->setAttribute("table:number-columns-repeated", $this->repeated);
+			$table_table_column->setAttribute("table:default-cell-style-name", "Default");
+		return $table_table_column;
+	}
+
+	public function setRepeated($repeated) {
+		$this->repeated = $repeated;
+	}
+	
+	function getOdsStyleTableColumn() {
+		return $this->odsStyleTableColumn;
+	}
+}
+
+class odsTableColumnWithWidth extends odsTableColumn {
+	public function __construct($width) {
+		$styleColumn = new odsStyleTableColumn();
+		$styleColumn->setColumnWidth($width);
+		parent::__construct($styleColumn);
+	}
+}
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableRow.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableRow.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/class/odsTableRow.php	(revision 17735)
@@ -0,0 +1,50 @@
+<?php
+/*-
+ * Copyright (c) 2009 Laurent VUIBERT
+ * License : GNU Lesser General Public License v3
+ */
+
+class odsTableRow {
+	private $styleName;
+	private $cells;
+	
+	public function __construct(odsStyleTableRow $odsStyleTableRow = null) {
+		if($odsStyleTableRow) $this->styleName = $odsStyleTableRow->getName;
+		else                  $this->styleName = "ro1";
+		$this->cells                           = array();
+	}
+	
+	public function addCell(odsTableCell $odsTableCell) {
+		array_push($this->cells,$odsTableCell);
+	}
+	
+	public function getContent(ods $ods, DOMDocument $dom) {
+		$table_table_row = $dom->createElement('table:table-row');
+			$table_table_row->setAttribute("table:style-name", $this->styleName);
+		
+			if(count($this->cells)) {
+				foreach($this->cells as $cell) {
+					$table_table_row->appendChild($cell->getContent($ods, $dom));
+					if($cell->getNumberColumnsSpanned() > 1) {
+						$odsCoveredTableCell = new odsCoveredTableCell();
+						$odsCoveredTableCell->setNumberColumnsRepeated($cell->getNumberColumnsSpanned()-1);
+						$table_table_row->appendChild($odsCoveredTableCell->getContent($ods, $dom));
+					}
+				}
+					
+			} else {
+				$cell = new odsTableCellEmpty();
+				$table_table_row->appendChild($cell->getContent($ods, $dom));
+			}
+		
+		return $table_table_row;
+	}
+	
+}
+
+
+
+
+
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/CellStyle.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/CellStyle.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/CellStyle.php	(revision 17735)
@@ -0,0 +1,106 @@
+<?php
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Red text
+$style1 = new odsStyleTableCell();
+$style1->setColor('#ff0000');
+
+// Green background
+$style2 = new odsStyleTableCell();
+$style2->setBackgroundColor('#00ff00');
+
+// Blue border
+$style3 = new odsStyleTableCell();
+$style3->setBorder('0.01cm solid #0000ff');
+
+// Align start
+$style4_1 = new odsStyleTableCell();
+$style4_1->setTextAlign('start');
+
+// Align center
+$style4_2 = new odsStyleTableCell();
+$style4_2->setTextAlign('center');
+
+// Align end
+$style4_3 = new odsStyleTableCell();
+$style4_3->setTextAlign('end');
+
+// Align justify
+$style4_4 = new odsStyleTableCell();
+$style4_4->setTextAlign('justify');
+
+// Bold [bold, normal]
+$style5 = new odsStyleTableCell();
+$style5->setFontWeight('bold');
+
+// Italic [italic, normal]
+$style6 = new odsStyleTableCell();
+$style6->setFontStyle('italic');
+
+// Underline [font-color, #000000, null]
+$style7 = new odsStyleTableCell();
+$style7->setUnderline("font-color"); 
+
+// Font size
+$style8 = new odsStyleTableCell();
+$style8->setFontSize("18pt"); 
+
+// Font Face
+$TimesNewRoman = new odsFontFace('Times New Roman');
+$ods->addFontFaces($TimesNewRoman);
+$style9 = new odsStyleTableCell();
+$style9->setFontFace($TimesNewRoman);
+
+// Font Face
+$Webdings = new odsFontFace('Webdings');
+$ods->addFontFaces($Webdings);
+$style10 = new odsStyleTableCell();
+$style10->setFontFace($Webdings);
+
+$table = new odsTable('odsStyleTableCell');
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Red text", $style1));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Green background", $style2));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Blue border", $style3));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Align :"));
+$row->addCell( new odsTableCellString("start", $style4_1));
+$row->addCell( new odsTableCellString("center", $style4_2));
+$row->addCell( new odsTableCellString("end", $style4_3));
+$row->addCell( new odsTableCellString("justify : 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 ...  ", $style4_4));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Bold", $style5));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Italic", $style6));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Underline", $style7));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Font size", $style8));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Times New Roman", $style9));
+
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("Webdings", $style10));
+
+$ods->addTable($table);
+
+// Download the file
+$ods->downloadOdsFile("Properties.ods");  
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/CellType.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/CellType.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/CellType.php	(revision 17735)
@@ -0,0 +1,101 @@
+<?php
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Create table named 'Cells'
+$table = new odsTable('Cells');
+
+// Empty cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Empty cell") );
+$row->addCell( new odsTableCellEmpty() );
+$table->addRow($row);
+
+// String cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("String cell") );
+$row->addCell( new odsTableCellString("String in my cell") );
+$table->addRow($row);
+
+// Email cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Email cell") );
+$row->addCell( new odsTableCellStringEmail("lapinator@gmx.fr") );
+$table->addRow($row);
+
+// Url cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Url cell") );
+$row->addCell( new odsTableCellStringUrl("http://odsphpgenerator.lapinator.net") );
+$table->addRow($row);
+
+// Foat cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Float cell") );
+$row->addCell( new odsTableCellFloat(5.216) );
+$table->addRow($row);
+
+// Date cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Date cell") );
+$row->addCell( new odsTableCellString("US :") );
+$row->addCell( new odsTableCellDate(date('Y-m-d'), 'MMDDYYYY') );
+$row->addCell( new odsTableCellString("FR :") );
+$row->addCell( new odsTableCellDate(date('Y-m-d'), 'DDMMYYYY') );
+$row->addCell( new odsTableCellString("Or :") );
+$row->addCell( new odsTableCellDate(date('Y-m-d'), 'MMMDYYYY') );
+$table->addRow($row);
+
+// Time cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Time cell") );
+$row->addCell( new odsTableCellString("US :") );
+$row->addCell( new odsTableCellTime('PT20H30M50S', 'HHMMSSAMPM') );
+$row->addCell( new odsTableCellString("FR :") );
+$row->addCell( new odsTableCellTime('PT20H30M50S', 'HHMMSS') );
+$table->addRow($row);
+
+// DateTime cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Time cell") );
+$row->addCell( new odsTableCellString("US :") );
+$row->addCell( new odsTableCellDateTime(date('Y-m-d').'T20:30:50', 'MMDDYYHHMMSSAMPM') );
+$row->addCell( new odsTableCellString("FR :") );
+$row->addCell( new odsTableCellDateTime(date('Y-m-d').'T20:30:50', 'DDMMYYHHMMSS') );
+$table->addRow($row);
+
+// EUR cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Euro cell") );
+$row->addCell( new odsTableCellCurrency(rand(0,100), 'EUR') );
+$row->addCell( new odsTableCellCurrency(-rand(0,100), 'EUR') );
+$table->addRow($row);
+
+// USD cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Dolars cell") );
+$row->addCell( new odsTableCellCurrency(rand(0,100), 'USD') );
+$row->addCell( new odsTableCellCurrency(-rand(0,100), 'USD') );
+$table->addRow($row);
+
+// GBP cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Pounds cell") );
+$row->addCell( new odsTableCellCurrency(rand(0,100), 'GBP') );
+$row->addCell( new odsTableCellCurrency(-rand(0,100), 'GBP') );
+$table->addRow($row);
+
+// Image cell
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Image cell") );
+$row->addCell( new odsTableCellImage("logo.png") );
+$table->addRow($row);
+
+$ods->addTable($table);
+// Download the file
+$ods->downloadOdsFile("CellType.ods");
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/ColumnWidth.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/ColumnWidth.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/ColumnWidth.php	(revision 17735)
@@ -0,0 +1,40 @@
+<?php
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+$table = new odsTable('Column Width');
+
+// create column width 1cm   
+$styleColumn = new odsStyleTableColumn();
+$styleColumn->setColumnWidth("1cm");
+$column1 = new odsTableColumn($styleColumn);
+
+// create column width 7cm
+$styleColumn = new odsStyleTableColumn();
+$styleColumn->setColumnWidth("7cm");
+$column2 = new odsTableColumn($styleColumn);
+
+// add 2 1cm column
+$table->addTableColumn($column1);
+$table->addTableColumn($column1);
+
+// add 1 7cm column
+$table->addTableColumn($column2);
+
+// Create data
+$table->addRow($row = new odsTableRow());
+$row->addCell( new odsTableCellString("1cm"));
+$row->addCell( new odsTableCellString("1cm"));
+$row->addCell( new odsTableCellString("7cm ..."));
+
+// Add table to ods
+$ods->addTable($table);
+
+// Download the file
+$ods->downloadOdsFile("ColumnWidth.ods");
+  
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Formula.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Formula.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Formula.php	(revision 17735)
@@ -0,0 +1,60 @@
+<?php
+// All file is writen in UTF-8
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Create table named 'table 1'
+$table = new odsTable('table 1');
+
+// Create the first row
+$row   = new odsTableRow();
+
+// Create 10 number cell
+for($i=0; $i<10; $i++) {
+	$row  = new odsTableRow();
+	$row->addCell( new odsTableCellEmpty());
+	$row->addCell( new odsTableCellFloat(rand(0,50)));
+	$table->addRow($row);
+}
+
+// Add Formula cell
+// Forumla is writen in english language, it's internal format for formula
+$row  = new odsTableRow();
+
+$row->addCell( new odsTableCellString("Sum :") );
+
+$cell = new odsTableCellFloat(0);
+$cell->setFormula("SUM([.B1:.B10])");
+$row->addCell( $cell );
+
+$table->addRow($row);
+
+// Empty row
+$row  = new odsTableRow();
+$table->addRow($row);
+
+// 2nd example contatenate string
+$row  = new odsTableRow();
+
+$row->addCell( new odsTableCellString("Laurent") );
+$row->addCell( new odsTableCellString("VUIBERT") );
+
+$cell = new odsTableCellString("");
+$row->addCell( $cell );
+$cell->setFormula('CONCATENATE([.A13];" ";[.B13];" : ";[.B11])');
+
+$table->addRow($row);
+
+
+// Attach talble to ods
+$ods->addTable($table);
+
+// Download the file
+$ods->downloadOdsFile("HelloWorld.ods");
+
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/HelloWorld.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/HelloWorld.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/HelloWorld.php	(revision 17735)
@@ -0,0 +1,31 @@
+<?php
+
+// All file is writen in UTF-8
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Create table named 'table 1'
+$table = new odsTable('table 1');
+
+// Create the first row
+$row   = new odsTableRow();
+
+// Create and add 2 cell 'Hello' and 'World'
+$row->addCell( new odsTableCellString("Hello") );
+$row->addCell( new odsTableCellString("World") );
+
+// Attach row to table
+$table->addRow($row);
+
+// Attach talble to ods
+$ods->addTable($table);
+
+// Download the file
+$ods->downloadOdsFile("HelloWorld.ods");
+
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/MergeCell.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/MergeCell.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/MergeCell.php	(revision 17735)
@@ -0,0 +1,53 @@
+<?php
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Create table
+$table = new odsTable('MergeCell');
+$ods->addTable($table);
+
+// Merge 4 horizontal cell
+$row = new odsTableRow();
+$cell = new odsTableCellString('Merge 4 cells');
+$cell->setNumberColumnsSpanned(4);
+$row->addCell( $cell );
+$table->addRow($row);
+
+// Merge 4 vertical cell
+$row = new odsTableRow();
+$cell = new odsTableCellString('Merge 4 cells');
+$cell->setNumberRowsSpanned(4);
+$row->addCell( $cell );
+$table->addRow($row);
+
+for($i=0; $i<3; $i++) { // You need add cell odsCoveredTableCell, in covered cell except the first row (implicit)
+	$row = new odsTableRow();
+	$row->addCell( new odsCoveredTableCell() );
+	$table->addRow($row);
+}
+
+// Merge 4*7 cell
+$row = new odsTableRow();
+$cell = new odsTableCellString('Merge 4*4 cells');
+$cell->setNumberColumnsSpanned(4);
+$cell->setNumberRowsSpanned(4);
+$row->addCell( $cell );
+$table->addRow($row);
+
+for($i=0; $i<3; $i++) { // You need add cell odsCoveredTableCell, in covered cell except the first row (implicit)
+	$row = new odsTableRow();
+	$row->addCell( new odsCoveredTableCell() );
+	$row->addCell( new odsCoveredTableCell() );
+	$row->addCell( new odsCoveredTableCell() );
+	$row->addCell( new odsCoveredTableCell() );
+	$table->addRow($row);
+}
+
+// Download the file
+$ods->downloadOdsFile("MergeCell.ods");
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/MultiTab.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/MultiTab.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/MultiTab.php	(revision 17735)
@@ -0,0 +1,39 @@
+<?php
+// This example is writen in UTF-8
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Create table named 'table 1'
+$table1 = new odsTable('table 1');
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Hello") );
+$row->addCell( new odsTableCellString("World") );
+$table1->addRow($row);
+$ods->addTable($table1);
+
+// Create table named 'table 2'
+$table2 = new odsTable('table 2');
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Rand1") );
+$row->addCell( new odsTableCellString("=") );
+$row->addCell( new odsTableCellString( rand() ) );
+$table2->addRow($row);
+
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Rand2") );
+$row->addCell( new odsTableCellString("=") );
+$row->addCell( new odsTableCellString( rand() ) );
+$table2->addRow($row);
+
+$ods->addTable($table2);
+
+//Select 'table 2'
+$ods->setDefaultTable($table2);
+
+// Download the file
+$ods->downloadOdsFile("multiTable.ods");
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Properties.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Properties.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Properties.php	(revision 17735)
@@ -0,0 +1,18 @@
+<?php
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Set properties
+$ods->setTitle("My title is cool");
+$ods->setSubject("My subject is cool too");
+$ods->setKeyword("ods, internet");
+$ods->setDescription("I love odsPhpGenerator !!\n\nOk, i'm a programmer, sorry");
+
+// Download the file
+$ods->downloadOdsFile("Properties.ods"); 
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/TableSplit.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/TableSplit.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/TableSplit.php	(revision 17735)
@@ -0,0 +1,28 @@
+<?php
+
+// Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+//Set vertical split
+$table = new odsTable('V Split');
+$table->setVerticalSplit(1);
+$ods->addTable($table);
+
+//Set Horizontal split
+$table = new odsTable('H Split');
+$table->setHorizontalSplit(1);
+$ods->addTable($table);
+
+// Both split
+$table = new odsTable('B Split');
+$table->setVerticalSplit(1);
+$table->setHorizontalSplit(1);
+$ods->addTable($table);
+
+// Download the file
+$ods->downloadOdsFile("TableSplit.ods");  
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Unicode.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Unicode.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/Unicode.php	(revision 17735)
@@ -0,0 +1,49 @@
+<?php
+// All file is writen in UTF-8
+
+ // Load library
+require_once('../ods.php');
+
+// Create Ods object
+$ods  = new ods();
+
+// Create table named 'utf8'
+$table = new odsTable('utf8');
+
+// Create french row
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("French") );
+$row->addCell( new odsTableCellString("àôïîéèç...") );
+$table->addRow($row);
+
+// Create greek row
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Greek") );
+$row->addCell( new odsTableCellString("αβγδεζϕΩ...") );
+$table->addRow($row);
+
+// Create hebrew row
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Hebrew") );
+$row->addCell( new odsTableCellString("ש֓חרםא...") );
+$table->addRow($row);
+
+// Create arab row
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("Arab") );
+$row->addCell( new odsTableCellString("ڤڦڪصى...") );
+$table->addRow($row);
+
+$row   = new odsTableRow();
+$row->addCell( new odsTableCellString("...") );
+$row->addCell( new odsTableCellString("...") );
+$table->addRow($row);
+
+// Attach talble to ods
+$ods->addTable($table);
+
+// Download the file
+$ods->downloadOdsFile("Unicode.ods"); 
+
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/projects.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/projects.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/examples/projects.php	(revision 17735)
@@ -0,0 +1,228 @@
+<?php
+
+require_once("../ods.php");
+
+$projet = new project();
+$projet->addItem("2010-01-05", "2010-01-10", "#1", "#aaaaff");
+$projet->addItem("2010-01-15", "2010-03-25", "#2", "#ffaaaa");
+$projet->addItem("2010-01-01", "2010-01-25", "#3", "#aaffaa");
+
+//echo $projet->html("2010-01-01","2010-02-28");
+$projet->ods("2010-01-01","2010-02-28");
+
+
+
+class project {
+	private $projectItems;
+	
+	public function __construct() {
+		$this->projectItems = array();
+	}
+	
+	private function gendate($start, $end) {
+		$data = array();
+		
+		if(!preg_match("/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/", $start))
+			throw new Exception("Error; start date YYYY-MM-DD :".$start);
+		$ex1 = explode("-",$start); 
+		
+		if(!preg_match("/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/", $end))
+			throw new Exception("Error; end date YYYY-MM-DD :".$end);
+		$ex2 = explode("-",$end);
+			
+		$start = mktime(0,0,0,$ex1[1],$ex1[2],$ex1[0]);
+		$end   = mktime(0,0,0,$ex2[1],$ex2[2],$ex2[0]);
+		
+		$data['days']       = array();
+		$data['days_nb']    = array();
+		$data['months']     = array();
+		$data['weeks']      = array();
+		$data['total_days'] = 0;
+	
+		$pstart = $start;
+		while($pstart<=$end) {
+			array_push($data['days'],array('title'=>date('D',$pstart).' '.date('j',$pstart),'day'=>'1'));
+			
+			$monthNb = date('n',$pstart);
+			if(!isset($data['months'][$monthNb])) {
+				$data['months'][$monthNb] = array(
+					'title' => date('F',$pstart),
+					'day'=>'0'
+				);
+			};
+			$data['months'][$monthNb]['day']++;
+			
+			$weekNb = date('W',$pstart);
+			if($weekNb == 53) $weekNb = 1;
+			if(!isset($data['weeks'][$weekNb])) {
+				$data['weeks'][$weekNb] = array(
+					'title' => $weekNb,
+					'day'=>'0'
+				);
+			};
+			$data['weeks'][$weekNb]['day']++;
+			
+			$pstart+=60*60*24;
+			$data['total_days']++;
+		}
+		
+		$data['projects'] = array();
+		foreach($this->projectItems as $projet) {
+			$ex1 = explode("-",$projet['start']); 
+			$ex2 = explode("-",$projet['end']);
+			$pstart = mktime(0,0,0,$ex1[1],$ex1[2],$ex1[0]);
+			$pend   = mktime(0,0,0,$ex2[1],$ex2[2],$ex2[0]);
+			
+			if( $pstart<=$end AND $pend>=$start ) {
+				$tmp = array();
+				$tmp['title'] = $projet['title'];
+				$tmp['color'] = $projet['color'];
+				$tmp['shift'] = ($pstart-$start)/(60*60*24);
+				if($tmp['shift']<0) $tmp['shift']=0;
+				if($pend>$end) 
+					$tmp['days'] = ($end-$pstart)/(60*60*24)+1;
+				else
+					$tmp['days'] = ($pend-$pstart)/(60*60*24)+1;
+				
+				array_push($data['projects'], $tmp);
+			}
+		}
+		
+		return $data;
+	}
+	
+	public function addItem($start, $end, $title, $color) {
+		if(!preg_match("/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/", $start))
+			throw new Exception("Error; start date YYYY-MM-DD :".$start);
+		
+		if(!preg_match("/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/", $end))
+			throw new Exception("Error; end date YYYY-MM-DD :".$end);
+		
+		if(!preg_match("/^\#[0-9a-fA-F]{6}$/", $color))
+			throw new Exception("Error; color #XXXXXX :".$color);
+			
+		array_push($this->projectItems,
+			array(
+				"start" => $start,
+				"end"   => $end,
+				"title" => $title,
+				"color" => $color
+			)
+		);
+	}
+	
+	public function html($start, $end) {
+		$data = $this->gendate($start, $end);
+		$r="";
+		
+		$r .= "<table>";
+		
+		$r .= "<tr>";
+		foreach($data['months'] AS $moi)
+			$r .= "<td style='border:1px solid black' colspan='$moi[day]'>$moi[title]</td>";
+		$r .= "</tr>\n";
+		
+		$r .= "<tr>";
+		foreach($data['weeks'] AS $week)
+			$r .= "<td style='border:1px solid black' colspan='$week[day]'>$week[title]</td>";
+		$r .= "</tr>\n";
+		
+		$r .= "<tr>";
+		foreach($data['days'] AS $day)
+			$r .= "<td style='border:1px solid black' colspan='$day[day]'>$day[title]</td>";
+		$r .= "</tr>\n";
+		
+		foreach($data['projects'] AS $projet) {
+			$r .= "<tr>";
+			if($projet["shift"])
+				$r .= "<td colspan='$projet[shift]'>&nbsp;</td>";
+			$r .= "<td style='border:1px solid black; background-color:$projet[color]' colspan='$projet[days]'>$projet[title]</td>";
+			$r .= "</tr>\n";
+		}
+		
+		$r .= "</table>";
+		
+		return $r;
+	}
+	
+	public function ods($start, $end) {
+		$data = $this->gendate($start, $end);
+		
+		$ods   = new ods();
+		$table = new odsTable('table 1');
+	
+		$table->setHorizontalSplit(1);
+		$table->setVerticalSplit(3);
+	
+		// Set coluomn width
+		$styleColumn = new odsStyleTableColumn();
+		$styleColumn->setColumnWidth("4cm");
+		$table->addTableColumn( new odsTableColumn($styleColumn) );
+		
+		$table->addTableColumn( $column = new odsTableColumn($styleColumn = new odsStyleTableColumn()) );
+		$styleColumn->setColumnWidth("1.5cm");
+		$column->setRepeated($data['total_days']);
+		
+		// Set Title Style
+		$styleTitle1 = new odsStyleTableCell();
+		$styleTitle1->setBorder("0.01cm solid #000000");
+		$styleTitle1->setFontWeight('bold');
+		
+		$styleTitle2 = clone $styleTitle1;
+		$styleTitle2->setTextAlign("center");
+		
+		
+		// Months style
+		$row   = new odsTableRow();
+		$row->addCell( new odsTableCellString("Months:",$styleTitle1));
+		foreach($data['months'] AS $moi) {
+			$cell = new odsTableCellString($moi['title'],$styleTitle2);
+			$cell->setNumberColumnsSpanned($moi['day']);
+			$row->addCell( $cell );
+		}
+		$table->addRow($row);
+		
+		$row   = new odsTableRow();
+		$row->addCell( new odsTableCellString("Weeks :",$styleTitle1));
+		foreach($data['weeks'] AS $week) {
+			$cell = new odsTableCellString($week['title'],$styleTitle2);
+			$cell->setNumberColumnsSpanned($week['day']);
+			$row->addCell( $cell );
+		}
+		$table->addRow($row);
+		
+		$row   = new odsTableRow();
+		$row->addCell( new odsTableCellString("Days:",$styleTitle1));
+		foreach($data['days'] AS $day) {
+			$cell = new odsTableCellString($day['title'],$styleTitle2);
+			$cell->setNumberColumnsSpanned($day['day']);
+			$row->addCell( $cell );
+		}
+		$table->addRow($row);	
+		
+		foreach($data['projects'] AS $projet) {
+			$row   = new odsTableRow();
+			
+			$row->addCell( new odsTableCellString($projet['title'],$styleTitle1));
+			
+			if($projet["shift"]) {
+				$cell = new odsTableCellEmpty();
+				$cell->setNumberColumnsRepeated($projet["shift"]);
+				$row->addCell( $cell );
+			}
+			
+			$styleX = clone($styleTitle2);
+			$styleX->setBackgroundColor($projet[color]);
+			
+			$cell = new odsTableCellString($projet['title'],$styleX);
+			$cell->setNumberColumnsSpanned($projet['days']);
+			$row->addCell( $cell );
+			$table->addRow($row);
+		}
+		
+		$ods->addTable($table);
+		$ods->downloadOdsFile("tab.ods"); exit();
+	}
+}
+
+?>
Index: /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/ods.php
===================================================================
--- /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/ods.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/External/odsPhpGenerator/ods.php	(revision 17735)
@@ -0,0 +1,1292 @@
+<?php
+/*-
+ * Copyright (c) 2009 Laurent VUIBERT
+ * License : GNU Lesser General Public License v3
+ *
+ * -----------------------------------------------------------------------------
+ * 2012-09-04 / modified by grum
+ *              . replace ZipArchive class by PclZip class (assume that the class
+ *                was already loaded before)
+ *
+ *              . fix bug on file format
+ */
+
+require_once("class/odsFontFace.php");
+require_once("class/odsStyle.php");
+require_once("class/odsTable.php");
+require_once("class/odsTableColumn.php");
+require_once("class/odsTableRow.php");
+require_once("class/odsTableCell.php");
+
+class ods {
+  private $defaultTable;
+
+  private $scripts;        // FIXME: Looking
+  private $fontFaces;
+  private $styles;
+  private $tmpStyles;
+  private $tmpPictures;
+  private $tables;
+
+  private $title;
+  private $subject;
+  private $keyword;
+  private $description;
+
+  public function __construct() {
+    $this->title         = null;
+    $this->subject       = null;
+    $this->keyword       = null;
+    $this->description   = null;
+    $this->path2OdsFiles = ".";
+
+    $this->defaultTable = null;
+
+    $this->scripts   = array();
+    $this->fontFaces = array();
+    $this->styles    = array();
+    $this->tables    = array();
+
+    $this->addFontFaces( new odsFontFace( "Nimbus Sans L", "swiss" ) );
+    $this->addFontFaces( new odsFontFace( "Bitstream Vera Sans", "system" ) );
+
+    $this->addStyles( new odsStyleTableColumn("co1") );
+    $this->addStyles( new odsStyleTable("ta1") );
+    $this->addStyles( new odsStyleTableRow("ro1") );
+    $this->addStyles( new odsStyleTableCell("ce1") );
+
+  }
+
+  public function setTitle($title) {
+    $this->title = $title;
+  }
+
+  public function setSubject($subject) {
+    $this->subject = $subject;
+  }
+
+  public function setKeyword($keyword) {
+    $this->keyword = $keyword;
+  }
+
+  public function setDescription($description) {
+    $this->description = $description;
+  }
+
+  // Deprecated
+  public function setPath2OdsFiles($path) {}
+
+  public function addFontFaces(odsFontFace $odsFontFace) {
+    if(in_array($odsFontFace,$this->fontFaces)) return;
+    $this->fontFaces[$odsFontFace->getFontName()] = $odsFontFace;
+  }
+
+  public function addStyles(odsStyle $odsStyle) {
+    if(in_array($odsStyle,$this->styles)) return;
+    $this->styles[$odsStyle->getName()] = $odsStyle;
+  }
+
+  public function addTmpStyles(odsStyle $odsStyle) {
+    if(in_array($odsStyle,$this->styles)) return;
+    if(in_array($odsStyle,$this->tmpStyles)) return;
+    $this->tmpStyles[$odsStyle->getName()] = $odsStyle;
+  }
+
+  public function addTmpPictures($file) {
+    if(in_array($file,$this->tmpPictures)) return;
+    $this->tmpPictures[$file] = "Pictures/".md5(time().rand()).'.jpg';
+    return $this->tmpPictures[$file];
+  }
+
+  public function getStyleByName($name) {
+    if(isset($this->styles[$name])) return $this->styles[$name];
+    if(isset($this->tmpStyles[$name])) return $this->tmpStyles[$name];
+    return null;
+  }
+
+  public function addTable(odsTable $odsTable) {
+    if(in_array($odsTable,$this->tables)) return;
+    $this->tables[$odsTable->getName()] = $odsTable;
+  }
+
+  public function setDefaultTable(odsTable $odsTable) {
+    $this->defaultTable = $odsTable;
+  }
+
+  private function getDefaultTableName() {
+    if($this->defaultTable) {
+      return $this->defaultTable->getName();
+    } elseif(count($this->tables)){
+      $keys = array_keys($this->tables);
+      //var_dump($keys);
+      return $this->tables[$keys[0]]->getName();
+    } else {
+      return "feuille1";
+    }
+  }
+
+  public function getContent() {
+    $this->tmpStyles = array();
+    $this->tmpPictures = array();
+
+    $dom = new DOMDocument('1.0', 'UTF-8');
+    $root = $dom->createElement('office:document-content');
+      $root->setAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
+      $root->setAttribute("xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
+      $root->setAttribute("xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
+      $root->setAttribute("xmlns:table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0");
+      $root->setAttribute("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
+      $root->setAttribute("xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
+      $root->setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
+      $root->setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
+      $root->setAttribute("xmlns:meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0");
+      $root->setAttribute("xmlns:number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0");
+      $root->setAttribute("xmlns:presentation", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0");
+      $root->setAttribute("xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
+      $root->setAttribute("xmlns:chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0");
+      $root->setAttribute("xmlns:dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0");
+      $root->setAttribute("xmlns:math", "http://www.w3.org/1998/Math/MathML");
+      $root->setAttribute("xmlns:form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0");
+      $root->setAttribute("xmlns:script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0");
+      $root->setAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
+      $root->setAttribute("xmlns:ooow", "http://openoffice.org/2004/writer");
+      $root->setAttribute("xmlns:oooc", "http://openoffice.org/2004/calc");
+      $root->setAttribute("xmlns:dom", "http://www.w3.org/2001/xml-events");
+      $root->setAttribute("xmlns:xforms", "http://www.w3.org/2002/xforms");
+      $root->setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
+      $root->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+      $root->setAttribute("xmlns:rpt", "http://openoffice.org/2005/report");
+      $root->setAttribute("xmlns:of", "urn:oasis:names:tc:opendocument:xmlns:of:1.2");
+      $root->setAttribute("xmlns:rdfa", "http://docs.oasis-open.org/opendocument/meta/rdfa#");
+      $root->setAttribute("xmlns:field", "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0");
+      $root->setAttribute("xmlns:formx", "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0");
+      $root->setAttribute("office:version", "1.2");
+      $dom->appendChild($root);
+
+    // office:scripts
+    $root->appendChild($dom->createElement('office:scripts'));
+
+    //office:font-face-decls
+    $office_font_face_decls =  $dom->createElement('office:font-face-decls');
+    $root->appendChild($office_font_face_decls);
+
+      foreach($this->fontFaces as $fontFace)
+        $office_font_face_decls->appendChild($fontFace->getContent($this,$dom));
+
+    // office:automatic-styles
+    $office_automatic_styles =  $dom->createElement('office:automatic-styles');
+      $root->appendChild($office_automatic_styles);
+
+      foreach($this->styles as $style)
+        $office_automatic_styles->appendChild($style->getContent($this,$dom));
+
+    // office:body
+    $office_body =  $dom->createElement('office:body');
+      $root->appendChild($office_body);
+
+      // office:spreadsheet
+      $office_spreadsheet = $dom->createElement('office:spreadsheet');
+        $office_body->appendChild($office_spreadsheet);
+
+          foreach($this->tables as $table)
+            $office_spreadsheet->appendChild($table->getContent($this,$dom));
+
+      foreach($this->tmpStyles as $style)
+        $office_automatic_styles->appendChild($style->getContent($this,$dom));
+
+    return $dom->saveXML();
+  }
+
+  public function getMeta() {
+    $dom = new DOMDocument('1.0', 'UTF-8');
+
+    $root = $dom->createElement('office:document-meta');
+      $root->setAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
+      $root->setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
+      $root->setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
+      $root->setAttribute("xmlns:meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0");
+      $root->setAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
+      $root->setAttribute("office:version", "1.2");
+      $dom->appendChild($root);
+
+    $meta =  $dom->createElement('office:meta');
+      $root->appendChild($meta);
+
+    $meta->appendChild($dom->createElement('meta:creation-date',date("Y-m-d\TH:j:s")));
+    $meta->appendChild($dom->createElement('meta:generator','ods générator'));
+    $meta->appendChild($dom->createElement('dc:date',date("Y-m-d\TH:j:s")));
+    $meta->appendChild($dom->createElement('meta:editing-duration','PT1S'));
+    $meta->appendChild($dom->createElement('meta:editing-cycles','1'));
+    if($this->title)
+      $meta->appendChild($dom->createElement('dc:title',$this->title));
+    if($this->subject)
+      $meta->appendChild($dom->createElement('dc:subject',$this->subject));
+    if($this->keyword)
+      $meta->appendChild($dom->createElement('meta:keyword',$this->keyword));
+    if($this->description)
+      $meta->appendChild($dom->createElement('dc:description',$this->description));
+    $elm = $dom->createElement('meta:document-statistic');
+      $elm->setAttribute("meta:table-count", "1");
+      $elm->setAttribute("meta:cell-count", "4");
+      $elm->setAttribute("meta:object-count", "0");
+      $meta->appendChild($elm);
+
+    return $dom->saveXML();
+  }
+
+  public function getSettings() {
+    $dom = new DOMDocument('1.0', 'UTF-8');
+
+    $root = $dom->createElement('office:document-settings');
+      $root->setAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
+      $root->setAttribute("xmlns:xlink",  "http://www.w3.org/1999/xlink");
+      $root->setAttribute("xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
+      $root->setAttribute("xmlns:ooo",    "http://openoffice.org/2004/office");
+      $root->setAttribute("office:version", "1.2");
+      $dom->appendChild($root);
+
+      $office_settings =  $dom->createElement('office:settings');
+        $root->appendChild($office_settings);
+
+        $config_config_item_set = $dom->createElement('config:config-item-set');
+          $config_config_item_set->setAttribute("config:name", "ooo:view-settings");
+          $office_settings->appendChild($config_config_item_set);
+
+          $config_config_item = $dom->createElement('config:config-item',0);
+            $config_config_item->setAttribute("config:name", "VisibleAreaTop");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item',0);
+            $config_config_item->setAttribute("config:name", "VisibleAreaLeft");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item',10018);
+            $config_config_item->setAttribute("config:name", "VisibleAreaWidth");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item',2592);
+            $config_config_item->setAttribute("config:name", "VisibleAreaHeight");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item_map_indexed = $dom->createElement('config:config-item-map-indexed');
+            $config_config_item_map_indexed->setAttribute("config:name", "Views");
+            $config_config_item_set->appendChild($config_config_item_map_indexed);
+
+            $config_config_item_map_entry1 = $dom->createElement('config:config-item-map-entry');
+              $config_config_item_map_indexed->appendChild($config_config_item_map_entry1);
+
+              //<config:config-item config:name="ViewId" config:type="string">View1</config:config-item>
+              $config_config_item = $dom->createElement('config:config-item', 'View1');
+                $config_config_item->setAttribute("config:name", "ViewId");
+                $config_config_item->setAttribute("config:type", "string");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              //<config:config-item-map-named config:name="Tables">
+              $config_config_item_map_named = $dom->createElement('config:config-item-map-named');
+                $config_config_item_map_named->setAttribute("config:name", "Tables");
+                $config_config_item_map_entry1->appendChild($config_config_item_map_named);
+
+                foreach($this->tables as $table)
+                  $config_config_item_map_named->appendChild($table->getSettings($this,$dom));
+
+              $config_config_item = $dom->createElement('config:config-item', $this->getDefaultTableName());
+                $config_config_item->setAttribute("config:name", "ActiveTable");
+                $config_config_item->setAttribute("config:type", "string");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '270');
+                $config_config_item->setAttribute("config:name", "HorizontalScrollbarWidth");
+                $config_config_item->setAttribute("config:type", "int");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+
+              $config_config_item = $dom->createElement('config:config-item', '0');
+                $config_config_item->setAttribute("config:name", "ZoomType");
+                $config_config_item->setAttribute("config:type", "short");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '100');
+                $config_config_item->setAttribute("config:name", "ZoomValue");
+                $config_config_item->setAttribute("config:type", "int");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '60');
+                $config_config_item->setAttribute("config:name", "PageViewZoomValue");
+                $config_config_item->setAttribute("config:type", "int");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'false');
+                $config_config_item->setAttribute("config:name", "ShowPageBreakPreview");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "ShowZeroValues");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "ShowNotes");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "ShowGrid");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '12632256');
+                $config_config_item->setAttribute("config:name", "GridColor");
+                $config_config_item->setAttribute("config:type", "long");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "ShowPageBreaks");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "HasColumnRowHeaders");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "HasSheetTabs");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "IsOutlineSymbolsSet");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'false');
+                $config_config_item->setAttribute("config:name", "IsSnapToRaster");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'false');
+                $config_config_item->setAttribute("config:name", "RasterIsVisible");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '1000');
+                $config_config_item->setAttribute("config:name", "RasterResolutionX");
+                $config_config_item->setAttribute("config:type", "int");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '1000');
+                $config_config_item->setAttribute("config:name", "RasterResolutionY");
+                $config_config_item->setAttribute("config:type", "int");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '1');
+                $config_config_item->setAttribute("config:name", "RasterSubdivisionX");
+                $config_config_item->setAttribute("config:type", "int");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', '1');
+                $config_config_item->setAttribute("config:name", "RasterSubdivisionY");
+                $config_config_item->setAttribute("config:type", "int");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+              $config_config_item = $dom->createElement('config:config-item', 'true');
+                $config_config_item->setAttribute("config:name", "IsRasterAxisSynchronized");
+                $config_config_item->setAttribute("config:type", "boolean");
+                $config_config_item_map_entry1->appendChild($config_config_item);
+
+        $config_config_item_set = $dom->createElement('config:config-item-set');
+          $config_config_item_set->setAttribute("config:name", "ooo:configuration-settings");
+          $office_settings->appendChild($config_config_item_set);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "ShowZeroValues");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "ShowNotes");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "ShowGrid");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', '12632256');// test 0
+            $config_config_item->setAttribute("config:name", "GridColor");
+            $config_config_item->setAttribute("config:type", "long");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "ShowPageBreaks");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', '3');
+            $config_config_item->setAttribute("config:name", "LinkUpdateMode");
+            $config_config_item->setAttribute("config:type", "short");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "HasColumnRowHeaders");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "HasSheetTabs");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "IsOutlineSymbolsSet");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'false');
+            $config_config_item->setAttribute("config:name", "IsSnapToRaster");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'false');
+            $config_config_item->setAttribute("config:name", "RasterIsVisible");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', '1000');
+            $config_config_item->setAttribute("config:name", "RasterResolutionX");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', '1000');
+            $config_config_item->setAttribute("config:name", "RasterResolutionY");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', '1');
+            $config_config_item->setAttribute("config:name", "RasterSubdivisionX");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', '1');
+            $config_config_item->setAttribute("config:name", "RasterSubdivisionY");
+            $config_config_item->setAttribute("config:type", "int");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "IsRasterAxisSynchronized");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "AutoCalculate");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item');
+            $config_config_item->setAttribute("config:name", "PrinterName");
+            $config_config_item->setAttribute("config:type", "string");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item');
+            $config_config_item->setAttribute("config:name", "PrinterSetup");
+            $config_config_item->setAttribute("config:type", "base64Binary");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "ApplyUserData");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', '0');
+            $config_config_item->setAttribute("config:name", "CharacterCompressionType");
+            $config_config_item->setAttribute("config:type", "short");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'false');
+            $config_config_item->setAttribute("config:name", "IsKernAsianPunctuation");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'false');
+            $config_config_item->setAttribute("config:name", "SaveVersionOnClose");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "UpdateFromTemplate");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'true');
+            $config_config_item->setAttribute("config:name", "AllowPrintJobCancel");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'false');
+            $config_config_item->setAttribute("config:name", "LoadReadonly");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+          $config_config_item = $dom->createElement('config:config-item', 'false');
+            $config_config_item->setAttribute("config:name", "IsDocumentShared");
+            $config_config_item->setAttribute("config:type", "boolean");
+            $config_config_item_set->appendChild($config_config_item);
+
+      return $dom->saveXML();
+  }
+
+  public function getStyles() {
+    $dom = new DOMDocument('1.0', 'UTF-8');
+
+    $root = $dom->createElement('office:document-styles');
+      $root->setAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
+      $root->setAttribute("xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
+      $root->setAttribute("xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
+      $root->setAttribute("xmlns:table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0");
+      $root->setAttribute("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
+      $root->setAttribute("xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
+      $root->setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
+      $root->setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
+      $root->setAttribute("xmlns:meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0");
+      $root->setAttribute("xmlns:number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0");
+      $root->setAttribute("xmlns:presentation", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0");
+      $root->setAttribute("xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
+      $root->setAttribute("xmlns:chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0");
+      $root->setAttribute("xmlns:dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0");
+      $root->setAttribute("xmlns:math", "http://www.w3.org/1998/Math/MathML");
+      $root->setAttribute("xmlns:form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0");
+      $root->setAttribute("xmlns:script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0");
+      $root->setAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
+      $root->setAttribute("xmlns:ooow", "http://openoffice.org/2004/writer");
+      $root->setAttribute("xmlns:oooc", "http://openoffice.org/2004/calc");
+      $root->setAttribute("xmlns:dom", "http://www.w3.org/2001/xml-events");
+      $root->setAttribute("xmlns:rpt", "http://openoffice.org/2005/report");
+      $root->setAttribute("xmlns:of", "urn:oasis:names:tc:opendocument:xmlns:of:1.2");
+      $root->setAttribute("xmlns:rdfa", "http://docs.oasis-open.org/opendocument/meta/rdfa#");
+      $root->setAttribute("office:version", "1.2");
+      $dom->appendChild($root);
+
+
+      $office_font_face_decls = $dom->createElement('office:font-face-decls');
+        $root->appendChild($office_font_face_decls);
+
+        foreach($this->fontFaces as $fontFace)
+          $office_font_face_decls->appendChild($fontFace->getStyles($this,$dom));
+
+      $office_styles = $dom->createElement('office:styles');
+        $root->appendChild($office_styles);
+
+        $style_default_style = $dom->createElement('style:default-style');
+          $style_default_style->setAttribute("style:family", "table-cell");
+          $office_styles->appendChild($style_default_style);
+
+          $style_table_cell_properties = $dom->createElement('style:table-cell-properties');
+            $style_table_cell_properties->setAttribute("style:decimal-places", "2");
+            $style_default_style->appendChild($style_table_cell_properties);
+
+          $style_paragraph_properties = $dom->createElement('style:paragraph-properties');
+            $style_paragraph_properties->setAttribute("style:tab-stop-distance", "1.25cm");
+            $style_default_style->appendChild($style_paragraph_properties);
+
+          $style_text_properties = $dom->createElement('style:text-properties');
+            $style_text_properties->setAttribute("style:font-name", "Nimbus Sans L");
+            $style_text_properties->setAttribute("fo:language", "fr");
+            $style_text_properties->setAttribute("fo:country", "FR");
+            $style_text_properties->setAttribute("style:font-name-asian", "Bitstream Vera Sans");
+            $style_text_properties->setAttribute("style:language-asian", "zxx");
+            $style_text_properties->setAttribute("style:country-asian", "none");
+            $style_text_properties->setAttribute("style:font-name-complex", "Bitstream Vera Sans");
+            $style_text_properties->setAttribute("style:language-complex", "zxx");
+            $style_text_properties->setAttribute("style:country-complex", "none");
+            $style_default_style->appendChild($style_text_properties);
+
+        $style_default_style = $dom->createElement('style:default-style');
+          $style_default_style->setAttribute("style:family", "graphic");
+          $office_styles->appendChild($style_default_style);
+
+          $style_graphic_properties = $dom->createElement('style:graphic-properties');
+            $style_graphic_properties->setAttribute("draw:shadow-offset-x", "0.3cm");
+            $style_graphic_properties->setAttribute("draw:shadow-offset-y", "0.3cm");
+            $style_default_style->appendChild($style_graphic_properties);
+
+          $style_paragraph_properties = $dom->createElement('style:paragraph-properties');
+            $style_paragraph_properties->setAttribute("style:text-autospace", "ideograph-alpha");
+            $style_paragraph_properties->setAttribute("style:punctuation-wrap", "simple");
+            $style_paragraph_properties->setAttribute("style:line-break", "strict");
+            $style_paragraph_properties->setAttribute("style:writing-mode", "page");
+            $style_paragraph_properties->setAttribute("style:font-independent-line-spacing", "false");
+            $style_default_style->appendChild($style_paragraph_properties);
+
+            $style_tab_stops = $dom->createElement('style:tab-stops');
+              $style_paragraph_properties->appendChild($style_tab_stops);
+
+          $style_text_properties =  $dom->createElement('style:text-properties');
+            $style_text_properties->setAttribute("style:use-window-font-color", "true");
+            $style_text_properties->setAttribute("fo:font-family", "'Nimbus Roman No9 L'");
+            $style_text_properties->setAttribute("style:font-family-generic", "roman");
+            $style_text_properties->setAttribute("style:font-pitch", "variable");
+            $style_text_properties->setAttribute("fo:font-size", "12pt");
+            $style_text_properties->setAttribute("fo:language", "fr");
+            $style_text_properties->setAttribute("fo:country", "FR");
+            $style_text_properties->setAttribute("style:letter-kerning", "true");
+            $style_text_properties->setAttribute("style:font-size-asian", "24pt");
+            $style_text_properties->setAttribute("style:language-asian", "zxx");
+            $style_text_properties->setAttribute("style:country-asian", "none");
+            $style_text_properties->setAttribute("style:font-size-complex", "24pt");
+            $style_text_properties->setAttribute("style:language-complex", "zxx");
+            $style_text_properties->setAttribute("style:country-complex", "none");
+            $style_default_style->appendChild($style_text_properties);
+
+        //<number:number-style style:name="N0">
+        $number_number_style = $dom->createElement('number:number-style');
+          $number_number_style->setAttribute("style:name", "N0");
+          $office_styles->appendChild($number_number_style);
+
+          $number_number = $dom->createElement('number:number');
+            $number_number->setAttribute("number:min-integer-digits", "1");
+            $number_number_style->appendChild($number_number);
+
+        $style_style = $dom->createElement('style:style');
+          $style_style->setAttribute("style:name", "Default");
+          $style_style->setAttribute("style:family", "table-cell");
+          $office_styles->appendChild($style_style);
+
+        $style_style = $dom->createElement('style:style');
+          $style_style->setAttribute("style:name", "Result");
+          $style_style->setAttribute("style:family", "table-cell");
+          $style_style->setAttribute("style:parent-style-name", "Default");
+          $office_styles->appendChild($style_style);
+
+          $style_text_properties = $dom->createElement('style:text-properties');
+            $style_text_properties->setAttribute("fo:font-style", "italic");
+            $style_text_properties->setAttribute("style:text-underline-style", "solid");
+            $style_text_properties->setAttribute("style:text-underline-width", "auto");
+            $style_text_properties->setAttribute("style:text-underline-color", "font-color");
+            $style_text_properties->setAttribute("fo:font-weight", "bold");
+            $style_style->appendChild($style_text_properties);
+
+        $style_style = $dom->createElement('style:style');
+          $style_style->setAttribute("style:name", "Result2");
+          $style_style->setAttribute("style:family", "table-cell");
+          $style_style->setAttribute("style:parent-style-name", "Result");
+          $style_style->setAttribute("style:data-style-name", "N106");
+          $office_styles->appendChild($style_style);
+
+        $style_style = $dom->createElement('style:style');
+          $style_style->setAttribute("style:name", "Heading");
+          $style_style->setAttribute("style:family", "table-cell");
+          $style_style->setAttribute("style:parent-style-name", "Default");
+          $office_styles->appendChild($style_style);
+
+          $style_table_cell_properties = $dom->createElement('style:table-cell-properties');
+            $style_table_cell_properties->setAttribute("style:text-align-source", "fix");
+            $style_table_cell_properties->setAttribute("style:repeat-content", "false");
+            $style_style->appendChild($style_table_cell_properties);
+
+          $style_paragraph_properties = $dom->createElement('style:paragraph-properties');
+            $style_paragraph_properties->setAttribute("fo:text-align", "center");
+            $style_style->appendChild($style_paragraph_properties);
+
+          $style_text_properties = $dom->createElement('style:text-properties');
+            $style_text_properties->setAttribute("fo:font-size", "16pt");
+            $style_text_properties->setAttribute("fo:font-style", "italic");
+            $style_text_properties->setAttribute("fo:font-weight", "bold");
+            $style_style->appendChild($style_text_properties);
+
+        $style_style = $dom->createElement('style:style');
+          $style_style->setAttribute("style:name", "Heading1");
+          $style_style->setAttribute("style:family", "table-cell");
+          $style_style->setAttribute("style:parent-style-name", "Heading");
+          $office_styles->appendChild($style_style);
+
+          $style_table_cell_properties = $dom->createElement('style:table-cell-properties');
+            $style_table_cell_properties->setAttribute("style:rotation-angle", "90");
+            $style_style->appendChild($style_table_cell_properties);
+
+      $office_automatic_styles = $dom->createElement('office:automatic-styles');
+        $root->appendChild($office_automatic_styles);
+
+        $style_page_layout = $dom->createElement('style:page-layout');
+          $style_page_layout->setAttribute("style:name", "Mpm1");
+          $office_automatic_styles->appendChild($style_page_layout);
+
+          $style_page_layout_properties = $dom->createElement('style:page-layout-properties');
+            $style_page_layout_properties->setAttribute("style:writing-mode", "lr-tb");
+            $style_page_layout->appendChild($style_page_layout_properties);
+
+          $style_header_style = $dom->createElement('style:header-style');
+            $style_page_layout->appendChild($style_header_style);
+
+            $style_header_footer_properties = $dom->createElement('style:header-footer-properties');
+              $style_header_footer_properties->setAttribute("fo:min-height", "0.751cm");
+              $style_header_footer_properties->setAttribute("fo:margin-left", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-right", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-bottom", "0.25cm");
+              $style_header_style->appendChild($style_header_footer_properties);
+
+          $style_footer_style = $dom->createElement('style:footer-style');
+            $style_page_layout->appendChild($style_footer_style);
+
+            $style_header_footer_properties = $dom->createElement('style:header-footer-properties');
+              $style_header_footer_properties->setAttribute("fo:min-height", "0.751cm");
+              $style_header_footer_properties->setAttribute("fo:margin-left", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-right", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-top", "0.25cm");
+              $style_footer_style->appendChild($style_header_footer_properties);
+
+        $style_page_layout = $dom->createElement('style:page-layout');
+          $style_page_layout->setAttribute("style:name", "Mpm2");
+          $office_automatic_styles->appendChild($style_page_layout);
+
+          $style_page_layout_properties = $dom->createElement('style:page-layout-properties');
+            $style_page_layout_properties->setAttribute("style:writing-mode", "lr-tb");
+            $style_page_layout->appendChild($style_page_layout_properties);
+
+          $style_header_style = $dom->createElement('style:header-style');
+            $style_page_layout->appendChild($style_header_style);
+
+            $style_header_footer_properties = $dom->createElement('style:header-footer-properties');
+              $style_header_footer_properties->setAttribute("fo:min-height", "0.751cm");
+              $style_header_footer_properties->setAttribute("fo:margin-left", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-right", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-bottom", "0.25cm");
+              $style_header_footer_properties->setAttribute("fo:border", "0.088cm solid #000000");
+              $style_header_footer_properties->setAttribute("fo:padding", "0.018cm");
+              $style_header_footer_properties->setAttribute("fo:background-color", "#c0c0c0");
+              $style_header_style->appendChild($style_header_footer_properties);
+
+              $style_background_image = $dom->createElement('style:background-image');
+                $style_header_footer_properties->appendChild($style_background_image);
+
+          $style_footer_style = $dom->createElement('style:footer-style');
+            $style_page_layout->appendChild($style_footer_style);
+
+            $style_header_footer_properties = $dom->createElement('style:header-footer-properties');
+              $style_header_footer_properties->setAttribute("fo:min-height", "0.751cm");
+              $style_header_footer_properties->setAttribute("fo:margin-left", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-right", "0cm");
+              $style_header_footer_properties->setAttribute("fo:margin-top", "0.25cm");
+              $style_header_footer_properties->setAttribute("fo:border", "0.088cm solid #000000");
+              $style_header_footer_properties->setAttribute("fo:padding", "0.018cm");
+              $style_header_footer_properties->setAttribute("fo:background-color", "#c0c0c0");
+              $style_footer_style->appendChild($style_header_footer_properties);
+
+              $style_background_image = $dom->createElement('style:background-image');
+                $style_header_footer_properties->appendChild($style_background_image);
+
+      $office_master_styles = $dom->createElement('office:master-styles');
+        $root->appendChild($office_master_styles);
+
+        $style_master_page = $dom->createElement('style:master-page');
+          $style_master_page->setAttribute("style:name", "Default");
+          $style_master_page->setAttribute("style:page-layout-name", "Mpm1");
+          $office_master_styles->appendChild($style_master_page);
+
+          $style_header = $dom->createElement('style:header');
+            $style_master_page->appendChild($style_header);
+
+            $text_p = $dom->createElement('text:p');
+              $style_header->appendChild($text_p);
+
+              $text_sheet_name = $dom->createElement('text:sheet-name', '???');
+                $text_p->appendChild($text_sheet_name);
+
+          $style_header_left = $dom->createElement('style:header-left');
+            $style_header_left->setAttribute("style:display", "false");
+            $style_master_page->appendChild($style_header_left);
+
+          $style_footer = $dom->createElement('style:footer');
+            $style_master_page->appendChild($style_footer);
+
+            $text_p = $dom->createElement('text:p', "Page");
+              $style_footer->appendChild($text_p);
+
+              $text_page_number = $dom->createElement('text:page-number', '1');
+                $text_p->appendChild($text_page_number);
+
+          $style_footer_left = $dom->createElement('style:footer-left');
+            $style_footer_left->setAttribute("style:display", "false");
+            $style_master_page->appendChild($style_footer_left);
+
+        $style_master_page = $dom->createElement('style:master-page');
+          $style_master_page->setAttribute("style:name", "Report");
+          $style_master_page->setAttribute("style:page-layout-name", "Mpm2");
+          $office_master_styles->appendChild($style_master_page);
+
+          $style_header = $dom->createElement('style:header');
+            $style_master_page->appendChild($style_header);
+
+            $style_region_left = $dom->createElement('style:region-left');
+              $style_header->appendChild($style_region_left);
+
+              $text_p = $dom->createElement('text:p');
+                $style_region_left->appendChild($text_p);
+
+                $text_sheet_name = $dom->createElement('text:sheet-name', '???');
+                  $text_p->appendChild($text_sheet_name);
+
+                $note_text = $dom->createTextNode('(');
+                  $text_p->appendChild($note_text);
+
+                $text_title = $dom->createElement('text:title', '???');
+                  $text_p->appendChild($text_title);
+
+                $note_text = $dom->createTextNode(')');
+                  $text_p->appendChild($note_text);
+
+            $style_region_right = $dom->createElement('style:region-right');
+              $style_header->appendChild($style_region_right);
+
+              $text_p = $dom->createElement('text:p');
+                $style_region_right->appendChild($text_p);
+
+                $text_date = $dom->createElement('text:date','31/10/2009');
+                  $text_date->setAttribute("style:data-style-name", "N2");
+                  $text_date->setAttribute("text:date-value", "2009-10-31");
+                  $text_p->appendChild($text_date);
+
+                $note_text = $dom->createTextNode(',');
+                  $text_p->appendChild($note_text);
+
+                $text_date = $dom->createElement('text:time','18:09:40');
+                  $text_p->appendChild($text_date);
+
+          $style_header_left = $dom->createElement('style:header-left');
+            $style_header_left->setAttribute("style:display", "false");
+            $style_master_page->appendChild($style_header_left);
+
+          $style_footer = $dom->createElement('style:footer');
+            $style_master_page->appendChild($style_footer);
+
+            $text_p = $dom->createElement('text:p', 'Page');
+              $style_footer->appendChild($text_p);
+
+              $text_page_number = $dom->createElement('text:page-number','1');
+                $text_p->appendChild($text_page_number);
+
+              $note_text = $dom->createTextNode('/');
+                $text_p->appendChild($note_text);
+
+              $text_page_count = $dom->createElement('text:page-count','99');
+                $text_p->appendChild($text_page_count);
+
+          $style_footer_left = $dom->createElement('style:footer-left');
+            $style_footer_left->setAttribute("style:display", "false");
+            $style_master_page->appendChild($style_footer_left);
+
+
+    return $dom->saveXML();
+  }
+
+  private function getMimeType() {
+    return "application/vnd.oasis.opendocument.spreadsheet";
+  }
+
+  private function getAcceleratorCurrent() {
+    return "";
+  }
+
+  private function getManifest() {
+    $dom = new DOMDocument('1.0', 'UTF-8');
+    $root = $dom->createElement('manifest:manifest');
+      $root->setAttribute("xmlns:manifest", "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0");
+      $dom->appendChild($root);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "application/vnd.oasis.opendocument.spreadsheet");
+        $manifest_file_entry->setAttribute("manifest:version", "1.2");
+        $manifest_file_entry->setAttribute("manifest:full-path", "/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "text/xml");
+        $manifest_file_entry->setAttribute("manifest:full-path", "content.xml");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "text/xml");
+        $manifest_file_entry->setAttribute("manifest:full-path", "styles.xml");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "text/xml");
+        $manifest_file_entry->setAttribute("manifest:full-path", "meta.xml");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Thumbnails/thumbnail.png");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Thumbnails/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/accelerator/current.xml");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/accelerator/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/progressbar/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/floater/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/popupmenu/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/menubar/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/toolbar/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/images/Bitmaps/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/images/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/statusbar/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "application/vnd.sun.xml.ui.configuration");
+        $manifest_file_entry->setAttribute("manifest:full-path", "Configurations2/");
+        $root->appendChild($manifest_file_entry);
+
+      $manifest_file_entry = $dom->createElement("manifest:file-entry");
+        $manifest_file_entry->setAttribute("manifest:media-type", "text/xml");
+        $manifest_file_entry->setAttribute("manifest:full-path", "settings.xml");
+        $root->appendChild($manifest_file_entry);
+
+    return $dom->saveXML();
+  }
+
+  private function getThumbnail() {
+    return base64_decode("
+      iVBORw0KGgoAAAANSUhEUgAAALoAAAEACAYAAAAEKGxWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
+      AAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURB
+      VHic7Z152F3T9cc/K3PMNcUUMZQ0hFJRQypiFmOpuai21NRWfmhNpWooRVDaGmqe1VDUUC1iaFHS
+      0BojIaExlRAlEQlZvz/WvnlPznuGO4/r8zz3ue89e+9z1r33e/e7z95rryWqiuO0Oz0abYDj1AMX
+      utMRuNCdjsCF7nQELnSnI3ChOx2BC93pCFzoTkfgQnfqhhg/F5G/isjvRWRo3a7tK6NOPRCRnsCN
+      wO6Rw68Bw1T1w1pf33t0p15sy/wiB1gFGFKPi7vQnXqxZXh+L3JMgVfqcXEXulMvvgjPewP3AS8B
+      O6vq+/W4uI/RnbogImsDzwK7q+pt9b6+9+hOTRGRr4vIb4E3gduAo0Wkd73tcKE7teZXwGHAROAD
+      YEPg0nob4UMXp2aIyCjg3pTic4GfquoXKeVVxXt0pyaISA/gjIwqRwKPisigWLveIrJzte1xoTu1
+      Yh/gqzl1Ngb+JSI/EpFe4dgvgTtEZP1qGuNDF6fqiIgAE4AvAaOA9YEjgMEZzV4DxgF7ALep6m5V
+      tcmF7tQCERkCLKiq48LrHsB3gdOBARlNZwFDVHVKVe1xoTv1REQWAU4Efgz0SahymqqeWPXrutCd
+      RiAiqwHnAdtHDr8JDFbVGVW/ngvdqTYiMhxYGVgW+Ay4Q1XfSKk7GhM8wL6qen1NbHKhO9VCRDbD
+      phQ3SCh+Gvixqj4Za7MKMAl4EhiuNRKkTy86VUFEzgAeIlnkYDMvD4rI9rHjB4TnI2olcvAe3akC
+      InIg8Psiq38ObK6qj4W2CwDbqurttbIPXOhOhYjIMOAJ4DngOOB9YDvgQGDFlGb3qep29bHQcKE7
+      FSEilwPfAlZQ1U8ix3sA22BL/VvGmikwVFVfrJedPkZ3yiYMO3YHnouKHEBV56rqfcDWmAfjfE2B
+      depjpeFCdypha2BhYJiILJZUQY1jge8BcyJFPetg3zxc6E4l9A/P/YB7RSR1aV9VrwS+GTkktTQs
+      jgvdqYRoD70R8JSIpHosquq9wMvh5eO1NCyOC92phGmx1ysCfxeRfUMclyQWAJ5Q1Um1NW1+XOhO
+      JTyCbZGLsiBwLTBVRM6ORuMSkaOwH8PV9TMxXNunF51KEJHDgN/mVHsJ801fBvgLsF29ttAVcKE7
+      RSMi/YGlVfX1yLE+wPVAMRslXgY2VNWPamRiKj50ceZDRAaKyFgR2TCh+KfAS8F5CwBVnQ3sSX6v
+      fi+21F93kYP36E4METkdOB5bvbwBOEZV3xSRgViP/AHmMz4zoe0G2ALS7sAiwFvAFGCMqj5Un3eQ
+      jAvdmY8wPLkdCwoKMBM4E1gLE/C3VfWGBplXNi50pxth3P0wNjceZQK2nzNRNCJyCnBv3Oe8GfAx
+      utONMO4+EJgdKxoMPBTiKM6HiCyBOXA9LCJ71d7K0nChO4kEz8KHE4pGAuNF5GIRWTJSfxowAnPT
+      vVJEVq+HncXiQneyeCHleE/gYGCiiIwuBB9S1fFYnMV+2E7/psGF7mSxbHiemlK+GLax+TkR2TtE
+      yS0sBGUFK6o7LnQni6HA68Dq2IzLlJR6X8GmIv8D3BKOzUmp2xBc6E4WmwC7qOqnqnorlm/oZ0Ba
+      3JUBdLnu3lgH+4rGpxedkhGR5bC59X1J9it/HVi3HtnmisV7dKdkVPUtVd0fC2Hx51jxdMxpq2lE
+      Dt6jOymEFdJZxcRaEZH1sGHOB8CdjfJnycKF7syHiOyHRdtaHgvlfAlwSTOKtxRc6A4wL6b5Ndi4
+      O8572E3oZao6t66GVQkfozsFjiJZ5ABLYT37eBEZWTgoIoNE5PA62FYx3qM7hWhbj2MzKFOBlXKa
+      3IWlYBkJnAKsoaqv1tDEinGhO4jIWGA9YDdV/YuIDMayU4wG+hZxiu3DDv+mxYXe4YQZk3HA0ao6
+      JlZ2E7ZFLi/Y0NKq+l6NTKwKPkZ3Dg7PD0QPhnAV22BL+1sCaUOTW5td5OBCd+Dr4fkCETlLRJYK
+      r4dhTlt/VdUHsXnyV0LZDCyw//nA3vU0tlx65Vdx2pyC3/iI8FgOm30pRMB9C0BV3w4zLs8AD6nq
+      PnW2syK8R3cmxF4vHp4LQp83LFHVt4F/YDFaWgoXunNl7PVtIRz0xuH1TwoFYdw+FNvh31L40KXD
+      UdULROQzLPfQg6p6fZiJKeQA3dcWTXkY2B9YhSZzwS0Gn17sMMJS/w+xTu4VVb0noc5guqLexlFg
+      VVWdXDsrq4/36B2EiCwIXEckTrmIHKaqF8WqfpBxmvtbTeTgY/RO4wTmD8YP8IuEeu8Ddycc/xA4
+      pNpG1QMXemexG12blwtMiVcKPuh7YUluC7yGLfW/Hq/fCvgYvYMQkTexYckDwI+Bj4G9VDW+Syja
+      ZgPMBWC8qs6qi6E1wIXeQYjIVViCrYHY/dkCzbblrVa40DsAEdkGeAMLMfcysGetMzU3Gy70Nics
+      /kwElgZ+h6VWGQFsrKrxVdG2xYXe5ojI8cDpkUNzsUmIV4FNVfXNhhhWZ1zobUyIcPsqsGhKlWnA
+      d1X1T7F2iwGfqupnNTaxbvj0YntzPOkiB1gCuEtEficiUUetK4B/ZqRQbDm8R29TRGQQ5pn4DhZV
+      6yDgaxlN3gcuxvKAHgmcpKqn1trOeuFCb1NCD/0L4EJVnRiObQGMAVKzOwdeB77SyvPmcVzoHYaI
+      9MB699OAJVOq7aGqt6SUtSQu9A4l3HCeDBzO/M59j6jqyEbYVEtc6G2IiGwMbIeFcO6JOWg9mBRH
+      UUSGAPcBg7Cpx/VU9dk6mlsXXOhtRMgb9Gu6UidGmQKcpqqXJ7Q7BLgIuFRVD46XtwPuj94miMgA
+      4K/YymcSK2FOXIhIj1gMxW8DH2HxFdsSn0dvA0SkH3Antsx/C7aBOf6v+lFV/YOILA6MjaY5By4F
+      jmyF+Czl4kOXNkBEDsA2OX+r4KwVslIciQUPnTf2FpFFsRAWk4F1VPXzxlhdX7xHbw/2Bf4H3FE4
+      oKpvAfeHl5cXbjBDnPObgTWBDetsZ8Nwobc4IrI8sBmwEBZZq3BcMGeuj7AtdFGuCs+b1sHEpsCF
+      3voMxL7HHsB1ISULWGiK9YFTEsbehR/EQvUxsfG40Fuf6ZG/RwH3h17+DMzX5cKENsPDc0e46IJP
+      L7YD02OvNwFeAhYGDlTV+RLbishAoBA38cHam9cceI/e4qjqO1hk2ygLh+fjROQIEVlBRPqELXUP
+      ACtggUJfqqetjcSnF9sAEdkWW8ZPQ4GZwILh9WfACFV9qta2NQveo7cBIVxF1mZnoUvkAId2ksjB
+      hd5O7IH5q2QxFzhVVeMRdNseH7q0GSKyN/AdYAvmn2wYBxyiqv9siGENxoXeYojIlpiD1gfAPWkb
+      mINPy3rAu8BUVc0KHNr2uNBbhJBb6E5go8jh/wK/Bcao6oyGGNYiuNBbABHpCzxEVxaKOFOBY1T1
+      hvpZ1Vr4zWhrsDfpIgebF79eRP4mIvN2+ovIEiJykoh0zFJ/Gi701mDHIusNB54WkStEZBRwPfBz
+      YHDNLGsRfOjS5IhIH+zGc0EsXvlhwGrATlgM87wgQ1eo6vdramQL4EJvcoK77btYysNFVXVmpGwo
+      cB5dqRLjfAyspqrv1tzQJseHLk2MiCwfdu7fD7wWFTmAqj6vqlsBOwOTEk5xqovccKE3KSLSC3hY
+      RP6GTSOuJiIrJdVV1buwHUPRfESTsIgADj50aVpE5FAsnnmUR4BdsxZ/wg9jOLBTPEpuJ+NCb0JC
+      8P5XgWUSil8FdkxysQ1hot8GxqrqNrW1srXwoUtzMppkkQOsCjwjImeFHf1R/gfsF9o7EVzoTUbo
+      lX+K+YynpTrsC/wEmCgiB4tILxHZCovGNaWTNlQUiwu9+dgE6IO53a4K7AmkxUJcCotpPh3zR+8L
+      vFIHG1sOH6M3ISKyePSGM4R6/h4WvmLpjKZJ6c4dXOgthYgsgsVHPALr9aM8B6yrqvHM0A4u9JZE
+      RL4MnMv8PjCbq+rYBpnU9LjQm4QQK/E4bLNEf+xm9CbgWlWdllBfsBB0OwG3q+q36mhuy+FCbwJE
+      5FjMy7BfQvFs4DuqelNCu4ex+IlDVHVyTY1scXzWpcGIyPexqFpJIgdzzLo/1F0h0m5BLBb6GBd5
+      Pt6jNxAR2Qhb1n8aC/s8DHPQii4WHaaqF4nI5liKlk1V9enQvh/2HX5aX8tbDxd6AxGRW4DNgUGq
+      +kk41gObRjyWyEyKiKyMLf8/oarD087pJONDlwYRlu93AMYXRA4QUq4UQsodUZguDMOTvwAbi0ia
+      e4CTggu9ceyMjcvXiYR6LmSJOxibSYlPFxYC/WftH3UScKE3jgXC85LAn8NiENiOoc+BoxPaDAnP
+      s2tsW9vhQm8c0XDPI7AEWgcA2wDnpsykFHry/9TYtrbDb0YbRIi49deEoo+AlVR1eqz+j7EdQxOw
+      eXP/4krAEwFUERHZHXgsxCzPYywwEdvRH2VR4FURuRO4FfgC2B1z6gL4nYu8dLxHrxJhFuU9bPx8
+      HnC2qv4vp823getKuMzfMJ+WObk1nflwoVeJ4HvyEV1Tg+8DpwEXqWrizWOYM78aS5+Yx1RgmO/q
+      Lw+/Ga0u0R1BSwLnAxNE5NvhhzAPEVkMWEBV98N+EFk8A4xykZePC70KhAWc+4ChCcUrYcOTeOiJ
+      X2E/gsVV9UTMa/EsLKOzYkGLxmO+5+ur6vO1sb4z8KFLhYjIepjIlwLuxbJOTMXG6wthAv4acJmq
+      vhzafBUT8QuqunbCOXv7OLy6+KxLBYThx63Yf8YNVfUfCdUmAPFwzr8ObRLjrrjIq48LvTIuwzwN
+      t0gReTdE5Ft0pSb/iYjMAM4MPi5OjfChS5mE8HCTMZEeV2SbfsCLwMqxomcwB67Hqmmj04XfjJbP
+      XuH53hLaHEl3kQOsCzwqIjeLyKCKLXO64T16mYjIv4C1gP5pCbNi9ZfFYq7kZZ+YBZwDnBGPnuuU
+      j/foZSAiawBrY4lqi80mcQYm8nOxBFv/TanXD/gR+T8IpwRc6OURnRLM3e0Twsx9E7hTVY9S1R8C
+      XwbuilQbgw1hRgKbqWraD8EpAx+6lEHYv/lgePk+tjSfFiex0GYAMFtVP4wcE2x6clfgGlX9To1M
+      7ni8Ry+P6FL8ksCdIdRzKqr6blTk4ZgC/4dttPhK1a105uFCL4+4z8lXgZsju4SKRlXfwP4rdAtS
+      5FQPF3p5TAPiMyI7AM+KyIalnCgMX3oCHuq5hrjQyyAMOS5IKFoZeExEjheRvLSIBUZgfjIPVMs+
+      pzt+M1omwc/lNSwtYhKTMQ/Fq9Lm2UWkIPD+wGDfOVQ7vEcvk7Cn81cZVVbGgvRPDmnKNxGRvmDe
+      iSIyDIvStTbwSxd5bfEevQJCPJZbgO2LbPIZFm1rVSw7BcAFqnpEDcxzIrjQKyRshzsNC/lcKn8C
+      vumei7XHhV4lRGRP4Aq6AhPl8QAm8hm1s8op4GP0KqGqN2NhnH+IRcdN4yFsiX8rF3n98B69RoQY
+      itsAczGPxFnAhGI3aDjVxYVeJiIyEPg+liWuDzAJuF5VPVxcE+JCLxER6QNcgsViiW9FnIuFdj5Q
+      Vd+st21OOi70EgjL9dcDe+dUfRu70Xyq9lY5xeA3o6UxmnyRAywLPCIi69TYHqdIXOilUQj0+QZw
+      LfBkRt1+2JY4pwnwoUuRiMhg4GUsAu5GhdyfIbntvsB+wCoJTbdV1fvrZqiTiPfoxVOInXhjNMGt
+      qk5S1ZOBNYHbEtqNqINtTg4u9CIQkTWBt4DUMNCqOgvYg+4xFlesoWlOkbjQcwh+5bdioeXmALuF
+      QETdUNW5qjoa2+hcwHfzNwEu9Hy+h+3nXAZYAlgDuCxnY8XFkb//XEPbnCJxoWcQNjyfnFD0bWz6
+      MCnqFsDi4XkuXSkTnQbiQs9mNLBcStlw4DkROSdE4QJARBbGghSBbajw4P1NgE8vpiAiS2KbJPpj
+      N6FLZFT/HJt2fBdYP7S5WFUPr7WdTnF4j57O1phv+T7ACsBBWOzEJHphyW5HAg8DX3aRNxfeo2cg
+      Iiuo6tTI696Yv/nPsTSJScwFLgd+Fg0rF+Ki/82HMo3Be/QMoiIPr+eo6nlYbtBLMVHH6YH1/hNF
+      5GgR6R9C2P2B5LTnTh3wHr0CgtPWr8le/fwCm3//BFgtnhHaqQ/eo8cQkT4ismReLEUAVX1WVTfF
+      VkTTgoz2xBy8TnKRNw4XegQROQrzTHwP+EhEbhKRDfLaqeot2KLSSXQPVQfwHDbUcRqED10CInIy
+      dpOZxC3AT/JCQ4fzrACcTVfqF7BkXg9VbKRTNh0hdBGRrEhYIrI+kLcbqJBy5czo7n0R+Zqqjk84
+      51XAd4A7VHWXsgx3qkbbD12Cv/i/RWTbjGq7FnGqfsDPgFdEZB8R6SUiRwD/FJEdE+ovjkXm8pmW
+      JqDte3QRuRI4ILy8BzhSVV+J1XkBc9aaCZwJDARGYQtFaXyG3WhOAtZS1c8j5+sFPAvcrarHVued
+      OJXQ1kIXkVWxXUHR3fpzsCnBU1X1f6Hem5hPy3BVfTwc6wn8ADiV7OX/UarazUMxiL23qn5ajffi
+      VEa7D11OoHtIit7YcGKiiHw/xE58BPgAeKJQSVW/UNWLsMWh32Dz4XHuSRJ5aP+5i7x5aNseXURW
+      wTZL5KWBHw88j7nerqCq76ScbyhwIebPAvafYWh8GOQ0J+3coxd683OAi4C0OIdfA/bHxtunpm2o
+      UNXnga2AR8OhC1zkrUM79+g/wLJIHBVeLwYcg2WB65vR9H5g73gGuXAOwdxxF8aW81P3kDrNRdsK
+      PY0wpBmDJbhN4w3gGFW9Kda2H5a76ElVvaJ2VjrVpuOEXkBEtgDOB4ZmVHsCOEJVnw4bMc7HZmsm
+      1MNGp3q0pdBDypUdgB2x6cUHgHHxzBJhPH4IcApd+zzjzMU2UywKrAeMVNVHamO5UyvaTugicihw
+      Ft3DTEwCtlbVyQltFgd+ARyK3ZSmcauq7l4tW5360VZCF5HjgF9mVHkbE/vzKe3XxIYnWyYUzwKG
+      qOqUSu106k/bTC+KyP5kixwsyu3ZaYWq+oKqbgXsguUQjXKOi7x1aYseXUSWxxZ9Fiui+hxgQNL0
+      YeycfbGpxk2BN7GpSs851KK0S49+GSby24ENsB35B2IbHuL0Br6ed8KQ7XlceHmMi7y1afkeXUT2
+      Am4EblbVvWJlPbBIWycw/496TVV9Mee8PbCefDLm7NXaH1SH09JCD9OIL2MiHqKqn6TUO5qusflc
+      YIHQY+edfzDQS1VfqJLJToNo9aHLT7CwzOekiTxwIbYPFOC5YkQOoKoTXOTtQcsKPezNPCa8TJwu
+      LBCEPSu8jMcvdzqAlhU68Cu60pHfLCKj0iqGwJ9LY8H8r6+DbU6T0ZJCF5GNsJiIBZYA7hWRu0Vk
+      9YQmB2Ieixeo6ux62Og0Fy13MxpcZf+BRa1NYg7mYXiqqn4UEuC+gmV3Xj1nLO+0KXm7b5qR/UkX
+      Odg8+VHAfiJyAtbbDwK+4yLvXFqqRxeRhbDeeVngbiy0c58imj4PrO1z4Z1Lq43Rj8NEfoaq7gis
+      jE0dfp7ZynzObxGRlZIKRWTpMCRy2pRW69EHY8lrT4r2ziIyBDgP2CbnFLOw3UVnFJb0w4zMk8Br
+      4cfjtCEtJfQ8RGR7LH9Q0sxLlLdCvcuxVOc7AIeq6sWZrZyWpa2EDvOyUvwIi2yblpWiwGxsjP9v
+      4GuqmhS7xWkD2k7oBURkKeA0bA49715kc1UdW3urnEbRajejRaOq76nqwdg+z6w9nre7yNuflha6
+      iPQWkbWy6oSsFCOB3YGpsWKPdtshtLTQsWHJsyJyjYismFVRVW8F1gZujRw+N2mztNN+tLrQB2Hv
+      YT8sbvk5aSHlAML2uUJW57fJ32PqtAktK3QR2R2LyVKgL5bINm/mZN/wfKy7BHQOLTnrEkT+B2Aa
+      tnPo+fB4A1gTS4y1OuYucJGqXhvaCfAilvJ8Q3cJ6BxaTugisgy2fe5jLEbLS5GyfYFL6PJTLzAG
+      S7alYSV0KVWNh7Nw2phWHLocgC0EjSqIXIwLsFXOpPygRwHbAqjqxy7yzqMVe/QXgf6qunLk2EXM
+      P15P4jZV3a2mxjlNSyv26AOBRUVkqTCP/nuSRf445sZ7VXidlXjLaXNasUefgQ1PJmDeiF9NqHY7
+      sJeqzgmpzj8AnlbVTWpkU39sqnMZ4H3gP6r6US2uVQ4hrvuKWEKyacDUvEhl9SRMCa+MuWC/jtk3
+      N7tViahqwx9Y5KyNiqx7I6AZjweAvpH6Q8LxX1bZ5v7Y/cKTKXY8jv2n6degz7QvlpfpMSyWTdy+
+      p4AfYjFu6m2bAHsCN2MOdbNits0CXgDuxKaDe1R8zUZ8CQlvvPBlXAcsn1N3HWx6MElcd2Pj92j9
+      MaFstSra+3Xg1ZwfXOHxMvCNOn+e64TrFmPfq5hTW71sG57ROaQ9XsRcOKRlhQ5sEXtTn2AZmlN7
+      QmAYFu+80GY6Ft+8V6zeoaH80iraezDm3hu1eSJwIrBJsH1KrPwLYL86fZ77J/SQk8PnswlwbOyz
+      09DJHFxju3qGjix63SlYassfYaEDb8WSGqcJ/nFg4VYV+mMpb2oysFtO26GY/8pCWJDRjbB/1ycC
+      Y8N5xmX9aEq0dTe6DwM+BpaJ1VsbcxiLi32vGn+W22PbCqPX/RQYFKu3eoKg5gLfq6FtZ0auNQs4
+      KN4xhXqDsWFVmtj/nNSuqYVO99486TEW+GrOeXpiY71429uBRapk63pBNPFrHJ9S/+yEujMxN4Va
+      fJZrYv8N49c8PaX+zxPqfoblTq22bbvGrrN7Tv2lsf/SaZq4rNWEXujN88aTXwAXA0umnKcHdmP4
+      RqTNx1Qwpks4/9MptiWO/RO+3MLjMapwc5VwvUdSrrdOSv2tU+qPK6fHzLBrCea/p5oNfKmIdsfm
+      aGLdlhA6sHkw+ArsLnwt4Oog6rQ39yEwOu2LAPph/uUfAI9V0dYfZNi0REqbNTLaHFrlz3KfjGut
+      mNJmxYw2R1fRtl0Szv8I5oaR1W5kjtD/r1WE3p+Q3DZ2fN2M3qnweAnYNuGchXWBxYBVqmSn0P3m
+      svCYC/RMadeH7uPlwmMCVfpvE671YsZntVDG+5qR0uaNtPdVhm1jUq7xFrBpRrvlcjRwR0sIvYgP
+      aDfMZzzrzd6NhZkrtPkp8Cdg0SrasXnG9T/MaftKRtstqmTfBhnXmJ3TdnxG252qZF/WVOLnwLIp
+      7QbmfPdvlmJHU7oAiMguwGHAgJyq2wPPi8h1InIUthl6EDY+rxYHZJR9kNM2vnUvyoGlm5LIARll
+      eaufb2aUHVS6KYkMyijrSXC2S2Bgznknl2JE0wldRA7EZktWBH6MLRRcC6QtqffGphTPCX+fpNVd
+      Pv5GRlmekD7NKNusDFuSyLIv74c4M6NsREhvUyl5nqJpn8PKKccL/LMUI5pK6CLyDeAibJrrG6r6
+      G1W9VVX3x3r3nUlOwFXgaVW9o4r29MJ+cGlUIqQBaSHySiRLEHn2Zf0QF8HcJyplXE75+ynH96jw
+      vPPRVELH/p33Al5U1XeiBar6mareha3upYWv+FmV7RlEdibpSoQENr4uGxEZACyYUaVS+zYszaJE
+      ziT7B39P/ICILIcNS9OYht2LFU3TCD30njuFl2uISGLOUDWvwG2A28Khwpf5mKr+pcpmrZJTXqmQ
+      8kLn5VGpfVkCBFitBFsSUdW3sd55WrwIOEtVH0xoNprsDuYUVZ1eih3NFB/9S+EB5nn3RxHZVRPc
+      SVX1MxHZA7shuQ5zTHopXq8K1FpIxSQAzmLVnPJKf4hfyikvClW9R0TWAEZh08fTgAdU9Yl4XRH5
+      OnBkxukmYcPbkmgaoavqeyLyCea3ArZg8HcR2U4TUpOr6lwReQDYWFVPqJFZte7RKxVSnn2V3CxD
+      5T/Eeajqf7EFwavT6gS/+atJ781nYc5nc0q9ftMMXQITYq+HAE+KyA5haBNnLfK/7ErImhoD88fI
+      otZCyrOvUqFXpUcvgfOBr6SUzQC2V9WHyjlxswn97IRjA7Abj7dF5GIR2VxEhoUtdOsD1R6XR8nr
+      sbPGkZC8UTvK/0qwJYlK7eufU163XVIi8lPMBTrNjq3KFTk0mdBV9WZsJS2JJbEP4kHMwaqw4PLH
+      GpqUNwecJ5TFc8onlWBLEnn25f3Qam1fUYQ092emFD+MOXB1G8+XQl3G6CLSF9ssMQwTh2KrhuOA
+      VzSs+Qb2Ae7CfM3zuA+4v7rWzkezC+nVnPJG/xBzEZER2Ab2eGqdGZgH429j+iiLmgo9BAs6HjiC
+      9A/9bRG5ELhYVT9U1ckisjE2m7JTShuAZ4A9tLbB+5tdSM3+Q8wkREK+E5tli/Iotgmk2+cvIpsB
+      m4aXZ2iR6e5r6ZR1IPAO2Y450cd0YJ/YOTbFBB/d8DAJ23q1YK1sj1x/4Rybz85p/0xO+8UqtK83
+      6R6SCvwup33a7q7CI3P/boW2r4R5MEavNwPrFFM9O7H1k4JDWNEeoLV6E8eVIPD44zJiGxOwX/zC
+      WA9VNffWIt/Lexm2/ian7esZbd+rkn1TMq5xVU7bFzLazqzVZw0sRXfPzqcoYvcVXR6t75Ryzarf
+      jIrIKMyLsPBF/xFzwCnuXwx8H/Nhnofa8v/HqjpTw7utIy9klFUyNHixDFuSyLKvkqHVS7X4rMNw
+      9j7mX3X9NebblDlUEpFNsNg5AP8t5bpVFbqIfBm4ARuyDFXVlVR1V1UdhvXI62J313nTVqNFZJ9q
+      2lYB12eUpc4zh6RhC6WVAzflXVhElsirQ5n2BbKEfmPehUVk8VLys4Z09X/E9t+CDVd3UdXRqjq7
+      iFNEXZtLEnq1/yUV3GkH59RbGNvyNpX0f51TiO0+asQD8+JL24nzYka7ARnvbSYpm0OwXvgc4N1Q
+      9wNsOJc4ng/10zYSv55h34IZ9s0BBqS064slUCgMIaYD15CynzfSrgcW6IisqQAAA8pJREFU6rtw
+      jeex+DOLZTyWxBYFt8VEHo1ccH1J32MVBbFoMOS6Etr0xRaJ0vaJfrfRQg92XpRi32zS968OSWmj
+      pMSZwRZ4Hk9pM5H0bXHnpLSZS8pNO9k7eG5IaSPYOkZSmzfI2PRMclSESh7nNUrohwQD9i6j7UiS
+      b9xuabTIg31LYcvpSR/46ilthqfUnw4sndLm8HK+XKyTeTelTeJueSxmZVL9GcDAlDYH5NiX9gNO
+      i4hQyeO4Ur7Dao7R9w7PedvfuqGqD2NBfx6PFY2szKTqoKrvYQl6k0jbnJCWLe8kNQenJLbOMSUx
+      Bbya6/KxKW3WSDm+dsrx01T1PyllJdsX7tuuzGlXDo0ZowPPYr+0eys4xxLMP+2Uufm4zr26YDd+
+      8Z7lKbqHwluI5I3d15I9R5wVoUqBaTk2/j6hzb/pHmmhH8nTkreREXOGruhnaY9Po+8Pu3/4V06b
+      ch87lvT91UDoc8mJxJRznlXpih34VqMFHrOtD/BQwod+CWFxBetBb06ocy/QuwyhRh9/yWnfC9ux
+      E293NSG+C7bZ45qEOmPjP4iE85+fY9/fY/WvrJHIFdig0UJX7KZ0vQrOdV84z6uNFneK2MfQPQbj
+      XGxJPv6FfIHNUuRGv8KmX+dkfLmjijhHL+B0km/wk+ybC5wH9Cni3EPoHsA0+tgtVj/rvVT6WLlR
+      Qr8/ZshblBkuma6bsnsaLewMGzcD/pog+KiA7gdGlHjegxLE9DnwsxLPMxz7L5Jmn2L/nbYs8bz7
+      0n269QsS4s/XWOgluYBULeOFiByOhQCOMhdbIDpZS9gVIiInAqcA31TVO6tiYI0QkcGY6FfCVu3e
+      wca/D6nqK2We8yvYPsuhWFzK21X12TLPtSqwJbZJY1nMpWEK8LCqlrU6G24w98JuuCcCd6rq0wn1
+      VsO2zU3XKoQgCQtOi2HTmPFNOtltqyj05bA9nH0SiscBBxX7ZYnIWGyJeJDW1jvR6RCqNr2oqm9h
+      PgtJDAOeEZH7gptlKiKyHzACCw3sIneqQlWTdYnIIpiz0vI5VZ/GshuMD48PsR58e2wFbTwwUlXz
+      dtE7TlFUPSudiKyNOc4vWkKzmXR5Ar6OTR29W1XDnI6m6m66qvpvYEfSQ40lURD5R9hObxe5U1Vq
+      sjlaVR/DlpiTojCl8SgWSjnLv9pxyqLmCXVFZH1sKmpPksfu44ATtPrh5BxnHnXLHB0c9DfBnL6m
+      Fx6qOrEuBjgdTculSHeccmiqAEaOUytc6E5H4EJ3OgIXutMRuNCdjsCF7nQELnSnI/h/RFS3BiKq
+      JXMAAAAASUVORK5CYII=");
+  }
+
+  public function genOdsFile($file) {
+    /*
+      --------------------------------------------------------------------------
+      2012-09-04 / replace ZipArchive class with PclZip
+      --------------------------------------------------------------------------
+
+    $zip = new ZipArchive();
+
+    if ($zip->open($file, ZIPARCHIVE::OVERWRITE)!==TRUE) {
+       exit("cannot open $file\n");
+    }
+
+    $zip->addFromString("meta.xml", $this->getMeta());
+    $zip->addFromString("content.xml", $this->getContent());
+    $zip->addFromString("files/mimetype", $this->getMimeType());
+    $zip->addFromString("settings.xml", $this->getSettings());
+    $zip->addFromString("styles.xml", $this->getStyles());
+    $zip->addFromString("files/Configurations2/accelerator/current.xml", $this->getAcceleratorCurrent());
+    $zip->addFromString("META-INF/manifest.xml", $this->getManifest());
+    $zip->addFromString("files/Thumbnails/thumbnail.png", $this->getThumbnail());
+    */
+
+    // create temporary files
+    $tmpDir=$file.'.tmp';
+    if(!file_exists($tmpDir))
+        mkdir($tmpDir, 0755, true);
+
+    $this->writeFile($tmpDir, 'meta.xml', $this->getMeta());
+    $this->writeFile($tmpDir, 'content.xml', $this->getContent());
+    $this->writeFile($tmpDir, 'mimetype', $this->getMimeType());
+    $this->writeFile($tmpDir, 'settings.xml', $this->getSettings());
+    $this->writeFile($tmpDir, 'styles.xml', $this->getStyles());
+    $this->writeFile($tmpDir, 'Configurations2/accelerator/current.xml', $this->getAcceleratorCurrent());
+    $this->writeFile($tmpDir, 'META-INF/manifest.xml', $this->getManifest());
+    //$this->writeFile($tmpDir, 'files/Thumbnails/thumbnail.png', $this->getThumbnail());
+
+    $fileList=array(
+      $tmpDir.'/meta.xml',
+      $tmpDir.'/content.xml',
+      $tmpDir.'/mimetype',
+      $tmpDir.'/settings.xml',
+      $tmpDir.'/styles.xml',
+      $tmpDir.'/Configurations2/accelerator/current.xml',
+      $tmpDir.'/META-INF/manifest.xml'
+    );
+    foreach($this->tmpPictures AS $imgfile => $name)
+    {
+      $fileList[$name]=$imgfile;
+    }
+    $zip=new PclZip($file);
+    $result=$zip->create($fileList, PCLZIP_OPT_REMOVE_PATH, $tmpDir);
+    $this->rmDir($tmpDir);
+
+    if($result===0)
+    {
+      return(false);
+    }
+    return(true);
+  }
+
+  public function downloadOdsFile($fileName) {
+    header('Content-type: application/vnd.oasis.opendocument.spreadsheet');
+    header('Content-Disposition: attachment; filename="'.$fileName.'"');
+    $tmpfile = tempnam("tmp", "genods");
+    $this->genOdsFile($tmpfile);
+    readfile($tmpfile);
+    unlink($tmpfile);
+  }
+
+  /**
+   * -- Added by grum
+   * write file content into tmp file
+   *
+   * @param String $tmpDir: temporary directory
+   * @param String $file: file name
+   * @param String $content: content of the file
+   * @return Boolean: true, or false :)
+   */
+  private function writeFile($tmpDir, $file, $content)
+  {
+    $tmpDir=dirname($tmpDir.'/'.$file);
+    if(!file_exists($tmpDir))
+        mkdir($tmpDir, 0755, true);
+
+    $fHandle=fopen($tmpDir.'/'.basename($file), 'w');
+    if($fHandle)
+    {
+      fwrite($fHandle, $content);
+      fclose($fHandle);
+      return(true);
+    }
+    return(false);
+  }
+
+  /**
+   * -- Added by grum
+   * remove a path recursively
+   *
+   * @param String $directory : directory to remove
+   * @return Bool : true if directory was succesfully removed, otherwise false
+   */
+  private function rmDir($directory)
+  {
+    $directory=rtrim($directory, '\/').'/';
+    $returned=true;
+    if(file_exists($directory) and is_dir($directory) and $directory!='./' and $directory!='../')
+    {
+      $dhandle=scandir($directory);
+      foreach($dhandle as $file)
+      {
+        if($file!='.' and $file!='..' )
+        {
+          if(is_dir($directory.$file))
+          {
+            $returned=self::rmDir($directory.$file, true) & $returned;
+          }
+          else
+          {
+            $returned=unlink($directory.$file) & $returned;
+          }
+        }
+      }
+      if($returned) $returned=rmdir($directory);
+    }
+    return($returned);
+  }
+
+}
+
+?>
Index: /extensions/GrumPluginClasses/classes/GPCCompress.class.inc.php
===================================================================
--- /extensions/GrumPluginClasses/classes/GPCCompress.class.inc.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/GPCCompress.class.inc.php	(revision 17735)
@@ -0,0 +1,253 @@
+<?php
+/* -----------------------------------------------------------------------------
+  class name     : GPCCompress
+  class version  : 1.0.0
+  plugin version : 3.5.4
+  date           : 2012-09-03
+  ------------------------------------------------------------------------------
+  author: grum at piwigo.org
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+  :: HISTORY
+
+| release | date       |
+| 1.0.0   | 2012/09/03 | * New class
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+
+  ------------------------------------------------------------------------------
+    no constructor, only static function are provided
+    - static function availableMethods
+    - static function gzip
+    - static function gunzip
+    - static function bzip2
+    - static function bunzip2
+   ---------------------------------------------------------------------- */
+
+include_once('GPCCore.class.inc.php');
+@include_once(GPCCore::getPiwigoSystemPath().'/admin/include/pclzip.lib.php');
+
+class GPCCompress {
+
+  /**
+   * return an array of available methods for compression
+   * current values are:
+   *    'zip'  for zip files
+   *    'gz'   for gzip files
+   *    'bz2'  for bzip2 files
+   *
+   * @return Array
+   */
+  static public function availableMethods()
+  {
+    $returned=array();
+
+    if(class_exists('PclZip')) $returned[]='zip';
+    if(function_exists('gzopen')) $returned[]='gz';
+    if(function_exists('bzopen')) $returned[]='bz2';
+
+    return($returned);
+  }
+
+  /**
+   * compress $fileName to $compressedFile in gz format
+   *
+   * @param String $fileName: source file to be compressed
+   * @param String $compressedFile: destination file compressed
+   * @param Integer $compressionLevel: level compression 0 (none) to 9 (high)
+   * @return Boolean: true if Ok, otherwise false
+   */
+  static public function gzip($fileName, $compressedFile, $compressionLevel=6)
+  {
+    if(!function_exists('gzopen')) return(false);
+    if(!file_exists($fileName)) return(false);
+    if(file_exists($compressedFile)) unlink($compressedFile);
+    if(file_exists($compressedFile)) return(false);
+
+    $fHandleSrc=fopen($fileName, 'r');
+    if($fHandleSrc)
+    {
+      $fHandleDest=gzopen($compressedFile, 'w'.$compressionLevel);
+
+      if($fHandleDest)
+      {
+        while(!feof($fHandleSrc))
+        {
+          $fContent=fread($fHandleSrc, 1048576);
+          gzwrite($fHandleDest, $fContent);
+        }
+        gzclose($fHandleDest);
+        fclose($fHandleSrc);
+        return(true);
+      }
+      fclose($fHandleSrc);
+    }
+    return(false);
+  }
+
+
+  /**
+   * uncompress $fileName in gz format to $uncompressedFile
+   *
+   * @param String $fileName: source file be uncompressed (in gzformat)
+   * @param String $uncompressedFile: destination file uncompressed
+   * @return Boolean: true if Ok, otherwise false
+   */
+  static public function gunzip($fileName, $uncompressedFile)
+  {
+    if(!function_exists('gzopen')) return(false);
+    if(!file_exists($fileName)) return(false);
+    if(file_exists($uncompressedFile)) unlink($uncompressedFile);
+    if(file_exists($uncompressedFile)) return(false);
+
+    $fHandleSrc=gzopen($fileName, 'r');
+    if($fHandleSrc)
+    {
+      $fHandleDest=fopen($uncompressedFile, 'w');
+
+      if($fHandleDest)
+      {
+        while(!feof($fHandleSrc))
+        {
+          $fContent=gzread($fHandleSrc, 8192);
+          fwrite($fHandleDest, $fContent);
+        }
+        fclose($fHandleDest);
+        gzclose($fHandleSrc);
+        return(true);
+      }
+      gzclose($fHandleSrc);
+    }
+    return(false);
+  }
+
+
+  /**
+   * compress $fileName to $compressedFile in bz2 format
+   *
+   * @param String $fileName: source file to be compressed
+   * @param String $compressedFile: destination file compressed
+   * @return Boolean: true if Ok, otherwise false
+   */
+  static public function bzip2($fileName, $compressedFile)
+  {
+    if(!function_exists('bzopen')) return(false);
+    if(!file_exists($fileName)) return(false);
+    if(file_exists($compressedFile)) unlink($compressedFile);
+    if(file_exists($compressedFile)) return(false);
+
+    $fHandleSrc=fopen($fileName, 'r');
+    if($fHandleSrc)
+    {
+      $fHandleDest=bzopen($compressedFile, 'w');
+
+      if($fHandleDest)
+      {
+        while(!feof($fHandleSrc))
+        {
+          $fContent=fread($fHandleSrc, 8192);
+          bzwrite($fHandleDest, $fContent);
+        }
+        bzclose($fHandleDest);
+        fclose($fHandleSrc);
+        return(true);
+      }
+      fclose($fHandleSrc);
+    }
+    return(false);
+  }
+
+
+  /**
+   * uncompress $fileName in bz2 format to $uncompressedFile
+   *
+   * @param String $fileName: source file be uncompressed (in bz2 format)
+   * @param String $uncompressedFile: destination file uncompressed
+   * @return Boolean: true if Ok, otherwise false
+   */
+  static public function bunzip2($fileName, $uncompressedFile)
+  {
+    if(!function_exists('bzopen')) return(false);
+    if(!file_exists($fileName)) return(false);
+    if(file_exists($uncompressedFile)) unlink($uncompressedFile);
+    if(file_exists($uncompressedFile)) return(false);
+
+    $fHandleSrc=bzopen($fileName, 'r');
+    if($fHandleSrc)
+    {
+      $fHandleDest=fopen($uncompressedFile, 'w');
+
+      if($fHandleDest)
+      {
+        while(!feof($fHandleSrc))
+        {
+          $fContent=bzread($fHandleSrc, 8192);
+          fwrite($fHandleDest, $fContent);
+        }
+        fclose($fHandleDest);
+        bzclose($fHandleSrc);
+        return(true);
+      }
+      bzclose($fHandleSrc);
+    }
+    return(false);
+  }
+
+
+  /**
+   * Encapsulate the PclZip class for a simpler useage
+   * compress $filesNames to $compressedFile in zip format
+   *
+   * @param Array $filesNames: source files to be compressed
+   * @param String $compressedFile: destination file compressed
+   * @param Integer $compressionLevel: level compression 0 (none) to 9 (high)
+   * @return Boolean: true if Ok, otherwise false
+   */
+  static public function zip($filesNames, $compressedFile, $addedPath='', $removedPath='')
+  {
+    if(is_array($filesNames) and count($filesNames)==0) return(false);
+    if(!is_array($filesNames) and !file_exists($filesNames)) return(false);
+    if(file_exists($compressedFile)) unlink($compressedFile);
+    if(file_exists($compressedFile)) return(false);
+
+    if(!is_array($filesNames))
+      $filesNames=array($filesNames);
+
+    $files=array();
+    foreach($filesNames as $file)
+    {
+      if(file_exists($file)) $files[]=$file;
+    }
+
+    if(count($filesNames)==0) return(false);
+
+    $zipFile=new PclZip($compressedFile);
+    $result=$zipFile->create($filesNames, $addedPath, $removedPath);
+    if($result==0) return(false);
+    return(true);
+  }
+
+
+  /**
+   * Encapsulate the PclZip class for a simpler useage
+   * uncompress $compressedFile in zip format to $destination
+   *
+   * @param String $fileName: source file be uncompressed (in zip format)
+   * @param String $destination: destination file uncompressed
+   * @return Boolean: true if Ok, otherwise false
+   */
+  static public function unzip($fileName, $destination)
+  {
+    if(!file_exists($fileName)) return(false);
+    $zipFile=new PclZip($fileName);
+
+    $result=$zipFile->extract($destination);
+  }
+
+}
+
+
+?>
Index: /extensions/GrumPluginClasses/classes/GPCCore.class.inc.php
===================================================================
--- /extensions/GrumPluginClasses/classes/GPCCore.class.inc.php	(revision 17734)
+++ /extensions/GrumPluginClasses/classes/GPCCore.class.inc.php	(revision 17735)
@@ -3,6 +3,6 @@
 /* -----------------------------------------------------------------------------
   class name     : GPCCore
-  class version  : 1.4.2
-  plugin version : 3.5.3
+  class version  : 1.4.3
+  plugin version : 3.5.4
   date           : 2012-07-27
   ------------------------------------------------------------------------------
@@ -74,4 +74,10 @@
 |         |            |
 | 1.4.2   | 2012/07/27 | * AddHeaderContent can manage 'raw' content
+|         |            |
+| 1.4.3   | 2012/08/29 | * Add js objects: inputTreeList + inputExportBox + download
+|         |            |
+|         |            | * Update js objects: inputText (bug fix)
+|         |            |
+|         |            | * Add urlBuild function
 |         |            |
 |         |            |
@@ -102,4 +108,5 @@
     - static function setTemplateToken
     - static function addHeaderContent
+    - static function urlBuild
    ---------------------------------------------------------------------- */
 
@@ -144,6 +151,8 @@
         Array('name' => "GPCAjax", 'version' => "3.1.0"),
         Array('name' => "GPCCategorySelector", 'version' => "1.0.1"),
-        Array('name' => "GPCCore", 'version' => "1.4.2"),
+        Array('name' => "GPCCompress", 'version' => "1.4.0"),
+        Array('name' => "GPCCore", 'version' => "1.4.3"),
         //Array('name' => "GPCCss", 'version' => "3.1.0"),  removed with v1.4.1
+        Array('name' => "GPCExport", 'version' => "1.0.0"),
         Array('name' => "GPCPagesNavigation", 'version' => "2.0.0"),
         Array('name' => "GPCPublicIntegration", 'version' => "2.0.0"),
@@ -151,7 +160,7 @@
         Array('name' => "GPCTables", 'version' => "1.5.0"),
         Array('name' => "GPCTabSheet", 'version' => "1.1.2"),
-        Array('name' => "GPCTranslate", 'version' => "2.1.1"),
-        Array('name' => "GPCUsersGroups", 'version' => "2.1.0"),
-        Array('name' => "GPCUserAgent", 'version' => "1.0.0")
+        //Array('name' => "GPCTranslate", 'version' => "2.1.1"), doesn't exist anymore
+        Array('name' => "GPCUserAgent", 'version' => "1.0.1"),
+        Array('name' => "GPCUsersGroups", 'version' => "2.1.0")
       )
     );
@@ -669,4 +678,5 @@
           break;
         case 'canvasDraw.graph':
+          self::addHeaderCSS('gpc.canvasDraw', GPC_PATH.'css/canvasDraw.css');
           self::addHeaderCSS('gpc.canvasDrawT', sprintf($themeFile, 'canvasDraw'));
           self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
@@ -746,4 +756,27 @@
           self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
           self::addHeaderJS('gpc.inputDotArea', GPC_PATH.'js/ui.inputDotArea.js', array('jquery.ui.widget'));
+          break;
+        case 'inputExportBox':
+          self::addHeaderCSS('gpc.inputText', GPC_PATH.'css/inputText.css');
+          self::addHeaderCSS('gpc.inputTextT', sprintf($themeFile, 'inputText'));
+          self::addHeaderCSS('gpc.inputList', GPC_PATH.'css/inputList.css');
+          self::addHeaderCSS('gpc.inputListT', sprintf($themeFile, 'inputList'));
+          self::addHeaderCSS('gpc.inputExportBox', GPC_PATH.'css/inputExportBox.css');
+          self::addHeaderCSS('gpc.inputExportBoxT', sprintf($themeFile, 'inputExportBox'));
+
+          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
+          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
+
+          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
+          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
+          self::addHeaderJS('jquery.ui.position', 'themes/default/js/ui/jquery.ui.position.js', array('jquery.ui.mouse'));
+          self::addHeaderJS('jquery.ui.resizable', 'themes/default/js/ui/jquery.ui.resizable.js', array('jquery.ui.position'));
+          self::addHeaderJS('jquery.ui.draggable', 'themes/default/js/ui/jquery.ui.draggable.js', array('jquery.ui.resizable'));
+          self::addHeaderJS('jquery.ui.sortable', 'themes/default/js/ui/jquery.ui.sortable.js', array('jquery.ui.draggable'));
+          self::addHeaderJS('jquery.ui.dialog', 'themes/default/js/ui/jquery.ui.dialog.js', array('jquery.ui.sortable'));
+
+          self::addHeaderJS('gpc.inputText', GPC_PATH.'js/ui.inputText.js', array('jquery.ui.dialog'));
+          self::addHeaderJS('gpc.inputList', GPC_PATH.'js/ui.inputList.js', array('jquery.ui.dialog'));
+          self::addHeaderJS('gpc.inputExportBox', GPC_PATH.'js/ui.inputExportBox.js', array('jquery.ui.dialog'));
           break;
         case 'inputFilterBox':
@@ -802,4 +835,11 @@
           self::addHeaderJS('gpc.inputPages', GPC_PATH.'js/ui.inputPages.js', array('jquery','jquery.ui.widget'));
           break;
+        case 'inputPath':
+          self::addHeaderCSS('gpc.inputPath', GPC_PATH.'css/inputPath.css');
+          self::addHeaderCSS('gpc.inputPathT', sprintf($themeFile, 'inputPath'));
+          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
+          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
+          self::addHeaderJS('gpc.inputPath', GPC_PATH.'js/ui.inputPath.js', array('jquery','jquery.ui.widget'));
+          break;
         case 'inputPosition':
           self::addHeaderCSS('gpc.inputPosition', GPC_PATH.'css/inputPosition.css');
@@ -854,4 +894,11 @@
           self::addHeaderJS('gpc.inputText', GPC_PATH.'js/ui.inputText.js', array('jquery.ui.widget'));
           break;
+        case 'inputTreeList':
+          self::addHeaderCSS('gpc.inputTreeList', GPC_PATH.'css/inputTreeList.css');
+          self::addHeaderCSS('gpc.inputTreeListT', sprintf($themeFile, 'inputTreeList'));
+          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
+          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
+          self::addHeaderJS('gpc.inputTreeList', GPC_PATH.'js/ui.inputTreeList.js', array('jquery.ui.widget'));
+          break;
         case 'simpleTip':
           self::addHeaderCSS('gpc.simpleTip', GPC_PATH.'css/simpleTip.css');
@@ -860,4 +907,8 @@
           self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
           self::addHeaderJS('gpc.simpleTip', GPC_PATH.'js/simpleTip.js', array('jquery.ui.widget'));
+          break;
+        case 'download':
+          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
+          self::addHeaderJS('gpc.download', GPC_PATH.'js/ui.download.js', array('jquery'));
           break;
         case 'dynamicTable':
@@ -918,4 +969,34 @@
       }
     }
+  }
+
+
+  /**
+   * build an url from given properties
+   *
+   * @param String $urlType: type of url to build
+   * @param Array $properties: properties used to build url
+   * @return String: url, or empty string if not possible to build it
+   */
+  static public function urlBuild($type, $properties=array())
+  {
+    $returned='';
+    switch($type)
+    {
+      case 'admin.picture':
+        if(isset($properties['pictureId']))
+        {
+          $returned='./admin.php?page=photo-'.$properties['pictureId'];
+        }
+        break;
+      case 'admin.category':
+      case 'admin.album':
+        if(isset($properties['categoryId']))
+        {
+          $returned='./admin.php?page=album-'.$properties['categoryId'];
+        }
+        break;
+    }
+    return($returned);
   }
 
Index: /extensions/GrumPluginClasses/classes/GPCExport.class.inc.php
===================================================================
--- /extensions/GrumPluginClasses/classes/GPCExport.class.inc.php	(revision 17735)
+++ /extensions/GrumPluginClasses/classes/GPCExport.class.inc.php	(revision 17735)
@@ -0,0 +1,668 @@
+<?php
+/* -----------------------------------------------------------------------------
+  class name     : GPCExport
+  class version  : 1.0.0
+  plugin version : 3.5.4
+  date           : 2012-09-03
+  ------------------------------------------------------------------------------
+  author: grum at piwigo.org
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+  :: HISTORY
+
+| release | date       |
+| 1.0.0   | 2012/09/03 | * New class
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+
+  ------------------------------------------------------------------------------
+
+Provided classes are:
+ - GPCGenericExport: generic class, ancestor for all other class. Not to be used directly
+ - GPCCSVExport: class for separated text (.csv) export
+ - GPCODSExport: class for OpenDocument Spreadsheet (.ods) export
+ - GPCSQLiteExport: class for SQLite (.db) export
+
+GPCGenericExport methods:
+  - public function __construct()
+  - public function __destruct()
+  - public function write()
+  - public function setDefaultFormat()
+  - public function setDefaultType
+  - public function setColumnsDef()
+  - public function getColumnsDef()
+  - public function setOptions()
+  - public function getOptions()
+  - public function setFileName()
+  - public function getFileName()
+  - public function setFileDir()
+  - public function getFileDir()
+  - public function setFileMode()
+  - public function getFileMode()
+
+   ---------------------------------------------------------------------- */
+
+include_once('GPCCore.class.inc.php');
+include_once('External/odsPhpGenerator/ods.php');
+
+/**
+ * Generic class, provide generic functions for derivated classes
+ */
+class GPCGenericExport {
+  protected $defaultFormat=array(
+                'INTEGER' => '%d',
+                'TEXT'    => '%s',
+                'REAL'   => '%f'
+              );
+  protected $defaultType='TEXT';
+  protected $fileName='';
+  protected $fileDir='';
+  protected $fileMode='w';
+  protected $columnsDef=array();
+  protected $options=array();
+
+  public function __construct($file='')
+  {
+    if($file!='')
+      $this->setFileName($file);
+  }
+
+  public function __destruct()
+  {
+  }
+
+  /**
+   * this methods have to be overrided to write the destination file
+   *
+   * @param Array $data: data to write
+   * @return Boolean: true if file is written, otherwise false
+   */
+  public function write($data)
+  {
+  } //write
+
+  /**
+   * set the default format for the given type
+   *
+   * @param String $type: 'INTEGER', 'REAL', 'TEXT'
+   * @param String $format: format to be applied (sprintf format)
+   * @return Boolean: true if ok otherwise false
+   */
+  public function setDefaultFormat($type, $format)
+  {
+    $type=strtoupper($type);
+
+    if($type=='INTEGER' or $type=='REAL' or $type=='TEXT')
+    {
+      $this->defaultFormat[$type]=$format;
+      return(true);
+    }
+    return(false);
+  } // setDefaultFormat
+
+  /**
+   * set the default type for file data
+   *
+   * @param String $type: 'INTEGER', 'REAL', 'TEXT'
+   * @return String: the current default column type
+   */
+  public function setDefaultType($type)
+  {
+    $type=strtoupper($type);
+
+    if($type=='INTEGER' or $type=='REAL' or $type=='TEXT')
+    {
+      $this->defaultType=$type;
+    }
+    return($this->defaultType);
+  } // setDefaultType
+
+  /**
+   * set columns definition
+   *  a definition is an array:
+   *   'name'   => (String) Name of the column (mandatory)
+   *   'type'   => (String) Type of column ('INTEGER', 'REAL', 'TEXT')
+   *   'format' => (String) Format applied to the column (sprintf format)
+   *
+   *  if 'type' if not defined, the $defaultType will be used
+   *  if 'format' if not defined, the $defaultFormat will be used
+   *
+   *  an empty array means to use default definition for the column
+   *
+   * @param Array $colsTypes: array of definition
+   * @return Array: the current columns definition
+   */
+  public function setColumnsDef($columnsDef)
+  {
+    if(!is_array($columnsDef))
+      return($this->colsTypes);
+
+    $this->columnsDef=array();
+    foreach($columnsDef as $colDef)
+    {
+      if(isset($colDef['name']))
+      {
+        $type=(isset($colDef['type']) and ($colDef['type']=='INTEGER' or $colDef['type']=='REAL' or $colDef['type']=='TEXT'))?$colDef['type']:$this->defaultType;
+        $format=isset($colDef['format'])?$colDef['format']:$this->defaultFormat[$type];
+        $this->columnsDef[]=array(
+            'name' => $colDef['name'],
+            'type' => $type,
+            'format' => $format
+          );
+      }
+    }
+    return($this->columnsDef);
+  } // setColumnsDef
+
+  /**
+   * get the current columns definition
+   *
+   * @return Array: the columns definition
+   */
+  public function getColumnsDef()
+  {
+    return($this->columnsDef);
+  } // getColumnsDef
+
+  /**
+   * set options values; need to be overrided...
+   *
+   * @param Array $options: associative array of options
+   * @return Array: current options
+   */
+  public function setOptions($options)
+  {
+    if(is_array($options))
+      $this->options=$options;
+    return($this->options);
+  } // setOptions
+
+  /**
+   * get options values
+   *
+   * @param String $option: optional option key
+   * @return Array: current options; if $option if set, return only the option value
+   */
+  public function getOptions($option=null)
+  {
+    if($option!=null and isset($this->options[$option]))
+      return($this->options[$option]);
+    return($this->options);
+  } // getOptions
+
+
+  /**
+   * set the file name
+   * if a directory is given in the filename, the $fileDir is overrided
+   *
+   * @param String $fileName: the file name
+   * @return String: the current file name
+   */
+  public function setFileName($fileName)
+  {
+    $tmpDir=dirname($fileName);
+    $tmpName=basename($fileName);
+    if($tmpName!='')
+      $this->fileName=$tmpName;
+    if($tmpDir!='')
+      $this->setFileDir($tmpDir);
+    return($this->fileName);
+  } // setFileName
+
+  /**
+   * get the file name
+   *
+   * @param Boolean $path: if true, return the file name with the complete path
+   * @return String: the current file name
+   */
+  public function getFileName($path=false)
+  {
+    $returned=$this->fileName;
+    if($path)
+      $returned=$this->fileDir.'/'.$returned;
+    return($returned);
+  } // getFileName
+
+  /**
+   * set the file directory
+   *
+   * @param String $fileDir: the file directory
+   * @return String: the current file directory
+   */
+  public function setFileDir($fileDir)
+  {
+    if($fileDir!='')
+      $this->fileDir=$fileDir;
+    if(substr($this->fileDir,-1)=='/')
+      $this->fileDir=substr($this->fileDir,0,-1);
+    return($this->fileDir);
+  } // setFileDir
+
+  /**
+   * get the file directory
+   *
+   * @return String: the current file directory
+   */
+  public function getFileDir()
+  {
+    return($this->fileDir);
+  } // getFileDir
+
+  /**
+   * set the file writting mode
+   *  'a' => append data to existing file; if file doesn't exist, create it
+   *  'w' => delete file if exists and create a new one
+   *
+   * @param String $mode: the file mode 'a' or 'w'
+   * @return String: the current file mode
+   */
+  public function setFileMode($fileMode)
+  {
+    if($fileMode=='a' or $fileMode=='w')
+      $this->fileMode=$fileMode;
+
+    return($this->fileMode);
+  } // setFileMode
+
+  /**
+   * get the file writting mode
+   *
+   * @return String: the current file mode
+   */
+  public function getFileMode()
+  {
+    return($this->fileMode);
+  }
+} // GPCGenericExport
+
+
+
+/**
+ * Class used to export data into CSV file
+ */
+class GPCCSVExport extends GPCGenericExport {
+  protected $options=array(
+                'separator' => ';',
+                'decimalDot' => ',',
+                'useQuotes' => false,
+                'lineFeed' => "\x0A"
+              );
+
+  /**
+   * set options values; need to be overrided...
+   *
+   * @param Array $options: associative array of options
+   * @return Array: current options
+   */
+  public function setOptions($options)
+  {
+    if(!is_array($options))
+      return($this->options);
+
+    foreach($options as $option => $value)
+    {
+      switch($option)
+      {
+        case 'separator':
+          if($value=='tab') $value=chr(9);
+          $this->options[$option]=$value;
+          break;
+        case 'decimalDot':
+          if($value=='.' or $value==',')
+            $this->options[$option]=$value;
+          break;
+        case 'useQuotes':
+          if($value==true or $value==false)
+            $this->options[$option]=$value;
+          break;
+        case 'lineFeed':
+          if($value=='unix')
+          {
+            $value="\x0A";
+          }
+          elseif($value=='windows')
+          {
+            $value="\x0D\x0A";
+          }
+
+          if($value=="\x0A" or $value=="\x0D\x0A")
+            $this->options[$option]=$value;
+          break;
+      }
+    }
+    return($this->options);
+  } // setOptions
+
+  /**
+   * write the CSV file
+   *
+   * @param Array $data: data to write
+   * @return Boolean: true if file is written, otherwise false
+   */
+  public function write($data)
+  {
+    if(!is_array($data)) return(false);
+
+    if(!file_exists($this->fileDir))
+        mkdir($this->fileDir, 0755, true);
+
+    $fHandle=fopen($this->getFileName(true), $this->fileMode);
+    if($fHandle)
+    {
+      $fileContent='';
+      // columns name
+      $line=array();
+      foreach($this->columnsDef as $column)
+      {
+        $value=$column['name'];
+        if($this->options['useQuotes']) $value='"'.$value.'"';
+        $line[]=$value;
+      }
+      $line=implode($this->options['separator'], $line).$this->options['lineFeed'];
+      $fileContent.=$line;
+
+      // rows
+      foreach($data as $row)
+      {
+        $i=0;
+        $line=array();
+        foreach($row as $column)
+        {
+          $value='';
+          switch($this->columnsDef[$i]['type'])
+          {
+            case 'INTEGER':
+              $value=sprintf($this->columnsDef[$i]['format'], $column);
+              break;
+            case 'REAL':
+              $value=sprintf($this->columnsDef[$i]['format'], $column);
+              if($this->options['decimalDot']!='.')
+                $value=str_replace('.', $this->options['decimalDot'], $value);
+              break;
+            case 'TEXT':
+              $value=sprintf($this->columnsDef[$i]['format'], $column);
+              if($this->options['useQuotes']) $value='"'.$value.'"';
+              break;
+          }
+          $line[]=$value;
+          $i++;
+        }
+        $line=implode($this->options['separator'], $line).$this->options['lineFeed'];
+        $fileContent.=$line;
+      }
+      fwrite($fHandle, $fileContent);
+      fclose($fHandle);
+      return(true);
+    }
+    return(false);
+  } //write
+
+} // GPCCSVExport
+
+
+
+
+/**
+ * Class used to export data into ODS file
+ */
+class GPCODSExport extends GPCGenericExport {
+  protected $options=array(
+                'sheetName' => 'Sheet1',
+                'fileTitle' => '',
+                'fileSubject' => '',
+                'keywords' => '',
+                'comments' => ''
+              );
+
+  /**
+   * set options values; need to be overrided...
+   *
+   * @param Array $options: associative array of options
+   * @return Array: current options
+   */
+  public function setOptions($options)
+  {
+    if(!is_array($options))
+      return($this->options);
+
+    foreach($options as $option => $value)
+    {
+      switch($option)
+      {
+        case 'sheetName':
+        case 'fileTitle':
+        case 'fileSubject':
+        case 'keywords':
+        case 'comments':
+          $this->options[$option]=$value;
+          break;
+      }
+    }
+    return($this->options);
+  } // setOptions
+
+  /**
+   * write the ODS file
+   *
+   * @param Array $data: data to write
+   * @return Boolean: true if file is written, otherwise false
+   */
+  public function write($data)
+  {
+    if(!is_array($data)) return(false);
+
+    if(!file_exists($this->fileDir))
+        mkdir($this->fileDir, 0755, true);
+
+    // append mode will be managed later...
+    if(file_exists($this->getFileName(true)))
+      unlink($this->getFileName(true));
+
+    $ods=new ods();
+
+    $ods->setTitle($this->options['fileTitle']);
+    $ods->setSubject($this->options['fileSubject']);
+    $ods->setKeyword($this->options['keywords']);
+    $ods->setDescription($this->options['comments']);
+
+    $sheet=new odsTable($this->options['sheetName']);
+
+    // columns name
+    $headerStyle = new odsStyleTableCell();
+    $headerStyle->setFontWeight('bold');
+    $row=new odsTableRow();
+    foreach($this->columnsDef as $column)
+    {
+      $row->addCell(new odsTableCellString($column['name'], $headerStyle));
+    }
+    $sheet->addRow($row);
+
+    // rows
+    $bodyStyle = new odsStyleTableCell();
+    //$bodyStyle->setFontWeight('bold');
+    foreach($data as $dataRow)
+    {
+      $i=0;
+      $row=new odsTableRow();
+      foreach($dataRow as $column)
+      {
+        switch($this->columnsDef[$i]['type'])
+        {
+          case 'INTEGER':
+          case 'REAL':
+            $cell=new odsTableCellFloat(1*sprintf($this->columnsDef[$i]['format'], $column), $bodyStyle);
+            break;
+          case 'TEXT':
+            $cell=new odsTableCellString(sprintf($this->columnsDef[$i]['format'], $column), $bodyStyle);
+            break;
+          default:
+            $cell=new odsTableCellEmpty();
+            break;
+        }
+        $row->addCell($cell);
+        $i++;
+      }
+      $sheet->addRow($row);
+    }
+
+    $ods->addTable($sheet);
+    return($ods->genOdsFile($this->getFileName(true)));
+  } //write
+
+} // GPCODSExport
+
+
+
+
+
+
+/**
+ * Class used to export data into SQLite file
+ */
+class GPCSQLiteExport extends GPCGenericExport {
+  protected $options=array(
+                'tableName' => 'exported'
+              );
+  protected $dbHandle=null;
+
+  /**
+   * set options values; need to be overrided...
+   *
+   * @param Array $options: associative array of options
+   * @return Array: current options
+   */
+  public function setOptions($options)
+  {
+    if(!is_array($options))
+      return($this->options);
+
+    foreach($options as $option => $value)
+    {
+      switch($option)
+      {
+        case 'separator':
+          if($value=='tab') $value=chr(9);
+          $this->options[$option]=$value;
+          break;
+        case 'decimalDot':
+          if($value=='.' or $value==',')
+            $this->options[$option]=$value;
+          break;
+        case 'useQuotes':
+          if($value==true or $value==false)
+            $this->options[$option]=$value;
+          break;
+        case 'lineFeed':
+          if($value=='unix')
+          {
+            $value="\x0A";
+          }
+          elseif($value=='windows')
+          {
+            $value="\x0D\x0A";
+          }
+
+          if($value=="\x0A" or $value=="\x0D\x0A")
+            $this->options[$option]=$value;
+          break;
+      }
+    }
+    return($this->options);
+  } // setOptions
+
+  /**
+   * write the SQLite file
+   *
+   * @param Array $data: data to write
+   * @return Boolean: true if file is written, otherwise false
+   */
+  public function write($data)
+  {
+    if(!is_array($data)) return(false);
+
+    if(!file_exists($this->fileDir))
+        mkdir($this->fileDir, 0755, true);
+
+
+    if($this->createSQLiteFile($this->getFileName(true)))
+    {
+      $this->dbHandle->exec("BEGIN TRANSACTION");
+
+      // rows
+      foreach($data as $row)
+      {
+        $i=0;
+        $line=array();
+        foreach($row as $column)
+        {
+          $value='';
+          switch($this->columnsDef[$i]['type'])
+          {
+            case 'INTEGER':
+            case 'REAL':
+              $value=sprintf($this->columnsDef[$i]['format'], $column);
+              break;
+            case 'TEXT':
+              $value=sprintf("'".$this->columnsDef[$i]['format']."'", $this->dbHandle->escapeString($column));
+              break;
+          }
+          $line[]=$value;
+          $i++;
+        }
+        $sql="INSERT INTO ".$this->options['tableName']." VALUES (".implode(',', $line).");";
+        $this->dbHandle->exec($sql);
+      }
+      $this->dbHandle->exec("COMMIT TRANSACTION");
+      $this->closeSQLiteFile();
+      return(true);
+    }
+    return(false);
+  } //write
+
+  /**
+   * create the SQLite file and create the table
+   *
+   * @param String $fileName: SQLite file
+   * @return Boolean: true if Ok, otherwise false
+   */
+  private function createSQLiteFile($file)
+  {
+    $this->dbHandle=new SQLite3($file, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
+
+    if($this->dbHandle)
+    {
+      $columns=array();
+      foreach($this->columnsDef as $column)
+      {
+        $columns[]=" '".$column['name']."' ".$column['type'];
+      }
+
+      $sql="CREATE TABLE '".$this->options['tableName']."' (".implode(', ', $columns).");";
+      $this->dbHandle->exec($sql);
+      return(true);
+    }
+    $this->dbHandle=false;
+    return(false);
+  }
+
+  /**
+   * close the SQLite file
+   */
+  private function closeSQLiteFile()
+  {
+    if($this->dbHandle)
+    {
+      $this->dbHandle->close();
+      $this->dbHandle=false;
+    }
+    return(true);
+  }
+
+} // GPCSQLiteExport
+
+
+
+?>
Index: /extensions/GrumPluginClasses/classes/GPCUserAgent.class.inc.php
===================================================================
--- /extensions/GrumPluginClasses/classes/GPCUserAgent.class.inc.php	(revision 17734)
+++ /extensions/GrumPluginClasses/classes/GPCUserAgent.class.inc.php	(revision 17735)
@@ -1,3 +1,20 @@
 <?php
+/* -----------------------------------------------------------------------------
+  class name: GPCUserAgent
+  class version  : 1.0.1
+  plugin version : 3.5.4
+  date           : 2012-09-04
+  ------------------------------------------------------------------------------
+  author: grum at piwog.org
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+
+| release | date       |
+| 1.0.1   | 2012/09/04 | * Fix some bot definition
+|         |            |
+|         |            |
+
+   ---------------------------------------------------------------------- */
 
 require_once('GPCUserAgent.const.inc.php');
Index: /extensions/GrumPluginClasses/classes/GPCUserAgent.const.inc.php
===================================================================
--- /extensions/GrumPluginClasses/classes/GPCUserAgent.const.inc.php	(revision 17734)
+++ /extensions/GrumPluginClasses/classes/GPCUserAgent.const.inc.php	(revision 17735)
@@ -263,4 +263,5 @@
               UA_BOT_EXALEAD           => array(UA_PROP_NAME => 'Exalead',              UA_PROP_TYPE=>UA_BROWSER_TYPE_CRAWLER, UA_PROP_URL => ''),
               UA_BOT_GAMESPY           => array(UA_PROP_NAME => 'GameSpy',              UA_PROP_TYPE=>UA_BROWSER_TYPE_CRAWLER, UA_PROP_URL => ''),
+              UA_BOT_GIGABLAST         => array(UA_PROP_NAME => 'Gigabot',              UA_PROP_TYPE=>UA_BROWSER_TYPE_CRAWLER, UA_PROP_URL => 'http://www.gigablast.com/spider.html'),
               UA_BOT_INKTOMI           => array(UA_PROP_NAME => 'Inktomi',              UA_PROP_TYPE=>UA_BROWSER_TYPE_CRAWLER, UA_PROP_URL => ''),
               UA_BOT_YAHOO_SEARCH      => array(UA_PROP_NAME => 'Yahoo! Search',        UA_PROP_TYPE=>UA_BROWSER_TYPE_CRAWLER, UA_PROP_URL => 'http://www.yahoo.com/'),
Index: /extensions/GrumPluginClasses/css/canvasDraw.css
===================================================================
--- /extensions/GrumPluginClasses/css/canvasDraw.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/canvasDraw.css	(revision 17735)
@@ -0,0 +1,237 @@
+/* dialog resizeable borders */
+div.cd-mainWindow .ui-resizable-n, div.cd-mainWindow .ui-resizable-s {
+  height:0px;
+}
+div.cd-mainWindow .ui-resizable-w, div.cd-mainWindow .ui-resizable-e {
+  width:0px;
+}
+div.ui-resizable-se {
+  width:14px;
+  height:14px;
+  display:block;
+}
+
+/* content */
+div.cd-mainWindow div.ui-dialog-content,
+div.cd-boxWindow div.ui-dialog-content {
+  overflow:hidden;
+}
+
+/* dialog title */
+div.cd-mainWindow div.ui-dialog-titlebar,
+div.cd-boxWindow div.ui-dialog-titlebar {
+  cursor:move;
+}
+div.cd-mainWindow div.ui-dialog-titlebar {
+  height:19px;
+}
+
+div.cd-mainWindow-titleBar-title {
+  display:inline-block;
+  padding:1x;
+}
+div.cd-mainWindow-titleBar-buttonsBar {
+  display:inline-block;
+  float:left;
+}
+div.cd-mainWindow a.ui-dialog-titlebar-close,
+div.cd-boxWindow a.ui-dialog-titlebar-close {
+  display:inline-block;
+  padding:3px 7px 4px 8px;
+  outline:none;
+}
+div.cd-mainWindow a.ui-dialog-titlebar-close {
+  padding:0 7px 3px 8px;
+}
+div.cd-boxWindow a.ui-dialog-titlebar-close {
+  margin: -2px 2px 0 0;
+  padding: 0;
+}
+div.cd-mainWindow a.ui-dialog-titlebar-close:hover,
+div.cd-boxWindow a.ui-dialog-titlebar-close:hover {
+  border:none;
+  outline:none;
+}
+
+/* console */
+div.cd-mainWindow-console div.ui-inputConsole {
+  border-left:0px;
+  border-right:0px
+}
+
+/* status bar */
+div.cd-mainWindow-statusBar table.ui-inputStatusBar {
+  border:none;
+  font-size:80%;
+}
+div.cd-mainWindow-statusBar table.ui-inputStatusBar td {
+  padding:1px;
+}
+#cd-mainWindow-sb-nfoHelp {
+  border-right:none;
+  text-align: left;
+}
+#cd-mainWindow-sb-nfoKeyCTRL, #cd-mainWindow-sb-nfoKeyALT {
+  border:none;
+}
+#cd-mainWindow-sb-nfoKeySHIFT, #cd-mainWindow-sb-nfoKeyALT, #cd-mainWindow-sb-nfoKeyCTRL {
+  text-align:center;
+}
+#cd-mainWindow-sb-nfoZoom {
+  text-align:center;
+}
+#cd-mainWindow-sb-nfoSize, #cd-mainWindow-sb-nfoPosition {
+  text-align:right;
+  padding-right:3px;
+}
+
+
+div#iBtToolsSelect,
+div#iBtToolsZoom,
+div#iBtToolsLines,
+div#iBtToolsTexts,
+div#iBtToolsShapes,
+div#iBtToolsArrows,
+div#iBtToolsImages {
+  width:22px;
+  height:22px;
+  margin:0;
+  padding:0;
+  float:left;
+}
+
+div#iBtToolsSelect {
+  background-position:0 0;
+}
+div#iBtToolsSelect:hover {
+  background-position:0 -24px;
+}
+div#iBtToolsZoom {
+  background-position:-24px 0;
+}
+div#iBtToolsZoom:hover {
+  background-position:-24px -24px;
+}
+div#iBtToolsLines {
+  background-position:-48px 0;
+}
+div#iBtToolsLines:hover {
+  background-position:-48px -24px;
+}
+div#iBtToolsTexts {
+  background-position:-70px 0;
+}
+div#iBtToolsTexts:hover {
+  background-position:-70px -24px;
+}
+div#iBtToolsShapes {
+  background-position:-94px 0;
+}
+div#iBtToolsShapes:hover {
+  background-position:-94px -24px;
+}
+div#iBtToolsArrows {
+  background-position:-118px 0;
+}
+div#iBtToolsArrows:hover {
+  background-position:-118px -24px;
+}
+div#iBtToolsImages {
+  background-position:-142px 0;
+}
+div#iBtToolsImages:hover {
+  background-position:-142px -24px;
+}
+
+/* drawing area */
+div.ui-drawingArea {
+  width:100%;
+  height:100%;
+  overflow:hidden;
+}
+table.ui-drawingArea-container {
+  width:100%;
+  height:100%;
+  border-collapse: collapse;
+  display:block;
+}
+div.ui-drawingArea-viewport {
+  position:absolute;
+  overflow:hidden;
+  width:100%;
+  height:100%;
+}
+div.ui-drawingArea-sheet {
+  width:100%;
+  height:100%;
+  position:relative;
+}
+canvas.ui-drawingArea-grid,
+canvas.ui-drawingArea-cursor,
+canvas.ui-drawingArea-prev,
+canvas.ui-drawingArea-current,
+canvas.ui-drawingArea-next {
+  position:absolute;
+  display:block;
+}
+canvas.ui-drawingArea-grid { z-index: 160; opacity:0.5; filter:alpha(opacity=50); }
+canvas.ui-drawingArea-cursor  { z-index: 150; opacity:0.5; filter:alpha(opacity=50); }
+canvas.ui-drawingArea-prev { z-index: 120; }
+canvas.ui-drawingArea-current  { z-index: 110; }
+canvas.ui-drawingArea-next  { z-index: 100; }
+
+div.ui-drawingArea-sliderH {
+  position:absolute;
+  height:14px;
+}
+div.ui-drawingArea-sliderV {
+  position:absolute;
+  width:14px;
+}
+div.ui-drawingArea div.ui-slider {
+  cursor:pointer;
+}
+
+div.ui-drawingArea div.ui-slider-horizontal {
+  height:13px;
+  margin:0px;
+}
+div.ui-drawingArea div.ui-slider-vertical {
+  width:13px;
+  margin:0px;
+}
+
+div.ui-drawingArea a.ui-slider-handle {
+  border-style:solid;
+  border-width:1px;
+  display:inline-block;
+  height:10px;
+  margin-top:1px;
+  outline:medium none;
+  position:absolute;
+  width:10px;
+}
+
+
+
+/* drawing graph */
+div.ui-drawingGraph {
+  overflow:hidden;
+}
+div.ui-drawingGraph-viewport {
+  position:absolute;
+  overflow:hidden;
+}
+div.ui-drawingGraph-sheet {
+  position:relative;
+}
+canvas.ui-drawingGraph-cursor,
+canvas.ui-drawingGraph-axis,
+canvas.ui-drawingGraph-graph {
+  position:absolute;
+  display:block;
+}
+canvas.ui-drawingGraph-cursor  { z-index: 120; }
+canvas.ui-drawingGraph-axis { z-index: 130; }
+canvas.ui-drawingGraph-graph { z-index: 110; }
+
Index: /extensions/GrumPluginClasses/css/canvasDraw_clear.css
===================================================================
--- /extensions/GrumPluginClasses/css/canvasDraw_clear.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/canvasDraw_clear.css	(revision 17735)
@@ -0,0 +1,66 @@
+
+/* --------------------------- clear --------------------------- */
+
+
+div.cd-mainWindow div.ui-dialog-content {
+  background:#202020;
+}
+div.cd-boxWindow div.ui-dialog-content {
+  background:#888888;
+}
+div.ui-drawingArea-viewport,
+div.ui-drawingGraph-viewport {
+  background:#000000;
+}
+
+/* dialog resizeable borders */
+div.ui-resizable-se {
+  background:#666666;
+}
+
+/* dialog title */
+div.cd-mainWindow div.ui-dialog-titlebar {
+  background:#666666;
+  color:#222222;
+}
+
+/* secondary windows */
+div.cd-boxWindow div.ui-dialog-titlebar {
+  background:#666666;
+  color:#222222;
+  font-weight:normal;
+  font-size:9px;
+}
+
+/* tool box buttons */
+div#iBtToolsSelect,
+div#iBtToolsZoom,
+div#iBtToolsLines,
+div#iBtToolsTexts,
+div#iBtToolsShapes,
+div#iBtToolsArrows,
+div#iBtToolsImages {
+  background-image:url(./../img/tools.png);
+  background-repeat:no-repeat;
+  background-color:#888888;
+  border-color:#888888;
+}
+div#iBtToolsSelect.ui-inputSwitchButton-checked,
+div#iBtToolsZoom.ui-inputSwitchButton-checked,
+div#iBtToolsLines.ui-inputSwitchButton-checked,
+div#iBtToolsTexts.ui-inputSwitchButton-checked,
+div#iBtToolsShapes.ui-inputSwitchButton-checked,
+div#iBtToolsArrows.ui-inputSwitchButton-checked,
+div#iBtToolsImages.ui-inputSwitchButton-checked {
+  background-color:#555555;
+  border-color:#444444 #999999 #999999 #444444;
+}
+
+div.ui-drawingArea-sheet,
+div.ui-drawingGraph-sheet {
+  background:#F1F1F1;
+}
+div.ui-drawingArea-viewport,
+div.ui-drawingGraph-viewport {
+  background:#202020;
+}
Index: /extensions/GrumPluginClasses/css/canvasDraw_roma.css
===================================================================
--- /extensions/GrumPluginClasses/css/canvasDraw_roma.css	(revision 17734)
+++ /extensions/GrumPluginClasses/css/canvasDraw_roma.css	(revision 17735)
@@ -1,240 +1,2 @@
-/* dialog resizeable borders */
-div.cd-mainWindow .ui-resizable-n, div.cd-mainWindow .ui-resizable-s {
-  height:0px;
-}
-div.cd-mainWindow .ui-resizable-w, div.cd-mainWindow .ui-resizable-e {
-  width:0px;
-}
-div.ui-resizable-se {
-  width:14px;
-  height:14px;
-  display:block;
-}
-
-/* content */
-div.cd-mainWindow div.ui-dialog-content,
-div.cd-boxWindow div.ui-dialog-content {
-  overflow:hidden;
-}
-
-/* dialog title */
-div.cd-mainWindow div.ui-dialog-titlebar,
-div.cd-boxWindow div.ui-dialog-titlebar {
-  cursor:move;
-}
-div.cd-mainWindow div.ui-dialog-titlebar {
-  height:19px;
-}
-
-div.cd-mainWindow-titleBar-title {
-  display:inline-block;
-  padding:1x;
-}
-div.cd-mainWindow-titleBar-buttonsBar {
-  display:inline-block;
-  float:left;
-}
-div.cd-mainWindow a.ui-dialog-titlebar-close,
-div.cd-boxWindow a.ui-dialog-titlebar-close {
-  display:inline-block;
-  padding:3px 7px 4px 8px;
-  outline:none;
-}
-div.cd-mainWindow a.ui-dialog-titlebar-close {
-  padding:0 7px 3px 8px;
-}
-div.cd-boxWindow a.ui-dialog-titlebar-close {
-  margin: -2px 2px 0 0;
-  padding: 0;
-}
-div.cd-mainWindow a.ui-dialog-titlebar-close:hover,
-div.cd-boxWindow a.ui-dialog-titlebar-close:hover {
-  border:none;
-  outline:none;
-}
-
-/* console */
-div.cd-mainWindow-console div.ui-inputConsole {
-  border-left:0px;
-  border-right:0px
-}
-
-/* status bar */
-div.cd-mainWindow-statusBar table.ui-inputStatusBar {
-  border:none;
-  font-size:80%;
-}
-div.cd-mainWindow-statusBar table.ui-inputStatusBar td {
-  padding:1px;
-}
-#cd-mainWindow-sb-nfoHelp {
-  border-right:none;
-  text-align: left;
-}
-#cd-mainWindow-sb-nfoKeyCTRL, #cd-mainWindow-sb-nfoKeyALT {
-  border:none;
-}
-#cd-mainWindow-sb-nfoKeySHIFT, #cd-mainWindow-sb-nfoKeyALT, #cd-mainWindow-sb-nfoKeyCTRL {
-  text-align:center;
-}
-#cd-mainWindow-sb-nfoZoom {
-  text-align:center;
-}
-#cd-mainWindow-sb-nfoSize, #cd-mainWindow-sb-nfoPosition {
-  text-align:right;
-  padding-right:3px;
-}
-
-
-div#iBtToolsSelect,
-div#iBtToolsZoom,
-div#iBtToolsLines,
-div#iBtToolsTexts,
-div#iBtToolsShapes,
-div#iBtToolsArrows,
-div#iBtToolsImages {
-  width:22px;
-  height:22px;
-  margin:0;
-  padding:0;
-  float:left;
-}
-
-div#iBtToolsSelect {
-  background-position:0 0;
-}
-div#iBtToolsSelect:hover {
-  background-position:0 -24px;
-}
-div#iBtToolsZoom {
-  background-position:-24px 0;
-}
-div#iBtToolsZoom:hover {
-  background-position:-24px -24px;
-}
-div#iBtToolsLines {
-  background-position:-48px 0;
-}
-div#iBtToolsLines:hover {
-  background-position:-48px -24px;
-}
-div#iBtToolsTexts {
-  background-position:-70px 0;
-}
-div#iBtToolsTexts:hover {
-  background-position:-70px -24px;
-}
-div#iBtToolsShapes {
-  background-position:-94px 0;
-}
-div#iBtToolsShapes:hover {
-  background-position:-94px -24px;
-}
-div#iBtToolsArrows {
-  background-position:-118px 0;
-}
-div#iBtToolsArrows:hover {
-  background-position:-118px -24px;
-}
-div#iBtToolsImages {
-  background-position:-142px 0;
-}
-div#iBtToolsImages:hover {
-  background-position:-142px -24px;
-}
-
-/* drawing area */
-div.ui-drawingArea {
-  width:100%;
-  height:100%;
-  overflow:hidden;
-}
-table.ui-drawingArea-container {
-  width:100%;
-  height:100%;
-  border-collapse: collapse;
-  display:block;
-}
-div.ui-drawingArea-viewport {
-  position:absolute;
-  overflow:hidden;
-  width:100%;
-  height:100%;
-}
-div.ui-drawingArea-sheet {
-  width:100%;
-  height:100%;
-  position:relative;
-}
-canvas.ui-drawingArea-grid,
-canvas.ui-drawingArea-cursor,
-canvas.ui-drawingArea-prev,
-canvas.ui-drawingArea-current,
-canvas.ui-drawingArea-next {
-  position:absolute;
-  display:block;
-}
-canvas.ui-drawingArea-grid { z-index: 160; opacity:0.5; filter:alpha(opacity=50); }
-canvas.ui-drawingArea-cursor  { z-index: 150; opacity:0.5; filter:alpha(opacity=50); }
-canvas.ui-drawingArea-prev { z-index: 120; }
-canvas.ui-drawingArea-current  { z-index: 110; }
-canvas.ui-drawingArea-next  { z-index: 100; }
-
-div.ui-drawingArea-sliderH {
-  position:absolute;
-  height:14px;
-}
-div.ui-drawingArea-sliderV {
-  position:absolute;
-  width:14px;
-}
-div.ui-drawingArea div.ui-slider {
-  cursor:pointer;
-}
-
-div.ui-drawingArea div.ui-slider-horizontal {
-  height:13px;
-  margin:0px;
-}
-div.ui-drawingArea div.ui-slider-vertical {
-  width:13px;
-  margin:0px;
-}
-
-div.ui-drawingArea a.ui-slider-handle {
-  border-style:solid;
-  border-width:1px;
-  display:inline-block;
-  height:10px;
-  margin-top:1px;
-  outline:medium none;
-  position:absolute;
-  width:10px;
-}
-
-
-
-/* drawing graph */
-div.ui-drawingGraph {
-  overflow:hidden;
-}
-div.ui-drawingGraph-viewport {
-  position:absolute;
-  overflow:hidden;
-}
-div.ui-drawingGraph-sheet {
-  position:relative;
-}
-canvas.ui-drawingGraph-cursor,
-canvas.ui-drawingGraph-axis,
-canvas.ui-drawingGraph-graph {
-  position:absolute;
-  display:block;
-}
-canvas.ui-drawingGraph-cursor  { z-index: 120; }
-canvas.ui-drawingGraph-axis { z-index: 130; }
-canvas.ui-drawingGraph-graph { z-index: 110; }
-
-
 /* --------------------------- roma --------------------------- */
 
Index: /extensions/GrumPluginClasses/css/dynamicTable.css
===================================================================
--- /extensions/GrumPluginClasses/css/dynamicTable.css	(revision 17734)
+++ /extensions/GrumPluginClasses/css/dynamicTable.css	(revision 17735)
@@ -43,5 +43,8 @@
 div.ui-dynamicTableFilterButton-inactive,
 div.ui-dynamicTableFilterButton-active,
-div.ui-dynamicTableSortButton {
+div.ui-dynamicTableSortButton,
+div.ui-dynamicTableGroupButton-inactive,
+div.ui-dynamicTableGroupButton-active,
+div.ui-dynamicTableFooter-saveButton {
   float:right;
   width:14px;
@@ -51,4 +54,5 @@
   padding: 0px;
 }
+
 
 div.ui-dynamicTableLoading {
@@ -75,4 +79,5 @@
 div.ui-dynamicTableFooter-nbItems {
   display:inline-block;
+  margin-top: 2px;
 }
 div.ui-dynamicTableFooter-pagesNavigator {
@@ -80,2 +85,15 @@
   float:right;
 }
+div.ui-dynamicTableFooter-saveButton {
+  display:inline-block;
+  float:left;
+  margin-right:4px;
+}
+div.ui-dynamicTableFooter-saveButtonWait {
+  display:inline-block;
+  float:left;
+  margin-right:4px;
+  background:url(./../icons/processing.gif) no-repeat scroll 0 0 transparent;
+  width:16px;
+  height:16px;
+}
Index: /extensions/GrumPluginClasses/css/dynamicTable_clear.css
===================================================================
--- /extensions/GrumPluginClasses/css/dynamicTable_clear.css	(revision 17734)
+++ /extensions/GrumPluginClasses/css/dynamicTable_clear.css	(revision 17735)
@@ -32,5 +32,7 @@
 div.ui-dynamicTableFilterButton-inactive,
 div.ui-dynamicTableFilterButton-active,
-div.ui-dynamicTableSortButton {
+div.ui-dynamicTableSortButton,
+div.ui-dynamicTableGroupButton-inactive,
+div.ui-dynamicTableGroupButton-active {
   background-image:url(./../icons/buttons.png);
   background-repeat:no-repeat;
@@ -43,5 +45,7 @@
 div.ui-dynamicTableFilterButton-inactive:hover,
 div.ui-dynamicTableFilterButton-active:hover,
-div.ui-dynamicTableSortButton:hover {
+div.ui-dynamicTableSortButton:hover,
+div.ui-dynamicTableGroupButton-inactive:hover,
+div.ui-dynamicTableGroupButton-active:hover {
   background-color:#999999;
 }
@@ -68,2 +72,14 @@
 }
 
+div.ui-dynamicTableGroupButton-active {
+  background-position:-360px -90px;
+}
+div.ui-dynamicTableGroupButton-active:hover {
+  background-position:-360px -105px;
+}
+div.ui-dynamicTableGroupButton-inactive {
+  background-position:-345px -90px;
+}
+div.ui-dynamicTableGroupButton-inactive:hover {
+  background-position:-345px -105px;
+}
Index: /extensions/GrumPluginClasses/css/dynamicTable_roma.css
===================================================================
--- /extensions/GrumPluginClasses/css/dynamicTable_roma.css	(revision 17734)
+++ /extensions/GrumPluginClasses/css/dynamicTable_roma.css	(revision 17735)
@@ -16,5 +16,5 @@
 thead.ui-dynamicTableHeader {
   background:#333333;
-  color:#FF7700;
+  color:#FF3366;
   font-weight:bold;
 }
@@ -32,5 +32,8 @@
 div.ui-dynamicTableFilterButton-inactive,
 div.ui-dynamicTableFilterButton-active,
-div.ui-dynamicTableSortButton {
+div.ui-dynamicTableSortButton,
+div.ui-dynamicTableGroupButton-inactive,
+div.ui-dynamicTableGroupButton-active,
+div.ui-dynamicTableFooter-saveButton {
   background-image:url(./../icons/buttons.png);
   background-repeat:no-repeat;
@@ -43,5 +46,8 @@
 div.ui-dynamicTableFilterButton-inactive:hover,
 div.ui-dynamicTableFilterButton-active:hover,
-div.ui-dynamicTableSortButton:hover {
+div.ui-dynamicTableSortButton:hover,
+div.ui-dynamicTableGroupButton-inactive:hover ,
+div.ui-dynamicTableGroupButton-active:hover,
+div.ui-dynamicTableFooter-saveButton:hover {
   background-color:#222222;
 }
@@ -68,2 +74,21 @@
 }
 
+div.ui-dynamicTableGroupButton-active {
+  background-position:-360px -15px;
+}
+div.ui-dynamicTableGroupButton-active:hover {
+  background-position:-360px 0px;
+}
+div.ui-dynamicTableGroupButton-inactive {
+  background-position:-345px -15px;
+}
+div.ui-dynamicTableGroupButton-inactive:hover {
+  background-position:-345px 0px;
+}
+
+div.ui-dynamicTableFooter-saveButton {
+  background-position:-375px -15px;
+}
+div.ui-dynamicTableFooter-saveButton:hover {
+  background-position:-375px 0px;
+}
Index: /extensions/GrumPluginClasses/css/inputExportBox.css
===================================================================
--- /extensions/GrumPluginClasses/css/inputExportBox.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/inputExportBox.css	(revision 17735)
@@ -0,0 +1,44 @@
+/* for inputFilterBox plugin */
+
+span.ui-inputExportBox-formatInput-info,
+span.ui-inputExportBox-compressionInput-info {
+  float:right;
+  font-size:85%;
+}
+
+table.ui-inputExportBox-content {
+  width:100%;
+  padding:4px;
+}
+
+/* dialog box */
+.ui-dialogExport {
+  text-align:justify;
+}
+.ui-dialogExport div.ui-dialog-titlebar {
+  cursor:move;
+}
+.ui-dialogExport div.ui-dialog-buttonpane {
+  text-align:left;
+}
+.ui-dialogExport div.ui-dialog-buttonpane button {
+  border-style:solid;
+  border-width:1px;
+  cursor:pointer;
+  font-weight:bold;
+  margin-top:1px;
+  text-align:center;
+  display:inline-block;
+}
+.ui-dialogExport div.ui-dialog-content {
+  margin:0px;
+}
+.ui-dialogExport a.ui-dialog-titlebar-close {
+  display:inline-block;
+  margin:0 4px;
+  outline:none;
+}
+
+.ui-dialogExport a.ui-dialog-titlebar-close:hover {
+  border:none;
+}
Index: /extensions/GrumPluginClasses/css/inputExportBox_clear.css
===================================================================
--- /extensions/GrumPluginClasses/css/inputExportBox_clear.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/inputExportBox_clear.css	(revision 17735)
@@ -0,0 +1,20 @@
+/* roma css */
+
+
+/* dialog box */
+.ui-dialogExport {
+  background:#AAAAAA;
+  border:1px solid #999999;
+}
+.ui-dialogExport div.ui-dialog-titlebar {
+  background:#DDDDDD;
+  color:#666666;
+}
+.ui-dialogExport div.ui-dialog-buttonpane button {
+  background:none repeat scroll 0 0 #999999;
+  border-color:#DDDDDD #666666 #666666 #DDDDDD;
+  color:#005E89;
+}
+.ui-dialogExport div.ui-dialog-buttonpane button:active {
+  border-color:#666666 #DDDDDD #DDDDDD #666666;
+}
Index: /extensions/GrumPluginClasses/css/inputExportBox_roma.css
===================================================================
--- /extensions/GrumPluginClasses/css/inputExportBox_roma.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/inputExportBox_roma.css	(revision 17735)
@@ -0,0 +1,20 @@
+/* roma css */
+
+
+/* dialog box */
+.ui-dialogExport{
+  background:#222222;
+  border:1px solid #666666;
+}
+.ui-dialogExport div.ui-dialog-titlebar {
+  background:#666666;
+  color:#222222;
+}
+.ui-dialogExport div.ui-dialog-buttonpane button {
+  background:none repeat scroll 0 0 #666666;
+  border-color:#999999 #444444 #444444 #999999;
+  color:#222222;
+}
+.ui-dialogExport div.ui-dialog-buttonpane button:active {
+  border-color:#444444 #999999 #999999 #444444;
+}
Index: /extensions/GrumPluginClasses/css/inputTreeList.css
===================================================================
--- /extensions/GrumPluginClasses/css/inputTreeList.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/inputTreeList.css	(revision 17735)
@@ -0,0 +1,91 @@
+/* for categorySelector plugin */
+.ui-inputTreeList {
+  cursor:default;
+  min-height:17px;
+  padding:0;
+}
+div.ui-inputTreeList:focus {
+  outline:none;
+}
+
+.ui-inputTreeList-nfo {
+  margin:3px;
+  padding-left:3px;
+  float:right;
+  font-size:8px;
+  max-height:8px;
+}
+
+.ui-inputTreeList-list {
+  margin-top:-1px;
+  cursor:default;
+  font-size:14px;
+  font-family:sans-serif;
+  z-index:9999;
+}
+
+.ui-inputTreeList-item {
+  min-height:15px;
+}
+
+div.ui-inputTreeList-multiple div.ui-inputTreeList-check,
+div.ui-inputTreeList-multiple div.ui-inputTreeList-name,
+li.ui-inputTreeList-expandable-item div.ui-inputTreeList-expand-item,
+li.ui-inputTreeList-collapsable-item div.ui-inputTreeList-expand-item {
+   display:inline-block;
+}
+.ui-inputTreeList-expandable-item,
+.ui-inputTreeList-collapsable-item {
+  background: none no-repeat scroll 0px 0px;
+}
+
+.ui-inputTreeList-check {
+  background:none no-repeat scroll 0 0 transparent;
+  display:inline-block;
+  height:13px;
+  width:17px;
+}
+
+
+/* --- */
+.ui-inputTreeList-name ul { list-style:none; margin:0; padding:0; }
+.ui-inputTreeList-name li.ui-inputTreeList-selected-cat {
+  -moz-border-radius:3px;
+  -webkit-border-radius:3px;
+  -khtml-border-radius:3px;
+  border-radius:3px;
+  float:left;
+  margin-bottom:1px;
+  margin-right:1px;
+  padding:0 4px;
+  cursor:default;
+}
+.ui-inputTreeList-name ul li.ui-inputTreeList-selected-cat span { cursor:pointer; }
+.ui-inputTreeList-name li span {
+  font-family:sans;
+  font-size:80%;
+  font-weight:bold;
+  padding:0 3px;
+  position:relative;
+  top:-1px;
+}
+.ui-inputTreeList-arrow {
+  border-style:solid;
+  border-width:1px;
+  cursor:pointer;
+  font-weight:bold;
+  width:14px;
+  margin-top:1px;
+  height:14px;
+  text-align:center;
+  display:inline-block;
+}
+.ui-inputTreeList-name {
+  padding: 1px;
+  display: inline-block;
+}
+div.ui-inputTreeList-list div.ui-inputTreeList-name {
+  position: relative;
+  top: -2px;
+}
+
Index: /extensions/GrumPluginClasses/css/inputTreeList_clear.css
===================================================================
--- /extensions/GrumPluginClasses/css/inputTreeList_clear.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/inputTreeList_clear.css	(revision 17735)
@@ -0,0 +1,73 @@
+/* roma css */
+
+.ui-inputTreeList,
+.ui-inputTreeList-list {
+  background-color:#DDDDDD;
+  border:1px solid #999999;
+  color:#666666;
+}
+
+li.ui-inputTreeList-item:hover {
+  background-color:#AAAAAA;
+  color:#DDDDDD;
+}
+
+.ui-inputTreeList-selected-item {
+  background-color:#999999;
+  color:#DDDDDD;
+}
+
+.ui-inputTreeList-arrow,
+li.ui-inputTreeList-selected-item div.ui-inputTreeList-check,
+li.ui-inputTreeList-item div.ui-inputTreeList-check,
+li.ui-inputTreeList-expandable-item div.ui-inputTreeList-expand-item,
+li.ui-inputTreeList-collapsable-item div.ui-inputTreeList-expand-item {
+  background-image:url(./../icons/buttons.png);
+  background-repeat:no-repeat;
+  width:15px;
+  height:15px;
+}
+
+
+li.ui-inputTreeList-selected-item div.ui-inputTreeList-check {
+  background-position:-195px -90px;
+}
+li.ui-inputTreeList-unselected-item div.ui-inputTreeList-check {
+  background-position:-180px -90px;
+}
+li.ui-inputTreeList-collapsable-item div.ui-inputTreeList-expand-item {
+  background-position:-165px -90px;
+}
+li.ui-inputTreeList-expandable-item div.ui-inputTreeList-expand-item {
+  background-position:-150px -90px;
+}
+
+
+
+/* --- */
+.ui-inputTreeList-name ul li.ui-inputTreeList-selected-cat {
+  background:#999999;
+  color:#DDDDDD;
+  margin-top:1px;
+  padding-top:1px;
+}
+
+.ui-error, input[type='text'].ui-error {
+  background:#ff8080;
+  border-color:#800000;
+  color:#800000;
+}
+
+.ui-inputTreeList-arrow {
+  background-position:-30px -90px;
+  -moz-border-radius:2px;
+  -webkit-border-radius:2px;
+  -khtml-border-radius:2px;
+  border-radius:2px;
+  color:#005E89;
+  border:0px;
+}
+.ui-inputTreeList-arrow:hover {
+  background-position:-30px -105px;
+  background-color:#999999;
+}
Index: /extensions/GrumPluginClasses/css/inputTreeList_roma.css
===================================================================
--- /extensions/GrumPluginClasses/css/inputTreeList_roma.css	(revision 17735)
+++ /extensions/GrumPluginClasses/css/inputTreeList_roma.css	(revision 17735)
@@ -0,0 +1,71 @@
+/* roma css */
+
+.ui-inputTreeList,
+.ui-inputTreeList-list {
+  background-color:#444444;
+  border:1px solid #666666;
+  color:#999999;
+}
+
+li.ui-inputTreeList-item:hover {
+  background-color:#666666;
+}
+
+.ui-inputTreeList-selected-item {
+  background-color:#777777;
+}
+
+.ui-inputTreeList-arrow,
+li.ui-inputTreeList-selected-item div.ui-inputTreeList-check,
+li.ui-inputTreeList-item div.ui-inputTreeList-check,
+li.ui-inputTreeList-expandable-item div.ui-inputTreeList-expand-item,
+li.ui-inputTreeList-collapsable-item div.ui-inputTreeList-expand-item {
+  background-image:url(./../icons/buttons.png);
+  background-repeat:no-repeat;
+  width:15px;
+  height:15px;
+}
+
+
+li.ui-inputTreeList-selected-item div.ui-inputTreeList-check {
+  background-position:-195px -15px;
+}
+li.ui-inputTreeList-unselected-item div.ui-inputTreeList-check {
+  background-position:-180px -15px;
+}
+li.ui-inputTreeList-collapsable-item div.ui-inputTreeList-expand-item {
+  background-position:-165px -15px;
+}
+li.ui-inputTreeList-expandable-item div.ui-inputTreeList-expand-item {
+  background-position:-150px -15px;
+}
+
+
+
+/* --- */
+.ui-inputTreeList-name ul li.ui-inputTreeList-selected-cat {
+  background-color:#666666;
+  color:#999999;
+  margin-top:1px;
+  padding-top:1px;
+}
+
+.ui-error, input[type='text'].ui-error {
+  background:#ff8080;
+  border-color:#800000;
+  color:#800000;
+}
+
+.ui-inputTreeList-arrow {
+  background-position:-30px -15px;
+  -moz-border-radius:2px;
+  -webkit-border-radius:2px;
+  -khtml-border-radius:2px;
+  border-radius:2px;
+  color:#FF7700;
+  border:0px;
+}
+.ui-inputTreeList-arrow:hover {
+  background-position:-30px 0px;
+  background-color:#222222;
+}
Index: /extensions/GrumPluginClasses/gpc_version.inc.php
===================================================================
--- /extensions/GrumPluginClasses/gpc_version.inc.php	(revision 17734)
+++ /extensions/GrumPluginClasses/gpc_version.inc.php	(revision 17735)
@@ -15,5 +15,5 @@
   if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
 
-  if(!defined('GPC_VERSION')) define('GPC_VERSION',  '3.5.3');
-  if(!defined('GPC_VERSION2')) define('GPC_VERSION2', '03.05.03');
+  if(!defined('GPC_VERSION')) define('GPC_VERSION',  '3.5.4');
+  if(!defined('GPC_VERSION2')) define('GPC_VERSION2', '03.05.04');
 ?>
Index: /extensions/GrumPluginClasses/js/CanvasDraw.GraphClasses.js
===================================================================
--- /extensions/GrumPluginClasses/js/CanvasDraw.GraphClasses.js	(revision 17734)
+++ /extensions/GrumPluginClasses/js/CanvasDraw.GraphClasses.js	(revision 17735)
@@ -335,4 +335,9 @@
             if(value.display.visible.XY.cursorV==true || value.display.visible.XY.cursorV==false) properties.display.visible.XY.cursorV=value.display.visible.XY.cursorV;
           }
+          if(value.display.visible.pie!=null)
+          {
+            if(value.display.visible.pie==true || value.display.visible.pie==false) properties.display.visible.pie=value.display.visible.pie;
+          }
+
         }
       }
@@ -847,5 +852,5 @@
       if(!$.isPlainObject(values)) return(false);
 
-      if(values.backgroundColor!=null && $.isArray(values.backgroundColors)) properties.backgroundColors=values.backgroundColors;
+      if(values.backgroundColors!=null && $.isArray(values.backgroundColors)) properties.backgroundColors=values.backgroundColors;
       if(values.borderColor!=null) properties.borderColor=values.borderColor;
       if(values.borderWidth!=null && values.borderWidth>=0) properties.borderWidth=values.borderWidth;
Index: /extensions/GrumPluginClasses/js/ui.categorySelector.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.categorySelector.js	(revision 17734)
+++ /extensions/GrumPluginClasses/js/ui.categorySelector.js	(revision 17735)
@@ -1162,5 +1162,5 @@
 
           }
-          return(options.userMode);
+          return(options.displayPath);
         }, //setDisplayPath
 
@@ -1571,5 +1571,5 @@
                         }
                        ).bind('click.categorySelector',
-                          {object:object, value:$(this).parent().parent().attr('catid')},
+                          {object:object, value:$(this).parent().parent().attr('catId')},
                           function (event)
                           {
Index: /extensions/GrumPluginClasses/js/ui.download.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.download.js	(revision 17735)
+++ /extensions/GrumPluginClasses/js/ui.download.js	(revision 17735)
@@ -0,0 +1,79 @@
+/**
+ * -----------------------------------------------------------------------------
+ * file: ui.download.js
+ * file version: 1.0.0
+ * date: 2012-09-04
+ *
+ * A jQuery plugin provided by the piwigo's plugin "GrumPluginClasses"
+ *
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.com
+ *   website  : http://www.grum.fr
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ * -----------------------------------------------------------------------------
+ *
+ *
+ *
+ *
+ * :: HISTORY ::
+ *
+ * | release | date       |
+ * | 1.0.0   | 2012/09/04 | first release
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ *
+ */
+
+
+
+/**
+ * Allows to download a file without having to open/refresh a page
+ *
+ * $.download(url)
+ *  => download file with the given url
+ *
+ * @param String url: a valid url
+ */
+$.download = function (url)
+{
+  var timer=null,
+      hif=null,
+
+    /**
+     * initialise the context
+     */
+    init = function (url)
+      {
+        hif=$('<iframe/>',
+            {
+              id:'hif',
+              style:'display:none;',
+              src:url
+            }
+          ).load(startDownload);
+        $('body').append(hif);
+      },
+
+    /**
+     * start file download
+     */
+    startDownload = function ()
+      {
+        timer=window.setInterval(
+            function ()
+            {
+              window.clearInterval(timer);
+              $(hif).remove();
+            }, 1500
+          );
+      };
+
+
+  init(url);
+} // $.downloadUrl
Index: /extensions/GrumPluginClasses/js/ui.dynamicTable.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.dynamicTable.js	(revision 17734)
+++ /extensions/GrumPluginClasses/js/ui.dynamicTable.js	(revision 17735)
@@ -2,6 +2,6 @@
  * -----------------------------------------------------------------------------
  * file: ui.dynamicTable.js
- * file version: 1.0.0
- * date: 2012-06-09
+ * file version: 1.0.1
+ * date: 2012-09-01
  *
  * A jQuery plugin provided by the piwigo's plugin "GrumPluginClasses"
@@ -22,6 +22,11 @@
  *
  * | release | date       |
- * | 1.0.0   | 2012/06/09 | first release
+ * | 1.0.0   | 2012/06/09 | * first release
  * |         |            |
+ * | 1.0.1   | 2012/09/01 |  * fix bugs
+ * |         |            |
+ * |         |            |  * add 'group' icon
+ * |         |            |
+ * |         |            |  * add 'save' button
  * |         |            |
  * |         |            |
@@ -62,13 +67,18 @@
                       contentLoading:null,
                       contentLoaded:null,
+                      contentDisplayed:null,
                       pageChanged:null,
+                      click:null,
+                      saveButtonClick:null,
                       nbItemsPage:50,
                       currentPage:1,
                       sortBoxTitle:'Sort by',
                       showTotalRow:'auto',     // visible, hidden, auto
+                      showSaveButton:false,
                       footerString:
                         {
                           singular:'% item',
-                          plural:'% items'
+                          plural:'% items',
+                          waitForDownload:'Please wait, download will start...'
                         },
                       pagesNavigator:{},
@@ -95,6 +105,8 @@
                     sortedColumns:[],
                     filteredColumns:[],
+                    groupedColumns:[],
                     loadedData:[],
-                    totalRowHasData:false
+                    totalRowHasData:false,
+                    downloadWaitState:false
                   }
                 );
@@ -153,4 +165,9 @@
                         }
                       ),
+                    footerSaveButton:$('<div/>',
+                        {
+                          'class':'ui-dynamicTableFooter-saveButton'
+                        }
+                      ),
                     footerNbItems:$('<div/>',
                         {
@@ -174,4 +191,5 @@
                   .append(objects.totalRowContent.append(objects.totalRowTr))
                   .append(objects.footer
+                            .append(objects.footerSaveButton)
                             .append(objects.footerNbItems)
                             .append(objects.footerPagesNavigator)
@@ -303,4 +321,25 @@
         }, // footerString
 
+      waitForDownload: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setDownloadWaitState($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var properties=this.data('properties');
+            return(properties.downloadWaitState);
+          }
+        }, // waitForDownload
+
       autoLoad: function (value)
         {
@@ -347,4 +386,27 @@
 
 
+
+      showSaveButton : function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setShowSaveButton($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.showSaveButton);
+          }
+        }, // showSaveButton
+
+
        currentPage: function (value)
         {
@@ -473,7 +535,68 @@
         }, // maxHeight
 
+      click: function (value)
+        {
+          if(value!=null && ($.isFunction(value) || value=='clear'))
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setEventClick($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            // return the selected value
+            var options=this.data('options');
+
+            if(options)
+            {
+              return(options.click);
+            }
+            else
+            {
+              return(null);
+            }
+          }
+        }, // click
+
+
+      saveButtonClick: function (value)
+        {
+          if(value!=null && ($.isFunction(value) || value=='clear'))
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setEventSaveButtonClick($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            // return the selected value
+            var options=this.data('options');
+
+            if(options)
+            {
+              return(options.saveButtonClick);
+            }
+            else
+            {
+              return(null);
+            }
+          }
+        }, // saveButtonClick
+
       contentLoading: function (value)
         {
-          if(value!=null && $.isFunction(value))
+          if(value!=null && ($.isFunction(value) || value=='clear'))
           {
             // set selected value
@@ -505,5 +628,5 @@
       contentLoaded: function (value)
         {
-          if(value!=null && $.isFunction(value))
+          if(value!=null && ($.isFunction(value) || value=='clear'))
           {
             // set selected value
@@ -533,7 +656,37 @@
         }, // contentLoaded
 
+      contentDisplayed: function (value)
+        {
+          if(value!=null && ($.isFunction(value) || value=='clear'))
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setEventContentDisplayed($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            // return the selected value
+            var options=this.data('options');
+
+            if(options)
+            {
+              return(options.contentDisplayed);
+            }
+            else
+            {
+              return(null);
+            }
+          }
+        }, // contentDisplayed
+
       pageChanged: function (value)
         {
-          if(value!=null && $.isFunction(value))
+          if(value!=null && ($.isFunction(value) || value=='clear'))
           {
             // set selected value
@@ -610,4 +763,5 @@
           privateMethods.setAutoLoad(object, (value.autoLoad!=null)?value.autoLoad:options.autoLoad);
           privateMethods.setShowTotalRow(object, (value.showTotalRow!=null)?value.showTotalRow:options.showTotalRow);
+          privateMethods.setShowSaveButton(object, (value.showSaveButton!=null)?value.showSaveButton:options.showSaveButton);
           privateMethods.setPostData(object, (value.postData!=null)?value.postData:options.postData);
           privateMethods.setPostUrl(object, (value.postUrl!=null)?value.postUrl:options.postUrl);
@@ -624,5 +778,7 @@
           privateMethods.setEventContentLoading(object, (value.contentLoading!=null)?value.contentLoading:options.contentLoading);
           privateMethods.setEventContentLoaded(object, (value.contentLoaded!=null)?value.contentLoaded:options.contentLoaded);
+          privateMethods.setEventContentDisplayed(object, (value.contentDisplayed!=null)?value.contentDisplayed:options.contentDisplayed);
           privateMethods.setEventPageChanged(object, (value.pageChanged!=null)?value.pageChanged:options.pageChanged);
+          privateMethods.setEventSaveButtonClick(object, (value.saveButtonClick!=null)?value.saveButtonClick:options.saveButtonClick);
           privateMethods.setEventClick(object, (value.click!=null)?value.click:options.click);
 
@@ -662,5 +818,21 @@
 
           return(options.showTotalRow);
-        }, // setAutoLoad
+        }, // setShowTotalRow
+
+
+      setShowSaveButton : function (object, value)
+        {
+          var properties=object.data('properties'),
+              options=object.data('options');
+
+          if((!properties.initialized || value!=options.showSaveButton) && (value==true || value==false))
+          {
+            options.showSaveButton=value;
+            if(properties.initialized)
+              privateMethods.showSaveButton(object);
+          }
+
+          return(options.showSaveButton);
+        }, // setShowSaveButton
 
 
@@ -696,4 +868,5 @@
             newCol.width=(value.width!=null)?value.width:'';
             newCol.sortable=(value.sortable=='asc' || value.sortable=='desc')?value.sortable:'no';
+            newCol.group=(value.group==true||value.group==false)?value.group:false;
             newCol.filter=null;
 
@@ -767,4 +940,7 @@
               options.footerString.plural=value.plural;
 
+            if((!properties.initialized || value.waitForDownload!=null) && value.waitForDownload!='' && value.waitForDownload!=options.footerString.waitForDownload)
+              options.footerString.waitForDownload=value.waitForDownload;
+
             privateMethods.updateNbItems(object);
           }
@@ -779,9 +955,22 @@
         }, // setFooterString
 
-      setDialogsButtons: function (object, value)
+      setDownloadWaitState: function (object, value)
         {
           var options=object.data('options'),
               properties=object.data('properties');
 
+          if((!properties.initialized || value!=null) && (value==true || value==false) && (value!=properties.downloadWaitState))
+          {
+            properties.downloadWaitState=value;
+            privateMethods.applyDownloadWaitState(object);
+          }
+          return(properties.downloadWaitState);
+        }, // setDownloadWaitState
+
+      setDialogsButtons: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties');
+
 
           if($.isPlainObject(value))
@@ -832,4 +1021,5 @@
           var options=object.data('options');
 
+          if(value=='clear') value=null;
           options.contentLoading=value;
           object.unbind('dynamicTableContentLoading');
@@ -842,4 +1032,5 @@
           var options=object.data('options');
 
+          if(value=='clear') value=null;
           options.contentLoaded=value;
           object.unbind('dynamicTableContentLoaded');
@@ -848,8 +1039,20 @@
         }, //setEventContentLoaded
 
+      setEventContentDisplayed : function (object, value)
+        {
+          var options=object.data('options');
+
+          if(value=='clear') value=null;
+          options.contentDisplayed=value;
+          object.unbind('dynamicTableContentDisplayed');
+          if(value) object.bind('dynamicTableContentDisplayed', options.contentDisplayed);
+          return(options.contentDisplayed);
+        }, //setEventContentDisplayed
+
       setEventPageChanged : function (object, value)
         {
           var options=object.data('options');
 
+          if(value=='clear') value=null;
           options.pageChanged=value;
           object.unbind('dynamicTablePageChanged');
@@ -863,4 +1066,5 @@
               objects=object.data('objects');
 
+          if(value=='clear') value=null;
           options.click=value;
           objects.content.find('tr').unbind('click.dynamicTable');
@@ -876,4 +1080,24 @@
           return(options.click);
         }, //setEventClick
+
+
+      setEventSaveButtonClick : function (object, value)
+        {
+          var options=object.data('options'),
+              objects=object.data('objects');
+
+          if(value=='clear') value=null;
+          options.saveButtonClick=value;
+          objects.footerSaveButton.unbind('click.dynamicTable');
+          if(value)
+            objects.footerSaveButton.bind('click.dynamicTable', function (event)
+              {
+                options.saveButtonClick(event, privateMethods.getPostProperties(object));
+              }
+            );
+
+          return(options.saveButtonClick);
+        }, //setEventSaveButtonClick
+
 
       setNbItems: function (object, value)
@@ -981,4 +1205,5 @@
             if(options.columns[i].filter!=null)
             {
+              // filter button
               button=$('<div/>',
                         {
@@ -1039,5 +1264,38 @@
                        );
               td.append(button);
-            }
+            } // filter button
+
+
+            if(options.columns[i].group==true)
+            {
+              // groupable button
+              button=$('<div/>',
+                        {
+                          class:'ui-dynamicTableGroupButton-inactive'
+                        }
+                      )
+                      .bind('click', i,
+                         function (event)
+                         {
+                           var columnIndex=event.data,
+                               $button=$(this);
+
+                          $button.toggleClass('ui-dynamicTableGroupButton-inactive ui-dynamicTableGroupButton-active');
+
+                          if($button.hasClass('ui-dynamicTableGroupButton-active'))
+                          {
+                            properties.groupedColumns[columnIndex]=options.columns[columnIndex].id;
+                          }
+                          else
+                          {
+                            delete properties.groupedColumns[columnIndex];
+                          }
+
+                          privateMethods.setCurrentPage(object, 1);
+                         }
+                       );
+              td.append(button);
+            } // groupable button
+
 
             objects.headerTr.append(td);
@@ -1111,5 +1369,6 @@
       loadContent : function (object, page)
         {
-          var data=null,
+          var tmpData=null,
+              data=null,
               tr=null,
               td=null,
@@ -1127,19 +1386,9 @@
           data.currentPage=options.currentPage;
           data.nbItemsPage=options.nbItemsPage;
-          data.sort=[];
-          for(var i=0;i<properties.sortedColumns.length;i++)
-          {
-            data.sort.push(
-              {
-                id:properties.sortedColumns[i].id,
-                direction:(properties.sortedColumns[i].direction=='asc')?'A':'D'
-              }
-            );
-          }
-          data.filter=[];
-          for(var i in properties.filteredColumns)
-          {
-            data.filter.push(properties.filteredColumns[i]);
-          }
+
+          tmpData=privateMethods.getPostProperties(object);
+          data.sort=tmpData.sort;
+          data.filter=tmpData.filter;
+          data.group=tmpData.group;
 
           if(options.contentLoading) object.trigger('dynamicTableContentLoading', data);
@@ -1178,8 +1427,11 @@
                     for(var col=0;col<msg.rows[row].length;col++)
                     {
-                      td=$('<td/>').html(msg.rows[row][col]);
-
-                      if((col==msg.rows[row].length-1) && properties.hasSortableButton) td.attr('colspan', '2');
-                      tr.append(td);
+                      if(col<options.columns.length)
+                      {
+                        td=$('<td/>').html(msg.rows[row][col]);
+
+                        if((col==msg.rows[row].length-1) && properties.hasSortableButton) td.attr('colspan', '2');
+                        tr.append(td);
+                      }
                     }
                     objects.content.append(tr);
@@ -1228,4 +1480,6 @@
                   privateMethods.showTotalRow(object);
                   privateMethods.setColumnsSize(object);
+
+                  if(options.contentDisplayed) object.trigger('dynamicTableContentDisplayed', msg);
                   privateMethods.displayLoading(object, false);
                 },
@@ -1239,4 +1493,34 @@
          );
         }, //loadContent
+
+      // return a ready-to-use filter/group/sort object
+      getPostProperties: function (object)
+        {
+          var data={},
+              properties=object.data('properties');
+
+          data.sort=[];
+          for(var i=0;i<properties.sortedColumns.length;i++)
+          {
+            data.sort.push(
+              {
+                id:properties.sortedColumns[i].id,
+                direction:(properties.sortedColumns[i].direction=='asc')?'A':'D'
+              }
+            );
+          }
+          data.filter=[];
+          for(var i in properties.filteredColumns)
+          {
+            data.filter.push(properties.filteredColumns[i]);
+          }
+
+          data.group=[];
+          for(var i in properties.groupedColumns)
+          {
+            data.group.push(properties.groupedColumns[i]);
+          }
+          return(data);
+        }, //getPostProperties
 
       setColumnsSize : function (object)
@@ -1364,6 +1648,53 @@
           }
 
-        } // updateNbItems
-
+          if(properties.nbItems>0)
+          {
+            privateMethods.showSaveButton(object);
+          }
+          else
+          {
+            privateMethods.showSaveButton(object, true); // force button hide
+          }
+
+        }, // updateNbItems
+
+      showSaveButton : function (object, hide)
+        {
+          var options=object.data('options'),
+              objects=object.data('objects');
+
+          if(hide==null) hide=false;
+
+          if(options.showSaveButton && hide!=true)
+          {
+            objects.footerSaveButton.css('display',  'block');
+          }
+          else
+          {
+            objects.footerSaveButton.css('display',  'none');
+          }
+        }, // showSaveButton
+
+      applyDownloadWaitState: function (object)
+        {
+          var options=object.data('options'),
+              objects=object.data('objects'),
+              properties=object.data('properties');
+
+          if(properties.downloadWaitState)
+          {
+            objects.footerSaveButton
+              .removeClass('ui-dynamicTableFooter-saveButton')
+              .addClass('ui-dynamicTableFooter-saveButtonWait');
+            objects.footerNbItems.html(options.footerString.waitForDownload);
+          }
+          else
+          {
+            objects.footerSaveButton
+              .removeClass('ui-dynamicTableFooter-saveButtonWait')
+              .addClass('ui-dynamicTableFooter-saveButton');
+            privateMethods.updateNbItems(object);
+          }
+        } // applyDownloadWaitState
     };
 
Index: /extensions/GrumPluginClasses/js/ui.inputExportBox.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.inputExportBox.js	(revision 17735)
+++ /extensions/GrumPluginClasses/js/ui.inputExportBox.js	(revision 17735)
@@ -0,0 +1,944 @@
+/**
+ * -----------------------------------------------------------------------------
+ * file: ui.inputExportBox.js
+ * file version: 1.0.0
+ * date: 2012-09-02
+ *
+ * A jQuery plugin provided by the piwigo's plugin "GrumPluginClasses"
+ *
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.com
+ *   website  : http://www.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ * -----------------------------------------------------------------------------
+ *
+ *
+ *
+ *
+ * :: HISTORY ::
+ *
+ * | release | date       |
+ * | 1.0.0   | 2012/09/02 | first release
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ *
+ */
+
+var inputExportBoxLang={
+    'export':'Export',
+    'name':'Name',
+    'format':'Format',
+    'compression':'Compression'
+  };
+
+
+(
+  function($)
+  {
+    /*
+     * plugin 'public' functions
+     */
+    var publicMethods =
+    {
+      init : function (opt)
+        {
+          return this.each(function()
+            {
+              // default values for the plugin
+              var $this=$(this),
+                  timeStamp=new Date(),
+                  data = $this.data('options'),
+                  objects = $this.data('objects'),
+                  properties = $this.data('properties'),
+                  options =
+                    {
+                      chooseFormat:true,
+                      chooseCompression:true,
+                      chooseName:true,
+                      formatList:[],
+                      compressionList:[],
+                      name:'',
+                      format:'',
+                      compression:''
+                    };
+
+              // if options given, merge it
+              // if(opt) $.extend(options, opt); ==> options are set by setters
+
+              $this.data('options', options);
+
+
+              if(!properties)
+              {
+                $this.data('properties',
+                  {
+                    isValid:false
+                  }
+                );
+                properties=$this.data('properties');
+              }
+
+              if(!objects)
+              {
+                objects =
+                  {
+                    content:$('<table/>',
+                        {
+                          'class':'ui-inputExportBox-content'
+                        }
+                      ),
+                    nameRow:$('<tr/>',
+                        {
+                          'class':'ui-inputExportBox-contentRow'
+                        }
+                      ),
+                    nameInput:$('<div/>',
+                        {
+                          'class':'ui-inputExportBox-inputName'
+                        }
+                      ),
+                    formatRow:$('<tr/>',
+                        {
+                          'class':'ui-inputExportBox-contentRow'
+                        }
+                      ),
+                    formatInput:$('<div/>',
+                        {
+                          'class':'ui-inputExportBox-inputFormat'
+                        }
+                      ),
+                    compressionRow:$('<tr/>',
+                        {
+                          'class':'ui-inputExportBox-contentRow'
+                        }
+                      ),
+                    compressionInput:$('<div/>',
+                        {
+                          'class':'ui-inputExportBox-inputCompression'
+                        }
+                      )
+                  };
+
+                $this
+                  .html('')
+                  .addClass('ui-inputExportBox')
+                  .append(objects.content
+                            .append(objects.nameRow
+                                      .append($('<td/>', {'html':inputExportBoxLang['name']}))
+                                      .append($('<td/>').append(objects.nameInput))
+                                   )
+                            .append(objects.formatRow
+                                      .append($('<td/>', {'html':inputExportBoxLang['format']}))
+                                      .append($('<td/>').append(objects.formatInput))
+                                   )
+                            .append(objects.compressionRow
+                                      .append($('<td/>', {'html':inputExportBoxLang['compression']}))
+                                      .append($('<td/>').append(objects.compressionInput))
+                                   )
+                         );
+
+                objects.nameInput.inputText(
+                  {
+                    regExp:'/^([a-z0-9_\.]|-)+$/i',
+                    change: function (event, value)
+                      {
+                        options.name=value;
+                        properties.isValid=$(this).inputText('isValid');
+                      }
+                  }
+                );
+                objects.formatInput.inputList(
+                  {
+                    listMaxWidth:500,
+                    listMaxHeight:200,
+                    multiple:false,
+                    colsWidth:[],
+                    colsDisplayed:[0,1],
+                    colsCss:["ui-inputExportBox-formatInput-value","ui-inputExportBox-formatInput-info"],
+                    change: function (event, value)
+                      {
+                        options.format=value;
+                      }
+                  }
+                );
+                objects.compressionInput.inputList(
+                  {
+                    listMaxWidth:500,
+                    listMaxHeight:200,
+                    multiple:false,
+                    colsWidth:[],
+                    colsDisplayed:[0,1],
+                    colsCss:["ui-inputExportBox-compressionInput-value","ui-inputExportBox-compressionInput-info"],
+                    change: function (event, value)
+                      {
+                        options.compression=value;
+                      }
+                  }
+                );
+
+                $this.data('objects', objects);
+              }
+
+              privateMethods.setOptions($this, opt);
+            }
+          );
+        }, // init
+      destroy : function ()
+        {
+          return this.each(
+            function()
+            {
+              // default values for the plugin
+              var $this=$(this),
+                  objects = $this.data('objects');
+              objects.compressionInput.inputList('destroy').remove();
+              objects.compressionRow.remove();
+              objects.formatInput.inputList('destroy').remove();
+              objects.formatRow.remove();
+              objects.nameInput.remove();
+              objects.nameRow.remove();
+              objects.content.remove();
+
+              delete objects.compressionInput;
+              delete objects.compressionRow;
+              delete objects.formatInput;
+              delete objects.formatRow;
+              delete objects.nameInput;
+              delete objects.nameRow;
+              delete objects.content;
+
+              $this.removeClass('ui-inputExportBox');
+            }
+          );
+        }, // destroy
+
+      options: function (value)
+        {
+          if(value!=null)
+          {
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setOptions($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options);
+          }
+        }, // options
+
+      // set or return the value for chooseName option
+      chooseName: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setChooseName($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.chooseName);
+          }
+        }, // chooseName
+
+      // set or return the value for chooseFormat option
+      chooseFormat: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setChooseFormat($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.chooseFormat);
+          }
+        }, // chooseFormat
+
+      // set or return the value for chooseCompression option
+      chooseCompression: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setChooseCompression($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.chooseCompression);
+          }
+        }, // chooseCompression
+
+      // set or return the available formats
+      formatList: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setFormatList($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.formatList);
+          }
+        }, // formatList
+
+      // set or return the available compression methods
+      compressionList: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setCompressionList($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.compressionList);
+          }
+        }, // formatList
+
+
+      // set or return the name
+      name: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setName($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.name);
+          }
+        }, // name
+
+
+      // set or return the selected format
+      format: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setFormat($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.format);
+          }
+        }, // format
+
+      // set or return the selected compression
+      compression: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.setCompression($(this), value);
+                }
+              )
+            );
+          }
+          else
+          {
+            var options=this.data('options');
+            return(options.compression);
+          }
+        }, // compression
+
+      // return true if export box is filled
+      isValid: function ()
+        {
+          var properties=this.data('properties');
+          privateMethods.checkValid($(this));
+          return(properties.isValid);
+        },
+
+      // add a new format to the list
+      addFormat: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.addFormat($(this), value);
+                }
+              )
+            );
+          }
+        }, // addFormat
+
+      // remove a format from the list
+      removeFormat: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.removeFormat($(this), value);
+                }
+              )
+            );
+          }
+        }, // removeFormat
+
+      // add a compression type to the list
+      addCompression: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.addCompression($(this), value);
+                }
+              )
+            );
+          }
+        }, // addCompression
+
+      // set or return the name
+      removeCompression: function (value)
+        {
+          if(value!=null)
+          {
+            // set selected value
+            return(
+              this.each(
+                function()
+                {
+                  privateMethods.removeCompression($(this), value);
+                }
+              )
+            );
+          }
+        } // removeCompression
+
+    }; // methods
+
+
+    /*
+     * plugin 'private' methods
+     */
+    var privateMethods =
+    {
+      setOptions : function (object, value)
+        {
+          var properties=object.data('properties'),
+              options=object.data('options'),
+              objects=object.data('objects');
+
+          if(!$.isPlainObject(value)) return(false);
+
+          properties.initialized=false;
+
+          privateMethods.setName(object, (value.name!=null)?value.name:options.name);
+          privateMethods.setCompressionList(object, (value.compressionList!=null)?value.compressionList:options.compressionList);
+          privateMethods.setFormatList(object, (value.formatList!=null)?value.formatList:options.formatList);
+          privateMethods.setCompression(object, (value.compression!=null)?value.compression:options.compression);
+          privateMethods.setFormat(object, (value.format!=null)?value.format:options.format);
+          privateMethods.setChooseName(object, (value.chooseName!=null)?value.chooseName:options.chooseName);
+          privateMethods.setChooseCompression(object, (value.chooseCompression!=null)?value.chooseCompression:options.chooseCompression);
+          privateMethods.setChooseFormat(object, (value.chooseFormat!=null)?value.chooseFormat:options.chooseFormat);
+
+          if((options.format==null || options.format=='') && options.chooseFormat)
+            options.format=objects.formatInput.inputList('value', ':first').inputList('value');
+
+          if((options.compression==null || options.compression=='') && options.chooseCompression)
+            options.compression=objects.compressionInput.inputList('value', ':first').inputList('value');
+
+
+          properties.initialized=true;
+        },
+
+
+      checkValid: function (object)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          properties.isValid=objects.nameInput.inputText('isValid', 'check').inputText('isValid');
+        },
+
+      setChooseCompression: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || value!=options.chooseCompression) && (value==true || value==false))
+          {
+            options.chooseCompression=value;
+            objects.compressionRow.css('display', options.chooseCompression?'table-row':'none');
+          }
+          return(options.chooseCompression);
+        }, // setChooseCompression
+
+      setChooseFormat: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || value!=options.chooseFormat) && (value==true || value==false))
+          {
+            options.chooseFormat=value;
+            objects.formatRow.css('display', options.chooseFormat?'table-row':'none');
+          }
+          return(options.chooseFormat);
+        }, // setChooseFormat
+
+      setChooseName: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || value!=options.chooseName) && (value==true || value==false))
+          {
+            options.chooseName=value;
+            objects.formatRow.css('display', options.chooseName?'table-row':'none');
+          }
+          return(options.chooseName);
+        }, // setChooseName
+
+      setName: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(!properties.initialized || value!=options.name)
+          {
+            options.name=value;
+            objects.nameInput.inputText('value', options.name);
+          }
+          return(options.name);
+        }, // setName
+
+      setFormat: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(!properties.initialized || value!=null)
+          {
+            options.format=objects.formatInput.inputList('value', value).inputList('value');
+          }
+          return(options.format);
+        }, // setFormat
+
+      setCompression: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(!properties.initialized || value!=null)
+          {
+            options.compression=objects.compressionInput.inputList('value', value).inputList('value');
+          }
+          return(options.compression);
+        }, // setCompression
+
+
+      setCompressionList: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(!properties.initialized || $.isArray(value))
+          {
+            privateMethods.removeCompression(object, 'all');
+            for(var i=0;i<value.length;i++)
+            {
+              privateMethods.addCompression(object, value[i]);
+            }
+          }
+          return(options.compressionList);
+        }, // setCompressionList
+
+      setFormatList: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(!properties.initialized || $.isArray(value))
+          {
+            privateMethods.removeFormat(object, 'all');
+            for(var i=0;i<value.length;i++)
+            {
+              privateMethods.addFormat(object, value[i]);
+            }
+          }
+          return(options.formatList);
+        }, // setFormatList
+
+      addCompression: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if($.isPlainObject(value) &&
+             value.id!=null &&
+             value.id!='' &&
+             value.text!=null &&
+             value.text!=''
+            )
+          {
+            options.compressionList.push(
+              {
+                id:value.id,
+                text:value.text,
+                infos:(value.infos!=null)?value.infos:''
+              }
+            );
+          }
+          else if(value=='all')
+          {
+            options.compressionList=[];
+          }
+          privateMethods.applyListValues(object, 'compressionList');
+        }, // addCompression
+
+      removeCompression: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(value!=null && value!='')
+          {
+            for(var i=0;i<options.compressionList.length;i++)
+            {
+              if(options.compressionList[i].id==value)
+              {
+                options.compressionList.splice(i, 1);
+                privateMethods.applyListValues(object, 'compressionList');
+                return(true);
+              }
+            }
+          }
+          return(false);
+        }, // removeCompression
+
+      addFormat: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if($.isPlainObject(value) &&
+             value.id!=null &&
+             value.id!='' &&
+             value.text!=null &&
+             value.text!=''
+            )
+          {
+            options.formatList.push(
+              {
+                id:value.id,
+                text:value.text,
+                infos:(value.infos!=null)?value.infos:''
+              }
+            );
+          }
+          else if(value=='all')
+          {
+            options.formatList=[];
+          }
+          privateMethods.applyListValues(object, 'formatList');
+        }, // addFormat
+
+      removeFormat: function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(value!=null && value!='')
+          {
+            for(var i=0;i<options.formatList.length;i++)
+            {
+              if(options.formatList[i].id==value)
+              {
+                options.formatList.splice(i, 1);
+                privateMethods.applyListValues(object, 'formatList');
+                return(true);
+              }
+            }
+          }
+          return(false);
+        }, // removeFormat
+
+      applyListValues: function (object, list)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects'),
+              target=null,
+              source=null,
+              values=[];
+
+          switch(list)
+          {
+            case 'compressionList':
+              target=objects.compressionInput;
+              source=options.compressionList;
+              break;
+            case 'formatList':
+              target=objects.formatInput;
+              source=options.formatList;
+              break;
+          }
+
+          for(var i=0;i<source.length;i++)
+          {
+            values.push(
+              {
+                value:source[i].id,
+                cols:[source[i].text, source[i].infos]
+              }
+            );
+          }
+          target.inputList('items', values);
+        } // applyListValues
+
+    };
+
+    $.fn.inputExportBox = function(method)
+    {
+      if(publicMethods[method])
+      {
+        return publicMethods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
+      }
+      else if(typeof method === 'object' || ! method)
+      {
+        return publicMethods.init.apply(this, arguments);
+      }
+      else
+      {
+        $.error( 'Method ' +  method + ' does not exist on jQuery.inputExportBox' );
+      }
+    } // $.fn.inputExportBox
+
+  }
+)(jQuery);
+
+
+/**
+ * open a modal dialog box for export
+ */
+$.dialogExport = function (opt)
+{
+  var options=
+        {
+          width:350,
+          height:150,
+          title:'Export',
+          buttons:
+            {
+              ok:'Ok',
+              cancel:'Cancel'
+            },
+          chooseFormat:true,
+          chooseCompression:true,
+          chooseName:true,
+          formatList:[],
+          compressionList:[],
+          name:'',
+          format:'',
+          compression:'',
+          validExport:null,
+          cancelExport:null
+        },
+      objects=
+        {
+          dialogBox:$('<div/>'),
+          iExport:$('<div/>')
+        },
+
+  setOptions = function (opt)
+    {
+      if(opt.width!=null && opt.width>0) options.width=opt.width;
+      if(opt.height!=null && opt.height>0) options.height=opt.height;
+      if(opt.title) options.title=opt.title;
+      if(opt.buttons && opt.buttons.ok) options.buttons.ok=opt.buttons.ok;
+      if(opt.buttons && opt.buttons.cancel) options.buttons.cancel=opt.buttons.cancel;
+      if(opt.chooseFormat!=null && (opt.chooseFormat==true || opt.chooseFormat==false)) options.chooseFormat=opt.chooseFormat;
+      if(opt.chooseCompression!=null && (opt.chooseCompression==true || opt.chooseCompression==false)) options.chooseCompression=opt.chooseCompression;
+      if(opt.chooseName!=null && (opt.chooseName==true || opt.chooseName==false)) options.chooseName=opt.chooseName;
+      if(opt.formatList && $.isArray(opt.formatList)) options.formatList=opt.formatList;
+      if(opt.compressionList && $.isArray(opt.compressionList)) options.compressionList=opt.compressionList;
+      if(opt.name) options.name=opt.name;
+      if(opt.format) options.format=opt.format;
+      if(opt.compression) options.compression=opt.compression;
+
+      if(opt.validExport && $.isFunction(opt.validExport)) options.validExport=opt.validExport;
+      if(opt.cancelExport && $.isFunction(opt.cancelExport)) options.cancelExport=opt.cancelExport;
+    },
+
+  initDialog = function ()
+    {
+      var dialogOpt={},
+          dialogButtons={};
+
+      dialogButtons[options.buttons.ok] = function (event)
+        {
+          if(objects.iExport.inputExportBox('isValid'))
+          {
+            if(options.validExport)
+              options.validExport(event,
+                {
+                  name:objects.iExport.inputExportBox('name'),
+                  format:objects.iExport.inputExportBox('format'),
+                  compression:objects.iExport.inputExportBox('compression')
+                }
+              );
+
+            $(this).dialog('close');
+          }
+        };
+
+      dialogButtons[options.buttons.cancel] = function (event)
+        {
+          if(options.cancelExport)
+            options.cancelExport(event,
+              {
+                name:objects.iExport.inputExportBox('name'),
+                format:objects.iExport.inputExportBox('format'),
+                compression:objects.iExport.inputExportBox('compression')
+              }
+            );
+
+          $(this).dialog('close');
+        };
+
+      dialogOpt=
+          {
+            width:options.width,
+            height:options.height,
+            closeOnEscape:false,
+            closeText:'',
+            dialogClass:'ui-dialogExport',
+            modal:true,
+            resizable:false,
+            title:options.title,
+            buttons:dialogButtons,
+            open: open= function ()
+                    {
+                      objects.iExport
+                        .inputExportBox(
+                          {
+                            name:options.name,
+                            format:options.format,
+                            compression:options.compression,
+                            chooseCompression:options.chooseCompression,
+                            chooseFormat:options.chooseFormat,
+                            chooseName:options.chooseName,
+                            formatList:options.formatList,
+                            compressionList:options.compressionList
+                          }
+                        );
+                    },
+            close: function ()
+                    {
+                      objects.iExport.inputExportBox('destroy').remove();
+                      $(this).dialog('destroy').remove();
+                    }
+          };
+
+      objects.dialogBox
+        .append(objects.iExport)
+        .dialog(dialogOpt);
+    };
+
+  setOptions(opt);
+  initDialog();
+
+  return(objects.iExport);
+} // $.dialogExport
Index: /extensions/GrumPluginClasses/js/ui.inputFilterBox.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.inputFilterBox.js	(revision 17734)
+++ /extensions/GrumPluginClasses/js/ui.inputFilterBox.js	(revision 17735)
@@ -31,21 +31,22 @@
  */
 
+
 var inputFilterBoxLang={
-  'Operator':'Operator',
-  'Value':'Value',
-  'MinValue':'Minimum value',
-  'MaxValue':'Maximum value',
-  '>':'Greater than',
-  '<':'Less than',
-  '>=':'Greater or equal to',
-  '<=':'Less or equal to',
-  '=':'Equal to',
-  '!=':'Different than',
-  'between':'Between',
-  'and':'and',
-  'like':'Like',
-  'not like':'Not like',
-  'invalidParam':'Filter is not valid'
-};
+    'Operator':'Operator',
+    'Value':'Value',
+    'MinValue':'Minimum value',
+    'MaxValue':'Maximum value',
+    '>':'Greater than',
+    '<':'Less than',
+    '>=':'Greater or equal to',
+    '<=':'Less or equal to',
+    '=':'Equal to',
+    '!=':'Different than',
+    'between':'Between',
+    'and':'and',
+    'like':'Like',
+    'not like':'Not like',
+    'invalidParam':'Filter is not valid'
+  };
 
 (
Index: /extensions/GrumPluginClasses/js/ui.inputPath.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.inputPath.js	(revision 17734)
+++ /extensions/GrumPluginClasses/js/ui.inputPath.js	(revision 17735)
@@ -607,7 +607,9 @@
           {
             var item=privateMethods.getItemLevel(event.data, $(this).attr('ip-level'));
-            event.data.trigger('inputPathClick', item);
+
             if(options.autoSetLevel)
               privateMethods.setLevel(event.data, item.level);
+
+            event.data.trigger('inputPathClick', item);
           }
         }
Index: /extensions/GrumPluginClasses/js/ui.inputText.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.inputText.js	(revision 17734)
+++ /extensions/GrumPluginClasses/js/ui.inputText.js	(revision 17735)
@@ -2,6 +2,6 @@
  * -----------------------------------------------------------------------------
  * file: ui.inputText.js
- * file version: 1.1.2
- * date: 2012-06-18
+ * file version: 1.1.3
+ * date: 2012-09-03
  *
  * A jQuery plugin provided by the piwigo's plugin "GrumPluginClasses"
@@ -34,4 +34,6 @@
  * |         |            | * fix bug on regExp option
  * |         |            |
+ * | 1.1.3   | 2012/09/03 | * fix bug on initial value settings & check value validity
+ * |         |            |
  * |         |            |
  * |         |            |
@@ -88,5 +90,5 @@
                     initialized:false,
                     re:/.*/,
-                    value:0,
+                    value:'',
                     isValid:true,
                     languagesValues:{}
@@ -601,10 +603,14 @@
         {
           var objects=object.data('objects'),
-              properties=object.data('properties');
+              properties=object.data('properties'),
+              check=false;
 
           if(value=='check')
+          {
             value=privateMethods.isValid(object, properties.value);
-
-          if(properties.isValid!=value && properties.initialized)
+            check=true;
+          }
+
+          if(properties.isValid!=value && properties.initialized || check)
           {
             properties.isValid=value;
Index: /extensions/GrumPluginClasses/js/ui.inputTreeList.js
===================================================================
--- /extensions/GrumPluginClasses/js/ui.inputTreeList.js	(revision 17735)
+++ /extensions/GrumPluginClasses/js/ui.inputTreeList.js	(revision 17735)
@@ -0,0 +1,1806 @@
+/**
+ * -----------------------------------------------------------------------------
+ * file: ui.inputTreeList.js
+ * file version: 1.0.0
+ * date: 2012-06-18
+ *
+ * A jQuery plugin provided by the piwigo's plugin "GrumPluginClasses"
+ *
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.com
+ *   website  : http://photos.grum.fr
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ * -----------------------------------------------------------------------------
+ *
+ * see ui.inputTreeList.help.txt for help about this plugin
+ *
+ * :: HISTORY ::
+ *
+ * | release | date       |
+ * | 1.0.0   | 2012/08/25 | * first release - fork from ui.categorySelector object
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ * |         |            |
+ *
+ */
+
+
+
+(
+  function($)
+  {
+    /*
+     * plugin 'public' functions
+     */
+    var publicMethods =
+    {
+      init : function (opt)
+        {
+          return this.each(function()
+            {
+              // default values for the plugin
+              var $this=$(this),
+                  timeStamp=new Date(),
+                  data = $this.data('options'),
+                  objects = $this.data('objects'),
+                  properties = $this.data('properties'),
+                  options =
+                    {
+                      triggerChange:'interface', // ''interface': only through user interface; 'all': when value is changed by function call
+                      autoLoad:true,
+                      displayNfo:true,
+                      listMaxWidth:0,
+                      listMaxHeight:0,
+                      levelIndent:16,
+                      iconWidthEC:15,
+                      postUrl:'',
+                      postData:{},
+                      popup:null,
+                      change:null,
+                      load:null,
+                      multiple:false,
+                      popupMode:'click',
+                      displayPath:false,
+                      downArrow:'' //'&dArr;'
+                    };
+
+              // if options given, merge it
+              // if(opt) $.extend(options, opt); ==> options are set by setters
+
+              $this.data('options', options);
+
+
+              if(!properties)
+              {
+                $this.data('properties',
+                  {
+                    objectId:'cs'+Math.ceil(timeStamp.getTime()*Math.random()),
+                    index:-1,
+                    initialized:false,
+                    selectorVisible:false,
+                    items:[],
+                    mouseOver:false,
+                    isValid:true
+                  }
+                );
+                properties=$this.data('properties');
+              }
+
+              if(!objects)
+              {
+                objects =
+                  {
+                    container:$('<div/>',
+                        {
+                          'class':'ui-inputTreeList',
+                          tabindex:0,
+                          css:{
+                            width:'100%'
+                          }
+                        }
+                    ).bind('click.inputTreeList',
+                        function ()
+                        {
+                          privateMethods.displaySelector($this, !$this.data('properties').selectorVisible);
+                          //$(this).focus(); // if get the focus, it hide the dorp-down list.. ?
+                        }
+                      ),
+                    containerName:$('<div/>',
+                      {
+                        html: '&nbsp;',
+                        'class':'ui-inputTreeList-name'
+                      }
+                    ),
+                    containerList:null,
+                    containerNfo:$('<div/>',
+                      {
+                        'class':'ui-inputTreeList-nfo',
+                        css: {
+                          'float':'right',
+                          'display':(options.displayNfo)?'block':'none'
+                        }
+                      }
+                    ),
+                    containerArrow:$('<div/>',
+                      {
+                        html: '&dArr;',
+                        'class':'ui-inputTreeList-arrow',
+                        css: {
+                          'float':'right',
+                          cursor:'pointer'
+                        }
+                      }
+                    ).bind('mousedown',
+                        function ()
+                        {
+                          $(this).addClass('ui-inputTreeList-arrow-active');
+                        }
+                    ).bind('mouseup',
+                        function ()
+                        {
+                          $(this).removeClass('ui-inputTreeList-arrow-active');
+                        }
+                    ),
+                    listContainer:$('<div/>',
+                        {
+                          html: "",
+                          'class':'ui-inputTreeList-list',
+                          css: {
+                            overflow:"auto",
+                            display:'none',
+                            position:'absolute'
+                          }
+                        }
+                    ),
+                    list:$('<ul/>',
+                      {
+                        css: {
+                          listStyle:'none',
+                          padding:'0px',
+                          margin:'0px'
+                        }
+                      }
+                    )
+                  };
+              }
+
+              $this.data('objects', objects);
+
+              privateMethods.setOptions($this, opt);
+
+
+              if($this.html()!='') privateMethods.setItems($this, $this.html());
+
+              $this
+                .html('')
+                .append(objects.container.append(objects.containerArrow).append(objects.containerNfo).append(objects.containerName))
+                .append(objects.listContainer.append(objects.list));
+
+            }
+          );
+        }, // init
+      destroy : function ()
+        {
+          return this.each(
+            function()
+            {
+              // default values for the plugin
+              var $this=$(this),
+                  objects = $this.data('objects');
+              objects.containerName.unbind().remove();
+              objects.containerList.unbind().remove();
+              objects.containerNfo.unbind().remove();
+              objects.containerArrow.unbind().remove();
+              objects.container.unbind().remove();
+              objects.list.children().unbind();
+              objects.listContainer.remove();
+              $(document).unbind('focusout.'+properties.objectId+' focusin.'+properties.objectId);
+              $this
+                .removeData()
+                .unbind('.inputTreeList')
+                .css(
+                  {
+                    width:'',
+                    height:''
+                  }
+                );
+              delete $this;
+            }
+          );
+        }, // destroy
+
+      options: function (value)
+        {
+          return this.each(function()
+            {
+              privateMethods.setOptions($(this), value);
+            }
+          );
+        }, // autoLoad
+
+      autoLoad: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setAutoLoad($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.autoLoad);
+            }
+            else
+            {
+              return(true);
+            }
+          }
+        }, // autoLoad
+
+      triggerChange: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setTriggerChange($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.triggerChange);
+            }
+            else
+            {
+              return(true);
+            }
+          }
+        }, // triggerChange
+
+      listMaxWidth: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setListMaxWidth($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.listMaxWidth);
+            }
+            else
+            {
+              return(0);
+            }
+          }
+        }, // listMaxWidth
+
+      listMaxHeight: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setListMaxHeight($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.listMaxHeight);
+            }
+            else
+            {
+              return(0);
+            }
+          }
+        }, // listMaxHeight
+
+      displayNfo: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setDisplayNfo($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.displayNfo);
+            }
+            else
+            {
+              return(true);
+            }
+          }
+        }, // displayNfo
+
+      levelIndent: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setLevelIndent($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.levelIndent);
+            }
+            else
+            {
+              return(0);
+            }
+          }
+        }, // levelIndent
+
+      postUrl: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setPostUrl($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.postUrl);
+            }
+            else
+            {
+              return('');
+            }
+          }
+        }, // postUrl
+
+      postData: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setPostData($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.postData);
+            }
+            else
+            {
+              return('');
+            }
+          }
+        }, // postData
+
+      collapse: function (value)
+        {
+          return this.each(function()
+            {
+              if(!value) value=':all';
+              privateMethods.setExpandCollapse($(this), value, 'C');
+            }
+          );
+        }, // collapse
+
+      expand: function (value)
+        {
+          return this.each(function()
+            {
+              if(!value) value=':all';
+              privateMethods.setExpandCollapse($(this), value, 'E');
+            }
+          );
+        }, // expand
+
+      iconWidthEC: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setIconWidthEC($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.iconWidthEC);
+            }
+            else
+            {
+              return(0);
+            }
+          }
+        }, // iconWidthEC
+
+      name: function ()
+        {
+          var options=this.data('options'),
+              properties=this.data('properties');
+
+          if(!options.multiple)
+          {
+            return(properties.items[properties.index].name);
+          }
+          else
+          {
+            var listNames=[];
+            for(var i=0;i<properties.index.length;i++)
+            {
+              listNames.push(properties.items[properties.index[i]].name);
+            }
+            return(listNames);
+          }
+        }, // name
+
+      popupMode: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setPopupMode($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.popupMode);
+            }
+            else
+            {
+              return(0);
+            }
+          }
+        }, // popupMode
+
+      displayPath: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setDisplayPath($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.displayPath);
+            }
+            else
+            {
+              return(0);
+            }
+          }
+        }, // displayPath
+
+      downArrow: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setDownArrow($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var options = this.data('options');
+
+            if(options)
+            {
+              return(options.downArrow);
+            }
+            else
+            {
+              return('');
+            }
+          }
+        }, // downArrow
+
+      value: function (value)
+        {
+          var options = this.data('options');
+
+          if(value!=null)
+          {
+            // set selected value
+            return this.each(function()
+              {
+                privateMethods.setValue($(this), value, (options.triggerChange=='all'));
+              }
+            );
+          }
+          else
+          {
+            // return the selected value
+            var properties=this.data('properties');
+
+
+            if(properties && properties.index!=null && !options.multiple && properties.index>-1 && properties.index<properties.items.length)
+            {
+              return(properties.items[properties.index].id);
+            }
+            else if(properties && properties.index!=null && options.multiple)
+            {
+              var returned=[];
+              for(var i=0;i<properties.index.length;i++)
+              {
+                if(properties.index[i]>-1 && properties.index[i]<properties.items.length)
+                  returned.push(properties.items[properties.index[i]].id);
+              }
+              return(returned);
+            }
+            else
+            {
+              return(null);
+            }
+          }
+        }, // value
+
+      isValid: function (value)
+        {
+          if(value!=null)
+          {
+            return this.each(function()
+              {
+                privateMethods.setIsValid($(this), value);
+              }
+            );
+          }
+          else
+          {
+            var properties=this.data('properties');
+            return(properties.isValid);
+          }
+        }, // isValid
+
+      load: function (value)
+        {
+          /*
+           * two functionnalities :
+           *  - if value is set, use it to set the load event function
+           *  - if no value, loads data from server
+           */
+          if(value && $.isFunction(value))
+          {
+            // set selected value
+            return this.each(function()
+              {
+                privateMethods.setEventLoad($(this), value);
+              }
+            );
+          }
+          else
+          {
+            // loads data from server
+            privateMethods.load(this);
+          }
+        },
+
+      popup: function (value)
+        {
+          if(value && $.isFunction(value))
+          {
+            // set selected value
+            return this.each(function()
+              {
+                privateMethods.setEventPopup($(this), value);
+              }
+            );
+          }
+          else
+          {
+            // return the selected value
+            var options=this.data('options');
+
+            if(options)
+            {
+              return(options.popup);
+            }
+            else
+            {
+              return(null);
+            }
+          }
+        }, // popup
+      change: function (value)
+        {
+          if(value && $.isFunction(value))
+          {
+            // set selected value
+            return this.each(function()
+              {
+                privateMethods.setEventChange($(this), value);
+              }
+            );
+          }
+          else
+          {
+            // return the selected value
+            var options=this.data('options');
+
+            if(options)
+            {
+              return(options.change);
+            }
+            else
+            {
+              return(null);
+            }
+          }
+        }, // popup
+
+      numberOfCategories: function ()
+        {
+          var properties=this.data('properties');
+
+          if(properties)
+          {
+            return(properties.items.length);
+          }
+          else
+          {
+            return(null);
+          }
+        }, // numberOfCategories
+
+      properties: function (value)
+        {
+          var properties=this.data('properties'),
+              options=this.data('options');
+
+          if(properties && value==':first' && properties.items.length>0)
+          {
+            return(properties.items[0]);
+          }
+          else if(properties && properties.index!=null && (value==':selected' || value==null) && properties.items.length>0)
+          {
+            if(!options.multiple && properties.index>-1 && properties.index<properties.items.length)
+            {
+              return(properties.items[properties.index]);
+            }
+            else if(options.multiple)
+            {
+              var returned=[];
+              for(var i=0;i<properties.index.length;i++)
+              {
+                if(properties.index[i]>-1 && properties.index<properties.items.length)
+                  returned.push(properties.items[properties.index[i]]);
+              }
+              return(returned);
+            }
+            return(null);
+          }
+          else if(properties && value>-1)
+          {
+            var index=privateMethods.findIndexByValue(this, value);
+            if(index>-1)
+            {
+              return(properties.items[index]);
+            }
+            return(null);
+          }
+          else
+          {
+            return(null);
+          }
+        }, // numberOfCategories
+    }; // methods
+
+
+    /*
+     * plugin 'private' methods
+     */
+    var privateMethods =
+    {
+      setOptions : function (object, value)
+        {
+          var properties=object.data('properties'),
+              options=object.data('options');
+
+          if(!$.isPlainObject(value)) return(false);
+
+          properties.initialized=false;
+
+          privateMethods.setTriggerChange(object, (value.triggerChange!=null)?value.triggerChange:options.triggerChange);
+          privateMethods.setAutoLoad(object, (value.autoLoad!=null)?value.autoLoad:options.autoLoad);
+          privateMethods.setDisplayNfo(object, (value.displayNfo!=null)?value.displayNfo:options.displayNfo);
+          privateMethods.setListMaxWidth(object, (value.listMaxWidth!=null)?value.listMaxWidth:options.listMaxWidth);
+          privateMethods.setListMaxHeight(object, (value.listMaxHeight!=null)?value.listMaxHeight:options.listMaxHeight);
+          privateMethods.setLevelIndent(object, (value.levelIndent!=null)?value.levelIndent:options.levelIndent);
+          privateMethods.setIconWidthEC(object, (value.iconWidthEC!=null)?value.iconWidthEC:options.iconWidthEC);
+          privateMethods.setPostUrl(object, (value.postUrl!=null)?value.postUrl:options.postUrl);
+          privateMethods.setPostData(object, (value.postData!=null)?value.postData:options.postData);
+          privateMethods.setPopupMode(object, (value.popupMode!=null)?value.popupMode:options.popupMode);
+          privateMethods.setDisplayPath(object, (value.displayPath!=null)?value.displayPath:options.displayPath);
+          privateMethods.setDownArrow(object, (value.downArrow!=null)?value.downArrow:options.downArrow);
+          privateMethods.setEventPopup(object, (value.popup!=null)?value.popup:options.popup);
+          privateMethods.setEventChange(object, (value.change!=null)?value.change:options.change);
+          privateMethods.setEventLoad(object, (value.load!=null)?value.load:options.load);
+          privateMethods.setMultiple(object, (value.multiple!=null)?value.multiple:options.multiple); // can be set only at the initialization
+
+          if(options.autoLoad) privateMethods.load(object);
+
+          properties.initialized=true;
+        },
+
+      setIsValid : function (object, value)
+        {
+          var objects=object.data('objects'),
+              properties=object.data('properties');
+
+          if(properties.isValid!=value)
+          {
+            properties.isValid=value;
+            if(properties.isValid)
+            {
+              objects.container.removeClass('ui-error');
+            }
+            else
+            {
+              objects.container.addClass('ui-error');
+            }
+          }
+          return(properties.isValid);
+        }, // setIsValid
+
+      setTriggerChange : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties');
+
+          if((!properties.initialized || options.triggerChange!=value) && (value=='interface' || value=='all'))
+          {
+            options.triggerChange=value;
+          }
+          return(options.triggerChange);
+        }, // setTriggerChange
+
+      setAutoLoad : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties');
+
+          if((!properties.initialized || options.autoLoad!=value) && (value==true || value==false))
+          {
+            options.autoLoad=value;
+          }
+          return(options.autoLoad);
+        }, // setAutoLoad
+
+
+      setListMaxWidth : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.listMaxWidth!=value) && value>=0)
+          {
+            options.listMaxWidth=value;
+            if(options.listMaxWidth>0)
+            {
+              objects.listContainer.css('max-width', options.listMaxWidth+'px');
+            }
+            else
+            {
+              objects.listContainer.css('max-width', '');
+            }
+          }
+          return(options.listMaxWidth);
+        }, // setListMaxWidth
+
+      setListMaxHeight : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.listMaxHeight!=value) && value>=0)
+          {
+            options.listMaxHeight=value;
+            if(options.listMaxHeight>0)
+            {
+              objects.listContainer.css('max-height', options.listMaxHeight+'px');
+            }
+            else
+            {
+              objects.listContainer.css('max-height', '');
+            }
+          }
+          return(options.listMaxHeight);
+        }, // setListMaxHeight
+
+      setDisplayNfo : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.displayNfo!=value) && (value==true || value==false))
+          {
+            options.displayNfo=value;
+            if(options.displayNfo)
+            {
+              object.find('.ui-inputTreeList-nfo').show();
+            }
+            else
+            {
+              object.find('.ui-inputTreeList-nfo').hide();
+            }
+          }
+          return(options.displayNfo);
+        }, // setDisplayNfo
+
+      setLevelIndent : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.levelIndent!=value) && value>=0)
+          {
+            options.levelIndent=value;
+            objects.list.find('.ui-inputTreeList-item div.ui-inputTreeList-expand-item').each(
+              function ()
+              {
+                $(this).css('padding-left', (options.iconWidthEC+$(this).attr('level')*options.levelIndent)+'px');
+              }
+            );
+          }
+          return(options.levelIndent);
+        }, // setLevelIndent
+
+      setPostUrl : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties');
+
+          if(!properties.initialized || options.postUrl!=value)
+          {
+            options.postUrl=value;
+            if(options.autoLoad && properties.initialized) privateMethods.load(object);
+          }
+          return(options.postUrl);
+        }, // setPostUrl
+
+      setPostData : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties');
+
+          if(!properties.initialized || options.postData!=value)
+          {
+            options.postData=value;
+            if(options.autoLoad && properties.initialized) privateMethods.load(object);
+          }
+          return(options.postData);
+        },  // setPostData
+
+      setIconWidthEC : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.iconWidthEC!=value) && value>=0)
+          {
+            options.iconWidthEC=value;
+            objects.list.find('.ui-inputTreeList-item div.ui-inputTreeList-expand-item').each(
+              function ()
+              {
+                $(this).css('padding-left', (options.iconWidthEC+$(this).attr('level')*options.levelIndent)+'px');
+              }
+            );
+          }
+          return(options.iconWidthEC);
+        }, // setIconWidthEC
+
+      setMultiple : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.multiple!=value) && (value==true || value==false))
+          {
+            if(!value)
+            {
+              properties.index=-1;
+              if(objects.containerList!=null)
+              {
+                objects.containerList.remove();
+                objects.containerList=null;
+              }
+            }
+            else
+            {
+              properties.index=[];
+              objects.listContainer.addClass('ui-inputTreeList-multiple');
+              if(objects.containerList==null)
+              {
+                objects.containerList=$('<ul/>',
+                  {
+                    css: {
+                      listStyle:'none',
+                      padding:'0px',
+                      margin:'0px',
+                      overflow:"auto"
+                    },
+                    html:'<li>&nbsp;</li>'
+                  }
+                );
+                objects.containerName.html('').append(objects.containerList);
+              }
+            }
+            options.multiple=value;
+          }
+          return(options.multiple);
+        }, //setMultiple
+
+      setPopupMode : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.popupMode!=value) && (value=='click' || value=='mouseout'))
+          {
+            options.popupMode=value;
+
+            if(value=='mouseout')
+            {
+              objects.listContainer
+                .unbind('mouseleave.inputTreeList')
+                .unbind('mouseenter.inputTreeList')
+                .bind('mouseleave.inputTreeList',
+                  function ()
+                  {
+                    privateMethods.displaySelector(object, false);
+                  }
+                );
+            }
+            else
+            {
+              objects.listContainer
+                .unbind('mouseleave.inputTreeList')
+                .bind('mouseleave.inputTreeList',
+                  function ()
+                  {
+                    properties.mouseOver=false;
+                  }
+                )
+                .bind('mouseenter.inputTreeList',
+                  function ()
+                  {
+                    properties.mouseOver=true;
+                  }
+                );
+              $(document).bind('focusout.'+properties.objectId+' focusin.'+properties.objectId,
+                function (event)
+                {
+                  if(!properties.mouseOver) privateMethods.displaySelector(object, false);
+                }
+              );
+            }
+          }
+          return(options.popupMode);
+        }, //setPopupMode
+
+
+      setDisplayPath : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if((!properties.initialized || options.displayPath!=value) && (value==true || value==false))
+          {
+            options.displayPath=value;
+
+          }
+          return(options.displayPath);
+        }, //setDisplayPath
+
+      setDownArrow : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(!properties.initialized || options.downArrow!=value)
+          {
+            options.downArrow=value;
+            objects.containerArrow.html(options.downArrow);
+          }
+          return(options.downArrow);
+        }, //setDownArrow
+
+
+      setItems : function (object, value)
+        {
+          var properties=object.data('properties'),
+              options=object.data('options'),
+              objects=object.data('objects');
+
+          if(value=='' || value==null)
+          {
+            value={
+              items:[]
+            }
+          }
+          else if($.isArray(value))
+          {
+            value={
+              items:value
+            }
+          }
+          else
+          {
+            try
+            {
+              value=$.parseJSON($.trim(value));
+            }
+            catch (e)
+            {
+              return(false);
+            }
+          }
+
+          privateMethods.listClear(object);
+          if(value.items.length>0) privateMethods.listAddItems(object, value.items, objects.list);
+
+          properties.initialized=false;
+          if(options.multiple)
+          {
+            privateMethods.setValue(object, ':none', (options.triggerChange=='all'));
+          }
+          else
+          {
+            privateMethods.setValue(object, ':first', (options.triggerChange=='all'));
+          }
+          properties.initialized=true;
+
+          if(options.load) object.trigger('inputTreeListLoad');
+        }, // setItems
+
+      /**
+       * usage : see notes on the header file
+       *
+       * @param jQuery object : the jQuery object
+       * @param String value : the filter
+       * @param String mode : 'C' for collapse, 'E' for expand
+       */
+      setExpandCollapse : function (object, value, mode)
+        {
+          var objects=object.data('objects');
+
+          /*
+           *  target[1] = ':all' or itemId
+           * target[2] = '=' or '<' or '>' or '+'
+           * target[3] = level
+           */
+          re=/^(?:(:all)(?:(=|<|>|\+)(\d+))?)|(?:(\d+)(<|>|\+))?$/i;
+          target=re.exec(value);
+
+          if(target!=null)
+          {
+            switch(mode)
+            {
+              case 'C':
+                applyExpandCollapse=privateMethods.applyCollapse;
+                break;
+              case 'E':
+                applyExpandCollapse=privateMethods.applyExpand;
+                break;
+            }
+
+
+            if(target[1]==':all')
+            {
+              objects.list.find('.ui-inputTreeList-expandable-item, .ui-inputTreeList-collapsable-item').each(applyExpandCollapse);
+            }
+            else if(target[4]!=null)
+            {
+              switch(target[5])
+              {
+                case '+':
+                  objects.list.find('.ui-inputTreeList-expandable-item, .ui-inputTreeList-collapsable-item').each(privateMethods.applyCollapse);
+                  objects.list.find(':has([itemId='+target[4]+'])').prev().each(privateMethods.applyExpand);
+                  objects.list.find('[itemId='+target[4]+']').each(applyExpandCollapse);
+                  break;
+                case '>':
+                  objects.list.find('[itemId='+target[4]+'] + ul').find('.ui-inputTreeList-expandable-item, .ui-inputTreeList-collapsable-item').each(applyExpandCollapse);
+                  objects.list.find('[itemId='+target[4]+']').each(applyExpandCollapse);
+                  break;
+                case '<':
+                  objects.list.find(':has([itemId='+target[4]+'])').prev().each(applyExpandCollapse);
+                  objects.list.find('[itemId='+target[4]+']').each(applyExpandCollapse);
+                  break;
+                default:
+                  objects.list.find('[itemId='+target[4]+']').each(applyExpandCollapse);
+                  break;
+              }
+            }
+
+          }
+        }, //setExpandCollapse
+
+      applyExpand : function (index, domElt)
+        {
+          privateMethods.applyExpandCollapse(index, domElt, 'E');
+        }, //applyExpand
+
+      applyCollapse : function (index, domElt)
+        {
+          privateMethods.applyExpandCollapse(index, domElt, 'C');
+        }, //applyCollapse
+
+      /**
+       * used by the setExpandCollapse function
+       * not aimed to be used directly
+       */
+      applyExpandCollapse : function (index, domElt, mode)
+              {
+                action='';
+                var $domElt=$(domElt);
+
+                if(target.length>2 && target[2]!=null && target[3]!=null)
+                {
+                  switch(target[2])
+                  {
+                    case '=':
+                      if($domElt.attr('level')==target[3]) action=mode;
+                      break;
+                    case '>':
+                      if($domElt.attr('level')>=target[3]) action=mode;
+                      break;
+                    case '<':
+                      if($domElt.attr('level')<=target[3]) action=mode;
+                      break;
+                    case '+':
+                      if((mode=='E' && $domElt.attr('level')<=target[3]) ||
+                         (mode=='C' && $domElt.attr('level')>=target[3]))
+                      {
+                        action=mode;
+                      }
+                      else
+                      {
+                        action=(mode=='C')?'E':'C';
+                      }
+                      break;
+                  }
+                }
+                else action=mode;
+
+                switch(action)
+                {
+                  case 'C':
+                    $domElt
+                      .removeClass('ui-inputTreeList-expandable-item ui-inputTreeList-collapsable-item')
+                      .addClass('ui-inputTreeList-expandable-item')
+                      .next().hide();
+                    break;
+                  case 'E':
+                    $domElt
+                      .removeClass('ui-inputTreeList-expandable-item ui-inputTreeList-collapsable-item')
+                      .addClass('ui-inputTreeList-collapsable-item')
+                      .next().show();
+                    break;
+                }
+
+              }, //applyExpandCollapse
+
+      setValue : function (object, value, trigger)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects'),
+              index=-1;
+
+          re=/^(:invert|:all|:none)(?:(=|<|>)(\d+))$/i;
+          target=re.exec(value);
+          if(target!=null) value=target[1];
+
+          switch(value)
+          {
+            case ':first':
+              if(properties.items.length>0) index=0;
+              break;
+            case ':last':
+              index=properties.items.length-1;
+              break;
+            case ':invert':
+              if(!options.multiple) return(false);
+              properties.index=[];
+              objects.list.find('.ui-inputTreeList-item').each(
+                function ()
+                {
+                  var $this=$(this),
+                      apply=true;
+
+                  if(target!=null)
+                  {
+                    switch(target[2])
+                    {
+                      case '=':
+                        apply=($this.attr('level')==target[3]);
+                        break;
+                      case '>':
+                        apply=($this.attr('level')>=target[3]);
+                        break;
+                      case '<':
+                        apply=($this.attr('level')<=target[3]);
+                        break;
+                    }
+                  }
+
+                  if(apply)
+                  {
+                    if($this.hasClass('ui-inputTreeList-selected-item'))
+                    {
+                      $this
+                        .removeClass('ui-inputTreeList-selected-item')
+                        .addClass('ui-inputTreeList-unselected-item');
+                    }
+                    else
+                    {
+                      $this
+                        .addClass('ui-inputTreeList-selected-item')
+                        .removeClass('ui-inputTreeList-unselected-item');
+                      tmp=privateMethods.findIndexByValue(object, $this.attr('itemId'));
+                      if(tmp>-1) properties.index.push(tmp);
+                    }
+                  }
+                }
+              );
+              privateMethods.setValue(object, [], (options.triggerChange=='all'));
+              return(false);
+              break;
+            case ':none':
+              if(!options.multiple) return(false);
+
+              properties.index=[];
+              objects.list.find('.ui-inputTreeList-selected-item').each(
+                function ()
+                {
+                  var $this=$(this),
+                      apply=true;
+
+                  if(target!=null)
+                  {
+                    switch(target[2])
+                    {
+                      case '=':
+                        apply=($this.attr('level')==target[3]);
+                        break;
+                      case '>':
+                        apply=($this.attr('level')>=target[3]);
+                        break;
+                      case '<':
+                        apply=($this.attr('level')<=target[3]);
+                        break;
+                    }
+                  }
+
+                  if(apply)
+                    $this
+                      .removeClass('ui-inputTreeList-selected-item')
+                      .addClass('ui-inputTreeList-unselected-item');
+                }
+              );
+              privateMethods.setValue(object, [], (options.triggerChange=='all'));
+              return(false);
+              break;
+            case ':all':
+              if(!options.multiple) return(false);
+              properties.index=[];
+              objects.list.find('.ui-inputTreeList-item').each(
+                function ()
+                {
+                  var $this=$(this),
+                      apply=true;
+
+                  if(target!=null)
+                  {
+                    switch(target[2])
+                    {
+                      case '=':
+                        apply=($this.attr('level')==target[3]);
+                        break;
+                      case '>':
+                        apply=($this.attr('level')>=target[3]);
+                        break;
+                      case '<':
+                        apply=($this.attr('level')<=target[3]);
+                        break;
+                    }
+                  }
+                  if(apply)
+                  {
+                    tmp=privateMethods.findIndexByValue(object, $this.attr('itemId'));
+                    if(tmp>-1) properties.index.push(tmp);
+
+                    $this
+                      .addClass('ui-inputTreeList-selected-item')
+                      .removeClass('ui-inputTreeList-unselected-item');
+                  }
+                }
+              );
+              privateMethods.setValue(object, [], (options.triggerChange=='all'));
+              return(false);
+              break;
+            default:
+              if($.isArray(value) && options.multiple)
+              {
+                index=[];
+                for(var i=0;i<value.length;i++)
+                {
+                  tmp=privateMethods.findIndexByValue(object, value[i]);
+                  if(tmp>-1) index.push(tmp);
+                }
+              }
+              else
+              {
+                index=privateMethods.findIndexByValue(object, value);
+              }
+
+              break;
+          }
+
+          if(!options.multiple && (!properties.initialized || properties.index!=index) && index>-1)
+          {
+            objects.list.find('.ui-inputTreeList-selected-item')
+              .removeClass('ui-inputTreeList-selected-item')
+              .addClass('ui-inputTreeList-unselected-item');
+
+            objects.list.find('[itemId="'+value+'"]')
+              .addClass('ui-inputTreeList-selected-item')
+              .removeClass('ui-inputTreeList-unselected-item');
+
+            title=privateMethods.getParentName(object, objects.list.find('[itemId="'+value+'"] div.ui-inputTreeList-name')).replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<');
+
+            if(!options.displayPath)
+            {
+              path=properties.items[properties.index].name;
+            }
+            else
+            {
+              path=title;
+            }
+
+            properties.index=index;
+            objects.containerName.html(path).attr('title', title);
+            objects.containerNfo.html(properties.items[properties.index].nfo);
+            if(trigger && options.change) object.trigger('inputTreeListChange', [properties.items[properties.index].id]);
+            if(properties.index>-1) return(properties.items[properties.index].id);
+          }
+          else if(options.multiple)
+          {
+            if(!$.isArray(index))
+            {
+              if(index<0 || index==null) return(-1);
+              index=[index];
+            }
+            tmp=[];
+            for(var i=0;i<index.length;i++)
+            {
+              var item=objects.list.find('[itemId="'+properties.items[index[i]].id+'"]');
+
+              if(item.hasClass('ui-inputTreeList-selected-item'))
+              {
+                item
+                  .removeClass('ui-inputTreeList-selected-item')
+                  .addClass('ui-inputTreeList-unselected-item');
+
+                tmpIndex=$.inArray(index[i] ,properties.index);
+                if(tmpIndex>-1) properties.index.splice(tmpIndex, 1);
+              }
+              else
+              {
+                item
+                  .addClass('ui-inputTreeList-selected-item')
+                  .removeClass('ui-inputTreeList-unselected-item');
+
+                properties.index.push(index[i]);
+              }
+              tmp.push(properties.items[index[i]].id);
+            }
+            objects.containerList.html('');
+            objects.list.find('.ui-inputTreeList-selected-item div.ui-inputTreeList-name').each(
+              function ()
+              {
+                var path='';
+
+                title=privateMethods.getParentName(object, $(this)).replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<');
+                if(!options.displayPath)
+                {
+                  path=$(this).html();
+                }
+                else
+                {
+                  path=title;
+                }
+
+                objects.containerList.append(
+                  $('<li/>',
+                    {
+                      html:path,
+                      title:title,
+                      'class':'ui-inputTreeList-selected-cat'
+                    }
+                  ).prepend(
+                      $('<span/>',
+                        {
+                          html:'x'
+                        }
+                       ).bind('click.inputTreeList',
+                          {object:object, value:$(this).parent().parent().attr('itemId')},
+                          function (event)
+                          {
+                            event.stopPropagation();
+                            privateMethods.setValue(event.data.object, event.data.value, true);
+                          }
+                        )
+                      )
+                )
+              }
+            );
+
+            if(objects.containerList.children().length==0) objects.containerList.append('<li>&nbsp;</li>');
+
+            if(trigger && options.change) object.trigger('inputTreeListChange', [tmp]);
+            return(tmp);
+          }
+          return(null);
+        }, //setValue
+
+      getParentName : function (object, item)
+      {
+        if(item==null || item.length==0) return('');
+        foundItem=item.parent().parent().parent().prev().find('div.ui-inputTreeList-name');
+
+        if(foundItem.length==0) return(item.html());
+
+        return(privateMethods.getParentName(object, foundItem)+' / '+item.html());
+      }, // getParentName
+
+      displaySelector : function (object, value)
+        {
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          if(properties.selectorVisible!=value)
+          {
+            properties.selectorVisible=value;
+
+            if(properties.selectorVisible && properties.items.length>0)
+            {
+              var index=0;
+              objects.listContainer
+                .css(
+                  {
+                    display:'block',
+                    'min-width':objects.listContainer.parent().css('width')
+                  }
+                );
+
+              if($.isArray(properties.index))
+              {
+                if (properties.index.length>0) index=properties.index[0];
+              }
+              else if(properties.index>-1)
+              {
+                index=properties.index;
+              }
+              objects.listContainer.scrollTop(objects.listContainer.scrollTop()+objects.list.find('[itemId="'+properties.items[index].id+'"]').position().top);
+            }
+            else
+            {
+              objects.listContainer.css('display', 'none');
+            }
+            if(options.popup) object.trigger('inputTreeListPopup', [properties.selectorVisible]);
+          }
+          return(properties.selectorVisible);
+        }, // displaySelector
+
+      load : function (object)
+        {
+          // load datas from server through an asynchronous ajax call
+          var options=object.data('options'),
+              objects=object.data('objects');
+
+          if(options.postUrl=='') return(false);
+
+          $.ajax(
+            {
+              type: "POST",
+              url: options.postUrl,
+              async: true,
+              data:options.postData,
+              success: function(msg)
+                {
+                  privateMethods.setItems(object, msg);
+                },
+              error: function(msg)
+                {
+                  objects.listContainer.html('Error ! '+msg);
+                },
+            }
+         );
+        }, // load
+
+      listClear : function (object)
+        {
+          // clear the item list
+          var objects=object.data('objects'),
+              options=object.data('options'),
+              properties=object.data('properties');
+
+          objects.list.children().unbind();
+          objects.list.html('');
+          if(options.multiple)
+          {
+            properties.index=[];
+          }
+          else
+          {
+            properties.index=-1;
+          }
+          properties.items=[];
+        }, // listClear
+
+      listAddItems : function (object, listItems, parent)
+        {
+          // add the items to the item list
+          var options=object.data('options'),
+              properties=object.data('properties'),
+              objects=object.data('objects');
+
+          var previousLevel=-1;
+          for(var i=0;i<listItems.length;i++)
+          {
+            properties.items.push(
+              {
+                id:listItems[i].id,
+                level:listItems[i].level,
+                name:listItems[i].name,
+                nfo:listItems[i].nfo,
+                childs:listItems[i].childs.length
+              }
+            );
+
+            if(options.displayNfo)
+            {
+              nfo="<div class='ui-inputTreeList-nfo'>"+listItems[i].nfo+"</div>";
+            }
+            else
+            {
+              nfo="";
+            }
+
+            var spaceWidth = listItems[i].level*options.levelIndent,
+                li=$('<li/>',
+                      {
+                        'class':'ui-inputTreeList-item ui-inputTreeList-unselected-item',
+                        html:"<div>"+nfo+"<div class='ui-inputTreeList-name'>"+listItems[i].name+"</div></div>",
+                        itemId:listItems[i].id,
+                        level:listItems[i].level,
+                        css:{
+                          'padding-left':spaceWidth+'px'
+                        }
+                      }
+                    ).bind('click.inputTreeList',
+                        {object:object, expandArea: spaceWidth+options.iconWidthEC, nbchilds:listItems[i].childs.length },
+                        function (event)
+                        {
+                          event.layerX=event.pageX-$(event.currentTarget).offset().left;
+                          event.layerY=event.pageY-$(event.currentTarget).offset().top;
+                          if(event.layerX<event.data.expandArea && event.data.nbchilds>0 )
+                          {
+                            if($(this).hasClass('ui-inputTreeList-expandable-item'))
+                            {
+                              $(this)
+                                .removeClass('ui-inputTreeList-expandable-item')
+                                .addClass('ui-inputTreeList-collapsable-item')
+                                .next().show();
+                            }
+                            else
+                            {
+                              $(this)
+                                .removeClass('ui-inputTreeList-collapsable-item')
+                                .addClass('ui-inputTreeList-expandable-item')
+                                .next().hide();
+                            }
+                          }
+                          else
+                          {
+                            privateMethods.setValue(event.data.object, $(this).attr('itemId'), true);
+                            if(options.multiple)
+                            {
+                            }
+                            else
+                            {
+                              privateMethods.displaySelector(event.data.object, false);
+                            }
+                          }
+
+                          if(options.multiple) objects.container.focus();
+                        }
+                      );
+            /*
+            if(listItems[i].childs.length>0)
+            {
+              li.addClass('ui-inputTreeList-collapsable-item').css('background-position', (options.levelIndent*listItems[i].level)+'px 0px');
+            }
+            */
+
+            if(options.multiple)
+            {
+              li.children().prepend('<div class="ui-inputTreeList-check"></div>');
+            }
+
+            parent.append(li);
+
+            if(listItems[i].childs.length>0)
+            {
+              li.addClass('ui-inputTreeList-expandable-item')
+                .children().prepend('<div class="ui-inputTreeList-expand-item"></div>');
+
+              var ul=$('<ul/>',
+                        {
+                          'class':'ui-inputTreeList-group',
+                          css: {
+                            listStyle:'none',
+                            padding:'0px',
+                            margin:'0px',
+                            'font-size':(100-listItems[i].level*2)+'%'
+                          }
+                        }
+                      );
+              li.after(ul);
+              privateMethods.listAddItems(object, listItems[i].childs, ul);
+            }
+            else
+            {
+              li.css('padding-left', (spaceWidth+options.iconWidthEC)+'px');
+            }
+
+          }
+        }, // listAddItems
+
+      findIndexByValue : function (object, value)
+        {
+          /*
+           * search an item inside the items list and return the index
+           * in the array
+           */
+          var properties=object.data('properties');
+
+          for(var i=0;i<properties.items.length;i++)
+          {
+            if(properties.items[i].id==value) return(i);
+          }
+          return(-1);
+        }, // findIndexByValue
+
+      setEventPopup : function (object, value)
+        {
+          var options=object.data('options');
+
+          options.popup=value;
+          object.unbind('inputTreeListPopup');
+          if(value) object.bind('inputTreeListPopup', options.popup);
+          return(options.popup);
+        }, // setEventPopup
+
+      setEventChange : function (object, value)
+        {
+          var options=object.data('options');
+
+          options.change=value;
+          object.unbind('inputTreeListChange');
+          if(value) object.bind('inputTreeListChange', options.change);
+          return(options.change);
+        }, // setEventChange
+
+      setEventLoad : function (object, value)
+        {
+          var options=object.data('options');
+
+          options.load=value;
+          object.unbind('inputTreeListLoad');
+          if(value) object.bind('inputTreeListLoad', options.load);
+          return(options.load);
+        } // setEventLoad
+    };
+
+
+    $.fn.inputTreeList = function(method)
+    {
+      if(publicMethods[method])
+      {
+        return publicMethods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
+      }
+      else if(typeof method === 'object' || ! method)
+      {
+        return publicMethods.init.apply(this, arguments);
+      }
+      else
+      {
+        $.error( 'Method ' +  method + ' does not exist on jQuery.inputTreeList' );
+      }
+    } // $.fn.inputTreeList
+
+  }
+)(jQuery);
+
+
Index: /extensions/GrumPluginClasses/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/GrumPluginClasses/language/en_UK/plugin.lang.php	(revision 17734)
+++ /extensions/GrumPluginClasses/language/en_UK/plugin.lang.php	(revision 17735)
@@ -15,3 +15,26 @@
 $lang['All the gallery'] = 'All the gallery';
 
+
+// gpc 3.5.4
+$lang['filter_operator']='Operator';
+$lang['filter_value']='Value';
+$lang['filter_minValue']='Minimal value';
+$lang['filter_maxValue']='Maximal value';
+$lang['filter_gt']='Greater than';
+$lang['filter_lt']='Less than';
+$lang['filter_ge']='Greater or equal to';
+$lang['filter_le']='Less or equal to';
+$lang['filter_equal']='Equal to';
+$lang['filter_notEqual']='Different than';
+$lang['filter_between']='Between';
+$lang['filter_and']='and';
+$lang['filter_like']='Like';
+$lang['filter_notLike']='Not like';
+$lang['filter_invalid']='Filter is not valid';
+
+$lang['export_dialogTitle']='Data export';
+$lang['export_Name']='File name';
+$lang['export_Format']='Format';
+$lang['export_Compression']='Compression';
+
 ?>
Index: /extensions/GrumPluginClasses/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/GrumPluginClasses/language/fr_FR/plugin.lang.php	(revision 17734)
+++ /extensions/GrumPluginClasses/language/fr_FR/plugin.lang.php	(revision 17735)
@@ -30,3 +30,25 @@
 $lang['Your message was sent to the webmaster!']='Votre message a bien &eacute;t&eacute; transmis !';
 
+// gpc 3.5.4
+$lang['filter_operator']='Opérateur';
+$lang['filter_value']='Valeur';
+$lang['filter_minValue']='Valeur minimale';
+$lang['filter_maxValue']='Valeur maximale';
+$lang['filter_gt']='Supérieur à';
+$lang['filter_lt']='Inférieur à';
+$lang['filter_ge']='Supérieur ou égal à';
+$lang['filter_le']='Inférieur ou égal à';
+$lang['filter_equal']='Egal à';
+$lang['filter_notEqual']='Différent de';
+$lang['filter_between']='Entre';
+$lang['filter_and']='et';
+$lang['filter_like']='Ressemble à';
+$lang['filter_notLike']='Ne ressemble pas à';
+$lang['filter_invalid']='Le filtre n\'est pas valide';
+
+$lang['export_dialogTitle']='Export des données';
+$lang['export_Name']='Nom du fichier';
+$lang['export_Format']='Format';
+$lang['export_Compression']='Compression';
+
 ?>
Index: /extensions/GrumPluginClasses/main.inc.php
===================================================================
--- /extensions/GrumPluginClasses/main.inc.php	(revision 17734)
+++ /extensions/GrumPluginClasses/main.inc.php	(revision 17735)
@@ -2,5 +2,5 @@
 /*
 Plugin Name: Grum Plugins Classes.3
-Version: 3.5.3
+Version: 3.5.4
 Description: Collection de classes partagées entre mes plugins (existants, ou à venir) / Partaged classes between my plugins (actuals or futures)
 Plugin URI: http://piwigo.org/ext/extension_view.php?eid=199
@@ -183,4 +183,11 @@
 |         |            |   . Error message when on page using GPC tabsheets
 |         |            |
+| 3.5.4   | 2012/08/29 | * Add ui.inputTreeList object
+|         |            |
+|         |            | * Improve ui.dynamicTable object
+|         |            |
+|         |            |
+|         |            |
+|         |            |
 |         |            |
 |         |            |
