Index: /branches/branch-1.7/docs/kernel/what.rst
===================================================================
--- /branches/branch-1.7/docs/kernel/what.rst	(revision 941)
+++ /branches/branch-1.7/docs/kernel/what.rst	(revision 942)
@@ -88,4 +88,5 @@
 C / C++      Shared Library      maps* M 	           integer
 Java 	     Class File 	 `HashMap`_ 	           integer
+C# 	     Class File 	 `ZMaps`_	           integer
 Python 	     Module File 	 `Dictionary`_ 	           integer
 PHP 	     Script File 	 `Array`_ 	           integer
@@ -93,4 +94,5 @@
 Ruby 	     Script File 	 `Hash`_	           integer
 Fortran      Shared Library      CHARACTER*(1024) M(10,30) integer
+R	     Script file 	 `R List`_	           integer
 JavaScript   Script file 	 `Object`_ or Array	   Object/Array
 ============ =================== ========================= ============
@@ -101,3 +103,5 @@
 .. _`Object`: http://www.json.org/
 .. _`Hash`: http://ruby-doc.org/core-2.2.0/Hash.html
+.. _`ZMaps`: https://docs.microsoft.com/fr-fr/dotnet/api/system.collections.generic.dictionary-2?view=netframework-4.8
+.. _`R List`: https://cran.r-project.org/doc/manuals/r-release/R-lang.html#List-objects
 
Index: /branches/branch-1.7/docs/services/zcfg-reference.rst
===================================================================
--- /branches/branch-1.7/docs/services/zcfg-reference.rst	(revision 941)
+++ /branches/branch-1.7/docs/services/zcfg-reference.rst	(revision 942)
@@ -223,15 +223,15 @@
        AllowedValues = -10,-8,-7,-5,-1
        rangeMin = 0
-       rangeMin = 100
+       rangeMax = 100
        rangeClosure = co
      </Default>
      <Supported>
        rangeMin = 200
-       rangeMin = 600
+       rangeMax = 600
        rangeClosure = co
      </Supported>
      <Supported>
        rangeMin = 750
-       rangeMin = 990
+       rangeMax = 990
        rangeClosure = co
        rangeSpacing = 10
Index: /branches/branch-1.7/zoo-project/zoo-kernel/otbZooWatcher.cxx
===================================================================
--- /branches/branch-1.7/zoo-project/zoo-kernel/otbZooWatcher.cxx	(revision 941)
+++ /branches/branch-1.7/zoo-project/zoo-kernel/otbZooWatcher.cxx	(revision 942)
@@ -16,4 +16,5 @@
 =========================================================================*/
 #include "otbZooWatcher.h"
+#include "otbConfigure.h"
 #include "service_internal.h"
 
@@ -52,5 +53,7 @@
 ::StartFilter()
 {
+#if OTB_VERSION_MAJOR < 6 
   m_TimeProbe.Start();
+#endif
 }
 
@@ -59,4 +62,5 @@
 ::EndFilter()
 {
+#if OTB_VERSION_MAJOR < 6 
   m_TimeProbe.Stop();
   std::ostringstream elapsedTime;
@@ -68,3 +72,4 @@
             << " seconds)"
             << std::endl;
+#endif
 }
Index: /branches/branch-1.7/zoo-project/zoo-kernel/request_parser.c
===================================================================
--- /branches/branch-1.7/zoo-project/zoo-kernel/request_parser.c	(revision 941)
+++ /branches/branch-1.7/zoo-project/zoo-kernel/request_parser.c	(revision 942)
@@ -1070,10 +1070,20 @@
 					       buffersize);
 				}
-			      else if (cur5 != NULL)/*
-				     && cur5->type == XML_CDATA_SECTION_NODE)*/{
-				xmlFree(mv);
-				if(cur5->content!=NULL){
-				  mv=xmlStrdup(cur5->content);
-				}
+			      else if (cur5 != NULL){
+				if(ltmp!= NULL && strstr(ltmp->value,"text/")!=NULL){
+				  xmlChar *tmp = xmlNodeListGetRawString (doc,
+									  cur4->xmlChildrenNode,
+									  0);
+				  addToMap (tmpmaps->content, "value",
+					    (char *) tmp);
+				  xmlFree (tmp);
+				}else{
+				  while(cur5!=NULL && cur5->type != XML_CDATA_SECTION_NODE)
+				    cur5=cur5->next;
+				  xmlFree(mv);
+				  if(cur5!=NULL && cur5->content!=NULL){
+				    mv=xmlStrdup(cur5->content);
+				  }
+			 	}
 			      }
 			    }
@@ -1859,5 +1869,5 @@
   if (r_inputs == NULL){
     if(mandatory>0){
-      char *replace=_("Mandatory parameter <%s> was not specified");
+      const char *replace=_("Mandatory parameter <%s> was not specified");
       char *message=(char*)malloc((strlen(replace)+strlen(toCheck)+1)*sizeof(char));
       sprintf(message,replace,toCheck);
@@ -1908,8 +1918,8 @@
     }
     if(hasValidValue<0){
-      char *replace=_("The value <%s> was not recognized, %s %s the only acceptable value.");
+      const char *replace=_("The value <%s> was not recognized, %s %s the only acceptable value.");
       nb=0;
       char *vvalues=NULL;
-      char* num=_("is");
+      const char* num=_("is");
       while(avalues[nb]!=NULL){
 	char *tvalues;
Index: /branches/branch-1.7/zoo-project/zoo-kernel/service_internal_hpc.c
===================================================================
--- /branches/branch-1.7/zoo-project/zoo-kernel/service_internal_hpc.c	(revision 941)
+++ /branches/branch-1.7/zoo-project/zoo-kernel/service_internal_hpc.c	(revision 942)
@@ -69,5 +69,5 @@
 	  dupElements(cur)
 	};
-	char *geoLink="wcs_link";
+	const char *geoLink="wcs_link";
 	if(geo==2){
 	  geoLink="wfs_link";
@@ -213,5 +213,5 @@
       zooLock* lck;
       if((lck=lockFile(*conf,argv[1]->value,'r'))==NULL){
-	char* templateStr=_("Unable to lock the file for %s in read mode.");
+	const char* templateStr=_("Unable to lock the file for %s in read mode.");
 	char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv[0]->value)+1)*sizeof(char));
 	sprintf(tmpMessage,templateStr,argv[0]->value);
@@ -251,5 +251,5 @@
       if(unlockFile(*conf,zoo_file_locks[i])<1){
 	map* argv=getMapArray(queueMaps->content,"input",i);
-	char* templateStr=_("Unable to unlock the file for %s after execution.");
+	const char* templateStr=_("Unable to unlock the file for %s after execution.");
 	char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv->value)+1)*sizeof(char));
 	sprintf(tmpMessage,templateStr,argv->value);
Index: /branches/branch-1.7/zoo-project/zoo-kernel/service_internal_python.c
===================================================================
--- /branches/branch-1.7/zoo-project/zoo-kernel/service_internal_python.c	(revision 941)
+++ /branches/branch-1.7/zoo-project/zoo-kernel/service_internal_python.c	(revision 942)
@@ -355,5 +355,5 @@
 #endif
     char *pStrErrorMessage = PyString_AsString(pvalue);
-  char *tmp0=_("Python module %s cannot be loaded. Message: %s\n");
+  const char *tmp0=_("Python module %s cannot be loaded. Message: %s\n");
   
   PyObject *trace=PyObject_Str(pvalue);
@@ -393,5 +393,5 @@
       if(pbt!=NULL)
 	free(pbt);
-      char* format=_("%s\nUnable to run your python process properly. Please check the following messages : %s");
+      const char* format=_("%s\nUnable to run your python process properly. Please check the following messages : %s");
       pbt=(char*)malloc((strlen(format)+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));
       sprintf(pbt,format,tpbt,PyString_AsString(trace));
@@ -400,5 +400,5 @@
       if(pbt!=NULL)
 	free(pbt);
-      char* format=_("%s \n Unable to run your python process properly. Unable to provide any further information.");
+      const char* format=_("%s \n Unable to run your python process properly. Unable to provide any further information.");
       pbt=(char*)malloc((strlen(format)+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));
       sprintf(pbt,format,tpbt);
Index: /branches/branch-1.7/zoo-project/zoo-kernel/sshapi.c
===================================================================
--- /branches/branch-1.7/zoo-project/zoo-kernel/sshapi.c	(revision 941)
+++ /branches/branch-1.7/zoo-project/zoo-kernel/sshapi.c	(revision 942)
@@ -730,5 +730,5 @@
 	if((lck=lockFile(*conf,argv[1]->value,'w'))!=NULL){/**/
 	  if(ssh_copy(*conf,argv[1]->value,argv[2]->value,ssh_get_cnt(*conf))!=true){
-	    char* templateStr=_("Unable to copy over SSH the file requested for setting the value of %s.");
+	    const char* templateStr=_("Unable to copy over SSH the file requested for setting the value of %s.");
 	    char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv[0]->value)+1)*sizeof(char));
 	    sprintf(tmpMessage,templateStr,argv[0]->value);
Index: /tags/rel-1.7.0/debian/changelog
===================================================================
--- /tags/rel-1.7.0/debian/changelog	(revision 942)
+++ /tags/rel-1.7.0/debian/changelog	(revision 942)
@@ -0,0 +1,20 @@
+zoo-project (1.4~devel01) UNRELEASED; urgency=low
+
+  * Added Gdal ZOO Services
+  * Added Cgal ZOO Services
+  * Added WPS Status Services
+
+ -- David Saggiorato <david@saggiorato.net>  Fri, 31 Oct 2014 17:54:34 +0100
+
+zoo-project (1.3.0-1~trusty10) trusty; urgency=low
+
+  * Added OGR ZOO Services.
+
+ -- Angelos Tzotsos <gcpp.kalxas@gmail.com>  Sun, 28 Jul 2014 19:48:00 +0200
+
+zoo-project (1.3.0-1~trusty7) trusty; urgency=low
+
+  * Initial Debian packaging.
+
+ -- Angelos Tzotsos <gcpp.kalxas@gmail.com>  Tue, 10 Jun 2014 21:17:04 +0200
+
Index: /tags/rel-1.7.0/debian/compat
===================================================================
--- /tags/rel-1.7.0/debian/compat	(revision 942)
+++ /tags/rel-1.7.0/debian/compat	(revision 942)
@@ -0,0 +1,1 @@
+9
Index: /tags/rel-1.7.0/debian/control
===================================================================
--- /tags/rel-1.7.0/debian/control	(revision 942)
+++ /tags/rel-1.7.0/debian/control	(revision 942)
@@ -0,0 +1,49 @@
+Source: zoo-project
+Maintainer: Angelos Tzotsos <gcpp.kalxas@gmail.com>
+Section: web
+Priority: optional
+Build-Depends: debhelper (>= 9),
+               dpkg-dev (>= 1.16.1.1),
+               autoconf,
+               automake,
+               autotools-dev,
+               flex,
+               bison,
+               libssl-dev,
+               libcurl4-gnutls-dev,
+               libcgic-dev (>= 2.06),
+               libgdal-dev,
+               python-all (>= 2.6.6-3~) |  python-dev,
+               libfcgi-dev,
+               libxml2-dev,
+               libxslt1-dev,
+               libcgal-dev,
+               libmozjs185-dev,
+Build-Conflicts: libcurl3-openssl-dev
+Standards-Version: 3.9.3
+X-Python-Version: >= 2.7
+Homepage: http://zoo-project.org
+
+Package: zoo-kernel
+Architecture: any
+Section: web
+Depends: ${shlibs:Depends},
+         ${misc:Depends}
+Description: This package contains the CGI ZOO Kernel
+ .
+ ZOO is a WPS (Web Processing Service) open source project released 
+ under a  MIT/X-11 style license . It provides an OGC WPS compliant
+ developer-friendly framework to create and chain WPS Web services. 
+
+Package: zoo-services
+Architecture: any
+Section: web
+Depends: ${shlibs:Depends},
+         ${misc:Depends},
+         python (>=2.7), 
+         python-gdal
+Description: This package contains the CGI ZOO Services
+ .
+ ZOO is a WPS (Web Processing Service) open source project released 
+ under a  MIT/X-11 style license . It provides an OGC WPS compliant
+ developer-friendly framework to create and chain WPS Web services. 
Index: /tags/rel-1.7.0/debian/copyright
===================================================================
--- /tags/rel-1.7.0/debian/copyright	(revision 942)
+++ /tags/rel-1.7.0/debian/copyright	(revision 942)
@@ -0,0 +1,37 @@
+This package was debianized by Angelos Tzotsos gcpp.kalxas@gmail.com on
+Tue, 10 Jun 2014 21:17:04 +0200.
+
+It was downloaded from:
+
+    http://zoo-project.org
+
+Upstream author:
+
+    Gerald Fenoy <gerald.fenoy@geolabs.fr>
+
+Copyright:
+
+    Copyright (C) 2010-2011 GeoLabs.
+
+License:
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+
Index: /tags/rel-1.7.0/debian/rules
===================================================================
--- /tags/rel-1.7.0/debian/rules	(revision 942)
+++ /tags/rel-1.7.0/debian/rules	(revision 942)
@@ -0,0 +1,41 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+%:
+	dh  $@
+
+override_dh_auto_configure:
+	cd zoo-project/zoo-kernel && autoconf && ./configure --with-python --with-js --with-cgi-dir=$(CURDIR)/debian/tmp/usr/lib/cgi-bin
+
+override_dh_auto_build:
+	dh_auto_build --builddirectory zoo-project/zoo-kernel
+	dh_auto_build --builddirectory zoo-project/zoo-services/cgal
+	dh_auto_build --builddirectory zoo-project/zoo-services/gdal/contour
+	dh_auto_build --builddirectory zoo-project/zoo-services/gdal/translate
+	dh_auto_build --builddirectory zoo-project/zoo-services/gdal/dem
+	dh_auto_build --builddirectory zoo-project/zoo-services/gdal/grid
+	dh_auto_build --builddirectory zoo-project/zoo-services/gdal/profile
+	dh_auto_build --builddirectory zoo-project/zoo-services/gdal/warp
+	dh_auto_build --builddirectory zoo-project/zoo-services/ogr/base-vect-ops
+	dh_auto_build --builddirectory zoo-project/zoo-services/ogr/ogr2ogr
+	dh_auto_build --builddirectory zoo-project/zoo-services/utils/status
+
+override_dh_auto_install:
+	dh_auto_install --builddirectory zoo-project/zoo-kernel
+	dh_auto_install --builddirectory zoo-project/zoo-services/cgal
+	dh_auto_install --builddirectory zoo-project/zoo-services/gdal/contour
+	dh_auto_install --builddirectory zoo-project/zoo-services/gdal/translate
+	dh_auto_install --builddirectory zoo-project/zoo-services/gdal/dem
+	dh_auto_install --builddirectory zoo-project/zoo-services/gdal/grid
+	dh_auto_install --builddirectory zoo-project/zoo-services/gdal/profile
+	dh_auto_install --builddirectory zoo-project/zoo-services/gdal/warp
+	install -d $(CURDIR)/debian/tmp/usr/lib/cgi-bin/gdal/ndvi
+	install $(CURDIR)/zoo-project/zoo-services/gdal/ndvi/cgi-env/* $(CURDIR)/debian/tmp/usr/lib/cgi-bin/gdal/ndvi/
+	dh_auto_install --builddirectory zoo-project/zoo-services/ogr/base-vect-ops
+	dh_auto_install --builddirectory zoo-project/zoo-services/ogr/ogr2ogr
+	install -d $(CURDIR)/debian/tmp/usr/lib/cgi-bin/ogr/base-vect-ops-py
+	install $(CURDIR)/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/* $(CURDIR)/debian/tmp/usr/lib/cgi-bin/ogr/base-vect-ops-py/
+	dh_auto_install --builddirectory zoo-project/zoo-services/utils/status
+
+#override_dh_auto_clean:
+#	dh_auto_clean --builddirectory zoo-project/zoo-kernel
Index: /tags/rel-1.7.0/debian/source/format
===================================================================
--- /tags/rel-1.7.0/debian/source/format	(revision 942)
+++ /tags/rel-1.7.0/debian/source/format	(revision 942)
@@ -0,0 +1,1 @@
+3.0 (native)
Index: /tags/rel-1.7.0/debian/zoo-kernel.install
===================================================================
--- /tags/rel-1.7.0/debian/zoo-kernel.install	(revision 942)
+++ /tags/rel-1.7.0/debian/zoo-kernel.install	(revision 942)
@@ -0,0 +1,3 @@
+usr/lib/cgi-bin/zoo_loader.cgi
+usr/lib/cgi-bin/main.cfg
+zoo-project/zoo-api/js/*    usr/lib/cgi-bin/
Index: /tags/rel-1.7.0/debian/zoo-services.install
===================================================================
--- /tags/rel-1.7.0/debian/zoo-services.install	(revision 942)
+++ /tags/rel-1.7.0/debian/zoo-services.install	(revision 942)
@@ -0,0 +1,9 @@
+usr/lib/cgi-bin/cgal	usr/lib/cgi-bin/
+usr/lib/cgi-bin/gdal	usr/lib/cgi-bin/
+usr/lib/cgi-bin/ogr	usr/lib/cgi-bin/
+usr/lib/cgi-bin/demo.zcfg	usr/lib/cgi-bin/
+usr/lib/cgi-bin/GetStatus.zcfg	usr/lib/cgi-bin/
+usr/lib/cgi-bin/longProcess.zcfg	usr/lib/cgi-bin/
+usr/lib/cgi-bin/service.py	usr/lib/cgi-bin/
+usr/lib/cgi-bin/updateStatus.xsl	usr/lib/cgi-bin/
+usr/lib/cgi-bin/wps_status.zo	usr/lib/cgi-bin/
Index: /tags/rel-1.7.0/docs/Makefile
===================================================================
--- /tags/rel-1.7.0/docs/Makefile	(revision 942)
+++ /tags/rel-1.7.0/docs/Makefile	(revision 942)
@@ -0,0 +1,130 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ZOOProject.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ZOOProject.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/ZOOProject"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ZOOProject"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	make -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
Index: /tags/rel-1.7.0/docs/_static/doctools.js
===================================================================
--- /tags/rel-1.7.0/docs/_static/doctools.js	(revision 942)
+++ /tags/rel-1.7.0/docs/_static/doctools.js	(revision 942)
@@ -0,0 +1,263 @@
+/*
+ * doctools.js
+ * ~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilities for all documentation.
+ *
+ * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/**
+ * select a different prefix for underscore
+ */
+$u = _.noConflict();
+
+/**
+ * make the code below compatible with browsers without
+ * an installed firebug like debugger
+if (!window.console || !console.firebug) {
+  var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
+    "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
+    "profile", "profileEnd"];
+  window.console = {};
+  for (var i = 0; i < names.length; ++i)
+    window.console[names[i]] = function() {};
+}
+ */
+
+/**
+ * small helper function to urldecode strings
+ */
+jQuery.urldecode = function(x) {
+  return decodeURIComponent(x).replace(/\+/g, ' ');
+};
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+  if (typeof s == 'undefined')
+    s = document.location.search;
+  var parts = s.substr(s.indexOf('?') + 1).split('&');
+  var result = {};
+  for (var i = 0; i < parts.length; i++) {
+    var tmp = parts[i].split('=', 2);
+    var key = jQuery.urldecode(tmp[0]);
+    var value = jQuery.urldecode(tmp[1]);
+    if (key in result)
+      result[key].push(value);
+    else
+      result[key] = [value];
+  }
+  return result;
+};
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+  function highlight(node) {
+    if (node.nodeType == 3) {
+      var val = node.nodeValue;
+      var pos = val.toLowerCase().indexOf(text);
+      if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
+        var span = document.createElement("span");
+        span.className = className;
+        span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+        node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+          document.createTextNode(val.substr(pos + text.length)),
+          node.nextSibling));
+        node.nodeValue = val.substr(0, pos);
+      }
+    }
+    else if (!jQuery(node).is("button, select, textarea")) {
+      jQuery.each(node.childNodes, function() {
+        highlight(this);
+      });
+    }
+  }
+  return this.each(function() {
+    highlight(this);
+  });
+};
+
+/*
+ * backward compatibility for jQuery.browser
+ * This will be supported until firefox bug is fixed.
+ */
+if (!jQuery.browser) {
+  jQuery.uaMatch = function(ua) {
+    ua = ua.toLowerCase();
+
+    var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
+      /(webkit)[ \/]([\w.]+)/.exec(ua) ||
+      /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
+      /(msie) ([\w.]+)/.exec(ua) ||
+      ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
+      [];
+
+    return {
+      browser: match[ 1 ] || "",
+      version: match[ 2 ] || "0"
+    };
+  };
+  jQuery.browser = {};
+  jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
+}
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+var Documentation = {
+
+  init : function() {
+    this.fixFirefoxAnchorBug();
+    this.highlightSearchWords();
+    this.initIndexTable();
+  },
+
+  /**
+   * i18n support
+   */
+  TRANSLATIONS : {},
+  PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
+  LOCALE : 'unknown',
+
+  // gettext and ngettext don't access this so that the functions
+  // can safely bound to a different name (_ = Documentation.gettext)
+  gettext : function(string) {
+    var translated = Documentation.TRANSLATIONS[string];
+    if (typeof translated == 'undefined')
+      return string;
+    return (typeof translated == 'string') ? translated : translated[0];
+  },
+
+  ngettext : function(singular, plural, n) {
+    var translated = Documentation.TRANSLATIONS[singular];
+    if (typeof translated == 'undefined')
+      return (n == 1) ? singular : plural;
+    return translated[Documentation.PLURALEXPR(n)];
+  },
+
+  addTranslations : function(catalog) {
+    for (var key in catalog.messages)
+      this.TRANSLATIONS[key] = catalog.messages[key];
+    this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
+    this.LOCALE = catalog.locale;
+  },
+
+  /**
+   * add context elements like header anchor links
+   */
+  addContextElements : function() {
+    $('div[id] > :header:first').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this headline')).
+      appendTo(this);
+    });
+    $('dt[id]').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this definition')).
+      appendTo(this);
+    });
+  },
+
+  /**
+   * workaround a firefox stupidity
+   * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
+   */
+  fixFirefoxAnchorBug : function() {
+    if (document.location.hash)
+      window.setTimeout(function() {
+        document.location.href += '';
+      }, 10);
+  },
+
+  /**
+   * highlight the search words provided in the url in the text
+   */
+  highlightSearchWords : function() {
+    var params = $.getQueryParameters();
+    var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
+    if (terms.length) {
+      var body = $('div.body');
+      if (!body.length) {
+        body = $('body');
+      }
+      window.setTimeout(function() {
+        $.each(terms, function() {
+          body.highlightText(this.toLowerCase(), 'highlighted');
+        });
+      }, 10);
+      $('<p class="highlight-link"><a href="javascript:Documentation.' +
+        'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
+          .appendTo($('#searchbox'));
+    }
+  },
+
+  /**
+   * init the domain index toggle buttons
+   */
+  initIndexTable : function() {
+    var togglers = $('img.toggler').click(function() {
+      var src = $(this).attr('src');
+      var idnum = $(this).attr('id').substr(7);
+      $('tr.cg-' + idnum).toggle();
+      if (src.substr(-9) == 'minus.png')
+        $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
+      else
+        $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
+    }).css('display', '');
+    if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
+        togglers.click();
+    }
+  },
+
+  /**
+   * helper function to hide the search marks again
+   */
+  hideSearchWords : function() {
+    $('#searchbox .highlight-link').fadeOut(300);
+    $('span.highlighted').removeClass('highlighted');
+  },
+
+  /**
+   * make the url absolute
+   */
+  makeURL : function(relativeURL) {
+    return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
+  },
+
+  /**
+   * get the current relative url
+   */
+  getCurrentURL : function() {
+    var path = document.location.pathname;
+    var parts = path.split(/\//);
+    $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
+      if (this == '..')
+        parts.pop();
+    });
+    var url = parts.join('/');
+    return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
+  }
+};
+
+// quick alias for translations
+_ = Documentation.gettext;
+
+$(document).ready(function() {
+  Documentation.init();
+});
Index: /tags/rel-1.7.0/docs/_static/hpc_schema.svg
===================================================================
--- /tags/rel-1.7.0/docs/_static/hpc_schema.svg	(revision 942)
+++ /tags/rel-1.7.0/docs/_static/hpc_schema.svg	(revision 942)
@@ -0,0 +1,1 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="813" height="1698"><defs/><g><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g/><g><rect fill="white" stroke="none" x="0" y="0" width="813" height="1698"/></g><g/><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 59.284222437999986 L 68.20503325732031 1698.8360121179992" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="13.532121076923076,5.863919133333333"/><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 340.86450169866146 59.284222437999986 L 340.86450169866146 1698.8360121179992" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="13.532121076923076,5.863919133333333"/><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 510.26668704875135 59.284222437999986 L 510.26668704875135 1698.8360121179992" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="13.532121076923076,5.863919133333333"/><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 664.1821322865366 59.284222437999986 L 664.1821322865366 1698.8360121179992" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="13.532121076923076,5.863919133333333"/></g><g><path fill="none" stroke="none"/><g><path fill="white" stroke="black" paint-order="fill stroke markers" d=" M 8.795878699999996 11.786477457999997 L 127.61418781464062 11.786477457999997 L 127.61418781464062 59.284222437999986 L 8.795878699999996 59.284222437999986 L 8.795878699999996 11.786477457999997 Z" stroke-miterlimit="10" stroke-width="2.814681184" stroke-dasharray=""/></g><g><g/><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="27.882935478999997" y="41.692465037999995" text-anchor="start" dominant-baseline="alphabetic">WPS Server</text></g><path fill="none" stroke="none"/><g><path fill="white" stroke="black" paint-order="fill stroke markers" d=" M 267.18907364280597 11.786477457999997 L 414.53992975451695 11.786477457999997 L 414.53992975451695 59.284222437999986 L 267.18907364280597 59.284222437999986 L 267.18907364280597 11.786477457999997 Z" stroke-miterlimit="10" stroke-width="2.814681184" stroke-dasharray=""/></g><g><g/><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="286.276130421806" y="41.692465037999995" text-anchor="start" dominant-baseline="alphabetic">Callback Service</text></g><path fill="none" stroke="none"/><g><path fill="white" stroke="black" paint-order="fill stroke markers" d=" M 432.13168715451695 11.786477457999997 L 588.4016869429857 11.786477457999997 L 588.4016869429857 59.284222437999986 L 432.13168715451695 59.284222437999986 L 432.13168715451695 11.786477457999997 Z" stroke-miterlimit="10" stroke-width="2.814681184" stroke-dasharray=""/></g><g><g/><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="451.218743933517" y="41.692465037999995" text-anchor="start" dominant-baseline="alphabetic">WCS/WFS Server</text></g><path fill="none" stroke="none"/><g><path fill="white" stroke="black" paint-order="fill stroke markers" d=" M 605.9934443429858 11.786477457999997 L 722.3708202300874 11.786477457999997 L 722.3708202300874 59.284222437999986 L 605.9934443429858 59.284222437999986 L 605.9934443429858 11.786477457999997 Z" stroke-miterlimit="10" stroke-width="2.814681184" stroke-dasharray=""/></g><g><g/><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="625.0805011219858" y="41.692465037999995" text-anchor="start" dominant-baseline="alphabetic">HPC Server</text></g></g><g><g><g><rect fill="white" stroke="none" x="143.63189711750258" y="94.46773723799997" width="98.16224706863281" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="143.63189711750258" y="112.05949463799996" width="121.80574072097656" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="146.2706607275026" y="110.30031889799997" text-anchor="start" dominant-baseline="alphabetic">       Step (0,0)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="146.2706607275026" y="127.89207629799998" text-anchor="start" dominant-baseline="alphabetic"> Analyze creation </text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 134.92877925799996 L 337.9325421319948 134.92877925799996" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,134.92877925799996) translate(-340.86450169866146,-134.92877925799996)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 127.5988803413333 L 340.86450169866146 134.92877925799996 L 326.2047038653281 142.25867817466664 Z"/></g></g><g><g><rect fill="white" stroke="none" x="132.22171797931898" y="161.31641535799997" width="110.381286985625" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="132.22171797931898" y="178.90817275799998" width="144.62609899734375" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="134.860481589319" y="177.148997018" text-anchor="start" dominant-baseline="alphabetic">          Step (1,0)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="134.860481589319" y="194.740754418" text-anchor="start" dominant-baseline="alphabetic"> Fetching DataInputs </text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 201.77745737799995 L 337.9325421319948 201.77745737799995" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,201.77745737799995) translate(-340.86450169866146,-201.77745737799995)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 194.44755846133327 L 340.86450169866146 201.77745737799995 L 326.2047038653281 209.10735629466663 Z"/></g></g><g><g><rect fill="white" stroke="none" x="199.81471739264515" y="228.16509347799993" width="178.84228552078125" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="202.45348100264516" y="243.99767513799995" text-anchor="start" dominant-baseline="alphabetic">GetCoverage / GetFeature</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 251.03437809799993 L 507.3347274820847 251.03437809799993" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(510.26668704875135,251.03437809799993) translate(-510.26668704875135,-251.03437809799993)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 495.606889215418 243.70447918133326 L 510.26668704875135 251.03437809799993 L 495.606889215418 258.3642770146666 Z"/></g></g><g><g><rect fill="white" stroke="none" x="253.59066496344593" y="277.42201419799994" width="71.29039037917968" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="256.22942857344594" y="293.25459585799996" text-anchor="start" dominant-baseline="alphabetic">Response</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 510.26668704875135 300.2912988179999 L 71.13699282398697 300.2912988179999" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(68.20503325732031,300.2912988179999) translate(-68.20503325732031,-300.2912988179999)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 82.86483109065364 292.96139990133327 L 68.20503325732031 300.2912988179999 L 82.86483109065364 307.62119773466657 Z"/></g></g><g><g><rect fill="white" stroke="none" x="89.02194618065364" y="326.6789349179999" width="236.71621740554687" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="89.02194618065364" y="344.27069231799993" width="217.1815341780078" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="89.02194618065364" y="361.86244971799994" width="108.76350439285156" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="342.51151657799994" text-anchor="start" dominant-baseline="alphabetic">Publish input data using MapServer</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="360.10327397799995" text-anchor="start" dominant-baseline="alphabetic">and update execute request with</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="377.69503137799995" text-anchor="start" dominant-baseline="alphabetic">local references</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 384.7317343379999 L 138.5720628573203 384.7317343379999 L 138.5720628573203 402.3234917379999 L 71.13699282398697 402.3234917379999" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(68.20503325732031,402.3234917379999) translate(-68.20503325732031,-402.3234917379999)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 82.86483109065364 394.99359282133327 L 68.20503325732031 402.3234917379999 L 82.86483109065364 409.65339065466657 Z"/></g></g><g><g><rect fill="white" stroke="none" x="132.22171797931898" y="428.7111278379999" width="110.381286985625" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="132.22171797931898" y="446.30288523799993" width="144.62609899734375" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="134.860481589319" y="444.54370949799994" text-anchor="start" dominant-baseline="alphabetic">          Step (1,1)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="134.860481589319" y="462.13546689799995" text-anchor="start" dominant-baseline="alphabetic"> Fetching DataInputs </text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 469.1721698579999 L 337.9325421319948 469.1721698579999" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,469.1721698579999) translate(-340.86450169866146,-469.1721698579999)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 461.84227094133325 L 340.86450169866146 469.1721698579999 L 326.2047038653281 476.50206877466655 Z"/></g></g><g><g><rect fill="white" stroke="none" x="127.32551589191665" y="495.5598059579999" width="118.52731359695312" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="127.32551589191665" y="513.1515633579999" width="154.41850317214843" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="129.96427950191665" y="511.39238761799993" text-anchor="start" dominant-baseline="alphabetic">            Step (2,0)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="129.96427950191665" y="528.9841450179999" text-anchor="start" dominant-baseline="alphabetic"> Uploading DataInputs </text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 536.0208479779999 L 337.9325421319948 536.0208479779999" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,536.0208479779999) translate(-340.86450169866146,-536.0208479779999)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 528.6909490613332 L 340.86450169866146 536.0208479779999 L 326.2047038653281 543.3507468946666 Z"/></g></g><g><g><rect fill="white" stroke="none" x="290.6199818206198" y="562.4084840779999" width="151.14720190261718" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="293.2587454306198" y="578.2410657379999" text-anchor="start" dominant-baseline="alphabetic">Upload data over SSH</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 585.2777686979999 L 661.2501727198699 585.2777686979999" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(664.1821322865366,585.2777686979999) translate(-664.1821322865366,-585.2777686979999)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 649.5223344532033 577.9478697813332 L 664.1821322865366 585.2777686979999 L 649.5223344532033 592.6076676146666 Z"/></g></g><g><g><rect fill="white" stroke="none" x="127.32551589191665" y="611.6654047979999" width="118.52731359695312" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="127.32551589191665" y="629.257162198" width="154.41850317214843" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="129.96427950191665" y="627.4979864579999" text-anchor="start" dominant-baseline="alphabetic">            Step (2,1)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="129.96427950191665" y="645.0897438579999" text-anchor="start" dominant-baseline="alphabetic"> Uploading DataInputs </text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 652.126446818 L 337.9325421319948 652.126446818" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,652.126446818) translate(-340.86450169866146,-652.126446818)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 644.7965479013333 L 340.86450169866146 652.126446818 L 326.2047038653281 659.4563457346667 Z"/></g></g><g><g><rect fill="white" stroke="none" x="121.37706008136978" y="678.5140829179999" width="126.67334020828125" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="121.37706008136978" y="696.1058403179999" width="166.31541479324218" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="124.01582369136977" y="694.3466645779998" text-anchor="start" dominant-baseline="alphabetic">              Step (3,0)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="124.01582369136977" y="711.9384219779998" text-anchor="start" dominant-baseline="alphabetic"> Creating SBATCH script</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 718.9751249379999 L 337.9325421319948 718.9751249379999" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,718.9751249379999) translate(-340.86450169866146,-718.9751249379999)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 711.6452260213332 L 340.86450169866146 718.9751249379999 L 326.2047038653281 726.3050238546666 Z"/></g></g><g><g><rect fill="white" stroke="none" x="89.02194618065364" y="745.3627610379998" width="162.24240148757812" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="761.1953426979998" text-anchor="start" dominant-baseline="alphabetic">Creating SBATCH script</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 768.2320456579998 L 138.5720628573203 768.2320456579998 L 138.5720628573203 785.8238030579998 L 71.13699282398697 785.8238030579998" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(68.20503325732031,785.8238030579998) translate(-68.20503325732031,-785.8238030579998)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 82.86483109065364 778.4939041413331 L 68.20503325732031 785.8238030579998 L 82.86483109065364 793.1537019746665 Z"/></g></g><g><g><rect fill="white" stroke="none" x="121.37706008136978" y="812.2114391579997" width="126.67334020828125" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="121.37706008136978" y="829.8031965579997" width="166.31541479324218" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="124.01582369136977" y="828.0440208179997" text-anchor="start" dominant-baseline="alphabetic">              Step (3,1)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="124.01582369136977" y="845.6357782179997" text-anchor="start" dominant-baseline="alphabetic"> Creating SBATCH script</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 852.6724811779998 L 337.9325421319948 852.6724811779998" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,852.6724811779998) translate(-340.86450169866146,-852.6724811779998)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 845.3425822613331 L 340.86450169866146 852.6724811779998 L 326.2047038653281 860.0023800946665 Z"/></g></g><g><g><rect fill="white" stroke="none" x="115.93325820148696" y="879.0601172779997" width="130.7463535139453" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="115.93325820148696" y="896.6518746779997" width="177.2030185530078" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="118.57202181148696" y="894.8926989379996" text-anchor="start" dominant-baseline="alphabetic">               Step (4,0)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="118.57202181148696" y="912.4844563379996" text-anchor="start" dominant-baseline="alphabetic"> Submitting Job to Cluster </text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 919.5211592979997 L 337.9325421319948 919.5211592979997" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,919.5211592979997) translate(-340.86450169866146,-919.5211592979997)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 912.191260381333 L 340.86450169866146 919.5211592979997 L 326.2047038653281 926.8510582146664 Z"/></g></g><g><g><rect fill="white" stroke="none" x="248.26137738946744" y="945.9087953979997" width="235.86441076492187" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="250.90014099946745" y="961.7413770579997" text-anchor="start" dominant-baseline="alphabetic">Submitting Job to Cluster over SSH</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 968.7780800179997 L 661.2501727198699 968.7780800179997" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(664.1821322865366,968.7780800179997) translate(-664.1821322865366,-968.7780800179997)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 649.5223344532033 961.448181101333 L 664.1821322865366 968.7780800179997 L 649.5223344532033 976.1079789346664 Z"/></g></g><g><g><rect fill="white" stroke="none" x="684.9990452098699" y="995.1657161179998" width="122.65042150710937" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="687.6378088198699" y="1010.9982977779997" text-anchor="start" dominant-baseline="alphabetic">Scheddule the job</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 664.1821322865366 1018.0350007379998 L 734.5491618865366 1018.0350007379998 L 734.5491618865366 1035.6267581379998 L 667.1140918532033 1035.6267581379998" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(664.1821322865366,1035.6267581379998) translate(-664.1821322865366,-1035.6267581379998)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 678.8419301198699 1028.296859221333 L 664.1821322865366 1035.6267581379998 L 678.8419301198699 1042.9566570546665 Z"/></g></g><g><g><rect fill="white" stroke="none" x="117.969764854319" y="1062.0143942379998" width="130.7463535139453" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="117.969764854319" y="1079.6061516379998" width="173.13000524734375" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="120.608528464319" y="1077.8469758979998" text-anchor="start" dominant-baseline="alphabetic">               Step (4,1)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="120.608528464319" y="1095.4387332979998" text-anchor="start" dominant-baseline="alphabetic"> Submitting Job to Cluster</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 1102.4754362579997 L 337.9325421319948 1102.4754362579997" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,1102.4754362579997) translate(-340.86450169866146,-1102.4754362579997)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 1095.145537341333 L 340.86450169866146 1102.4754362579997 L 326.2047038653281 1109.8053351746664 Z"/></g></g><g><g><rect fill="white" stroke="none" x="684.9990452098699" y="1128.8630723579997" width="106.33689916824218" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="687.6378088198699" y="1144.6956540179997" text-anchor="start" dominant-baseline="alphabetic">Execute the job</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 664.1821322865366 1151.7323569779996 L 734.5491618865366 1151.7323569779996 L 734.5491618865366 1169.3241143779996 L 667.1140918532033 1169.3241143779996" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(664.1821322865366,1169.3241143779996) translate(-664.1821322865366,-1169.3241143779996)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 678.8419301198699 1161.994215461333 L 664.1821322865366 1169.3241143779996 L 678.8419301198699 1176.6540132946664 Z"/></g></g><g><g><rect fill="white" stroke="none" x="237.24492078546353" y="1195.7117504779997" width="257.8973239729297" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="239.88368439546355" y="1211.5443321379996" text-anchor="start" dominant-baseline="alphabetic">sendmail informing that the job has run</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 664.1821322865366 1218.5810350979996 L 71.13699282398697 1218.5810350979996" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(68.20503325732031,1218.5810350979996) translate(-68.20503325732031,-1218.5810350979996)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 82.86483109065364 1211.2511361813329 L 68.20503325732031 1218.5810350979996 L 82.86483109065364 1225.9109340146663 Z"/></g></g><g><g><rect fill="white" stroke="none" x="89.02194618065364" y="1244.9686711979996" width="206.55876196121093" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="89.02194618065364" y="1262.5604285979996" width="164.96252477859375" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="89.02194618065364" y="1280.1521859979996" width="147.87588537429687" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="1260.8012528579995" text-anchor="start" dominant-baseline="alphabetic">Mail daemon invoke execution </text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="1278.3930102579995" text-anchor="start" dominant-baseline="alphabetic">of the FinalizeHPC WPS</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="1295.9847676579996" text-anchor="start" dominant-baseline="alphabetic">Service with the job id</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 1303.0214706179995 L 138.5720628573203 1303.0214706179995 L 138.5720628573203 1320.6132280179995 L 71.13699282398697 1320.6132280179995" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(68.20503325732031,1320.6132280179995) translate(-68.20503325732031,-1320.6132280179995)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 82.86483109065364 1313.2833291013328 L 68.20503325732031 1320.6132280179995 L 82.86483109065364 1327.9431269346662 Z"/></g></g><g><g><rect fill="white" stroke="none" x="131.3985291975807" y="1347.0008641179995" width="114.45430029128906" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="131.3985291975807" y="1364.5926215179995" width="146.2724765608203" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="134.0372928075807" y="1362.8334457779995" text-anchor="start" dominant-baseline="alphabetic">           Step (5,0)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="134.0372928075807" y="1380.4252031779995" text-anchor="start" dominant-baseline="alphabetic"> Downloading outputs</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 1387.4619061379994 L 337.9325421319948 1387.4619061379994" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,1387.4619061379994) translate(-340.86450169866146,-1387.4619061379994)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 1380.1320072213327 L 340.86450169866146 1387.4619061379994 L 326.2047038653281 1394.7918050546662 Z"/></g></g><g><g><rect fill="white" stroke="none" x="258.8340168547995" y="1413.8495422379995" width="214.7191318342578" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="261.4727804647995" y="1429.6821238979994" text-anchor="start" dominant-baseline="alphabetic">Download output data over SSH</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 1436.7188268579994 L 661.2501727198699 1436.7188268579994" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(664.1821322865366,1436.7188268579994) translate(-664.1821322865366,-1436.7188268579994)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 649.5223344532033 1429.3889279413327 L 664.1821322865366 1436.7188268579994 L 649.5223344532033 1444.048725774666 Z"/></g></g><g><g><rect fill="white" stroke="none" x="89.02194618065364" y="1463.1064629579994" width="245.6854404280078" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="91.66070979065364" y="1478.9390446179993" text-anchor="start" dominant-baseline="alphabetic">Publish output data using MapServer</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 1485.9757475779993 L 138.5720628573203 1485.9757475779993 L 138.5720628573203 1503.5675049779993 L 71.13699282398697 1503.5675049779993" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray=""/><g transform="translate(68.20503325732031,1503.5675049779993) translate(-68.20503325732031,-1503.5675049779993)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 82.86483109065364 1496.2376060613326 L 68.20503325732031 1503.5675049779993 L 82.86483109065364 1510.897403894666 Z"/></g></g><g><g><rect fill="white" stroke="none" x="129.36202254474867" y="1529.9551410779993" width="110.381286985625" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="129.36202254474867" y="1547.5468984779993" width="150.34548986648437" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="132.00078615474868" y="1545.7877227379993" text-anchor="start" dominant-baseline="alphabetic">          Step (5,1)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="132.00078615474868" y="1563.3794801379993" text-anchor="start" dominant-baseline="alphabetic"> Downloading outputs </text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 1570.4161830979992 L 337.9325421319948 1570.4161830979992" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,1570.4161830979992) translate(-340.86450169866146,-1570.4161830979992)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 1563.0862841813325 L 340.86450169866146 1570.4161830979992 L 326.2047038653281 1577.746082014666 Z"/></g></g><g><g><rect fill="white" stroke="none" x="169.70919051349867" y="1596.8038191979992" width="69.65115392898437" height="22.86928462"/></g><g><rect fill="white" stroke="none" x="169.70919051349867" y="1614.3955765979993" width="59.865906126249996" height="22.86928462"/></g><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="172.34795412349868" y="1612.6364008579992" text-anchor="start" dominant-baseline="alphabetic">Step (6,0)</text><text fill="black" stroke="none" font-family="sans-serif" font-size="11pt" font-style="normal" font-weight="normal" text-decoration="normal" x="172.34795412349868" y="1630.2281582579992" text-anchor="start" dominant-baseline="alphabetic"> Finalize</text></g><g><path fill="none" stroke="black" paint-order="fill stroke markers" d=" M 68.20503325732031 1637.2648612179992 L 337.9325421319948 1637.2648612179992" stroke-miterlimit="10" stroke-width="1.4659797833333332" stroke-dasharray="7.0367029599999995"/><g transform="translate(340.86450169866146,1637.2648612179992) translate(-340.86450169866146,-1637.2648612179992)"><path fill="black" stroke="none" paint-order="stroke fill markers" d=" M 326.2047038653281 1629.9349623013325 L 340.86450169866146 1637.2648612179992 L 326.2047038653281 1644.5947601346659 Z"/></g></g></g><g/><g/><g/><g/></g></svg>
Index: /tags/rel-1.7.0/docs/_static/jquery.js
===================================================================
--- /tags/rel-1.7.0/docs/_static/jquery.js	(revision 942)
+++ /tags/rel-1.7.0/docs/_static/jquery.js	(revision 942)
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
+},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
Index: /tags/rel-1.7.0/docs/_static/underscore.js
===================================================================
--- /tags/rel-1.7.0/docs/_static/underscore.js	(revision 942)
+++ /tags/rel-1.7.0/docs/_static/underscore.js	(revision 942)
@@ -0,0 +1,31 @@
+// Underscore.js 1.3.1
+// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
+c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
+h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
+b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
+null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
+function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
+e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
+function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
+return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
+c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
+b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
+return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
+d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
+var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
+c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
+a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
+b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
+1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
+b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
+b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),
+function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
+u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
+function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
+true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
Index: /tags/rel-1.7.0/docs/_templates/index.html
===================================================================
--- /tags/rel-1.7.0/docs/_templates/index.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_templates/index.html	(revision 942)
@@ -0,0 +1,3 @@
+{% extends "layout.html" %}
+{% set title = 'Overview' %}
+
Index: /tags/rel-1.7.0/docs/_templates/indexsidebar.html
===================================================================
--- /tags/rel-1.7.0/docs/_templates/indexsidebar.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_templates/indexsidebar.html	(revision 942)
@@ -0,0 +1,39 @@
+<p class="logo">A <a href="http://pocoo.org/">
+  <img src="{{ pathto("_static/pocoo.png", 1) }}" alt="Pocoo" /></a>
+  {%trans%}project{%endtrans%}</p>
+
+<h3>Download</h3>
+{% if version.endswith('a0') %}
+<p>{%trans%}This documentation is for version <b>{{ version }}</b>, which is
+  not released yet.{%endtrans%}</p>
+<p>{%trans%}You can use it from the
+  <a href="https://github.com/sphinx-doc/sphinx/">Git repo</a> or look for
+  released versions in the <a href="https://pypi.python.org/pypi/Sphinx">Python
+    Package Index</a>.{%endtrans%}</p>
+{% else %}
+<p>{%trans%}Current version: <b>{{ version }}</b>{%endtrans%}</p>
+<p>{%trans%}Get Sphinx from the <a href="https://pypi.python.org/pypi/Sphinx">Python Package
+Index</a>, or install it with:{%endtrans%}</p>
+{% if version.split('b')|length > 1 %}
+<pre>pip install Sphinx=={{ version }}</pre>
+<p>{%trans%}<a href="http://sphinx-doc.org/">Stable version docs</a>
+are also available.{%endtrans%}</p>
+{% else %}
+<pre>pip install -U Sphinx</pre>
+<p>{%trans%}Latest <a href="http://sphinx-doc.org/latest/">development version docs</a>
+are also available.{%endtrans%}</p>
+{% endif %}
+{% endif %}
+
+<h3>{%trans%}Questions? Suggestions?{%endtrans%}</h3>
+
+<p>{%trans%}Join the <a href="http://groups.google.com/group/sphinx-users">Google group</a>:{%endtrans%}</p>
+<form action="http://groups.google.com/group/sphinx-users/boxsubscribe"
+      style="padding-left: 0.5em">
+  <input type="text" name="email" value="your@email" style="font-size: 90%; width: 120px"
+         onfocus="$(this).val('');"/>
+  <input type="submit" name="sub" value="Subscribe" style="font-size: 90%; width: 70px"/>
+</form>
+<p>{%trans%}or come to the <tt>#sphinx-doc</tt> channel on FreeNode.{%endtrans%}</p>
+<p>{%trans%}You can also open an issue at the
+  <a href="https://github.com/sphinx-doc/sphinx/issues">tracker</a>.{%endtrans%}</p>
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/__init__.py
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/__init__.py	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/__init__.py	(revision 942)
@@ -0,0 +1,17 @@
+"""Sphinx ReadTheDocs theme.
+
+From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
+
+"""
+import os
+
+VERSION = (0, 1, 7)
+
+__version__ = ".".join(str(v) for v in VERSION)
+__version_full__ = __version__
+
+
+def get_html_theme_path():
+    """Return list of HTML theme paths."""
+    cur_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+    return cur_dir
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/breadcrumbs.html
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/breadcrumbs.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/breadcrumbs.html	(revision 942)
@@ -0,0 +1,14 @@
+<div role="navigation" aria-label="breadcrumbs navigation">
+  <ul class="wy-breadcrumbs">
+
+    <li><a href="{{pathto(master_doc) }}"> Documentation</a> &#8725; &#160;</li>
+      {% for doc in parents %}
+          <li><a href="{{ doc.link|e }}">{{ doc.title }}</a> &#8725; &#160;</li>
+      {% endfor %}
+    <li>{{ title }}</li>
+      <li class="wy-breadcrumbs-aside">
+       $Date$
+      </li>
+  </ul>
+  <hr/>
+</div>
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/footer.html
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/footer.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/footer.html	(revision 942)
@@ -0,0 +1,36 @@
+<footer>
+  {% if next or prev %}
+    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
+      {% if next %}
+        <a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}">Next <span class="fa fa-arrow-circle-right"></span></a>
+      {% endif %}
+      {% if prev %}
+        <a href="{{ prev.link|e }}" class="btn btn-neutral" title="{{ prev.title|striptags|e }}"><span class="fa fa-arrow-circle-left"></span> Previous</a>
+      {% endif %}
+    </div>
+  {% endif %}
+
+  <hr/>
+  <div class="pfoot">
+  <div role="contentinfo">
+    <p>
+    {%- if show_copyright %}
+      {%- if hasdoc('copyright') %}
+        {% trans path=pathto('copyright'), copyright=copyright|e %}&copy; <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
+      {%- else %}
+        {% trans copyright=copyright|e %}&copy; Copyright {{ copyright }}.{% endtrans %}
+      {%- endif %}
+    {%- endif %}
+
+    {%- if last_updated %}
+      {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
+    {%- endif %}
+    </p>
+  </div>
+
+  {%- if show_sphinx %}
+  {% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> inspired by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
+  {%- endif %}
+</div>
+</footer>
+
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/layout.html
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/layout.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/layout.html	(revision 942)
@@ -0,0 +1,180 @@
+{# TEMPLATE VAR SETTINGS #}
+{%- set url_root = pathto('', 1) %}
+{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
+{%- if not embedded and docstitle %}
+  {%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
+{%- else %}
+  {%- set titlesuffix = "" %}
+{%- endif %}
+
+<!DOCTYPE html>
+<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
+<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  {% block htmltitle %}
+  <title>{{ title|striptags|e }}{{ titlesuffix }}</title>
+  {% endblock %}
+  <link href="http://fonts.googleapis.com/css?family=Days+One" rel="stylesheet" type="text/css">
+  {# FAVICON #}
+  {% if favicon %}
+    <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
+  {% endif %}
+
+  {# CSS #}
+
+  {# OPENSEARCH #}
+  {% if not embedded %}
+    {% if use_opensearch %}
+      <link rel="search" type="application/opensearchdescription+xml" title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}" href="{{ pathto('_static/opensearch.xml', 1) }}"/>
+    {% endif %}
+
+  {% endif %}
+
+  {# RTD hosts this file, so just load on non RTD builds #}
+  {% if not READTHEDOCS %}
+    <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
+  {% endif %}
+
+  {% for cssfile in css_files %}
+    <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
+  {% endfor %}
+
+  {% for cssfile in extra_css_files %}
+    <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
+  {% endfor %}
+
+  {%- block linktags %}
+    {%- if hasdoc('about') %}
+        <link rel="author" title="{{ _('About these documents') }}"
+              href="{{ pathto('about') }}"/>
+    {%- endif %}
+    {%- if hasdoc('genindex') %}
+        <link rel="index" title="{{ _('Index') }}"
+              href="{{ pathto('genindex') }}"/>
+    {%- endif %}
+    {%- if hasdoc('search') %}
+        <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}"/>
+    {%- endif %}
+    {%- if hasdoc('copyright') %}
+        <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}"/>
+    {%- endif %}
+    <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}"/>
+    {%- if parents %}
+        <link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}"/>
+    {%- endif %}
+    {%- if next %}
+        <link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}"/>
+    {%- endif %}
+    {%- if prev %}
+        <link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}"/>
+    {%- endif %}
+  {%- endblock %}
+  {%- block extrahead %} {% endblock %}
+
+  {# Keep modernizr in head - http://modernizr.com/docs/#installing #}
+  <script src="{{ pathto('_static/' + 'js/modernizr.min.js', 1) }}"></script>
+
+</head>
+
+<body class="wy-body-for-nav" role="document">
+
+  <div class="wy-grid-for-nav">
+
+    {# SIDE NAV, TOGGLES ON MOBILE #}
+    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
+      <div class="wy-side-nav-search">
+        {% block sidebartitle %}
+
+        {% if logo and theme_logo_only %}
+          <a href="{{ pathto(master_doc) }}">
+        {% else %}
+	  <a class="shrink" href="http://zoo-project.org"><img src="http://zoo-project.org/img/zoo-sun-logo.png" class="img-responsive sun" style="display: inline;"> ZOO</a>
+        {% endif %}
+
+        {% if logo %}
+          {# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #}
+          <img src="{{ pathto('_static/' + logo, 1) }}" class="logo" />
+        {% endif %}
+        </a>
+
+        {% include "searchbox.html" %}
+
+        {% endblock %}
+      </div>
+
+      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
+        {% block menu %}
+          {% set toctree = toctree(maxdepth=2, collapse=False, includehidden=False) %}
+          {% if toctree %}
+              {{ toctree }}
+          {% else %}
+              <!-- Local TOC -->
+              <div class="local-toc">{{ toc }}</div>
+          {% endif %}
+        {% endblock %}
+      </div>
+      &nbsp;
+    </nav>
+
+    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
+
+      {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
+      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
+        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
+        <a href="{{ pathto(master_doc) }}">{{ project }}</a>
+      </nav>
+
+
+      {# PAGE CONTENT #}
+      <div class="wy-nav-content">
+        <div class="rst-content">
+          {% include "breadcrumbs.html" %}
+          <div role="main" class="document">
+            {% block body %}{% endblock %}
+          </div>
+          {% include "footer.html" %}
+        </div>
+      </div>
+
+    </section>
+
+  </div>
+  {% include "versions.html" %}
+
+  {% if not embedded %}
+
+    <script type="text/javascript">
+        var DOCUMENTATION_OPTIONS = {
+            URL_ROOT:'{{ url_root }}',
+            VERSION:'{{ release|e }}',
+            COLLAPSE_INDEX:false,
+            FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}',
+            HAS_SOURCE:  {{ has_source|lower }}
+        };
+    </script>
+    {%- for scriptfile in script_files %}
+      <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
+    {%- endfor %}
+
+  {% endif %}
+
+  {# RTD hosts this file, so just load on non RTD builds #}
+  {% if not READTHEDOCS %}
+    <script type="text/javascript" src="{{ pathto('_static/js/theme.js', 1) }}"></script>
+  {% endif %}
+
+  {# STICKY NAVIGATION #}
+  {% if theme_sticky_navigation %}
+  <script type="text/javascript">
+      jQuery(function () {
+          SphinxRtdTheme.StickyNav.enable();
+      });
+  </script>
+  {% endif %}
+
+  {%- block footer %} {% endblock %}
+
+</body>
+</html>
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/layout_old.html
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/layout_old.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/layout_old.html	(revision 942)
@@ -0,0 +1,205 @@
+{#
+    basic/layout.html
+    ~~~~~~~~~~~~~~~~~
+
+    Master layout template for Sphinx themes.
+
+    :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+#}
+{%- block doctype -%}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+{%- endblock %}
+{%- set reldelim1 = reldelim1 is not defined and ' &raquo;' or reldelim1 %}
+{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
+{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
+                         (sidebars != []) %}
+{%- set url_root = pathto('', 1) %}
+{# XXX necessary? #}
+{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
+{%- if not embedded and docstitle %}
+  {%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
+{%- else %}
+  {%- set titlesuffix = "" %}
+{%- endif %}
+
+{%- macro relbar() %}
+    <div class="related">
+      <h3>{{ _('Navigation') }}</h3>
+      <ul>
+        {%- for rellink in rellinks %}
+        <li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
+          <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
+             {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
+          {%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
+        {%- endfor %}
+        {%- block rootrellink %}
+        <li><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a>{{ reldelim1 }}</li>
+        {%- endblock %}
+        {%- for parent in parents %}
+          <li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
+        {%- endfor %}
+        {%- block relbaritems %} {% endblock %}
+      </ul>
+    </div>
+{%- endmacro %}
+
+{%- macro sidebar() %}
+      {%- if render_sidebar %}
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+          {%- block sidebarlogo %}
+          {%- if logo %}
+            <p class="logo"><a href="{{ pathto(master_doc) }}">
+              <img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
+            </a></p>
+          {%- endif %}
+          {%- endblock %}
+          {%- if sidebars != None %}
+            {#- new style sidebar: explicitly include/exclude templates #}
+            {%- for sidebartemplate in sidebars %}
+            {%- include sidebartemplate %}
+            {%- endfor %}
+          {%- else %}
+            {#- old style sidebars: using blocks -- should be deprecated #}
+            {%- block sidebartoc %}
+            {%- include "localtoc.html" %}
+            {%- endblock %}
+            {%- block sidebarrel %}
+            {%- include "relations.html" %}
+            {%- endblock %}
+            {%- block sidebarsourcelink %}
+            {%- include "sourcelink.html" %}
+            {%- endblock %}
+            {%- if customsidebar %}
+            {%- include customsidebar %}
+            {%- endif %}
+            {%- block sidebarsearch %}
+            {%- include "searchbox.html" %}
+            {%- endblock %}
+          {%- endif %}
+        </div>
+      </div>
+      {%- endif %}
+{%- endmacro %}
+
+{%- macro script() %}
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    '{{ url_root }}',
+        VERSION:     '{{ release|e }}',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
+        HAS_SOURCE:  {{ has_source|lower }}
+      };
+    </script>
+    {%- for scriptfile in script_files %}
+    <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
+    {%- endfor %}
+{%- endmacro %}
+
+{%- macro css() %}
+    <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
+    <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
+    {%- for cssfile in css_files %}
+    <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
+    {%- endfor %}
+{%- endmacro %}
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
+    {{ metatags }}
+    {%- block htmltitle %}
+    <title>{{ title|striptags|e }}{{ titlesuffix }}</title>
+    {%- endblock %}
+    {{ css() }}
+    {%- if not embedded %}
+    {{ script() }}
+    {%- if use_opensearch %}
+    <link rel="search" type="application/opensearchdescription+xml"
+          title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
+          href="{{ pathto('_static/opensearch.xml', 1) }}"/>
+    {%- endif %}
+    {%- if favicon %}
+    <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
+    {%- endif %}
+    {%- endif %}
+{%- block linktags %}
+    {%- if hasdoc('about') %}
+    <link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
+    {%- endif %}
+    {%- if hasdoc('genindex') %}
+    <link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
+    {%- endif %}
+    {%- if hasdoc('search') %}
+    <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
+    {%- endif %}
+    {%- if hasdoc('copyright') %}
+    <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
+    {%- endif %}
+    <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}" />
+    {%- if parents %}
+    <link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}" />
+    {%- endif %}
+    {%- if next %}
+    <link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
+    {%- endif %}
+    {%- if prev %}
+    <link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
+    {%- endif %}
+{%- endblock %}
+{%- block extrahead %} {% endblock %}
+  </head>
+  <body>
+{%- block header %}{% endblock %}
+
+{%- block relbar1 %}{{ relbar() }}{% endblock %}
+
+{%- block content %}
+  {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %}
+
+    <div class="document">
+  {%- block document %}
+      <div class="documentwrapper">
+      {%- if render_sidebar %}
+        <div class="bodywrapper">
+      {%- endif %}
+          <div class="body">
+            {% block body %} {% endblock %}
+          </div>
+      {%- if render_sidebar %}
+        </div>
+      {%- endif %}
+      </div>
+  {%- endblock %}
+
+  {%- block sidebar2 %}{{ sidebar() }}{% endblock %}
+      <div class="clearer"></div>
+    </div>
+{%- endblock %}
+
+{%- block relbar2 %}{{ relbar() }}{% endblock %}
+
+{%- block footer %}
+    <div class="footer">
+    {%- if show_copyright %}
+      {%- if hasdoc('copyright') %}
+        {% trans path=pathto('copyright'), copyright=copyright|e %}&copy; <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
+      {%- else %}
+        {% trans copyright=copyright|e %}&copy; Copyright {{ copyright }}.{% endtrans %}
+      {%- endif %}
+    {%- endif %}
+    {%- if last_updated %}
+      {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
+    {%- endif %}
+    {%- if show_sphinx %}
+      {% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
+    {%- endif %}
+    </div>
+    <p>asdf asdf asdf asdf 22</p>
+{%- endblock %}
+  </body>
+</html>
+
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/search.html
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/search.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/search.html	(revision 942)
@@ -0,0 +1,50 @@
+{#
+    basic/search.html
+    ~~~~~~~~~~~~~~~~~
+
+    Template for the search page.
+
+    :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+#}
+{%- extends "layout.html" %}
+{% set title = _('Search') %}
+{% set script_files = script_files + ['_static/searchtools.js'] %}
+{% block footer %}
+  <script type="text/javascript">
+    jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
+  </script>
+  {# this is used when loading the search index using $.ajax fails,
+     such as on Chrome for documents on localhost #}
+  <script type="text/javascript" id="searchindexloader"></script>
+  {{ super() }}
+{% endblock %}
+{% block body %}
+  <noscript>
+  <div id="fallback" class="admonition warning">
+    <p class="last">
+      {% trans %}Please activate JavaScript to enable the search
+      functionality.{% endtrans %}
+    </p>
+  </div>
+  </noscript>
+
+  {% if search_performed %}
+    <h2>{{ _('Search Results') }}</h2>
+    {% if not search_results %}
+      <p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
+    {% endif %}
+  {% endif %}
+  <div id="search-results">
+  {% if search_results %}
+    <ul>
+    {% for href, caption, context in search_results %}
+      <li>
+        <a href="{{ pathto(item.href) }}">{{ caption }}</a>
+        <p class="context">{{ context|e }}</p>
+      </li>
+    {% endfor %}
+    </ul>
+  {% endif %}
+  </div>
+{% endblock %}
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/searchbox.html
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/searchbox.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/searchbox.html	(revision 942)
@@ -0,0 +1,9 @@
+{%- if builder != 'singlehtml' %}
+<div role="search">
+  <form id="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
+    <input type="text" name="q" placeholder="Search docs" />
+    <input type="hidden" name="check_keywords" value="yes" />
+    <input type="hidden" name="area" value="default" />
+  </form>
+</div>
+{%- endif %}
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css	(revision 942)
@@ -0,0 +1,2 @@
+﻿.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
+/*# sourceMappingURL=badge_only.css.map */
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css.map
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css.map	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css.map	(revision 942)
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "CAyDA,SAAY,EACV,qBAAsB,EAAE,UAAW,EAqDrC,QAAS,EARP,IAAK,EAAE,AAAC,EACR,+BAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,cAAO,EACL,IAAK,EAAE,GAAI,EC1Gb,SAkBC,EAjBC,UAAW,ECFJ,UAAW,EDGlB,UAAW,EAHqC,KAAM,EAItD,SAAU,EAJsD,KAAM,EAapE,EAAG,EAAE,qCAAwB,EAC7B,EAAG,EAAE,0PAAyE,ECZpF,SAAU,EACR,MAAO,EAAE,WAAY,EACrB,UAAW,EAAE,UAAW,EACxB,SAAU,EAAE,KAAM,EAClB,UAAW,EAAE,KAAM,EACnB,UAAW,EAAE,AAAC,EACd,cAAe,EAAE,MAAO,EAG1B,IAAK,EACH,MAAO,EAAE,WAAY,EACrB,cAAe,EAAE,MAAO,EAIxB,KAAG,EACD,MAAO,EAAE,WAAY,EACvB,sCAAiB,EAGf,IAAK,EAAE,MAAY,EAEvB,KAAM,EACJ,cAAe,EAAE,GAAI,EACrB,UAAW,EAAE,EAAG,EAChB,UAAW,EAAE,KAAM,EAEjB,YAAG,EACD,IAAK,EAAE,IAAI,EACb,oDAAiB,EAGf,aAAc,EAAE,OAAQ,EAG9B,cAAe,EACb,MAAO,EAAE,EAAO,EAElB,gBAAiB,EACf,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,kBAAmB,EACjB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,oBAAqB,EACnB,MAAO,EAAE,EAAO,EAElB,sBAAuB,EACrB,MAAO,EAAE,EAAO,EAElB,qBAAsB,EACpB,MAAO,EAAE,EAAO,EAElB,uBAAwB,EACtB,MAAO,EAAE,EAAO,ECnElB,YAAa,EACX,OAAQ,EAAE,IAAK,EACf,KAAM,EAAE,AAAC,EACT,GAAI,EAAE,AAAC,EACP,IAAK,EC6E+B,IAAK,ED5EzC,IAAK,ECE+B,MAAyB,EDD7D,SAAU,EAAE,MAAkC,EAC9C,SAAU,EAAE,iBAAiC,EAC7C,UAAW,EEAyB,sDAAM,EFC1C,MAAO,EC+E6B,EAAG,ED9EvC,cAAC,EACC,IAAK,ECqE6B,MAAW,EDpE7C,cAAe,EAAE,GAAI,EACvB,6BAAgB,EACd,MAAO,EAAE,GAAI,EACf,iCAAoB,EAClB,MAAO,EAAE,GAAqB,EAC9B,eAAgB,EAAE,MAAkC,EACpD,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,IAAK,EACjB,QAAS,EAAE,EAAG,EACd,KAAM,EAAE,MAAO,EACf,IAAK,ECiD6B,MAAM,EJgC1C,IAAK,EAAE,AAAC,EACR,iFAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,uCAAO,EACL,IAAK,EAAE,GAAI,EGrFX,qCAAG,EACD,IAAK,EClB2B,MAAyB,EDmB3D,0CAAQ,EACN,IAAK,EAAE,GAAI,EACb,4CAAU,EACR,IAAK,EAAE,GAAI,EACb,iDAAiB,EACf,eAAgB,ECQgB,MAAI,EDPpC,IAAK,EC0B2B,GAAM,EDzBxC,wDAAwB,EACtB,eAAgB,ECXgB,MAAO,EDYvC,IAAK,ECzB2B,GAAI,ED0BxC,yCAA8B,EAC5B,MAAO,EAAE,IAAK,EAChB,gCAAmB,EACjB,QAAS,EAAE,EAAG,EACd,MAAO,EAAE,GAAqB,EAC9B,IAAK,ECE6B,GAAwB,EDD1D,MAAO,EAAE,GAAI,EACb,mCAAE,EACA,MAAO,EAAE,IAAK,EACd,KAAM,EAAE,EAAG,EACX,KAAM,EAAE,AAAC,EACT,KAAM,EAAE,KAAM,EACd,MAAO,EAAE,AAAC,EACV,SAAU,EAAE,gBAA6C,EAC3D,mCAAE,EACA,MAAO,EAAE,WAAY,EACrB,KAAM,EAAE,AAAC,EACT,qCAAC,EACC,MAAO,EAAE,WAAY,EACrB,MAAO,EAAE,EAAqB,EAC9B,IAAK,ECjDyB,MAAyB,EDkD7D,sBAAW,EACT,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,IAAK,EAAE,GAAI,EACX,GAAI,EAAE,GAAI,EACV,KAAM,EAAE,GAAI,EACZ,QAAS,ECkByB,IAAK,EDjBvC,iCAAU,EACR,IAAK,EAAE,GAAI,EACb,+BAAQ,EACN,IAAK,EAAE,GAAI,EACb,oDAA+B,EAC7B,SAAU,EAAE,IAAK,EACjB,6DAAQ,EACN,IAAK,EAAE,GAAI,EACb,+DAAU,EACR,IAAK,EAAE,GAAI,EACf,2CAAoB,EAClB,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI,EACZ,UAAW,EAAE,GAAI,EACjB,MAAO,EAAE,IAAuB,EAChC,MAAO,EAAE,IAAK,EACd,SAAU,EAAE,KAAM,EGhDpB,mCAAsB,EHmDxB,YAAa,EACX,IAAK,EAAE,EAAG,EACV,MAAO,EAAE,GAAI,EACb,kBAAO,EACL,MAAO,EAAE,IAAK,EAClB,EAAG,EACD,IAAK,EAAE,GAAI,EACX,KAAM,EAAE,GAAI",
+"sources": ["../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/bourbon/dist/css3/_font-face.scss","../../../sass/_theme_badge_fa.sass","../../../sass/_theme_badge.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss"],
+"names": [],
+"file": "badge_only.css"
+}
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/theme.css
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/theme.css	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/theme.css	(revision 942)
@@ -0,0 +1,29 @@
+﻿*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0;}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.fa:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*!
+ *  Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content code.download span:first-child,.rst-content tt.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content code.download span.pull-left:first-child,.rst-content tt.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content code.download span.pull-right:first-child,.rst-content tt.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content code.download span:first-child,.rst-content tt.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .icon,.nav .fa,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:0.9em}.btn .fa.fa-spin,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content tt.download span.btn:first-child:before,.btn.icon:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.fa:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all 0.3s ease-in;-moz-transition:all 0.3s ease-in;transition:all 0.3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#c0b8a0 !important;color:#857d69 !important}.btn-neutral:hover{background-color:#663e05 !important;color:#c0b8a0;text-decoration:none !important;}.btn-neutral:visited{color:#857d69 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 0.3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.35765%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:0.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:0.34375em 0.625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:0.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:0.5em 0.625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{width:36px;height:12px;margin:12px 0;position:relative;border-radius:4px;background:#ccc;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:before{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:after{content:"false";position:absolute;left:48px;display:block;font-size:12px;color:#ccc}.wy-switch.active{background:#1e8449}.wy-switch.active:before{left:24px;background:#27AE60}.wy-switch.active:after{content:"true"}.wy-switch.disabled,.wy-switch.active.disabled{cursor:not-allowed}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:0.5em 0.625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:14px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#f0980c;text-decoration:none;cursor:pointer}a:hover{color:#663d05;text-decoration:underline}html{height:100%;overflow-x:hidden}body{font-family:"Arial",Helvetica Neue,Arial,sans-serif;font-weight:normal;color:#9c8a71;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:500;font-family: 'Days One',Arial,sans-serif;color:#9c8a71;}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9B59B6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],pre.literal-block div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}@media print{.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#EAF2F5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical header{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#2980B9;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:0.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:0.4045em 1.618em;display:block;position:relative;font-size:90%;color:#857d69}.wy-menu-vertical a:hover{background-color:#653e0e;cursor:pointer !important;color:#c0b8a1;}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-side-nav-search{z-index:200;background-color:#fefdeb;text-align:center;padding:0.809em;display:block;color:#fcfcfc;margin-bottom:0.809em}.wy-side-nav-search input[type=text]{box-shadow:inset 0 0 0 !important;width:100%;border-radius:3px;padding:6px 12px;border:1px solid #e7e1cf}.wy-side-nav-search img{display:block;margin:-5px auto 0 auto !important;height:27px;width:50px;vertical-align:middle;background-color:transparent;padding:0}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:0.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:0.85em}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:absolute;top:0;left:0;width:300px;overflow:hidden;min-height:100%;background:#c0b8a0;z-index:200}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:0.4045em 0.809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:100%;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:0}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}nav.stickynav{position:fixed;top:0;bottom:0;overflow-x:hidden;overflow-y:hidden}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}.rst-content img{max-width:100%;height:auto !important}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content blockquote{margin-left:0;;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#9c8a71}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after{visibility:visible;content:"";font-family:FontAwesome;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list td>strong{display:inline-block;margin-top:3px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt{color:#000;display:inline-block}.rst-content tt big,.rst-content tt em{font-size:100% !important;line-height:normal}.rst-content tt .xref,a .rst-content tt{font-weight:bold}.rst-content a tt{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:gray}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:400;src:local("Inconsolata"),url(../fonts/Inconsolata.ttf) format("truetype")}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:700;src:local("Inconsolata Bold"),local("Inconsolata-Bold"),url(../fonts/Inconsolata-Bold.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:400;src:local("Lato Regular"),local("Lato-Regular"),url(../fonts/Lato-Regular.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:700;src:local("Lato Bold"),local("Lato-Bold"),url(../fonts/Lato-Bold.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:local("Roboto Slab Regular"),local("RobotoSlab-Regular"),url(../fonts/RobotoSlab-Regular.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:local("Roboto Slab Bold"),local("RobotoSlab-Bold"),url(../fonts/RobotoSlab-Bold.ttf) format("truetype")}
+.mb{margin-bottom:20px;}
+.shrink{font-family: 'Days One', sans-serif;font-size:2em !important;color:#663e05 !important;vertical-align:bottom;}
+.shrink:hover{text-decoration:none;}
+.text-center{text-align:center}
+.biglink{font-size:1.05em;margin:10px auto 10px auto;}
+.linkdescr{font-size:.9em;color:#c0b8a0}
+.zoo-title{
+width:90px;
+height:90px;
+border-radius:50%;
+display:inline-block;	    
+background:#FFFFFF;
+box-shadow: 0 1px 2px rgba(141,128,87,0.6);
+margin:20px 0 0 0;
+color:#c0b8a0;
+line-height:90px;}
+.zoo-title i{padding:20px;}
+.circ{border-radius:50%;}
+.circb{border-radius:50%;border:1px solid #c0b8a0;}
+.img-circle{border-radius:50%;border:1px solid #a19678;box-shadow:0 1px 2px rgba(254,253,235,0.6)}
+ul.simple li{margin-bottom:10px;}
+.pfoot,.pfoot p{font-size:13px !important;}
+p.rubric{color:#c0b8a0;}
+span.zoo{display:block !important;margin-top:5px;color:orange;}
+.ctnr{width:33%;}
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/theme.css.map
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/theme.css.map	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/css/theme.css.map	(revision 942)
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "CACE,AAAE,ECQI,iBAAoB,EDPJ,SAAU,ECY1B,cAAiB,EDZD,SAAU,EC2B1B,SAAY,ED3BI,SAAU,EEFlC,uEAAiF,EAC/E,MAAO,EAAE,IAAK,EAEhB,iBAAoB,EAClB,MAAO,EAAE,WAAY,EACrB,OAAQ,EAAE,KAAM,EAChB,IAAK,EAAE,AAAC,EAEV,oBAAqB,EACnB,MAAO,EAAE,GAAI,EAEf,OAAQ,EACN,MAAO,EAAE,GAAI,EAEf,AAAC,EDLO,iBAAoB,ECMd,SAAU,EDDhB,cAAiB,ECCX,SAAU,EDchB,SAAY,ECdN,SAAU,EAExB,GAAI,EACF,QAAS,EAAE,GAAI,EACf,uBAAwB,EAAE,GAAI,EAC9B,mBAAoB,EAAE,GAAI,EAE5B,GAAI,EACF,KAAM,EAAE,AAAC,EAEX,eAAiB,EACf,MAAO,EAAE,AAAC,EAEZ,UAAW,EACT,YAAa,EAAE,SAAU,EAE3B,OAAS,EACP,UAAW,EAAE,GAAI,EAEnB,SAAU,EACR,KAAM,EAAE,AAAC,EAEX,EAAG,EACD,SAAU,EAAE,KAAM,EAGpB,EAAG,EACD,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAI,EACX,cAAe,EAAE,GAAI,EAEvB,GAAI,EACF,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAI,EACX,SAAU,EAAE,KAAM,EAClB,UAAW,EAAE,GAAI,EAEnB,gCAAoB,EAClB,UAAW,EAAE,cAAS,EACtB,WAAY,EAAE,sBAAa,EAC3B,QAAS,EAAE,EAAG,EAEhB,EAAG,EACD,UAAW,EAAE,EAAG,EAElB,AAAC,EACC,KAAM,EAAE,GAAI,EAEd,eAAiB,EACf,MAAO,EAAE,CAAE,EACX,MAAO,EAAE,GAAI,EAEf,IAAK,EACH,QAAS,EAAE,EAAG,EAEhB,MAAQ,EACN,QAAS,EAAE,EAAG,EACd,UAAW,EAAE,AAAC,EACd,OAAQ,EAAE,OAAQ,EAClB,aAAc,EAAE,OAAQ,EAE1B,EAAG,EACD,EAAG,EAAE,KAAM,EAEb,EAAG,EACD,KAAM,EAAE,MAAO,EAEjB,OAAU,EACR,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EACV,SAAU,EAAE,GAAI,EAChB,eAAgB,EAAE,GAAI,EAExB,CAAE,EACA,SAAU,EAAE,GAAI,EAElB,CAAE,EACA,KAAM,EAAE,AAAC,EAEX,EAAG,EACD,KAAM,EAAE,AAAC,EACT,qBAAsB,EAAE,MAAO,EAC/B,aAAc,EAAE,KAAM,EACtB,QAAS,EAAE,GAAI,EAEjB,aAAc,EACZ,OAAQ,EAAE,KAAM,EAElB,KAAM,EACJ,KAAM,EAAE,AAAC,EAEX,GAAI,EACF,KAAM,EAAE,AAAC,EAEX,OAAQ,EACN,KAAM,EAAE,AAAC,EACT,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EAEZ,IAAK,EACH,KAAM,EAAE,MAAO,EAEjB,KAAM,EACJ,KAAM,EAAE,AAAC,EACT,WAAY,EAAE,GAAI,EAClB,MAAO,EAAE,AAAC,EACV,UAAW,EAAE,KAAM,EAErB,2BAA+B,EAC7B,QAAS,EAAE,GAAI,EACf,KAAM,EAAE,AAAC,EACT,aAAc,EAAE,OAAQ,EACxB,cAAe,EAAE,KAAM,EAEzB,WAAa,EACX,UAAW,EAAE,KAAM,EAErB,mEAAuE,EACrE,KAAM,EAAE,MAAO,EACf,iBAAkB,EAAE,KAAM,EAC1B,QAAS,EAAE,MAAO,EAEpB,+BAAiC,EAC/B,KAAM,EAAE,MAAO,EAEjB,yCAA2C,EACzC,SAAU,EAAE,SAAU,EACtB,MAAO,EAAE,AAAC,EACV,KAAM,EAAE,GAAI,EACZ,MAAO,EAAE,GAAI,EAEf,mBAAoB,EAClB,iBAAkB,EAAE,QAAS,EAC7B,cAAe,EAAE,UAAW,EAC5B,iBAAkB,EAAE,UAAW,EAC/B,SAAU,EAAE,UAAW,EAEzB,iGAAmG,EACjG,iBAAkB,EAAE,GAAI,EAE1B,+CAAiD,EAC/C,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EAEZ,OAAQ,EACN,OAAQ,EAAE,GAAI,EACd,aAAc,EAAE,EAAG,EACnB,KAAM,EAAE,OAAQ,EAElB,IAAK,EACH,cAAe,EAAE,OAAQ,EACzB,aAAc,EAAE,AAAC,EAEnB,CAAE,EACA,aAAc,EAAE,EAAG,EAErB,WAAY,EACV,KAAM,EAAE,MAAO,EACf,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAK,EACZ,MAAO,EAAE,MAAO,EAElB,EAAG,EACD,MAAO,EAAE,IAAK,EACd,KAAM,EAAE,AAAC,EACT,UAAW,EAAE,KAAM,EACnB,OAAQ,EAAE,KAAM,EAChB,eAAgB,EAAE,UAAW,EAC7B,gBAAiB,EAAE,QAAS,EAC5B,SAAU,EAAE,GAAI,EAChB,QAAS,EAAE,EAAG,EACd,WAAY,EAAE,AAAC,EAEjB,KAAM,EACJ,MAAO,EAAE,GAAI,EAEf,MAAO,EACL,MAAO,EAAE,cAAe,EACxB,SAAU,EAAE,KAAM,EAEpB,cAAe,EACb,KAAM,EAAE,AAAC,EACT,GAAI,EAAE,YAAa,EACnB,KAAM,EAAE,EAAG,EACX,KAAM,EAAE,GAAI,EACZ,OAAQ,EAAE,KAAM,EAChB,MAAO,EAAE,AAAC,EACV,OAAQ,EAAE,OAAQ,EAClB,IAAK,EAAE,EAAG,EAEZ,+DAAiE,EAC/D,GAAI,EAAE,GAAI,EACV,KAAM,EAAE,GAAI,EACZ,KAAM,EAAE,AAAC,EACT,OAAQ,EAAE,MAAO,EACjB,OAAQ,EAAE,KAAM,EAChB,IAAK,EAAE,GAAI,EAEb,SAAU,EACR,SAAU,EAAE,KAAM,EAEpB,QAAS,EACP,OAAQ,EAAE,OAAQ,EAEpB,QAAU,EACR,QAAS,EAAE,GAAI,EAEjB,WAAY,EACV,gBAAmB,EACjB,SAAU,EAAE,cAAe,EAC7B,AAAC,EACC,SAAU,EAAE,cAAe,EAC3B,UAAW,EAAE,cAAe,EAC5B,KAAM,EAAE,cAAe,EACvB,SAAU,EAAE,cAAe,EAC7B,UAAY,EACV,cAAe,EAAE,QAAS,EAC5B,0DAA6D,EAC3D,MAAO,EAAE,CAAE,EACb,aAAe,EACb,gBAAiB,EAAE,IAAK,EAC1B,IAAK,EACH,MAAO,EAAE,iBAAkB,EAC7B,KAAO,EACL,gBAAiB,EAAE,IAAK,EAC1B,EAAG,EACD,QAAS,EAAE,cAAe,QAE1B,KAAM,EAAE,IAAK,EAEf,MAAS,EACP,MAAO,EAAE,AAAC,EACV,KAAM,EAAE,AAAC,EACX,IAAM,EACJ,eAAgB,EAAE,IAAK,GChM3B,g4CAAY,EACV,qBAAsB,EAAE,UAAW,EAqDrC,QAAS,EARP,IAAK,EAAE,AAAC,EACR,+BAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,cAAO,EACL,IAAK,EAAE,GAAI;;;GC1Gf,UAUC,CATC,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,+CAAgE,CACrE,GAAG,CAAE,sSAAmG,CAKxG,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CCTpB,qUAAmB,CACjB,OAAO,CAAE,YAAY,CACrB,IAAI,CAAE,uCAAuC,CAC7C,SAAS,CAAE,OAAO,CAClB,cAAc,CAAE,IAAI,CACpB,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CCLpC,MAAsB,CACpB,SAAS,CAAE,SAAS,CACpB,WAAW,CAAE,MAAS,CACtB,cAAc,CAAE,IAAI,CAEtB,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CCVtC,MAAsB,CACpB,KAAK,CAAE,SAAW,CAClB,UAAU,CAAE,MAAM,CCDpB,MAAsB,CACpB,YAAY,CAAE,CAAC,CACf,WAAW,CCIU,SAAS,CDH9B,eAAe,CAAE,IAAI,CACrB,SAAK,CAAE,QAAQ,CAAE,QAAQ,CAE3B,MAAsB,CACpB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,UAAa,CACnB,KAAK,CCHgB,SAAS,CDI9B,GAAG,CAAE,SAAU,CACf,UAAU,CAAE,MAAM,CAClB,YAAuB,CACrB,IAAI,CAAE,UAA0B,CEbpC,UAA0B,CACxB,OAAO,CAAE,gBAAgB,CACzB,MAAM,CAAE,iBAA4B,CACpC,aAAa,CAAE,IAAI,CAGrB,WAAY,CAAE,KAAK,CAAE,KAAK,CAC1B,UAAW,CAAE,KAAK,CAAE,IAAI,CAGtB,6bAAY,CAAE,YAAY,CAAE,IAAI,CAChC,ycAAa,CAAE,WAAW,CAAE,IAAI,CCXlC,QAAwB,CACtB,iBAAiB,CAAE,0BAA0B,CACrC,SAAS,CAAE,0BAA0B,CAG/C,0BASC,CARC,EAAG,CACD,iBAAiB,CAAE,YAAY,CACvB,SAAS,CAAE,YAAY,CAEjC,IAAK,CACH,iBAAiB,CAAE,cAAc,CACzB,SAAS,CAAE,cAAc,EAIrC,kBASC,CARC,EAAG,CACD,iBAAiB,CAAE,YAAY,CACvB,SAAS,CAAE,YAAY,CAEjC,IAAK,CACH,iBAAiB,CAAE,cAAc,CACzB,SAAS,CAAE,cAAc,ECvBrC,aAA8B,CCU5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,aAAgB,CAC/B,aAAa,CAAE,aAAgB,CAC3B,SAAS,CAAE,aAAgB,CDZrC,cAA8B,CCS5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,cAAgB,CAC/B,aAAa,CAAE,cAAgB,CAC3B,SAAS,CAAE,cAAgB,CDXrC,cAA8B,CCQ5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,cAAgB,CAC/B,aAAa,CAAE,cAAgB,CAC3B,SAAS,CAAE,cAAgB,CDTrC,mBAAmC,CCajC,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,YAAoB,CACnC,aAAa,CAAE,YAAoB,CAC/B,SAAS,CAAE,YAAoB,CDfzC,iBAAmC,CCYjC,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,YAAoB,CACnC,aAAa,CAAE,YAAoB,CAC/B,SAAS,CAAE,YAAoB,CDVzC,+GAIuC,CACrC,MAAM,CAAE,IAAI,CEfd,SAAyB,CACvB,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,YAAY,CACrB,KAAK,CAAE,GAAG,CACV,MAAM,CAAE,GAAG,CACX,WAAW,CAAE,GAAG,CAChB,cAAc,CAAE,MAAM,CAExB,yBAAyD,CACvD,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,MAAM,CAEpB,YAA4B,CAAE,WAAW,CAAE,OAAO,CAClD,YAA4B,CAAE,SAAS,CAAE,GAAG,CAC5C,WAA2B,CAAE,KAAK,CLXZ,IAAI,CML1B,gBAAgC,CAAE,OAAO,CNwP1B,GAAO,CMvPtB,gBAAgC,CAAE,OAAO,CNkV1B,GAAO,CMjVtB,qCAAiC,CAAE,OAAO,CNyZ1B,GAAO,CMxZvB,qBAAqC,CAAE,OAAO,CN2K1B,GAAO,CM1K3B,gBAAgC,CAAE,OAAO,CNqQ1B,GAAO,CMpQtB,eAA+B,CAAE,OAAO,CNkc1B,GAAO,CMjcrB,iBAAiC,CAAE,OAAO,CNsc1B,GAAO,CMrcvB,eAA+B,CAAE,OAAO,CN0gB1B,GAAO,CMzgBrB,eAA+B,CAAE,OAAO,CN+M1B,GAAO,CM9MrB,mBAAmC,CAAE,OAAO,CN8d1B,GAAO,CM7dzB,aAA6B,CAAE,OAAO,CN4d1B,GAAO,CM3dnB,kBAAkC,CAAE,OAAO,CN6d1B,GAAO,CM5dxB,gBAAgC,CAAE,OAAO,CN+F1B,GAAO,CM9FtB,mDAEgC,CAAE,OAAO,CNge1B,GAAO,CM/dtB,sBAAsC,CAAE,OAAO,CN6Y1B,GAAO,CM5Y5B,uBAAuC,CAAE,OAAO,CN2Y1B,GAAO,CM1Y7B,oBAAoC,CAAE,OAAO,CNqW1B,GAAO,CMpW1B,iBAAiC,CAAE,OAAO,CNwZ1B,GAAO,CMvZvB,8BAC8B,CAAE,OAAO,CNmH1B,GAAO,CMlHpB,kBAAkC,CAAE,OAAO,CNoe1B,GAAO,CMnexB,iCAA+B,CAAE,OAAO,CNqP1B,GAAO,CMpPrB,iBAAiC,CAAE,OAAO,CNmL1B,GAAO,CMlLvB,kBAAkC,CAAE,OAAO,CNqG1B,GAAO,CMpGxB,eAA+B,CAAE,OAAO,CNqX1B,GAAO,CMpXrB,uHAAmC,CAAE,OAAO,CNyI1B,GAAO,CMxIzB,8BAA8C,CAAE,OAAO,CNG1B,GAAO,CMFpC,4BAA4C,CAAE,OAAO,CNK1B,GAAO,CMJlC,gBAAgC,CAAE,OAAO,CNmP1B,GAAO,CMlPtB,wBAAwC,CAAE,OAAO,CNkV1B,GAAO,CMjV9B,yCACiC,CAAE,OAAO,CNyW1B,GAAO,CMxWvB,kBAAkC,CAAE,OAAO,CNoW1B,GAAO,CMnWxB,mBAAmC,CAAE,OAAO,CNiR1B,GAAO,CMhRzB,eAA+B,CAAE,OAAO,CNoR1B,GAAO,CMnRrB,eAA+B,CAAE,OAAO,CNsL1B,GAAO,CMrLrB,qBAAqC,CAAE,OAAO,CNkO1B,GAAO,CMjO3B,qBAAqC,CAAE,OAAO,CNkf1B,GAAO,CMjf3B,sBAAsC,CAAE,OAAO,CNgf1B,GAAO,CM/e5B,oBAAoC,CAAE,OAAO,CNif1B,GAAO,CMhf1B,iBAAiC,CAAE,OAAO,CNiV1B,GAAO,CMhVvB,kBAAkC,CAAE,OAAO,CNU1B,GAAO,CMTxB,cAA8B,CAAE,OAAO,CNkb1B,GAAO,CMjbpB,eAA+B,CAAE,OAAO,CNkb1B,GAAO,CMjbrB,iCAA+B,CAAE,OAAO,CNyB1B,GAAO,CMxBrB,mBAAmC,CAAE,OAAO,CNyB1B,GAAO,CMxBzB,gBAAgC,CAAE,OAAO,CNwU1B,GAAO,CMvUtB,iBAAiC,CAAE,OAAO,CNqC1B,GAAO,CMpCvB,eAA+B,CAAE,OAAO,CNoL1B,GAAO,CMnLrB,eAA+B,CAAE,OAAO,CNiB1B,GAAO,CMhBrB,iBAAiC,CAAE,OAAO,CNqO1B,GAAO,CMpOvB,sBAAsC,CAAE,OAAO,CN+a1B,GAAO,CM9a5B,qBAAqC,CAAE,OAAO,CN+a1B,GAAO,CM9a3B,qBAAqC,CAAE,OAAO,CN3C1B,GAAO,CM4C3B,uBAAuC,CAAE,OAAO,CN9C1B,GAAO,CM+C7B,sBAAsC,CAAE,OAAO,CN5C1B,GAAO,CM6C5B,wBAAwC,CAAE,OAAO,CN/C1B,GAAO,CMgD9B,eAA+B,CAAE,OAAO,CNwP1B,GAAO,CMvPrB,oCACkC,CAAE,OAAO,CN0R1B,GAAO,CMzRxB,iBAAiC,CAAE,OAAO,CNoN1B,GAAO,CMnNvB,uBAAuC,CAAE,OAAO,CNqd1B,GAAO,CMpd7B,sDAEoC,CAAE,OAAO,CNsS1B,GAAO,CMrS1B,iBAAiC,CAAE,OAAO,CN+R1B,GAAO,CM9RvB,qBAAqC,CAAE,OAAO,CN+P1B,GAAO,CM9P3B,iBAAiC,CAAE,OAAO,CN7D1B,GAAO,CM8DvB,eAA+B,CAAE,OAAO,CN4a1B,GAAO,CM3arB,0CAC0C,CAAE,OAAO,CN4R1B,GAAO,CM3RhC,yBAAyC,CAAE,OAAO,CN2V1B,GAAO,CM1V/B,yBAAyC,CAAE,OAAO,CNqC1B,GAAO,CMpC/B,iBAAiC,CAAE,OAAO,CNlC1B,GAAO,CMmCvB,wBAAwC,CAAE,OAAO,CNmY1B,GAAO,CMlY9B,wBAAwC,CAAE,OAAO,CNkH1B,GAAO,CMjH9B,mBAAmC,CAAE,OAAO,CN9B1B,GAAO,CM+BzB,eAA+B,CAAE,OAAO,CNgS1B,GAAO,CM/RrB,gBAAgC,CAAE,OAAO,CN+Q1B,GAAO,CM9QtB,eAA+B,CAAE,OAAO,CNiY1B,GAAO,CMhYrB,kBAAkC,CAAE,OAAO,CNqJ1B,GAAO,CMpJxB,uBAAuC,CAAE,OAAO,CN6G1B,GAAO,CM5G7B,uBAAuC,CAAE,OAAO,CN4X1B,GAAO,CM3X7B,gBAAgC,CAAE,OAAO,CNoF1B,GAAO,CMnFtB,uBAAuC,CAAE,OAAO,CN+B1B,GAAO,CM9B7B,wBAAwC,CAAE,OAAO,CN+B1B,GAAO,CM9B9B,sBAAsC,CAAE,OAAO,CN4R1B,GAAO,CM3R5B,uBAAuC,CAAE,OAAO,CNkP1B,GAAO,CMjP7B,8FAAuC,CAAE,OAAO,CNsZ1B,GAAO,CMrZ7B,+FAAuC,CAAE,OAAO,CNiB1B,GAAO,CMhB7B,0BAA0C,CAAE,OAAO,CNiS1B,GAAO,CMhShC,sBAAsC,CAAE,OAAO,CNuL1B,GAAO,CMtL5B,qBAAqC,CAAE,OAAO,CNuD1B,GAAO,CMtD3B,yBAAyC,CAAE,OAAO,CNkZ1B,GAAO,CMjZ/B,yBAAyC,CAAE,OAAO,CNa1B,GAAO,CMZ/B,cAA8B,CAAE,OAAO,CNhD1B,GAAO,CMiDpB,qBAAqC,CAAE,OAAO,CN5D1B,GAAO,CM6D3B,sBAAsC,CAAE,OAAO,CN5D1B,GAAO,CM6D5B,mBAAmC,CAAE,OAAO,CN5D1B,GAAO,CM6DzB,qBAAqC,CAAE,OAAO,CNhE1B,GAAO,CMiE3B,wCACgC,CAAE,OAAO,CNyT1B,GAAO,CMxTtB,iBAAiC,CAAE,OAAO,CN+E1B,GAAO,CM9EvB,mBAAmC,CAAE,OAAO,CNuC1B,GAAO,CMtCzB,eAA+B,CAAE,OAAO,CNyQ1B,GAAO,CMxQrB,gBAAgC,CAAE,OAAO,CN+N1B,GAAO,CM9NtB,mBAAmC,CAAE,OAAO,CN/D1B,GAAO,CMgEzB,gNAA6C,CAAE,OAAO,CNwE1B,GAAO,CMvEnC,eAA+B,CAAE,OAAO,CNmI1B,GAAO,CMlIrB,eAA+B,CAAE,OAAO,CNqL1B,GAAO,CMpLrB,iCAA+B,CAAE,OAAO,CNyG1B,GAAO,CMxGrB,cAA8B,CAAE,OAAO,CNyE1B,GAAO,CMxEpB,oBAAoC,CAAE,OAAO,CNyE1B,GAAO,CMxE1B,kDAC+C,CAAE,OAAO,CNkE1B,GAAO,CMjErC,gBAAgC,CAAE,OAAO,CNyP1B,GAAO,CMxPtB,mBAAmC,CAAE,OAAO,CNlC1B,GAAO,CMmCzB,iBAAiC,CAAE,OAAO,CN0Q1B,GAAO,CMzQvB,kBAAkC,CAAE,OAAO,CNmB1B,GAAO,CMlBxB,iBAAiC,CAAE,OAAO,CNqM1B,GAAO,CMpMvB,qBAAqC,CAAE,OAAO,CNH1B,GAAO,CMI3B,uBAAuC,CAAE,OAAO,CNP1B,GAAO,CMQ7B,kBAAkC,CAAE,OAAO,CNiR1B,GAAO,CMhRxB,wBAAwC,CAAE,OAAO,CN2S1B,GAAO,CM1S9B,iBAAiC,CAAE,OAAO,CNoG1B,GAAO,CMnGvB,sBAAsC,CAAE,OAAO,CNqG1B,GAAO,CMpG5B,mBAAmC,CAAE,OAAO,CNpF1B,GAAO,CMqFzB,mBAAmC,CAAE,OAAO,CNtF1B,GAAO,CMuFzB,2CACoC,CAAE,OAAO,CNhF1B,GAAO,CMiF1B,yBAAyC,CAAE,OAAO,CNkY1B,GAAO,CMjY/B,0BAA0C,CAAE,OAAO,CNyD1B,GAAO,CMxDhC,uBAAuC,CAAE,OAAO,CN/C1B,GAAO,CMgD7B,cAA8B,CAAE,OAAO,CNsJ1B,GAAO,CMrJpB,gCAC+B,CAAE,OAAO,CNA1B,GAAO,CMCrB,mBAAmC,CAAE,OAAO,CNG1B,GAAO,CMFzB,sBAAsC,CAAE,OAAO,CNiW1B,GAAO,CMhW5B,wBAAwC,CAAE,OAAO,CN+V1B,GAAO,CM9V9B,oBAAoC,CAAE,OAAO,CN2T1B,GAAO,CM1T1B,kBAAkC,CAAE,OAAO,CN4H1B,GAAO,CM3HxB,mBAAmC,CAAE,OAAO,CN2R1B,GAAO,CM1RzB,0BAA0C,CAAE,OAAO,CNiK1B,GAAO,CMhKhC,qBAAqC,CAAE,OAAO,CNwV1B,GAAO,CMvV3B,wBAAwC,CAAE,OAAO,CNsC1B,GAAO,CMrC9B,kBAAkC,CAAE,OAAO,CNsR1B,GAAO,CMrRxB,iBAAiC,CAAE,OAAO,CNyW1B,GAAO,CMxWvB,wBAAwC,CAAE,OAAO,CNiG1B,GAAO,CMhG9B,iBAAiC,CAAE,OAAO,CNyX1B,GAAO,CMxXvB,kBAAkC,CAAE,OAAO,CN+I1B,GAAO,CM9IxB,gBAAgC,CAAE,OAAO,CN6M1B,GAAO,CM5MtB,mBAAmC,CAAE,OAAO,CN2S1B,GAAO,CM1SzB,qBAAqC,CAAE,OAAO,CNjF1B,GAAO,CMkF3B,uBAAuC,CAAE,OAAO,CN2M1B,GAAO,CM1M7B,kBAAkC,CAAE,OAAO,CNyW1B,GAAO,CMxWxB,mBAAmC,CAAE,OAAO,CNgC1B,GAAO,CM/BzB,qCAAiC,CAAE,OAAO,CNsF1B,GAAO,CMrFvB,iBAAiC,CAAE,OAAO,CN6W1B,GAAO,CM5WvB,sBAAsC,CAAE,OAAO,CNb1B,GAAO,CMc5B,cAA8B,CAAE,OAAO,CNmP1B,GAAO,CMlPpB,gBAAgC,CAAE,OAAO,CNoG1B,GAAO,CMnGtB,mBAAmC,CAAE,OAAO,CNpF1B,GAAO,CMqFzB,eAA+B,CAAE,OAAO,CN1G1B,GAAO,CM2GrB,sBAAsC,CAAE,OAAO,CN7D1B,GAAO,CM8D5B,uBAAuC,CAAE,OAAO,CN8F1B,GAAO,CM7F7B,sBAAsC,CAAE,OAAO,CN4F1B,GAAO,CM3F5B,oBAAoC,CAAE,OAAO,CN6F1B,GAAO,CM5F1B,sBAAsC,CAAE,OAAO,CNyF1B,GAAO,CMxF5B,2DAA4C,CAAE,OAAO,CN5I1B,GAAO,CM6IlC,6DAA6C,CAAE,OAAO,CNxI1B,GAAO,CMyInC,0BAA0C,CAAE,OAAO,CNxI1B,GAAO,CMyIhC,4BAA4C,CAAE,OAAO,CNhJ1B,GAAO,CMiJlC,gBAAgC,CAAE,OAAO,CN2E1B,GAAO,CM1EtB,iBAAiC,CAAE,OAAO,CNqX1B,GAAO,CMpXvB,gBAAgC,CAAE,OAAO,CNgT1B,GAAO,CM/StB,iBAAiC,CAAE,OAAO,CNuC1B,GAAO,CMtCvB,oBAAoC,CAAE,OAAO,CNxG1B,GAAO,CMyG1B,qBAAqC,CAAE,OAAO,CNzI1B,GAAO,CM0I3B,iCACgC,CAAE,OAAO,CN8V1B,GAAO,CM7VtB,kDAC+B,CAAE,OAAO,CNwH1B,GAAO,CMvHrB,gBAAgC,CAAE,OAAO,CNxD1B,GAAO,CMyDtB,gBAAgC,CAAE,OAAO,CNsC1B,GAAO,CMrCtB,kCACmC,CAAE,OAAO,CN+N1B,GAAO,CM9NzB,kCACkC,CAAE,OAAO,CNyB1B,GAAO,CMxBxB,oBAAoC,CAAE,OAAO,CN8J1B,GAAO,CM7J1B,mCACmC,CAAE,OAAO,CNiC1B,GAAO,CMhCzB,iBAAiC,CAAE,OAAO,CNkQ1B,GAAO,CMjQvB,qDAE+B,CAAE,OAAO,CN9I1B,GAAO,CM+IrB,kBAAkC,CAAE,OAAO,CNiH1B,GAAO,CMhHxB,kBAAkC,CAAE,OAAO,CN+G1B,GAAO,CM9GxB,wBAAwC,CAAE,OAAO,CN4Q1B,GAAO,CM3Q9B,oBAAoC,CAAE,OAAO,CNgU1B,GAAO,CM/T1B,gBAAgC,CAAE,OAAO,CNkR1B,GAAO,CMjRtB,gBAAgC,CAAE,OAAO,CNmH1B,GAAO,CMlHtB,gBAAgC,CAAE,OAAO,CNmT1B,GAAO,CMlTtB,oBAAoC,CAAE,OAAO,CNgK1B,GAAO,CM/J1B,2BAA2C,CAAE,OAAO,CNgK1B,GAAO,CM/JjC,6BAA6C,CAAE,OAAO,CN8C1B,GAAO,CM7CnC,sBAAsC,CAAE,OAAO,CN4C1B,GAAO,CM3C5B,gBAAgC,CAAE,OAAO,CNgI1B,GAAO,CM/HtB,wEAAqC,CAAE,OAAO,CNxH1B,GAAO,CMyH3B,mBAAmC,CAAE,OAAO,CNlH1B,GAAO,CMmHzB,qBAAqC,CAAE,OAAO,CNzH1B,GAAO,CM0H3B,sBAAsC,CAAE,OAAO,CNzH1B,GAAO,CM0H5B,kBAAkC,CAAE,OAAO,CN3E1B,GAAO,CM4ExB,mCAC+B,CAAE,OAAO,CN4N1B,GAAO,CM3NrB,yCACoC,CAAE,OAAO,CNgO1B,GAAO,CM/N1B,sCACmC,CAAE,OAAO,CN6N1B,GAAO,CM5NzB,mBAAmC,CAAE,OAAO,CN/C1B,GAAO,CMgDzB,mBAAmC,CAAE,OAAO,CNmF1B,GAAO,CMlFzB,sCAC+B,CAAE,OAAO,CN0S1B,GAAO,CMzSrB,iCACgC,CAAE,OAAO,CNW1B,GAAO,CMVtB,0CACqC,CAAE,OAAO,CN0P1B,GAAO,CMzP3B,oBAAoC,CAAE,OAAO,CNxF1B,GAAO,CMyF1B,qBAAqC,CAAE,OAAO,CNvF1B,GAAO,CMwF3B,gCAC+B,CAAE,OAAO,CNlK1B,GAAO,CMmKrB,kBAAkC,CAAE,OAAO,CNoM1B,GAAO,CMnMxB,mBAAmC,CAAE,OAAO,CN8R1B,GAAO,CM7RzB,qCACoC,CAAE,OAAO,CN9G1B,GAAO,CM+G1B,sBAAsC,CAAE,OAAO,CNiE1B,GAAO,CMhE5B,mBAAmC,CAAE,OAAO,CN1D1B,GAAO,CM2DzB,yBAAyC,CAAE,OAAO,CN7G1B,GAAO,CM8G/B,uBAAuC,CAAE,OAAO,CN7G1B,GAAO,CM8G7B,kBAAkC,CAAE,OAAO,CNkS1B,GAAO,CMjSxB,sBAAsC,CAAE,OAAO,CNgO1B,GAAO,CM/N5B,mBAAmC,CAAE,OAAO,CNqO1B,GAAO,CMpOzB,iBAAiC,CAAE,OAAO,CNxL1B,GAAO,CMyLvB,iBAAiC,CAAE,OAAO,CN7G1B,GAAO,CM8GvB,kBAAkC,CAAE,OAAO,CN3F1B,GAAO,CM4FxB,sBAAsC,CAAE,OAAO,CNpC1B,GAAO,CMqC5B,qBAAqC,CAAE,OAAO,CNzK1B,GAAO,CM0K3B,qBAAqC,CAAE,OAAO,CNqB1B,GAAO,CMpB3B,oBAAoC,CAAE,OAAO,CN3O1B,GAAO,CM4O1B,iBAAiC,CAAE,OAAO,CN4E1B,GAAO,CM3EvB,sBAAsC,CAAE,OAAO,CNxD1B,GAAO,CMyD5B,eAA+B,CAAE,OAAO,CNrM1B,GAAO,CMsMrB,mBAAmC,CAAE,OAAO,CNG1B,GAAO,CMFzB,sBAAsC,CAAE,OAAO,CNuH1B,GAAO,CMtH5B,4BAA4C,CAAE,OAAO,CN5O1B,GAAO,CM6OlC,6BAA6C,CAAE,OAAO,CN5O1B,GAAO,CM6OnC,0BAA0C,CAAE,OAAO,CN5O1B,GAAO,CM6OhC,4BAA4C,CAAE,OAAO,CNhP1B,GAAO,CMiPlC,qBAAqC,CAAE,OAAO,CN5O1B,GAAO,CM6O3B,sBAAsC,CAAE,OAAO,CN5O1B,GAAO,CM6O5B,mBAAmC,CAAE,OAAO,CN5O1B,GAAO,CM6OzB,qBAAqC,CAAE,OAAO,CNhP1B,GAAO,CMiP3B,kBAAkC,CAAE,OAAO,CNxG1B,GAAO,CMyGxB,iBAAiC,CAAE,OAAO,CNyB1B,GAAO,CMxBvB,iBAAiC,CAAE,OAAO,CNmN1B,GAAO,CMlNvB,yCACiC,CAAE,OAAO,CNmE1B,GAAO,CMlEvB,mBAAmC,CAAE,OAAO,CNlJ1B,GAAO,CMmJzB,qBAAqC,CAAE,OAAO,CNiH1B,GAAO,CMhH3B,sBAAsC,CAAE,OAAO,CNiH1B,GAAO,CMhH5B,kBAAkC,CAAE,OAAO,CNiL1B,GAAO,CMhLxB,iBAAiC,CAAE,OAAO,CNvJ1B,GAAO,CMwJvB,sCACgC,CAAE,OAAO,CNyH1B,GAAO,CMxHtB,qBAAqC,CAAE,OAAO,CN9B1B,GAAO,CM+B3B,mBAAmC,CAAE,OAAO,CNjD1B,GAAO,CMkDzB,wBAAwC,CAAE,OAAO,CNhD1B,GAAO,CMiD9B,kBAAkC,CAAE,OAAO,CN2J1B,GAAO,CM1JxB,kBAAkC,CAAE,OAAO,CN9C1B,GAAO,CM+CxB,gBAAgC,CAAE,OAAO,CN+C1B,GAAO,CM9CtB,kBAAkC,CAAE,OAAO,CN9C1B,GAAO,CM+CxB,qBAAqC,CAAE,OAAO,CNI1B,GAAO,CMH3B,iBAAiC,CAAE,OAAO,CN9D1B,GAAO,CM+DvB,yBAAyC,CAAE,OAAO,CNhE1B,GAAO,CMiE/B,mBAAmC,CAAE,OAAO,CNsM1B,GAAO,CMrMzB,eAA+B,CAAE,OAAO,CN1J1B,GAAO,CM2JrB,8CACoC,CAAE,OAAO,CN4G1B,GAAO,CM3G1B,2EAEsC,CAAE,OAAO,CNwK1B,GAAO,CMvK5B,yBAAyC,CAAE,OAAO,CNmB1B,GAAO,CMlB/B,eAA+B,CAAE,OAAO,CNjJ1B,GAAO,CMkJrB,oBAAoC,CAAE,OAAO,CNjK1B,GAAO,CMkK1B,yCACuC,CAAE,OAAO,CN9L1B,GAAO,CM+L7B,mBAAmC,CAAE,OAAO,CNmF1B,GAAO,CMlFzB,eAA+B,CAAE,OAAO,CNvB1B,GAAO,CMwBrB,sBAAsC,CAAE,OAAO,CNvH1B,GAAO,CMwH5B,sBAAsC,CAAE,OAAO,CN6K1B,GAAO,CM5K5B,oBAAoC,CAAE,OAAO,CNyK1B,GAAO,CMxK1B,iBAAiC,CAAE,OAAO,CN9H1B,GAAO,CM+HvB,uBAAuC,CAAE,OAAO,CN0E1B,GAAO,CMzE7B,qBAAqC,CAAE,OAAO,CNwB1B,GAAO,CMvB3B,2BAA2C,CAAE,OAAO,CNwB1B,GAAO,CMvBjC,iBAAiC,CAAE,OAAO,CNqH1B,GAAO,CMpHvB,qBAAqC,CAAE,OAAO,CN9N1B,GAAO,CM+N3B,4BAA4C,CAAE,OAAO,CN1F1B,GAAO,CM2FlC,iBAAiC,CAAE,OAAO,CN2F1B,GAAO,CM1FvB,iBAAiC,CAAE,OAAO,CNc1B,GAAO,CMbvB,8BAA8C,CAAE,OAAO,CNtM1B,GAAO,CMuMpC,+BAA+C,CAAE,OAAO,CNtM1B,GAAO,CMuMrC,4BAA4C,CAAE,OAAO,CNtM1B,GAAO,CMuMlC,8BAA8C,CAAE,OAAO,CN1M1B,GAAO,CM2MpC,gBAAgC,CAAE,OAAO,CN7C1B,GAAO,CM8CtB,eAA+B,CAAE,OAAO,CNtK1B,GAAO,CMuKrB,iBAAiC,CAAE,OAAO,CN9S1B,GAAO,CM+SvB,qBAAqC,CAAE,OAAO,CN+M1B,GAAO,CM9M3B,mBAAmC,CAAE,OAAO,CN/O1B,GAAO,CMgPzB,qBAAqC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ3B,qBAAqC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ3B,qBAAqC,CAAE,OAAO,CNmF1B,GAAO,CMlF3B,sBAAsC,CAAE,OAAO,CN6C1B,GAAO,CM5C5B,iBAAiC,CAAE,OAAO,CN0K1B,GAAO,CMzKvB,uBAAuC,CAAE,OAAO,CNO1B,GAAO,CMN7B,yBAAyC,CAAE,OAAO,CNO1B,GAAO,CMN/B,mBAAmC,CAAE,OAAO,CN/B1B,GAAO,CMgCzB,qBAAqC,CAAE,OAAO,CNjC1B,GAAO,CMkC3B,uBAAuC,CAAE,OAAO,CN3N1B,GAAO,CM4N7B,wBAAwC,CAAE,OAAO,CNyB1B,GAAO,CMxB9B,+BAA+C,CAAE,OAAO,CNlJ1B,GAAO,CMmJrC,uBAAuC,CAAE,OAAO,CNuF1B,GAAO,CMtF7B,kBAAkC,CAAE,OAAO,CN9L1B,GAAO,CM+LxB,qDAC8C,CAAE,OAAO,CNnP1B,GAAO,CMoPpC,iDAC4C,CAAE,OAAO,CNlP1B,GAAO,CMmPlC,uDAC+C,CAAE,OAAO,CNrP1B,GAAO,CMsPrC,8BAC8B,CAAE,OAAO,CNpK1B,GAAO,CMqKpB,cAA8B,CAAE,OAAO,CNzG1B,GAAO,CM0GpB,gCAC8B,CAAE,OAAO,CNwL1B,GAAO,CMvLpB,+BAC8B,CAAE,OAAO,CNrE1B,GAAO,CMsEpB,2DAG8B,CAAE,OAAO,CNnE1B,GAAO,CMoEpB,iDAE8B,CAAE,OAAO,CNqD1B,GAAO,CMpDpB,6BAC8B,CAAE,OAAO,CNpE1B,GAAO,CMqEpB,iCAC8B,CAAE,OAAO,CN1R1B,GAAO,CM2RpB,eAA+B,CAAE,OAAO,CNlK1B,GAAO,CMmKrB,oBAAoC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ1B,yBAAyC,CAAE,OAAO,CN4E1B,GAAO,CM3E/B,0BAA0C,CAAE,OAAO,CN4E1B,GAAO,CM3EhC,0BAA0C,CAAE,OAAO,CN4E1B,GAAO,CM3EhC,2BAA2C,CAAE,OAAO,CN4E1B,GAAO,CM3EjC,2BAA2C,CAAE,OAAO,CN+E1B,GAAO,CM9EjC,4BAA4C,CAAE,OAAO,CN+E1B,GAAO,CM9ElC,oBAAoC,CAAE,OAAO,CN+H1B,GAAO,CM9H1B,sBAAsC,CAAE,OAAO,CN2H1B,GAAO,CM1H5B,yBAAyC,CAAE,OAAO,CN4L1B,GAAO,CM3L/B,kBAAkC,CAAE,OAAO,CNyL1B,GAAO,CMxLxB,eAA+B,CAAE,OAAO,CNmL1B,GAAO,CMlLrB,sBAAsC,CAAE,OAAO,CNmL1B,GAAO,CMlL5B,uBAAuC,CAAE,OAAO,CNuL1B,GAAO,CMtL7B,kBAAkC,CAAE,OAAO,CN/M1B,GAAO,CMgNxB,yBAAyC,CAAE,OAAO,CNgF1B,GAAO,CM/E/B,oBAAoC,CAAE,OAAO,CNjG1B,GAAO,CMkG1B,iBAAiC,CAAE,OAAO,CNxJ1B,GAAO,CMyJvB,cAA8B,CAAE,OAAO,CNhX1B,GAAO,CMiXpB,2CAAoC,CAAE,OAAO,CNzT1B,GAAO,CM0T1B,2BAA2C,CAAE,OAAO,CNzT1B,GAAO,CM0TjC,iBAAiC,CAAE,OAAO,CNqI1B,GAAO,CMpIvB,wBAAwC,CAAE,OAAO,CNqI1B,GAAO,CMpI9B,0BAA0C,CAAE,OAAO,CNrE1B,GAAO,CMsEhC,wBAAwC,CAAE,OAAO,CNnE1B,GAAO,CMoE9B,0BAA0C,CAAE,OAAO,CNtE1B,GAAO,CMuEhC,2BAA2C,CAAE,OAAO,CNtE1B,GAAO,CMuEjC,gBAAgC,CAAE,OAAO,CNxW1B,GAAO,CMyWtB,kBAAkC,CAAE,OAAO,CN8J1B,GAAO,CM7JxB,kBAAkC,CAAE,OAAO,CNpX1B,GAAO,CMqXxB,gBAAgC,CAAE,OAAO,CNnF1B,GAAO,CMoFtB,mBAAmC,CAAE,OAAO,CNjO1B,GAAO,CMkOzB,gBAAgC,CAAE,OAAO,CNsC1B,GAAO,CMrCtB,qBAAqC,CAAE,OAAO,CNhK1B,GAAO,CMiK3B,iBAAiC,CAAE,OAAO,CNmH1B,GAAO,CMlHvB,iBAAiC,CAAE,OAAO,CNxM1B,GAAO,CMyMvB,eAA+B,CAAE,OAAO,CNzE1B,GAAO,CM0ErB,iBAAiC,CAAE,OAAO,CNrJ1B,GAAO,CMsJvB,gBAAgC,CAAE,OAAO,CN2E1B,GAAO,CM1EtB,iBAAiC,CAAE,OAAO,CN7D1B,GAAO,CM8DvB,kBAAkC,CAAE,OAAO,CNpX1B,GAAO,CMqXxB,cAA8B,CAAE,OAAO,CNpU1B,GAAO,CMqUpB,aAA6B,CAAE,OAAO,CNsI1B,GAAO,CMrInB,gBAAgC,CAAE,OAAO,CN2I1B,GAAO,CM1ItB,iBAAiC,CAAE,OAAO,CNX1B,GAAO,CMYvB,oBAAoC,CAAE,OAAO,CN5D1B,GAAO,CM6D1B,yBAAyC,CAAE,OAAO,CNgD1B,GAAO,CM/C/B,+BAA+C,CAAE,OAAO,CNrX1B,GAAO,CMsXrC,8BAA8C,CAAE,OAAO,CNvX1B,GAAO,CMwXpC,qDAC8C,CAAE,OAAO,CN5T1B,GAAO,CM6TpC,uBAAuC,CAAE,OAAO,CNvP1B,GAAO,CMwP7B,qBAAqC,CAAE,OAAO,CNoI1B,GAAO,CMnI3B,uBAAuC,CAAE,OAAO,CNyH1B,GAAO,CMxH7B,sCAC8B,CAAE,OAAO,CNiG1B,GAAO,CMhGpB,wBAAwC,CAAE,OAAO,CNzC1B,GAAO,CM0C9B,wBAAwC,CAAE,OAAO,CN+B1B,GAAO,CM9B9B,gBAAgC,CAAE,OAAO,CNa1B,GAAO,CMZtB,0BAA0C,CAAE,OAAO,CNnP1B,GAAO,CMoPhC,oBAAoC,CAAE,OAAO,CNgI1B,GAAO,CM/H1B,iBAAiC,CAAE,OAAO,CN9E1B,GAAO,CM+EvB,4DAEqC,CAAE,OAAO,CNmG1B,GAAO,CMlG3B,iDACyC,CAAE,OAAO,CN3K1B,GAAO,CM4K/B,gBAAgC,CAAE,OAAO,CN6H1B,GAAO,CM5HtB,iBAAiC,CAAE,OAAO,CNjL1B,GAAO,CMkLvB,iBAAiC,CAAE,OAAO,CNxC1B,GAAO,CMyCvB,wBAAwC,CAAE,OAAO,CNxC1B,GAAO,CMyC9B,6BAA6C,CAAE,OAAO,CNuC1B,GAAO,CMtCnC,sBAAsC,CAAE,OAAO,CNqC1B,GAAO,CMpC5B,oBAAoC,CAAE,OAAO,CNlR1B,GAAO,CMmR1B,eAA+B,CAAE,OAAO,CNhR1B,GAAO,CMiRrB,qBAAqC,CAAE,OAAO,CNxE1B,GAAO,CMyE3B,yBAAyC,CAAE,OAAO,CNxE1B,GAAO,CMyE/B,iBAAiC,CAAE,OAAO,CN7Q1B,GAAO,CM8QvB,iBAAiC,CAAE,OAAO,CN3J1B,GAAO,CM4JvB,mBAAmC,CAAE,OAAO,CNtJ1B,GAAO,CMuJzB,cAA8B,CAAE,OAAO,CNtP1B,GAAO,CMuPpB,mBAAmC,CAAE,OAAO,CN3W1B,GAAO,CM4WzB,gBAAgC,CAAE,OAAO,CNjU1B,GAAO,CMkUtB,cAA8B,CAAE,OAAO,CN1F1B,GAAO,CM2FpB,gBAAgC,CAAE,OAAO,CNM1B,GAAO,CMLtB,eAA+B,CAAE,OAAO,CNrS1B,GAAO,CMsSrB,gBAAgC,CAAE,OAAO,CNrS1B,GAAO,CMsStB,kBAAkC,CAAE,OAAO,CNtY1B,GAAO,CMuYxB,yBAAyC,CAAE,OAAO,CNtY1B,GAAO,CMuY/B,gBAAgC,CAAE,OAAO,CNa1B,GAAO,CMZtB,uBAAuC,CAAE,OAAO,CNa1B,GAAO,CMZ7B,kBAAkC,CAAE,OAAO,CN/D1B,GAAO,CMgExB,oCAC8B,CAAE,OAAO,CN5W1B,GAAO,CM6WpB,8BAC+B,CAAE,OAAO,CN2B1B,GAAO,CM1BrB,eAA+B,CAAE,OAAO,CNoD1B,GAAO,CMnDrB,kBAAkC,CAAE,OAAO,CNN1B,GAAO,CMOxB,qBAAqC,CAAE,OAAO,CNzS1B,GAAO,CM0S3B,qBAAqC,CAAE,OAAO,CNZ1B,GAAO,CMa3B,mBAAmC,CAAE,OAAO,CN/S1B,GAAO,CMgTzB,qBAAqC,CAAE,OAAO,CNhQ1B,GAAO,CMiQ3B,sBAAsC,CAAE,OAAO,CNzP1B,GAAO,CM0P5B,uBAAuC,CAAE,OAAO,CNtQ1B,GAAO,CMuQ7B,4BAA4C,CAAE,OAAO,CNhQ1B,GAAO,CMiQlC,yEAEuC,CAAE,OAAO,CNzQ1B,GAAO,CM0Q7B,+CACyC,CAAE,OAAO,CN/Q1B,GAAO,CMgR/B,+CACuC,CAAE,OAAO,CNhR1B,GAAO,CMiR7B,+CACuC,CAAE,OAAO,CNrQ1B,GAAO,CMsQ7B,sBAAsC,CAAE,OAAO,CNlR1B,GAAO,CMmR5B,eAA+B,CAAE,OAAO,CN4D1B,GAAO,CM3DrB,kBAAkC,CAAE,OAAO,CNrV1B,GAAO,CMsVxB,mBAAmC,CAAE,OAAO,CNhM1B,GAAO,CMiMzB,uGAIoC,CAAE,OAAO,CNtL1B,GAAO,CMuL1B,yBAAyC,CAAE,OAAO,CNvW1B,GAAO,CMwW/B,8BACgC,CAAE,OAAO,CNlG1B,GAAO,CMmGtB,+BACiC,CAAE,OAAO,CN1T1B,GAAO,CM2TvB,qBAAqC,CAAE,OAAO,CNpP1B,GAAO,CMqP3B,cAA8B,CAAE,OAAO,CNtP1B,GAAO,CMuPpB,sBAAsC,CAAE,OAAO,CNxO1B,GAAO,CMyO5B,wBAAwC,CAAE,OAAO,CNR1B,GAAO,CMS9B,aAA6B,CAAE,OAAO,CNjH1B,GAAO,CMkHnB,mCACiC,CAAE,OAAO,CNiD1B,GAAO,CMhDvB,sCACsC,CAAE,OAAO,CNrJ1B,GAAO,CMsJ5B,0CACwC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ9B,kBAAkC,CAAE,OAAO,CNvO1B,GAAO,CMwOxB,sBAAsC,CAAE,OAAO,CNvX1B,GAAO,CMwX5B,iBAAiC,CAAE,OAAO,CN7O1B,GAAO,CM8OvB,oBAAoC,CAAE,OAAO,CNxJ1B,GAAO,CMyJ1B,kBAAkC,CAAE,OAAO,CNvE1B,GAAO,CMwExB,oBAAoC,CAAE,OAAO,CNtF1B,GAAO,CMuF1B,2BAA2C,CAAE,OAAO,CNtF1B,GAAO,CMuFjC,eAA+B,CAAE,OAAO,CNnb1B,GAAO,CMobrB,4CACmC,CAAE,OAAO,CNjR1B,GAAO,CMkRzB,cAA8B,CAAE,OAAO,CNI1B,GAAO,CMHpB,qBAAqC,CAAE,OAAO,CN9b1B,GAAO,CM+b3B,eAA+B,CAAE,OAAO,CN5I1B,GAAO,CM6IrB,qBAAqC,CAAE,OAAO,CN/E1B,GAAO,CMgF3B,iBAAiC,CAAE,OAAO,CNI1B,GAAO,CMHvB,eAA+B,CAAE,OAAO,CNuC1B,GAAO,CMtCrB,sBAAsC,CAAE,OAAO,CN7K1B,GAAO,CM8K5B,eAA+B,CAAE,OAAO,CN6B1B,GAAO,CM5BrB,qBAAqC,CAAE,OAAO,CNjb1B,GAAO,CMkb3B,iBAAiC,CAAE,OAAO,CNpK1B,GAAO,CMqKvB,wBAAwC,CAAE,OAAO,CNzQ1B,GAAO,CM0Q9B,kBAAkC,CAAE,OAAO,CNha1B,GAAO,CMiaxB,wBAAwC,CAAE,OAAO,CNpa1B,GAAO,CMqa9B,sBAAsC,CAAE,OAAO,CNta1B,GAAO,CMua5B,kBAAkC,CAAE,OAAO,CNxa1B,GAAO,CMyaxB,oBAAoC,CAAE,OAAO,CNta1B,GAAO,CMua1B,oBAAoC,CAAE,OAAO,CNta1B,GAAO,CMua1B,qBAAqC,CAAE,OAAO,CNjd1B,GAAO,CMkd3B,uBAAuC,CAAE,OAAO,CNjd1B,GAAO,CMkd7B,gBAAgC,CAAE,OAAO,CNtB1B,GAAO,CMuBtB,oBAAoC,CAAE,OAAO,CN9X1B,GAAO,CM+X1B,aAA6B,CAAE,OAAO,CNne1B,GAAO,CMoenB,qBAAqC,CAAE,OAAO,CNtV1B,GAAO,CMuV3B,sBAAsC,CAAE,OAAO,CN1L1B,GAAO,CM2L5B,wBAAwC,CAAE,OAAO,CNpd1B,GAAO,CMqd9B,qBAAqC,CAAE,OAAO,CNzf1B,GAAO,CM0f3B,oBAAoC,CAAE,OAAO,CN7K1B,GAAO,CM8K1B,qBAAqC,CAAE,OAAO,CNzO1B,GAAO,CM0O3B,iBAAiC,CAAE,OAAO,CNtP1B,GAAO,CMuPvB,wBAAwC,CAAE,OAAO,CNtP1B,GAAO,CMuP9B,qBAAqC,CAAE,OAAO,CNrC1B,GAAO,CMsC3B,oBAAoC,CAAE,OAAO,CNrC1B,GAAO,CMsC1B,kBAAkC,CAAE,OAAO,CN9d1B,GAAO,CM+dxB,cAA8B,CAAE,OAAO,CN5c1B,GAAO,CM6cpB,kBAAkC,CAAE,OAAO,CNtQ1B,GAAO,CMuQxB,oBAAoC,CAAE,OAAO,CN9gB1B,GAAO,CM+gB1B,aAA6B,CAAE,OAAO,CN/b1B,GAAO,CMgcnB,kDAE8B,CAAE,OAAO,CNpR1B,GAAO,CMqRpB,mBAAmC,CAAE,OAAO,CN/N1B,GAAO,COtUzB,ylBAAK,CACH,WAAW,CAAE,OAAO,CACpB,gtBAAQ,CACN,WAAW,CC+BuB,aAAa,CD9B/C,OAAO,CAAE,YAAY,CACrB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,eAAe,CAAE,OAAO,CAM5B,6qBAAkB,CAChB,OAAO,CAAE,YAAY,CACrB,eAAe,CAAE,OAAO,CAGxB,+9CAAgB,CACd,OAAO,CAAE,MAAM,CACf,22DAAuB,CACrB,WAAW,CAAE,KAAI,CACnB,+zDAAsB,CACpB,OAAO,CAAE,YAAY,CAE3B,ycAA2B,CACzB,OAAO,CAAE,GAAE,CfpBL,kBAAoB,CAAE,qBAAM,CAK5B,eAAiB,CAAE,qBAAM,CAezB,UAAY,CAAE,qBAAM,CeE5B,ihBAAiC,CAC/B,OAAO,CAAE,CAAC,CAGV,u/BAAuB,CACrB,SAAS,CAAE,IAAI,CACf,cAAc,CAAE,IAAI,CEpBxB,0PAAS,CACP,OAAO,CAAE,IAAqB,CAC9B,WAAW,CDayB,IAAI,CCZxC,aAAa,CDYuB,IAAI,CCXxC,UAAU,CAAE,OAAmB,CAEjC,8CAAe,CACb,KAAK,CDkC+B,IAAM,CCjC1C,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAK,CACd,KAAK,CD+B+B,IAAM,CC9B1C,UAAU,CAAE,OAAkB,CAC9B,MAAM,CAAE,KAAsB,CAC9B,OAAO,CAAE,QAA2C,CACpD,aAAa,CAAE,IAAqB,CAEtC,0ZAAyB,CACvB,UAAU,CAAE,OAAkB,CAC9B,mxCAAe,CACb,UAAU,CAAE,OAAiB,CACjC,kYAA0B,CACxB,UAAU,CAAE,OAAmB,CAC/B,ouCAAe,CACb,UAAU,CAAE,OAAoB,CAEpC,sYAAuB,CACrB,UAAU,CAAE,OAAmB,CAC/B,yuCAAe,CACb,UAAU,CAAE,OAAkB,CAElC,mZAA0B,CACxB,UAAU,CAAE,OAAuB,CACnC,swCAAe,CACb,UAAU,CAAE,OAAqB,CAErC,scAA0B,CACxB,UAAU,CDmB0B,OAAmB,CClBvD,42CAAe,CACb,KAAK,CCjD6B,OAAW,CDkD7C,UAAU,CDJwB,OAAmB,CCKvD,8dAAC,CACC,KAAK,CDsB6B,OAAW,CCpBjD,sZAAsB,CACpB,aAAa,CAAE,CAAC,CAsBlB,kBAAkB,CAChB,QAAQ,CAAE,KAAK,CACf,MAAM,CAAE,GAAG,CACX,IAAI,CAAE,CAAC,CACP,OAAO,CDG6B,GAAG,CCFvC,qBAAE,CACA,OAAO,CAAE,KAAK,CACd,KAAK,CDT6B,KAAK,CCUvC,UAAU,CAAE,WAAW,CACvB,KAAK,CDlC6B,IAAM,CCmCxC,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,2BAA0B,CACtC,OAAO,CAAE,MAAmB,CAC5B,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CACT,WAAW,CAAE,IAAI,CACjB,QAAQ,CAAE,MAAM,CjB3FZ,kBAAoB,CAAE,gBAAM,CAK5B,eAAiB,CAAE,gBAAM,CAezB,UAAY,CAAE,gBAAM,CiByExB,0CAAsB,CACpB,UAAU,CDhCsB,OAAM,CCiCxC,uCAAmB,CACjB,UAAU,CDzBsB,OAAW,CC0B7C,0CAAsB,CACpB,UAAU,CDnFsB,OAAO,CCoFzC,yCAAqB,CACnB,UAAU,CDtEsB,OAAI,CCuEtC,wBAAI,CACF,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,IAAI,CEhFd,oCAAsB,CFmFxB,kBAAkB,CAChB,MAAM,CAAE,IAAI,CACZ,GAAG,CAAE,CAAC,CACN,KAAK,CAAE,IAAI,CACX,qBAAE,CACA,KAAK,CAAE,IAAI,EG3FjB,MAAM,CACJ,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,CAAC,CACT,cAAc,CAAE,QAAQ,CACxB,eAAe,CAAE,MAAM,CACvB,MAAM,CAAE,OAAO,CACf,WAAW,CAAE,MAAM,CACnB,kBAAkB,CAAE,MAAM,CAC1B,SAAS,CAAE,OAAO,CACpB,gDAAiD,CAC/C,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACZ,gBAAgB,CACd,MAAM,CAAE,OAAO,CAEjB,IAAI,CAEF,OAAO,CAAE,YAAY,CACrB,aAAa,CAAE,GAAG,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,MAAM,CAAE,OAAO,CACf,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,iBAA6F,CACtG,KAAK,CJI+B,IAAM,CIH1C,MAAM,CAAE,yBAAyB,CACjC,gBAAgB,CJeoB,OAAM,CId1C,eAAe,CAAE,IAAI,CACrB,WAAW,CAAE,MAAM,CACnB,WAAW,CFnDyB,uDAAM,CEoD1C,UAAU,CAAE,mFAA8C,CAC1D,YAAY,CAAE,KAAK,CACnB,cAAc,CAAE,MAAM,CACtB,QAAQ,CAAE,MAAM,CAChB,IAAI,CAAE,CAAC,CACP,iBAAiB,CAAE,IAAI,CpBxDjB,mBAAoB,CoByDb,IAAI,CpBpDX,gBAAiB,CoBoDV,IAAI,CpB/CX,eAAgB,CoB+CT,IAAI,CpBrCX,WAAY,CoBqCL,IAAI,CpBzDX,kBAAoB,CAAE,eAAM,CAK5B,eAAiB,CAAE,eAAM,CAezB,UAAY,CAAE,eAAM,CoByC5B,UAAU,CACR,UAAU,CAAE,OAAwB,CACpC,KAAK,CJd+B,IAAM,CIiB1C,UAAO,CACL,UAAU,CAAE,OAAqC,CACjD,KAAK,CJnB6B,IAAM,CIoB1C,UAAO,CACL,UAAU,CAAE,OAAqC,CACjD,OAAO,CAAE,CAAC,CACZ,WAAQ,CACN,UAAU,CAAE,6EAAyC,CACrD,OAAO,CAAE,iBAA6F,CACxG,YAAS,CACP,KAAK,CJ3B6B,IAAM,CI4B1C,aAAU,CACR,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAG,CACZ,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAEpB,aAAa,CACX,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAG,CACZ,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAChB,4DAA0B,CACxB,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAI,CACb,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAGpB,sBAAsB,CACpB,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CAEX,UAAU,CACR,SAAS,CAAE,GAAG,CAEhB,SAAS,CACP,gBAAgB,CAAE,kBAAgB,CAClC,eAAO,CACL,gBAAgB,CAAE,kBAA6B,CAEnD,YAAY,CACV,gBAAgB,CAAE,kBAA2C,CAC7D,KAAK,CAAE,kBAAsB,CAC7B,kBAAO,CACL,gBAAgB,CAAE,kBAAuD,CACzE,KAAK,CFzH6B,OAAW,CE0H/C,oBAAS,CACP,KAAK,CAAE,kBAAsB,CAEjC,YAAY,CACV,gBAAgB,CAAE,kBAAiB,CACnC,kBAAO,CACL,gBAAgB,CAAE,eAA6B,CAEnD,WAAW,CACT,gBAAgB,CAAE,kBAAe,CACjC,iBAAO,CACL,gBAAgB,CAAE,kBAA4B,CAElD,YAAY,CACV,gBAAgB,CAAE,kBAAkB,CACpC,kBAAO,CACL,gBAAgB,CAAE,kBAA+B,CACrD,WAAW,CACT,gBAAgB,CJvIoB,IAAI,CIwIxC,iBAAO,CACL,gBAAgB,CAAE,kBAAoC,CAE1D,SAAS,CACP,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CJxE+B,OAAW,CIyE/C,UAAU,CAAE,IAAI,CAChB,YAAY,CAAE,sBAAsB,CACpC,eAAO,CACL,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CAAE,kBAAoC,CAC3C,UAAU,CAAE,IAAI,CAClB,gBAAQ,CACN,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CAAE,kBAAoC,CAC3C,UAAU,CAAE,IAAI,CAClB,iBAAS,CACP,KAAK,CJnG6B,OAAO,CIqG7C,mCAAoC,CAClC,cAAc,CAAE,MAAM,CAExB,aAAa,CACX,aAAa,CJ1IuB,IAAI,CduExC,KAAK,CAAE,CAAC,CACR,wCAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,mBAAO,CACL,KAAK,CAAE,IAAI,CmB3Ff,YAAY,CACV,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,YAAY,CAIvB,qCAAqC,CACnC,OAAO,CAAE,KAAK,CAChB,iBAAiB,CACf,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,CAAC,CACP,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,IAAI,CACX,GAAG,CAAE,IAAI,CACT,SAAS,CAAE,IAAI,CACf,UAAU,CL1B0B,OAAyB,CK2B7D,OAAO,CLmD6B,GAAG,CKlDvC,MAAM,CAAE,iBAAgC,CACxC,UAAU,CAAE,2BAA0B,CACtC,OAAO,CAAE,IAAqB,CAC9B,sBAAQ,CACN,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,KAAK,CHnC6B,OAAW,CGoC7C,WAAW,CAAE,MAAM,CACnB,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,MAAuB,CAChC,MAAM,CAAE,OAAO,CACf,4BAAO,CACL,UAAU,CLiCsB,OAAW,CKhC3C,KAAK,CLU2B,IAAM,CKT1C,4BAAY,CACV,UAAU,CAAE,iBAAgC,CAC5C,MAAM,CAAE,KAAuB,CACjC,2BAAW,CACT,cAAc,CAAE,IAAqB,CACrC,gDAAoB,CAClB,KAAK,CAAE,IAAI,CACf,mCAAmB,CACjB,UAAU,CAAE,OAA4B,CACxC,cAAc,CAAE,SAAS,CACzB,WAAW,CAAE,GAAG,CAChB,SAAS,CAAE,GAAG,CACd,yCAAO,CACL,UAAU,CAAE,OAA4B,CAC1C,wCAAI,CACF,KAAK,CLN2B,IAAM,CKQ5C,6CAA6C,CAC3C,MAAM,CAAE,IAAI,CACZ,GAAG,CAAE,IAAI,CACT,IAAI,CAAE,IAAI,CACV,KAAK,CAAE,CAAC,CAGR,iDAAiB,CACf,UAAU,CLnEwB,OAAyB,CKoE3D,UAAU,CAAE,GAAG,CACjB,mDAAmB,CACjB,OAAO,CAAE,QAA2C,CACpD,yDAAO,CACL,UAAU,CLCsB,OAAW,CKA3C,KAAK,CLtB2B,IAAM,CKwB5C,+CAA+C,CAC7C,KAAK,CAAE,CAAC,CACR,IAAI,CAAE,IAAI,CACV,UAAU,CAAE,KAAK,CAGjB,yBAAQ,CACN,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,iBAA0B,CACzC,WAAW,CAAE,qBAAqB,CAClC,YAAY,CAAE,qBAAqB,CACnC,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,KAAK,CACd,GAAG,CAAE,IAAI,CACT,IAAI,CAAE,GAAG,CACT,WAAW,CAAE,IAAI,CACnB,gDAA+B,CAC7B,IAAI,CAAE,IAAI,CCtEZ,uBAAM,CACJ,OAAO,CAAE,KAAK,CAEhB,gIAA+C,CAC7C,OAAO,CAAE,YAAY,CACrB,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,CAAC,CACR,cAAc,CAAE,MAAM,CAItB,wCAAO,CACL,OAAO,CAAE,YAAY,CACrB,cAAc,CAAE,MAAM,CACtB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,YAA+C,CACvD,KAAK,CAAE,IAAI,CACf,4BAAW,CACT,KAAK,CAAE,IAAI,CACX,kCAAK,CACH,OAAO,CAAE,KAAK,CAChB,mCAAM,CACJ,UAAU,CAAE,GAAqB,CAEvC,QAAQ,CACN,MAAM,CAAE,CAAC,CACT,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACZ,MAAM,CACJ,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACV,WAAW,CAAE,MAAM,CACnB,aAAa,CN/BuB,IAAI,CMgCxC,SAAS,CAAE,IAAI,CACf,YAAY,CAAE,IAAI,CACpB,KAAK,CACH,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,cAAa,CACrB,KAAK,CNR+B,IAAU,CMS9C,SAAS,CAAE,GAAG,CAEhB,qBAAuB,CACrB,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,CAAC,CACT,cAAc,CAAE,QAAQ,CACxB,eAAe,CAAE,MAAM,CAGzB,iBAAiB,CACf,aAAa,CNhDuB,IAAI,CduExC,KAAK,CAAE,CAAC,CqBrGR,SAAS,CCCC,IAAQ,CDChB,WAAI,CAAE,IAAI,CACV,YAAK,CAAE,IAAI,CrBkGb,KAAK,CAAE,CAAC,CACR,gDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,uBAAO,CACL,KAAK,CAAE,IAAI,CALb,gDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,uBAAO,CACL,KAAK,CAAE,IAAI,CoBzBf,uDAAyD,CACvD,OAAO,CAAE,IAAI,CACb,KAAK,CN/C+B,OAAI,CMoDxC,mGAA+C,CAC7C,cAAc,CAAE,IAAqB,CACrC,wHAAM,CACJ,KAAK,CAAE,IAAI,CAEX,0tEAAqP,CACnP,KAAK,CAAE,IAAI,CACnB,+BAA+B,CGlF3B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,IAAuC,CCnB5C,YAAoB,CAAE,CAAC,CDqBzB,0CAAa,CACX,YAAoB,CAAE,CAAC,CHgE/B,iCAAiC,CGtF7B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,SAAuC,CAE9C,4CAAa,CACX,YAAoB,CAAE,CAAC,CCA7B,iDAAwB,CACtB,YAAoB,CAAE,CAAC,CAEvB,mDAA0B,CACxB,KAAK,CALY,IAAkC,CJqEzD,iCAAiC,CG1F7B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,SAAuC,CAE9C,4CAAa,CACX,YAAoB,CAAE,CAAC,CCA7B,iDAAwB,CACtB,YAAoB,CAAE,CAAC,CAEvB,mDAA0B,CACxB,KAAK,CALY,IAAkC,CJ0EzD,uDAAuD,CACrD,MAAM,CAAE,SAA2B,CACnC,SAAS,CAAE,GAAG,CAEhB,oBAAoB,CAClB,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,SAA2B,CACnC,SAAS,CAAE,GAAG,CAOZ,osBAAqP,CACnP,KAAK,CAAE,IAAI,CAIjB,uBAAuB,CACrB,OAAO,CAAE,YAAY,CACrB,YAAY,CAAE,KAAK,CACnB,KAAK,CAAE,IAAI,CACX,cAAc,CAAE,MAAM,CACtB,SAAS,CAAE,GAAG,CAEhB,gBAAgB,CACd,OAAO,CAAE,KAAK,CACd,KAAK,CN7H+B,IAAI,CM8HxC,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,QAAO,CACnB,UAAU,CAAE,MAAM,CAClB,kBAAC,CACC,SAAS,CAAE,OAAO,CAClB,UAAU,CAAE,MAAM,CAClB,aAAa,CAAE,GAAqB,CACtC,6BAAY,CACV,aAAa,CAAE,CAAC,CA4DpB,KAAK,CACH,WAAW,CAAE,MAAM,CAGnB,6DAAmD,CACjD,kBAAkB,CAAE,MAAM,CAC1B,MAAM,CAAE,OAAO,CACf,WAAW,CJ/MuB,uDAAM,CIgNxC,SAAS,CAAE,OAAO,CACpB,gSAAqP,CACnP,kBAAkB,CAAE,IAAI,CACxB,OAAO,CAAE,GAAqB,CAC9B,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAA6B,CACrC,SAAS,CAAE,GAAG,CACd,WAAW,CJvNuB,uDAAM,CIwNxC,UAAU,CAAE,oBAAmC,CAC/C,aAAa,CAAE,CAAC,CtBxNZ,kBAAoB,CAAE,kBAAM,CAK5B,eAAiB,CAAE,kBAAM,CAezB,UAAY,CAAE,kBAAM,CsBuM1B,4BAAwB,CACtB,OAAO,CAAE,iBAAkB,CAC7B,eAAW,CACT,MAAM,CAAE,OAAO,CACjB,0CAAmC,CtB/N7B,kBAAoB,CsBgOZ,UAAU,CtB3NlB,eAAiB,CsB2NT,UAAU,CtB5MlB,UAAY,CsB4MJ,UAAU,CACtB,OAAO,CAAE,CAAC,CACV,YAAY,CAAE,QAAO,CACrB,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,IAAI,CACd,oBAAgB,CtBrOV,kBAAoB,CsBsOZ,UAAU,CtBjOlB,eAAiB,CsBiOT,UAAU,CtBlNlB,UAAY,CsBkNJ,UAAU,CACtB,kGAA6D,CAC3D,kBAAkB,CAAE,IAAI,CAC5B,oXAAyU,CACvU,OAAO,CAAE,CAAC,CACV,OAAO,CAAE,cAAc,CACvB,YAAY,CNxLsB,IAAU,CMyL9C,oBAAgB,CACd,YAAY,CAAE,eAA8B,CAC9C,+EAAqE,CACnE,OAAO,CAAE,gBAAsB,CAC/B,OAAO,CAAE,gBAAgB,CAC3B,4aAAiY,CAC/X,MAAM,CAAE,WAAW,CACnB,gBAAgB,CAAE,OAAmC,CAEzD,+DAAiE,CAC/D,KAAK,CNzN+B,OAAI,CM0NxC,MAAM,CAAE,iBAAc,CACxB,iFAAmF,CACjF,YAAY,CN5NwB,OAAI,CM8NxC,yHAA+G,CAC7G,aAAa,CN/NqB,OAAI,CMiO1C,oBAAoB,CAClB,OAAO,CAAE,IAAqB,CAC9B,SAAS,CAAE,IAAI,CAKjB,QAAQ,CACN,QAAQ,CAAE,IAAI,CACd,cAAc,CAAE,GAAG,CACnB,KAAK,CAAE,IAAI,CACX,WAAW,CJ3QyB,uDAAM,CI4Q5C,eAAgB,CACd,OAAO,CAAE,aAAgB,CACzB,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAA6B,CACrC,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,oBAAmC,CtBhRzC,kBAAoB,CAAE,kBAAM,CAK5B,eAAiB,CAAE,kBAAM,CAezB,UAAY,CAAE,kBAAM,CsB+P5B,MAAM,CACJ,MAAM,CAAE,cAA6B,CACrC,gBAAgB,CNpOoB,IAAM,CMqO1C,gBAAW,CACT,MAAM,CAAE,IAAI,CAChB,2BAA4B,CAC1B,OAAO,CAAE,CAAC,CACZ,uFAA2F,CACzF,MAAM,CAAE,WAAW,CACnB,gBAAgB,CAAE,OAAmC,CAKrD,8DAAuD,CACrD,MAAM,CAAE,WAAW,CACvB,sBAAuB,CACrB,MAAM,CAAE,KAAuB,CAE/B,KAAK,CJzS+B,OAAW,CI0S/C,OAAO,CAAE,KAAK,CACd,kCAAK,CACH,cAAc,CAAE,QAAQ,CAI5B,uBAAuB,CACrB,OAAO,CAAE,YAAY,CACrB,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,CAAC,CACR,cAAc,CAAE,MAAM,CAuBxB,iCAAkC,CAChC,WAAW,CAAE,MAAM,CACnB,OAAO,CAAE,GAAqB,CAC9B,qEAAiB,CACf,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CACd,gBAAgB,CNjRkB,OAAmB,CMkRrD,MAAM,CAAE,cAA6B,CACrC,KAAK,CN7U6B,IAAI,CM+U1C,kCAAkC,CAChC,WAAW,CAAE,CAAC,CAChB,kCAAkC,CAChC,YAAY,CAAE,CAAC,CAcjB,UAAU,CACR,KAAK,CAAE,IAAuB,CAC9B,MAAM,CAAE,IAAqB,CAC7B,MAAM,CAAE,MAAwB,CAChC,QAAQ,CAAE,QAAQ,CAClB,aAAa,CAAE,GAAG,CAClB,UAAU,CNrW0B,IAAI,CMsWxC,MAAM,CAAE,OAAO,CtB5WT,kBAAoB,CAAE,oBAAM,CAK5B,eAAiB,CAAE,oBAAM,CAezB,UAAY,CAAE,oBAAM,CsB0V1B,iBAAQ,CACN,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,EAAE,CACX,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,GAAG,CAClB,UAAU,CNhXwB,IAAI,CMiXtC,IAAI,CAAE,IAAI,CACV,GAAG,CAAE,IAAI,CtBvXL,kBAAoB,CAAE,oBAAM,CAK5B,eAAiB,CAAE,oBAAM,CAezB,UAAY,CAAE,oBAAM,CsBqW1B,gBAAO,CACL,OAAO,CAAE,OAAO,CAChB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,IAAqB,CAC3B,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,IAAI,CACf,KAAK,CNzX6B,IAAI,CM0X1C,iBAAiB,CACf,UAAU,CAAE,OAAmB,CAC/B,wBAAQ,CACN,IAAI,CN5W8B,IAAI,CM6WtC,UAAU,CNtUwB,OAAM,CMuU1C,uBAAO,CACL,OAAO,CAAE,MAAM,CAEnB,8CAA+C,CAC7C,MAAM,CAAE,WAAW,CAiDnB,wGAAyB,CACvB,KAAK,CN7Z6B,OAAI,CM+ZtC,81BAAqP,CACnP,MAAM,CAAE,iBAAc,CAC1B,iDAAQ,CACN,MAAM,CAAE,iBAAc,CAE1B,mBAAmB,CACjB,WAAW,CAAE,MAAM,CACnB,qCAAiB,CACf,OAAO,CAAE,aAAgB,CACzB,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CAClB,gEAAgE,CAC9D,KAAK,CN3Y+B,OAAM,CM8Y5C,+DAA+D,CAC7D,KAAK,CN/a+B,OAAI,CMkb1C,gEAAgE,CAC9D,KAAK,CNlc+B,OAAO,CMqc7C,6DAA6D,CAC3D,KAAK,CN9Y+B,OAAW,CMoZjD,UAAU,CtB3dF,iBAAoB,CAAE,aAAM,CAK5B,cAAiB,CAAE,aAAM,CAKzB,aAAgB,CAAE,aAAM,CAKxB,YAAe,CAAE,aAAM,CAKvB,SAAY,CAAE,aAAM,CsByc5B,WAAW,CtB7dH,iBAAoB,CAAE,cAAM,CAK5B,cAAiB,CAAE,cAAM,CAKzB,aAAgB,CAAE,cAAM,CAKxB,YAAe,CAAE,cAAM,CAKvB,SAAY,CAAE,cAAM,CsB2c5B,WAAW,CtB/dH,iBAAoB,CAAE,cAAM,CAK5B,cAAiB,CAAE,cAAM,CAKzB,aAAgB,CAAE,cAAM,CAKxB,YAAe,CAAE,cAAM,CAKvB,SAAY,CAAE,cAAM,CsB6c5B,OAAO,CtBjeC,iBAAoB,CAAE,UAAM,CAK5B,cAAiB,CAAE,UAAM,CAKzB,aAAgB,CAAE,UAAM,CAKxB,YAAe,CAAE,UAAM,CAKvB,SAAY,CAAE,UAAM,CsB+c1B,iBAAW,CtBneL,iBAAoB,CsBoeL,wBAAwB,CtB/dvC,cAAiB,CsB+dF,wBAAwB,CtB1dvC,aAAgB,CsB0dD,wBAAwB,CtBrdvC,YAAe,CsBqdA,wBAAwB,CtBhdvC,SAAY,CsBgdG,wBAAwB,CAC7C,kBAAY,CtBreN,iBAAoB,CsBseL,yBAAyB,CtBjexC,cAAiB,CsBieF,yBAAyB,CtB5dxC,aAAgB,CsB4dD,yBAAyB,CtBvdxC,YAAe,CsBudA,yBAAyB,CtBldxC,SAAY,CsBkdG,yBAAyB,CAC9C,kBAAY,CtBveN,iBAAoB,CsBweL,yBAAyB,CtBnexC,cAAiB,CsBmeF,yBAAyB,CtB9dxC,aAAgB,CsB8dD,yBAAyB,CtBzdxC,YAAe,CsBydA,yBAAyB,CtBpdxC,SAAY,CsBodG,yBAAyB,CAEhD,yCAAyC,CAErC,8BAAqB,CACnB,MAAM,CAAE,SAAS,CAEjB,8ZAAqP,CACnP,aAAa,CAAE,KAAK,CACpB,OAAO,CAAE,KAAK,CAClB,cAAK,CACH,aAAa,CAAE,KAAK,CACpB,OAAO,CAAE,KAAK,CAEhB,kYAAqO,CACnO,aAAa,CAAE,CAAC,CAElB,wCAAuB,CACrB,aAAa,CAAE,KAAK,CACpB,UAAU,CAAE,IAAI,CAChB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACb,4BAAW,CACT,MAAM,CAAE,WAAW,CACvB,iEAAmE,CACjE,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,KAAuB,EH5ehC,oCAAsB,CQhC1B,YAAY,CAER,OAAO,CAAE,IAAI,ER8Bb,oCAAsB,CQ5B1B,YAAY,CAER,OAAO,CAAE,IAAI,EAEjB,WAAW,CACT,KAAK,CAAE,IAAI,CAEb,YAAY,CACV,KAAK,CAAE,KAAK,CAEd,WAAW,CACT,KAAK,CAAE,IAAI,CC4Cb,mEAAS,CACP,eAAe,CAAE,QAAQ,CACzB,cAAc,CAAE,CAAC,CACjB,WAAW,CAAE,IAAI,CACjB,aAAa,CZ/BuB,IAAI,CYgCxC,2FAAO,CACL,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,6BAAkB,CACxB,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,CACpB,yJAAM,CACJ,SAAS,CZjByB,GAAG,CYkBrC,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CACjB,OAAO,CZnB2B,QAAmC,CYoBvE,iOAA8B,CAC5B,iBAAiB,CAAE,CAAC,CACtB,qFAAK,CACH,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,IAAI,CAChB,cAAc,CAAE,MAAM,CACtB,WAAW,CAAE,MAAM,CACnB,8FAAE,CACA,WAAW,CZnDqB,IAAI,CYoDpC,aAAa,CAAE,iBAA6B,CAChD,4EAAE,CACA,gBAAgB,CAAE,WAAW,CAC7B,cAAc,CAAE,MAAM,CAE1B,kFAAc,CACZ,WAAW,CAAE,IAAuB,CACpC,mHAAY,CACV,aAAa,CAAE,CAAC,CACpB,4HAA4B,CAC1B,KAAK,CAAE,EAAE,CACT,aAAa,CAAE,CAAC,CAChB,uXAA0C,CACxC,MAAM,CAAE,CAAC,CAEb,mBAAmB,CACjB,KAAK,CZxD+B,IAAwB,CYyD5D,SAAS,CAAE,GAAG,CAChB,kBAAkB,CAChB,KAAK,CZ3D+B,IAAwB,CY4D5D,SAAS,CAAE,GAAG,CAIhB,2HAAyD,CACvD,gBAAgB,CZpCoB,OAAmB,CYsCzD,gBAAgB,CACd,gBAAgB,CZvCoB,OAAmB,CY4CzD,kDAAsB,CACpB,MAAM,CAAE,iBAA6B,CACrC,wDAAE,CACA,aAAa,CAAE,iBAA6B,CAC5C,WAAW,CAAE,iBAA6B,CAC5C,gGAAwB,CACtB,mBAAmB,CAAE,CAAC,CAE1B,kBAAkB,CAChB,MAAM,CAAE,iBAA6B,CAGrC,0BAAE,CACA,aAAa,CAAE,iBAA6B,CAC9C,8CAAwB,CACtB,mBAAmB,CAAE,CAAC,CAGxB,2CAAwB,CACtB,mBAAmB,CAAE,CAAC,CACxB,+CAAM,CACJ,YAAY,CAAE,SAAS,CACvB,aAAa,CAAE,iBAA6B,CAC9C,2CAAwB,CACtB,mBAAmB,CAAE,CAAC,CAG1B,oBAAoB,CAClB,aAAa,CZhHuB,IAAI,CYiHxC,SAAS,CAAE,IAAI,CACf,QAAQ,CAAE,IAAI,CACd,0BAAK,CACH,aAAa,CAAE,YAAY,CAC3B,2DAAM,CACJ,WAAW,CAAE,MAAM,CCzIzB,CAAC,CACC,KAAK,CbkE+B,OAAW,CajE/C,eAAe,CAAE,IAAI,CACrB,MAAM,CAAE,OAAO,CACf,OAAO,CACL,KAAK,CbgD6B,OAAwB,Ca/C5D,SAAS,CACP,KAAK,Cb6C6B,OAAO,CanB7C,IAAI,CACF,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,MAAM,CAEpB,IAAI,CACF,WAAW,CX3CyB,uDAAM,CW4C1C,WAAW,CAAE,MAAM,CACnB,KAAK,CX/C+B,OAAW,CWgD/C,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,MAAM,CAClB,UAAU,CbnD0B,OAAO,CaqD7C,aAAa,CACX,UAAU,CAAE,IAAI,CAElB,eAAe,CACb,UAAU,CAAE,MAAM,CAEpB,cAAc,CACZ,UAAU,CAAE,KAAK,CAEnB,cAAc,CACZ,SAAS,CAAE,IAAI,CAEjB,eAAe,CACb,SAAS,CAAE,IAAI,CAEjB,oBAAqB,CACnB,SAAS,CAAE,GAAG,CAEhB,eAAe,CACb,eAAe,CAAE,YAAY,CAE/B,gBAAgB,CACd,KAAK,CAAE,kBAAkB,CAC3B,uBAAuB,CACrB,KAAK,CAAE,kBAAgC,CACzC,aAAa,CACX,KAAK,CAAE,kBAAgB,CACzB,oBAAoB,CAClB,KAAK,CAAE,kBAA8B,CACvC,gBAAgB,CACd,KAAK,CAAE,kBAAiB,CAC1B,uBAAuB,CACrB,KAAK,CAAE,kBAA+B,CACxC,eAAe,CACb,KAAK,CAAE,kBAAe,CACxB,sBAAsB,CACpB,KAAK,CAAE,kBAA6B,CACtC,gBAAgB,CACd,KAAK,CAAE,kBAAsB,CAC/B,uBAAuB,CACrB,KAAK,CAAE,kBAAoC,CAkB7C,wBAAyB,CACvB,UAAU,CAAE,CAAC,CACb,WAAW,CAAE,GAAG,CAChB,WAAW,CX9GyB,0DAAa,CWgHnD,CAAC,CACC,WAAW,Cb1FyB,IAAI,Ca2FxC,MAAM,CAAE,CAAC,CACT,SAAS,Cb/F2B,IAAI,CagGxC,aAAa,Cb7FuB,IAAI,Ca+F1C,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,iBAA6B,CACzC,MAAM,CAAE,MAAmB,CAC3B,OAAO,CAAE,CAAC,CAEZ,oBAAI,CACF,WAAW,CAAE,MAAM,CACnB,SAAS,CAAE,IAAI,CACf,UAAU,CblG0B,IAAM,CamG1C,MAAM,CAAE,iBAAiC,CACzC,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,KAAK,CACd,WAAW,CXrJyB,wMAAQ,CWsJ5C,KAAK,Cb1H+B,OAAI,Ca2HxC,UAAU,CAAE,IAAI,CAChB,0CAAY,CACV,SAAS,CAAE,GAAG,CAmClB,wFAAmB,CACjB,UAAU,CAAE,IAAI,CAChB,WAAW,CbzKyB,IAAI,Ca0KxC,aAAa,Cb1KuB,IAAI,Ca2KxC,oGAAE,CACA,UAAU,CAAE,IAAI,CAChB,WAAW,Cb7KuB,IAAI,Ca8KtC,wJAAY,CACV,aAAa,CAAE,CAAC,CAClB,gHAAE,CACA,aAAa,CAAE,CAAC,CAClB,gHAAE,CACA,UAAU,CAAE,MAAM,CAClB,4HAAE,CACA,UAAU,CAAE,MAAM,CACtB,4HAAK,CACH,UAAU,CAAE,OAAO,CAEzB,iFAAsB,CACpB,UAAU,CAAE,OAAO,CACnB,WAAW,Cb3LyB,IAAI,Ca4LxC,aAAa,Cb5LuB,IAAI,Ca6LxC,6FAAE,CACA,UAAU,CAAE,OAAO,CACnB,WAAW,Cb/LuB,IAAI,CagMtC,iJAAY,CACV,aAAa,CAAE,CAAC,CAClB,yGAAE,CACA,aAAa,CAAE,CAAC,CAChB,qHAAE,CACA,UAAU,CAAE,IAAI,CCrOxB,kBAAkB,CAChB,MAAM,CAAE,iBAA6B,CACrC,aAAa,CAAE,IAAI,CACnB,OAAO,Cd6B6B,IAAI,Cc5BxC,WAAW,CAAE,IAAqB,CAClC,WAAW,CAAE,GAAG,CAChB,UAAU,CdoD0B,IAAM,CcnD1C,QAAQ,CAAE,QAAQ,CAClB,wBAAO,CACL,OAAO,CAAE,SAAS,CAClB,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,GAAG,CACR,IAAI,CAAE,GAAG,CACT,UAAU,CdoDwB,OAAO,CcnDzC,KAAK,CAAE,IAAoB,CAC3B,OAAO,CAAE,QAA2C,CACtD,2CAA0B,CACxB,MAAM,CAAE,iBAA6B,CACrC,aAAa,CdcqB,IAAI,CcZ1C,+GAAmC,CACjC,MAAM,CAAE,iBAA6B,CACrC,OAAO,CAAE,GAAG,CACZ,UAAU,CAAE,IAAI,CAChB,UAAU,CdkC0B,IAAM,CchC1C,MAAM,CAAE,YAAyB,CACjC,gLAAuB,CACrB,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,CAAC,CAEb,+BAA+B,CAC7B,KAAK,CAAE,IAAI,CACb,cAAc,CACZ,YAAY,CAAE,iBAA0C,CACxD,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,SAA2C,CACpD,WAAW,CZ3ByB,wMAAQ,CY4B5C,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,GAAG,CAChB,KAAK,CdI+B,OAAwB,CcH9D,2BAA2B,CACzB,WAAW,CAAE,GAAG,CAChB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,SAA2C,CACpD,WAAW,CZnCyB,wMAAQ,CYoC5C,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,GAAG,CAChB,OAAO,CAAE,KAAK,CACd,QAAQ,CAAE,IAAI,CACd,KAAK,CZ7C+B,OAAW,CYiDjD,YAAY,CACV,2IAAgE,CAC9D,WAAW,CAAE,QAAQ,ECzDzB,IAAI,CACF,gBAAgB,CAAE,IAAO,CACzB,MAAM,CAAE,OAAO,CACf,OAAO,CAAE,MAAM,CACf,OAAO,CAAE,KAAK,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,IAAI,CACF,KAAK,CAAE,OAAO,CACd,gBAAgB,CAAE,OAAO,CAC3B,EAAE,CACA,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACjB,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,MAAM,CACJ,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,GAAG,CACD,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,MAAM,CACJ,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,MAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,MAAM,CACf,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACX,gBAAgB,CAAE,OAAO,CCjJ3B,kBAAkB,CAChB,OAAO,CAAE,YAAY,CACrB,uCAAsB,CACpB,KAAK,CAAE,KAAK,CACd,oBAAC,CACC,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,GAAG,CACZ,gCAAa,CACX,YAAY,CAAE,CAAC,CACrB,qBAAqB,CACnB,aAAa,CAAE,CAAC,CAChB,KAAK,ChBiC+B,OAAwB,CgBhC5D,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,YAAY,CbmBnB,oCAAsB,CafxB,qBAAqB,CACnB,OAAO,CAAE,IAAI,CACf,uCAAuC,CACrC,OAAO,CAAE,IAAI,EAEjB,YAAY,CACV,uCAAuC,CACrC,OAAO,CAAE,IAAI,ECxBjB,SAAS,CACP,QAAQ,CAAE,KAAK,CACf,GAAG,CCAO,OAAO,CDGjB,gBAAO,CACL,eAAe,CAAE,IAAI,CAEzB,cAAc,C/B+FZ,KAAK,CAAE,CAAC,CACR,0CAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,oBAAO,CACL,KAAK,CAAE,IAAI,C+BnGb,mCAAM,CACJ,OAAO,CAAE,YAAY,CACvB,uBAAQ,CACN,UAAU,CAAE,qBAAoB,CAEhC,6BAAa,CACX,WAAW,CAAE,iBAAyB,CACxC,8BAAc,CACZ,YAAY,CAAE,iBAAyB,CAC3C,gBAAC,CACC,MAAM,CAAE,IAAmB,CAC3B,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAmB,CAChC,OAAO,CAAE,MAAiB,CAG5B,wBAAM,CACJ,MAAM,CAAE,IAAmB,CAC3B,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAmB,CAChC,OAAO,CAAE,SAAS,CAClB,OAAO,CAAE,KAAK,CACd,WAAW,CAAE,IAAI,CACjB,cAAc,CAAE,SAAS,CACzB,SAAS,CAAE,GAAG,CACd,KAAK,CjB6C6B,OAAW,CiB5C7C,WAAW,CAAE,MAAM,CAErB,oBAAE,CACA,aAAa,CAAE,CAAC,CAEhB,+BAAY,CACV,UAAU,CAAE,iBAAyB,CACvC,kCAAe,CACb,aAAa,CAAE,iBAAyB,CAC1C,4BAAS,CACP,UAAU,CAAE,OAAsC,CAClD,8BAAC,CACC,KAAK,CjBLyB,IAAwB,CiBMtD,YAAY,CAAE,iBAAgD,CAC9D,OAAO,CAAE,gBAAyB,CAClC,oCAAO,CACL,UAAU,CAAE,OAAsC,CAE1D,wDAAuB,CACrB,KAAK,CfjD6B,OAAW,CekD7C,OAAO,CAAE,gBAAmB,CAC5B,WAAW,CAAE,IAAI,CACjB,QAAQ,CAAE,QAAQ,CAClB,UAAU,CjBpDwB,OAAyB,CiBqD3D,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,iBAAgD,CAC/D,UAAU,CAAE,iBAAgD,CAC5D,YAAY,CAAE,YAAY,CAE1B,oEAAO,CACL,UAAU,CjB3DsB,OAAyB,CiB6D7D,yCAAyB,CACvB,UAAU,CAAE,OAAsC,CAClD,OAAO,CAAE,gBAAyB,CACpC,+BAAa,CACX,OAAO,CAAE,KAAK,CAChB,uBAAK,CACH,aAAa,CAAE,CAAC,CAChB,OAAO,CAAE,IAAI,CAEb,kCAAK,CACH,OAAO,CAAE,KAAK,CAClB,4BAAU,CACR,aAAa,CAAE,CAAC,CAChB,KAAK,CjBrC6B,OAAwB,CiBsC1D,WAAW,CAAE,MAAM,CACrB,mBAAC,CACC,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,gBAAmB,CAC5B,OAAO,CAAE,KAAK,CACd,QAAQ,CAAE,QAAQ,CAClB,SAAS,CAAE,GAAG,CACd,KAAK,CjB9C6B,OAAwB,CiB+C1D,yBAAO,CACL,gBAAgB,CAAE,OAAoC,CACtD,MAAM,CAAE,OAAO,CACjB,0BAAQ,CACN,gBAAgB,CjBfgB,OAAW,CiBgB3C,MAAM,CAAE,OAAO,CACf,KAAK,CjBvC2B,IAAM,CiByC5C,mBAAmB,CACjB,OAAO,CjBd6B,GAAG,CiBevC,gBAAgB,CjBrBoB,OAAW,CiBsB/C,UAAU,CAAE,MAAM,CAClB,OAAO,CAAE,OAAW,CACpB,OAAO,CAAE,KAAK,CACd,KAAK,CjBlG+B,OAAyB,CiBmG7D,aAAa,CAAE,OAAW,CAC1B,oCAAgB,CACd,KAAK,CAAE,IAAI,CACX,aAAa,CAAE,IAAI,CACnB,OAAO,CAAE,QAAQ,CACjB,YAAY,CAAE,OAAuB,CACvC,uBAAG,CACD,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,sBAA0B,CAClC,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,gBAAgB,CjBrCkB,OAAW,CiBsC7C,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,IAAI,CACrB,wDAAqB,CACnB,KAAK,CjBlH6B,OAAyB,CiBmH3D,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,OAA2C,CACpD,aAAa,CAAE,OAAW,CAE1B,oEAAO,CACL,UAAU,CAAE,qBAAoB,CAClC,0EAAQ,CACN,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,MAAM,CACd,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,aAAa,CAAE,CAAC,CAChB,SAAS,CAAE,IAAI,CACf,UAAU,CAAE,WAAa,CAEzB,oFAAQ,CACN,UAAU,CAAE,MAAM,CAGxB,gCAAM,CACJ,KAAK,CjBhE6B,OAAW,CiBiE/C,2BAAC,CACC,KAAK,CjBtG6B,OAAwB,CiBuG1D,iCAAO,CACL,gBAAgB,CjBpEgB,OAAW,CiBqE3C,KAAK,CjB3F2B,IAAM,CiB6F5C,gBAAgB,CjC9IR,kBAAoB,CAAE,gBAAM,CAK5B,eAAiB,CAAE,gBAAM,CAezB,UAAY,CAAE,gBAAM,CiC4H1B,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,CAAC,CACV,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,CAAC,CACV,4BAAa,CACX,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,CAAC,CACZ,0BAAW,CACT,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,KAAK,CACX,OAAO,CAAE,CAAC,CACZ,2BAAY,CACV,KAAK,CAAE,KAAK,CACZ,IAAI,CAAE,IAAI,CACV,OAAO,CAAE,CAAC,CAGd,gBAAgB,CACd,UAAU,CAAE,qBAAuC,CACnD,gBAAgB,CAAE,2uCAA2uC,CAC7vC,eAAe,CAAE,SAAsB,CAEzC,gBAAgB,CACd,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEd,YAAY,CACV,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,CAAC,CACN,IAAI,CAAE,CAAC,CACP,KAAK,CjBxG+B,KAAK,CiByGzC,QAAQ,CAAE,MAAM,CAChB,UAAU,CAAE,IAAI,CAChB,UAAU,CjB7GsB,OAAe,CiB8G/C,OAAO,CjBvG6B,GAAG,CiByGzC,WAAW,CACT,OAAO,CAAE,IAAI,CACb,UAAU,CjBjH0B,OAAW,CiBkH/C,KAAK,CjBxI+B,IAAM,CiByI1C,OAAO,CAAE,gBAAuB,CAChC,QAAQ,CAAE,QAAQ,CAClB,WAAW,CAAE,IAAI,CACjB,UAAU,CAAE,MAAM,CAClB,SAAS,CAAE,IAAI,C/BhGf,KAAK,CAAE,CAAC,CACR,oCAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,iBAAO,CACL,KAAK,CAAE,IAAI,C+B4Fb,aAAC,CACC,KAAK,CjBhJ6B,IAAM,CiBiJxC,WAAW,CAAE,IAAI,CAEnB,eAAG,CACD,YAAY,CAAE,IAAqB,CACnC,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,gBAAgB,CjBjIkB,OAAW,CiBkI7C,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,IAAI,CACrB,aAAC,CACC,SAAS,CAAE,IAAI,CACf,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,OAAO,CAEnB,oBAAoB,CAClB,WAAW,CjBzIyB,KAAK,CiB0IzC,UAAU,CjBpN0B,OAAyB,CiBqN7D,UAAU,CAAE,IAAI,CAElB,eAAe,CACb,OAAO,CAAE,eAAmB,CAC5B,MAAM,CAAE,IAAI,CACZ,SAAS,CAAE,KAAK,CAChB,MAAM,CAAE,IAAI,CAEd,aAAa,CACX,QAAQ,CAAE,KAAK,CACf,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,eAAc,CAC1B,OAAO,CAAE,IAAI,CACb,OAAO,CAAE,GAAkB,CAC3B,gBAAI,CACF,OAAO,CAAE,KAAK,CAClB,MAAM,CACJ,KAAK,CjBhO+B,IAAI,CiBiOxC,QAAC,CACC,aAAa,CAAE,IAAqB,CAExC,mBAAmB,C/B3IjB,KAAK,CAAE,CAAC,CACR,oDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,yBAAO,CACL,KAAK,CAAE,IAAI,C+ByIb,0BAAU,CACR,aAAa,CjBvNqB,IAAI,CiBwNtC,aAAa,CAAE,iBAA6B,CAC5C,cAAc,CjBzNoB,IAAI,CiB0NxC,sCAAsB,CACpB,UAAU,CAAE,iBAA6B,CACzC,WAAW,CjB5NuB,IAAI,CiB6NxC,4BAAY,CACV,SAAS,CAAE,IAAI,CACf,aAAa,CAAE,IAAqB,CACpC,OAAO,CAAE,YAAY,CACvB,wBAAQ,CACN,KAAK,CjBvN6B,IAAwB,CiBwN1D,SAAS,CAAE,GAAG,CdnOd,oCAAsB,CcuOxB,gBAAgB,CACd,UAAU,CjBjQwB,OAAyB,CiBkQ7D,WAAW,CACT,OAAO,CAAE,KAAK,CAChB,YAAY,CAER,IAAI,CAAE,MAAmB,CAG3B,kBAAO,CACL,KAAK,CAAE,GAAG,CACV,IAAI,CAAE,CAAC,CACX,oBAAoB,CAClB,WAAW,CAAE,CAAC,CACd,oCAAe,CACb,OAAO,CCpRD,OAAO,CDqRf,0BAAO,CACL,QAAQ,CAAE,KAAK,CACf,SAAS,CAAE,IAAI,CACf,IAAI,CAAE,GAAG,CACT,GAAG,CAAE,CAAC,CACN,MAAM,CAAE,IAAI,CACZ,QAAQ,CAAE,MAAM,Ed7PlB,qCAAsB,CcgQxB,oBAAoB,CAClB,UAAU,CAAE,gBAAe,CAC7B,eAAe,CACb,MAAM,CAAE,CAAC,CACT,UAAU,CjB7RwB,OAAyB,EiB+R/D,YAAY,CACV,iCAAmC,CACjC,OAAO,CAAE,IAAI,CACf,oBAAoB,CAClB,WAAW,CAAE,CAAC,EAElB,aAAa,CACX,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CACN,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,MAAM,CEjTpB,aAAa,CACX,QAAQ,CAAE,KAAK,CACf,MAAM,CAAE,CAAC,CACT,IAAI,CAAE,CAAC,CACP,KAAK,CnB6E+B,KAAK,CmB5EzC,KAAK,CnBE+B,OAAyB,CmBD7D,UAAU,CAAE,OAAkC,CAC9C,UAAU,CAAE,kBAAiC,CAC7C,WAAW,CjBAyB,uDAAM,CiBC1C,OAAO,CnB+E6B,GAAG,CmB9EvC,eAAC,CACC,KAAK,CnBqE6B,OAAW,CmBpE7C,eAAe,CAAE,IAAI,CACvB,8BAAgB,CACd,OAAO,CAAE,IAAI,CACf,kCAAoB,CAClB,OAAO,CAAE,IAAqB,CAC9B,gBAAgB,CAAE,OAAkC,CACpD,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,KAAK,CACjB,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,OAAO,CACf,KAAK,CnBiD6B,OAAM,CdgC1C,KAAK,CAAE,CAAC,CACR,kFAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,wCAAO,CACL,KAAK,CAAE,IAAI,CiCrFX,m4CAAG,CACD,KAAK,CnBlB2B,OAAyB,CmBmB3D,yFAAQ,CACN,KAAK,CAAE,IAAI,CACb,6CAAU,CACR,KAAK,CAAE,IAAI,CACb,kDAAiB,CACf,gBAAgB,CnBQgB,OAAI,CmBPpC,KAAK,CnB0B2B,IAAM,CmBzBxC,yDAAwB,CACtB,gBAAgB,CnBXgB,OAAO,CmBYvC,KAAK,CnBzB2B,IAAI,CmB0BxC,0CAA8B,CAC5B,OAAO,CAAE,KAAK,CAChB,iCAAmB,CACjB,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,IAAqB,CAC9B,KAAK,CnBE6B,IAAwB,CmBD1D,OAAO,CAAE,IAAI,CACb,oCAAE,CACA,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,CAAC,CACT,MAAM,CAAE,MAAM,CACd,OAAO,CAAE,CAAC,CACV,UAAU,CAAE,iBAA6C,CAC3D,oCAAE,CACA,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,CAAC,CACT,sCAAC,CACC,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,GAAqB,CAC9B,KAAK,CnBjDyB,OAAyB,CmBkD7D,uBAAW,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,IAAI,CACV,MAAM,CAAE,IAAI,CACZ,SAAS,CnBkByB,KAAK,CmBjBvC,kCAAU,CACR,KAAK,CAAE,IAAI,CACb,mEAAQ,CACN,KAAK,CAAE,IAAI,CACb,qDAA+B,CAC7B,UAAU,CAAE,KAAK,CACjB,+HAAQ,CACN,KAAK,CAAE,IAAI,CACb,gEAAU,CACR,KAAK,CAAE,IAAI,CACf,4CAAoB,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAuB,CAChC,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,ChBhDpB,oCAAsB,CgBmDxB,aAAa,CACX,KAAK,CAAE,GAAG,CACV,OAAO,CAAE,IAAI,CACb,mBAAO,CACL,OAAO,CAAE,KAAK,CAClB,GAAG,CACD,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,ECzEd,gBAAG,CACD,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,eAAe,CAEzB,uBAAU,CACR,aAAa,CpBUqB,IAAI,CoBRxC,oCAAuB,CACrB,UAAU,CAAE,MAAM,CAGpB,qDAAoC,CAClC,aAAa,CpBGqB,IAAI,CoBQxC,uBAAU,CACR,WAAW,CpBTuB,IAAI,CoBUtC,WAAW,CpBVuB,IAAI,CoBWtC,aAAa,CpBXqB,IAAI,CoBiBtC,kTAAK,CACH,aAAa,CAAE,CAAC,CAKlB,qCAAQ,CACN,YAAY,CAAE,GAAG,CAUrB,8BAAiB,CACf,YAAY,CAAE,eAAc,CAC5B,mEAAM,CACJ,UAAU,CAAE,sBAAsB,CAClC,YAAY,CAAE,0BAAyB,CAG3C,0EAAiD,CAC/C,UAAU,CAAE,WAAW,CACzB,0EAAiD,CAC/C,UAAU,CAAE,WAAW,CAGzB,qDAA4B,CAC1B,aAAa,CAAE,IAAqB,CACtC,wBAAW,CACT,WAAW,CpBlDuB,IAAI,CoBqDxC,yBAAY,CACV,WAAW,CAAE,IAAI,CACjB,aAAa,CAAE,IAAqB,CACtC,yBAAY,CACV,KAAK,ClBnF6B,OAAW,CkBoF/C,yBAAY,CACV,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,iBAA2C,CACrD,wBAAW,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,iBAA2C,CACrD,0BAAa,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,KAAK,CAId,sMAAW,CACT,OAAO,CAAE,IAAI,CACb,UAAU,CAAE,MAAM,CAClB,SAAS,CAAE,IAAI,CAEf,gPAAO,CACL,UAAU,CAAE,OAAO,CACnB,OAAO,CAAE,GAAO,CAChB,WAAW,CAAE,WAAW,CACxB,OAAO,CAAE,YAAY,CACzB,gPAAmB,CACjB,OAAO,CAAE,YAAY,CAGzB,qBAAQ,CACN,KAAK,CAAE,KAAK,CACZ,KAAK,CAAE,GAAG,CACV,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,aAAuC,CAC/C,OAAO,CpBzF2B,IAAI,CoB0FtC,UAAU,CpBlDwB,OAAmB,CoBmDrD,MAAM,CAAE,iBAA6B,CAErC,yEAAS,CACP,SAAS,CAAE,GAAG,CAChB,2BAAK,CACH,aAAa,CAAE,CAAC,CAClB,oCAAc,CACZ,OAAO,CAAE,KAAK,CACd,WAAW,ClB1HqB,0DAAa,CkB2H7C,WAAW,CAAE,IAAI,CACjB,UAAU,CpBjFsB,OAAmB,CoBkFnD,OAAO,CAAE,QAA2C,CACpD,MAAM,CAAE,KAAkB,CAC1B,aAAa,CpBxGmB,IAAI,CoByGpC,SAAS,CAAE,IAAI,CAEnB,yBAAY,CACV,UAAU,CpBrHwB,OAAO,CoBsHzC,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAuB,CAGlC,iEAAwC,CACtC,cAAc,CAAE,KAAK,CACrB,SAAS,CAAE,GAAG,CAIhB,yEAAgD,CAC9C,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,IAAI,CACZ,KAAK,CpB7I6B,IAAI,CoB8ItC,+JAAM,CACJ,MAAM,CAAE,IAAI,CACZ,gBAAgB,CAAE,sBAAsB,CACxC,WAAW,CAAE,MAAM,CACrB,2FAAQ,CACN,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAChB,cAAc,CAAE,GAAG,CAOvB,6BAAgB,CAEd,MAAM,CAAE,IAAI,CACZ,gCAAE,CACA,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,GAAG,CAClB,uCAAW,CACT,OAAO,CAAE,YAAY,CACrB,UAAU,CAAE,GAAG,CACjB,yCAAW,CACT,aAAa,CAAE,IAAI,CACnB,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,MAAM,CACrB,yCAAW,CACT,UAAU,CAAE,IAAI,CAChB,YAAY,CAAE,CAAC,CAGnB,eAAE,CAEA,KAAK,CpBpL6B,IAAI,CoBqLtC,OAAO,CAAE,YAAY,CACrB,sCAAO,CACL,SAAS,CAAE,eAAe,CAC1B,WAAW,CAAE,MAAM,CAErB,uCAAU,CACR,WAAW,CAAE,IAAI,CAErB,iBAAI,CACF,KAAK,CpBxH6B,OAAW,CoByH/C,eAAE,CACA,aAAa,CpB1KqB,IAAI,CoB2KtC,kBAAE,CACA,WAAW,CAAE,IAAI,CAEnB,6EAAgB,CACd,aAAa,CAAE,eAAgC,CAEjD,kBAAE,CACA,MAAM,CAAE,aAA4C,CAMxD,8BAAiB,CACf,aAAa,CpBzLqB,IAAI,CoB2LtC,iCAAE,CACA,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,KAAuB,CAC/B,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,OAAmB,CAC/B,KAAK,CpBjJ2B,OAAW,CoBkJ3C,UAAU,CAAE,iBAA6B,CACzC,OAAO,CAAE,GAAqB,CAC9B,QAAQ,CAAE,QAAQ,CAClB,wCAAQ,CACN,KAAK,CAAE,OAAmB,CAC5B,6CAAW,CACT,KAAK,ClBlOyB,OAAW,CkBmOzC,SAAS,CAAE,eAAe,CAE9B,oCAAK,CACH,aAAa,CAAE,GAAqB,CACpC,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,cAAuB,CACpC,UAAU,CAAE,OAAa,CACzB,KAAK,CpBrM2B,IAAwB,CoBsMxD,gDAAW,CACT,KAAK,ClB5OyB,OAAW,CkB6OzC,SAAS,CAAE,eAAe,CAC9B,6CAAc,CACZ,UAAU,CAAE,CAAC,CAEf,iCAAE,CACA,WAAW,CAAE,IAAI,CACjB,0FAA2B,CACzB,gBAAgB,CAAE,WAAW,CAC7B,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,CAAC,CACV,SAAS,CAAE,eAAe,CAC5B,0CAAU,CACR,WAAW,CAAE,IAAI,CAErB,wCAAS,CACP,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,KAAK,CACd,KAAK,CpB1P2B,IAAI,CoB2PpC,WAAW,CAAE,IAAI,CACnB,wCAAS,CACP,OAAO,CAAE,YAAY,CACrB,aAAa,CAAE,GAAG,CAEtB,uDAA8B,CAC5B,OAAO,CAAE,YAAY,CACrB,KAAK,CpBrM6B,OAAM,CoBsMxC,SAAS,CAAE,GAAG,CACd,YAAY,CpB9OsB,IAAI,CoB+OxC,2BAAc,CACZ,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,KAAK,CACd,qBAAQ,CACN,aAAa,CAAE,IAAI,CACnB,WAAW,CAAE,IAAI,CAEnB,mDAAa,CACX,UAAU,CAAE,OAAO,CACnB,OAAO,CAAE,OAAO,CAChB,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,KAAK,CAAE,OAAO,CACd,MAAM,CAAE,OAAO,CACf,WAAW,CAAE,OAAO,CAIlB,mGAAQ,CACN,YAAY,CAAE,GAAG,CjBlQrB,oCAAsB,CiBuQtB,qBAAQ,CACN,KAAK,CAAE,IAAI,ECxSjB,wBAAwB,CACtB,KAAK,CnBK+B,OAAW,CmBHjD,KAAK,CACH,UAAU,CAAE,MAAM,YCHlB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,qEAAoB,YAGzB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,yGAAyB,YAG9B,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,6FAAqB,YAG1B,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,oFAAkB,YAGvB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,gHAA4B,YAGjC,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,uGAAyB",
+"sources": ["../../../bower_components/neat/app/assets/stylesheets/grid/_grid.scss","../../../bower_components/bourbon/dist/addons/_prefixer.scss","../../../bower_components/wyrm/sass/wyrm_core/_reset.sass","../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/font-awesome/scss/_path.scss","../../../bower_components/font-awesome/scss/_core.scss","../../../bower_components/font-awesome/scss/_larger.scss","../../../bower_components/font-awesome/scss/_fixed-width.scss","../../../bower_components/font-awesome/scss/_list.scss","../../../bower_components/font-awesome/scss/_variables.scss","../../../bower_components/font-awesome/scss/_bordered-pulled.scss","../../../bower_components/font-awesome/scss/_spinning.scss","../../../bower_components/font-awesome/scss/_rotated-flipped.scss","../../../bower_components/font-awesome/scss/_mixins.scss","../../../bower_components/font-awesome/scss/_stacked.scss","../../../bower_components/font-awesome/scss/_icons.scss","../../../bower_components/wyrm/sass/wyrm_core/_font_icon_defaults.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../bower_components/wyrm/sass/wyrm_core/_alert.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss","../../../bower_components/wyrm/sass/wyrm_core/_button.sass","../../../bower_components/wyrm/sass/wyrm_core/_dropdown.sass","../../../bower_components/wyrm/sass/wyrm_core/_form.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_outer-container.scss","../../../bower_components/neat/app/assets/stylesheets/settings/_grid.scss","../../../bower_components/neat/app/assets/stylesheets/grid/_span-columns.scss","../../../bower_components/wyrm/sass/wyrm_core/_neat_extra.sass","../../../bower_components/wyrm/sass/wyrm_core/_generic.sass","../../../bower_components/wyrm/sass/wyrm_core/_table.sass","../../../bower_components/wyrm/sass/wyrm_core/_type.sass","../../../bower_components/wyrm/sass/wyrm_addons/pygments/_pygments.sass","../../../bower_components/wyrm/sass/wyrm_addons/pygments/_pygments_light.sass","../../../sass/_theme_breadcrumbs.sass","../../../sass/_theme_layout.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_private.scss","../../../sass/_theme_badge.sass","../../../sass/_theme_rst.sass","../../../sass/_theme_mathjax.sass","../../../sass/_theme_font_local.sass"],
+"names": [],
+"file": "theme.css"
+}
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg	(revision 942)
@@ -0,0 +1,414 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="fontawesomeregular" horiz-adv-x="1536" >
+<font-face units-per-em="1792" ascent="1536" descent="-256" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode=" "  horiz-adv-x="448" />
+<glyph unicode="&#x09;" horiz-adv-x="448" />
+<glyph unicode="&#xa0;" horiz-adv-x="448" />
+<glyph unicode="&#xa8;" horiz-adv-x="1792" />
+<glyph unicode="&#xa9;" horiz-adv-x="1792" />
+<glyph unicode="&#xae;" horiz-adv-x="1792" />
+<glyph unicode="&#xb4;" horiz-adv-x="1792" />
+<glyph unicode="&#xc6;" horiz-adv-x="1792" />
+<glyph unicode="&#x2000;" horiz-adv-x="768" />
+<glyph unicode="&#x2001;" />
+<glyph unicode="&#x2002;" horiz-adv-x="768" />
+<glyph unicode="&#x2003;" />
+<glyph unicode="&#x2004;" horiz-adv-x="512" />
+<glyph unicode="&#x2005;" horiz-adv-x="384" />
+<glyph unicode="&#x2006;" horiz-adv-x="256" />
+<glyph unicode="&#x2007;" horiz-adv-x="256" />
+<glyph unicode="&#x2008;" horiz-adv-x="192" />
+<glyph unicode="&#x2009;" horiz-adv-x="307" />
+<glyph unicode="&#x200a;" horiz-adv-x="85" />
+<glyph unicode="&#x202f;" horiz-adv-x="307" />
+<glyph unicode="&#x205f;" horiz-adv-x="384" />
+<glyph unicode="&#x2122;" horiz-adv-x="1792" />
+<glyph unicode="&#x221e;" horiz-adv-x="1792" />
+<glyph unicode="&#x2260;" horiz-adv-x="1792" />
+<glyph unicode="&#xe000;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
+<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
+<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
+<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
+<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+<glyph unicode="&#xf016;" horiz-adv-x="1280" d="M128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280zM768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z " />
+<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
+<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
+<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
+<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
+<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
+<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
+<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
+<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q73 -1 153.5 -2t119 -1.5t52.5 -0.5l29 2q-32 95 -92 241q-53 132 -92 211zM21 -128h-21l2 79q22 7 80 18q89 16 110 31q20 16 48 68l237 616l280 724h75h53l11 -21l205 -480q103 -242 124 -297q39 -102 96 -235q26 -58 65 -164q24 -67 65 -149 q22 -49 35 -57q22 -19 69 -23q47 -6 103 -27q6 -39 6 -57q0 -14 -1 -26q-80 0 -192 8q-93 8 -189 8q-79 0 -135 -2l-200 -11l-58 -2q0 45 4 78l131 28q56 13 68 23q12 12 12 27t-6 32l-47 114l-92 228l-450 2q-29 -65 -104 -274q-23 -64 -23 -84q0 -31 17 -43 q26 -21 103 -32q3 0 13.5 -2t30 -5t40.5 -6q1 -28 1 -58q0 -17 -2 -27q-66 0 -349 20l-48 -8q-81 -14 -167 -14z" />
+<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q76 -32 140 -32q131 0 216 41t122 113q38 70 38 181q0 114 -41 180q-58 94 -141 126q-80 32 -247 32q-74 0 -101 -10v-144l-1 -173l3 -270q0 -15 12 -44zM541 761q43 -7 109 -7q175 0 264 65t89 224q0 112 -85 187q-84 75 -255 75q-52 0 -130 -13q0 -44 2 -77 q7 -122 6 -279l-1 -98q0 -43 1 -77zM0 -128l2 94q45 9 68 12q77 12 123 31q17 27 21 51q9 66 9 194l-2 497q-5 256 -9 404q-1 87 -11 109q-1 4 -12 12q-18 12 -69 15q-30 2 -114 13l-4 83l260 6l380 13l45 1q5 0 14 0.5t14 0.5q1 0 21.5 -0.5t40.5 -0.5h74q88 0 191 -27 q43 -13 96 -39q57 -29 102 -76q44 -47 65 -104t21 -122q0 -70 -32 -128t-95 -105q-26 -20 -150 -77q177 -41 267 -146q92 -106 92 -236q0 -76 -29 -161q-21 -62 -71 -117q-66 -72 -140 -108q-73 -36 -203 -60q-82 -15 -198 -11l-197 4q-84 2 -298 -11q-33 -3 -272 -11z" />
+<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q4 1 77 20q76 19 116 39q29 37 41 101l27 139l56 268l12 64q8 44 17 84.5t16 67t12.5 46.5t9 30.5t3.5 11.5l29 157l16 63l22 135l8 50v38q-41 22 -144 28q-28 2 -38 4l19 103l317 -14q39 -2 73 -2q66 0 214 9q33 2 68 4.5t36 2.5q-2 -19 -6 -38 q-7 -29 -13 -51q-55 -19 -109 -31q-64 -16 -101 -31q-12 -31 -24 -88q-9 -44 -13 -82q-44 -199 -66 -306l-61 -311l-38 -158l-43 -235l-12 -45q-2 -7 1 -27q64 -15 119 -21q36 -5 66 -10q-1 -29 -7 -58q-7 -31 -9 -41q-18 0 -23 -1q-24 -2 -42 -2q-9 0 -28 3q-19 4 -145 17 l-198 2q-41 1 -174 -11q-74 -7 -98 -9z" />
+<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l215 -1h293l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -42.5 2t-103.5 -1t-111 -1 q-34 0 -67 -5q-10 -97 -8 -136l1 -152v-332l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-88 0 -233 -14q-48 -4 -70 -4q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q8 192 6 433l-5 428q-1 62 -0.5 118.5t0.5 102.5t-2 57t-6 15q-6 5 -14 6q-38 6 -148 6q-43 0 -100 -13.5t-73 -24.5q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1744 128q33 0 42 -18.5t-11 -44.5 l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80z" />
+<glyph unicode="&#xf035;" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l446 -1h318l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -58.5 2t-138.5 -1t-128 -1 q-94 0 -127 -5q-10 -97 -8 -136l1 -152v52l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-82 0 -233 -13q-45 -5 -70 -5q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q6 137 6 433l-5 44q0 265 -2 278q-2 11 -6 15q-6 5 -14 6q-38 6 -148 6q-50 0 -168.5 -14t-132.5 -24q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1505 113q26 -20 26 -49t-26 -49l-162 -126 q-26 -20 -44.5 -11t-18.5 42v80h-1024v-80q0 -33 -18.5 -42t-44.5 11l-162 126q-26 20 -26 49t26 49l162 126q26 20 44.5 11t18.5 -42v-80h1024v80q0 33 18.5 42t44.5 -11z" />
+<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
+<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
+<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
+<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
+<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
+<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
+<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
+<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
+<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+<glyph unicode="&#xf053;" horiz-adv-x="1152" d="M742 -37l-652 651q-37 37 -37 90.5t37 90.5l652 651q37 37 90.5 37t90.5 -37l75 -75q37 -37 37 -90.5t-37 -90.5l-486 -486l486 -485q37 -38 37 -91t-37 -90l-75 -75q-37 -37 -90.5 -37t-90.5 37z" />
+<glyph unicode="&#xf054;" horiz-adv-x="1152" d="M1099 704q0 -52 -37 -91l-652 -651q-37 -37 -90 -37t-90 37l-76 75q-37 39 -37 91q0 53 37 90l486 486l-486 485q-37 39 -37 91q0 53 37 90l76 75q36 38 90 38t90 -38l652 -651q37 -37 37 -90z" />
+<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
+<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
+<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
+<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
+<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
+<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
+<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf077;" horiz-adv-x="1664" d="M1611 320q0 -53 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-486 485l-486 -485q-36 -38 -90 -38t-90 38l-75 75q-38 36 -38 90q0 53 38 91l651 651q37 37 90 37q52 0 91 -37l650 -651q38 -38 38 -91z" />
+<glyph unicode="&#xf078;" horiz-adv-x="1664" d="M1611 832q0 -53 -37 -90l-651 -651q-38 -38 -91 -38q-54 0 -90 38l-651 651q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l486 -486l486 486q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
+<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf080;" horiz-adv-x="1920" d="M512 512v-384h-256v384h256zM896 1024v-896h-256v896h256zM1280 768v-640h-256v640h256zM1664 1152v-1024h-256v1024h256zM1792 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5z M1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf082;" d="M1307 618l23 219h-198v109q0 49 15.5 68.5t71.5 19.5h110v219h-175q-152 0 -218 -72t-66 -213v-131h-131v-219h131v-635h262v635h175zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
+<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
+<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
+<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
+<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
+<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
+<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
+<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
+<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
+<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+<glyph unicode="&#xf09a;" horiz-adv-x="768" d="M511 980h257l-30 -284h-227v-824h-341v824h-170v284h170v171q0 182 86 275.5t283 93.5h227v-284h-142q-39 0 -62.5 -6.5t-34 -23.5t-13.5 -34.5t-3 -49.5v-142z" />
+<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
+<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
+<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+<glyph unicode="&#xf0a2;" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM183 128h1298q-164 181 -246.5 411.5t-82.5 484.5q0 256 -320 256t-320 -256q0 -254 -82.5 -484.5t-246.5 -411.5zM1664 128q0 -52 -38 -90t-90 -38 h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
+<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
+<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
+<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
+<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
+<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
+<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
+<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
+<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
+<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
+<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
+<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
+<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
+<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
+<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf0d4;" d="M678 -57q0 -38 -10 -71h-380q-95 0 -171.5 56.5t-103.5 147.5q24 45 69 77.5t100 49.5t107 24t107 7q32 0 49 -2q6 -4 30.5 -21t33 -23t31 -23t32 -25.5t27.5 -25.5t26.5 -29.5t21 -30.5t17.5 -34.5t9.5 -36t4.5 -40.5zM385 294q-234 -7 -385 -85v433q103 -118 273 -118 q32 0 70 5q-21 -61 -21 -86q0 -67 63 -149zM558 805q0 -100 -43.5 -160.5t-140.5 -60.5q-51 0 -97 26t-78 67.5t-56 93.5t-35.5 104t-11.5 99q0 96 51.5 165t144.5 69q66 0 119 -41t84 -104t47 -130t16 -128zM1536 896v-736q0 -119 -84.5 -203.5t-203.5 -84.5h-468 q39 73 39 157q0 66 -22 122.5t-55.5 93t-72 71t-72 59.5t-55.5 54.5t-22 59.5q0 36 23 68t56 61.5t65.5 64.5t55.5 93t23 131t-26.5 145.5t-75.5 118.5q-6 6 -14 11t-12.5 7.5t-10 9.5t-10.5 17h135l135 64h-437q-138 0 -244.5 -38.5t-182.5 -133.5q0 126 81 213t207 87h960 q119 0 203.5 -84.5t84.5 -203.5v-96h-256v256h-128v-256h-256v-128h256v-256h128v256h256z" />
+<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M876 71q0 21 -4.5 40.5t-9.5 36t-17.5 34.5t-21 30.5t-26.5 29.5t-27.5 25.5t-32 25.5t-31 23t-33 23t-30.5 21q-17 2 -50 2q-54 0 -106 -7t-108 -25t-98 -46t-69 -75t-27 -107q0 -68 35.5 -121.5t93 -84t120.5 -45.5t127 -15q59 0 112.5 12.5t100.5 39t74.5 73.5 t27.5 110zM756 933q0 60 -16.5 127.5t-47 130.5t-84 104t-119.5 41q-93 0 -144 -69t-51 -165q0 -47 11.5 -99t35.5 -104t56 -93.5t78 -67.5t97 -26q97 0 140.5 60.5t43.5 160.5zM625 1408h437l-135 -79h-135q71 -45 110 -126t39 -169q0 -74 -23 -131.5t-56 -92.5t-66 -64.5 t-56 -61t-23 -67.5q0 -26 16.5 -51t43 -48t58.5 -48t64 -55.5t58.5 -66t43 -85t16.5 -106.5q0 -160 -140 -282q-152 -131 -420 -131q-59 0 -119.5 10t-122 33.5t-108.5 58t-77 89t-30 121.5q0 61 37 135q32 64 96 110.5t145 71t155 36t150 13.5q-64 83 -64 149q0 12 2 23.5 t5 19.5t8 21.5t7 21.5q-40 -5 -70 -5q-149 0 -255.5 98t-106.5 246q0 140 95 250.5t234 141.5q94 20 187 20zM1664 1152v-128h-256v-256h-128v256h-256v128h256v256h128v-256h256z" />
+<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
+<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
+<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
+<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
+<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
+<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
+<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
+<glyph unicode="&#xf0f3;" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1664 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5 q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
+<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f6;" horiz-adv-x="1280" d="M1024 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1024 608v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280z M768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
+<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf110;" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" />
+<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
+<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
+<glyph unicode="&#xf116;" horiz-adv-x="1792" />
+<glyph unicode="&#xf117;" horiz-adv-x="1792" />
+<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
+<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
+<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
+<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
+<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
+<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
+<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
+<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
+<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
+<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
+<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
+<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
+<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
+<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
+<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
+<glyph unicode="&#xf15b;" horiz-adv-x="1280" d="M1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
+<glyph unicode="&#xf15c;" horiz-adv-x="1280" d="M1024 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1024 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28 t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
+<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
+<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
+<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
+<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
+<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
+<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
+<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
+<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
+<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
+<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
+<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
+<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
+<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M390 1408h219v-388h364v-241h-364v-394q0 -136 14 -172q13 -37 52 -60q50 -31 117 -31q117 0 232 76v-242q-102 -48 -178 -65q-77 -19 -173 -19q-105 0 -186 27q-78 25 -138 75q-58 51 -79 105q-22 54 -22 161v539h-170v217q91 30 155 84q64 55 103 132q39 78 54 196z " />
+<glyph unicode="&#xf174;" d="M1123 127v181q-88 -56 -174 -56q-51 0 -88 23q-29 17 -39 45q-11 30 -11 129v295h274v181h-274v291h-164q-11 -90 -40 -147t-78 -99q-48 -40 -116 -63v-163h127v-404q0 -78 17 -121q17 -42 59 -78q43 -37 104 -57q62 -20 140 -20q67 0 129 14q57 13 134 49zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
+<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
+<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
+<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
+<glyph unicode="&#xf180;" horiz-adv-x="1664" d="M1483 512l-587 -587q-52 -53 -127.5 -53t-128.5 53l-587 587q-53 53 -53 128t53 128l587 587q53 53 128 53t128 -53l265 -265l-398 -399l-188 188q-42 42 -99 42q-59 0 -100 -41l-120 -121q-42 -40 -42 -99q0 -58 42 -100l406 -408q30 -28 67 -37l6 -4h28q60 0 99 41 l619 619l2 -3q53 -53 53 -128t-53 -128zM1406 1138l120 -120q14 -15 14 -36t-14 -36l-730 -730q-17 -15 -37 -15v0q-4 0 -6 1q-18 2 -30 14l-407 408q-14 15 -14 36t14 35l121 120q13 15 35 15t36 -15l252 -252l574 575q15 15 36 15t36 -15z" />
+<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
+<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
+<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
+<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
+<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
+<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
+<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
+<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf197;" horiz-adv-x="1792" />
+<glyph unicode="&#xf198;" horiz-adv-x="1792" />
+<glyph unicode="&#xf199;" horiz-adv-x="1792" />
+<glyph unicode="&#xf19a;" horiz-adv-x="1792" />
+<glyph unicode="&#xf19b;" horiz-adv-x="1792" />
+<glyph unicode="&#xf19c;" horiz-adv-x="1792" />
+<glyph unicode="&#xf19d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf19e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf500;" horiz-adv-x="1792" />
+</font>
+</defs></svg> 
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/js/modernizr.min.js
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/js/modernizr.min.js	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/js/modernizr.min.js	(revision 942)
@@ -0,0 +1,4 @@
+/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
+ * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load
+ */
+;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d<e;d++)u[c[d]]=c[d]in k;return u.list&&(u.list=!!b.createElement("datalist")&&!!a.HTMLDataListElement),u}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),e.inputtypes=function(a){for(var d=0,e,f,h,i=a.length;d<i;d++)k.setAttribute("type",f=a[d]),e=k.type!=="text",e&&(k.value=l,k.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(f)&&k.style.WebkitAppearance!==c?(g.appendChild(k),h=b.defaultView,e=h.getComputedStyle&&h.getComputedStyle(k,null).WebkitAppearance!=="textfield"&&k.offsetHeight!==0,g.removeChild(k)):/^(search|tel)$/.test(f)||(/^(url|email)$/.test(f)?e=k.checkValidity&&k.checkValidity()===!1:e=k.value!=l)),t[a[d]]=!!e;return t}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var d="2.6.2",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k=b.createElement("input"),l=":)",m={}.toString,n=" -webkit- -moz- -o- -ms- ".split(" "),o="Webkit Moz O ms",p=o.split(" "),q=o.toLowerCase().split(" "),r={svg:"http://www.w3.org/2000/svg"},s={},t={},u={},v=[],w=v.slice,x,y=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["&#173;",'<style id="s',h,'">',a,"</style>"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="<svg/>",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e<g;e++)d.createElement(f[e]);return d}function p(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return r.shivMethods?n(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+l().join().replace(/\w+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(r,b.frag)}function q(a){a||(a=b);var c=m(a);return r.shivCSS&&!f&&!c.hasCSS&&(c.hasCSS=!!k(a,"article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}")),j||p(a,c),a}var c=a.html5||{},d=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,e=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,f,g="_html5shiv",h=0,i={},j;(function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,h){var i=b(a),j=i.autoCallback;i.url.split(".").pop().split("?").shift(),i.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]),i.instead?i.instead(a,e,f,g,h):(y[i.url]?i.noexec=!0:y[i.url]=1,f.load(i.url,i.forceCSS||!i.forceJS&&"css"==i.url.split(".").pop().split("?").shift()?"c":c,i.noexec,i.attrs,i.timeout),(d(e)||d(j))&&f.load(function(){k(),e&&e(i.origUrl,h,g),j&&j(i.origUrl,h,g),y[i.url]=2})))}function h(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var i,j,l=this.yepnope.loader;if(e(a))g(a,0,l,0);else if(w(a))for(i=0;i<a.length;i++)j=a[i],e(j)?g(j,0,l,0):w(j)?B(j):Object(j)===j&&h(j,l);else Object(a)===a&&h(a,l)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,null==b.readyState&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}}(this,document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))};
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/js/theme.js
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/js/theme.js	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/static/js/theme.js	(revision 942)
@@ -0,0 +1,50 @@
+$( document ).ready(function() {
+    // Shift nav in mobile when clicking the menu.
+    $(document).on('click', "[data-toggle='wy-nav-top']", function() {
+      $("[data-toggle='wy-nav-shift']").toggleClass("shift");
+      $("[data-toggle='rst-versions']").toggleClass("shift");
+    });
+    // Close menu when you click a link.
+    $(document).on('click', ".wy-menu-vertical .current ul li a", function() {
+      $("[data-toggle='wy-nav-shift']").removeClass("shift");
+      $("[data-toggle='rst-versions']").toggleClass("shift");
+    });
+    $(document).on('click', "[data-toggle='rst-current-version']", function() {
+      $("[data-toggle='rst-versions']").toggleClass("shift-up");
+    });  
+    // Make tables responsive
+    $("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
+});
+
+window.SphinxRtdTheme = (function (jquery) {
+    var stickyNav = (function () {
+        var navBar,
+            win,
+            stickyNavCssClass = 'stickynav',
+            winScroll = false,
+            enable = function () {
+                navBar.addClass(stickyNavCssClass);
+                win.on('scroll', function() { // set flag on scroll event
+                    winScroll = true;
+                });
+                // use setInterval to only handle a subset of scroll events so we don't kill scroll performance
+                setInterval(function() {
+                    if (winScroll) {
+                        winScroll = false;
+                        navBar.scrollTop(win.scrollTop());
+                    }
+                }, 100);
+            },
+            init = function () {
+                navBar = jquery('nav.wy-nav-side:first');
+                win    = jquery(window);
+            };
+        jquery(init);
+        return {
+            enable : enable
+        };
+    }());
+    return {
+        StickyNav : stickyNav
+    };
+}($));
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/theme.conf
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/theme.conf	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/theme.conf	(revision 942)
@@ -0,0 +1,9 @@
+[theme]
+inherit = basic
+stylesheet = css/theme.css
+
+[options]
+typekit_id = hiw1hhg
+analytics_id = 
+sticky_navigation = False
+logo_only =
Index: /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/versions.html
===================================================================
--- /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/versions.html	(revision 942)
+++ /tags/rel-1.7.0/docs/_themes/sphinx_rtd_theme/versions.html	(revision 942)
@@ -0,0 +1,37 @@
+{% if READTHEDOCS %}
+{# Add rst-badge after rst-versions for small badge style. #}
+  <div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions">
+    <span class="rst-current-version" data-toggle="rst-current-version">
+      <span class="fa fa-book"> Read the Docs</span>
+      v: {{ current_version }}
+      <span class="fa fa-caret-down"></span>
+    </span>
+    <div class="rst-other-versions">
+      <dl>
+        <dt>Versions</dt>
+        {% for slug, url in versions %}
+          <dd><a href="{{ url }}">{{ slug }}</a></dd>
+        {% endfor %}
+      </dl>
+      <dl>
+        <dt>Downloads</dt>
+        {% for type, url in downloads %}
+          <dd><a href="{{ url }}">{{ type }}</a></dd>
+        {% endfor %}
+      </dl>
+      <dl>
+        <dt>On Read the Docs</dt>
+          <dd>
+            <a href="//{{ PRODUCTION_DOMAIN }}/projects/{{ slug }}/?fromdocs={{ slug }}">Project Home</a>
+          </dd>
+          <dd>
+            <a href="//{{ PRODUCTION_DOMAIN }}/builds/{{ slug }}/?fromdocs={{ slug }}">Builds</a>
+          </dd>
+      </dl>
+      <hr/>
+      Free document hosting provided by <a href="http://www.readthedocs.org">Read the Docs</a>.
+
+    </div>
+  </div>
+{% endif %}
+
Index: /tags/rel-1.7.0/docs/api/classes.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/classes.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/classes.rst	(revision 942)
@@ -0,0 +1,14 @@
+.. _api-classes:
+
+ZOO-API Classes
+=============
+
+The following classes are available in the ZOO API:
+
+.. toctree::
+   :maxdepth: 2
+   
+   zoo 
+   zoo-format-wps  
+   zoo-process   
+   zoo-request
Index: /tags/rel-1.7.0/docs/api/description.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/description.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/description.rst	(revision 942)
@@ -0,0 +1,19 @@
+.. _api-what:
+
+What is ZOO-API ?
+==============
+
+ZOO-API is a server-side JavaScript library designed to make the WPS Process creation and chaining 
+easier. It works on the server-side using the Mozilla foundation `JavaScript <https://developer.mozilla.org/en/JavaScript>`__
+engine,  `SpiderMonkey <https://developer.mozilla.org/en/SpiderMonkey>`__. 
+It uses a  `Proj4js <http://proj4js.org/>`__ adaptation for server-side reprojection. It also allows to easily 
+convert vector formats (such as `GML <http://www.opengeospatial.org/standards/gml>`__,  `KML <http://www.opengeospatial.org/standards/kml>`__,  
+`GeoJSON <http://geojson.org/geojson-spec.html>`__, etc). The API lets you orchestrate WPS 
+services simply and offers the ability to add logic and controls in the WPS chaining.
+
+
+Server-side JavaScript WPS
+---------------------
+
+
+
Index: /tags/rel-1.7.0/docs/api/examples.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/examples.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/examples.rst	(revision 942)
@@ -0,0 +1,53 @@
+.. _api-examples:
+
+Examples
+========
+
+This section gathers sample scripts using :ref:`ZOO-API <api-what>`, the `ZOO-Project <http://zoo-project.org>`__ server-side JavaScript API.
+
+ZOO-API contains many classes and functions. You can find the description list :ref:`here <api-classes>`.
+
+ZOO.Process example
+--------------------------
+
+::
+
+  function SampleService(conf,inputs,outputs){
+     var myProcess = new ZOO.Process('http://localhost/cgi-bin-new1/zoo_loader_new1.cgi','Boundary');
+     var myInputs = {InputPolygon: { type: 'complex', value: '{"type":"Polygon","coordinates":[[[-106.993853,35.998758],[-107.407233,35.997524],[-107.430525,35.997726],[-107.4824,35.99878],[-108.37013,35.999472],[-109.043633,35.996652],[-109.096265,35.997817],[-109.148763,36.001751],[-109.200981,36.008442],[-109.252775,36.017871],[-109.304,36.030014],[-109.354516,36.044835],[-106.468201,35.991497],[-106.855511,35.989504],[-106.90933,35.990676],[-106.963008,35.994743],[-106.993853,35.998758]]]}', mimeType: "application/json"} };
+     var myExecuteResult=myProcess.Execute(myInputs);
+     return {result: ZOO.SERVICE_SUCCEEDED, outputs: [ {name:"Result", value: myExecuteResult} ] };
+  }
+
+In this really short example you can see how to create ``ZOO.Process`` class instance and 
+call the Execute method on such an instance. Then you'll just need to return a JavaScript 
+object containing the attributes result and outputs, which I'm sure you already know 
+what is about. The first is about the status of the process (can be ``ZOO.SERVICE_SUCEEDED``,
+``ZOO.SERVICE_FAILED`` and so on), the last is obviously the resulting maps (take a 
+look at the maps internal data structure used by ZOO Kernel in ``service.h``).
+
+ZOO.UpdateStatus example
+-----------------------
+
+::
+
+  function SampleLongService(conf,inputs,outputs){
+     var my_i=0;
+     while(my_i<100){
+         try{
+           conf["lenv"]["status"]=my_i;
+         }
+         catch(e){
+         }
+         ZOOUpdateStatus(conf,my_i);
+         SampleService(conf,inputs,outputs);
+         my_i+=10;
+     }
+     return SampleService(conf,inputs,outputs);
+  }
+
+You can see in this sample code how to use the ``ZOOUpdateStatus`` function to update the 
+current status of your running process. This information will be really helpfull when the 
+ZOO Kernel will run your JavaScript Service in background mode (if the user set to ``true`` 
+the ``storeExecuteResponse`` parameter in his request).
+
Index: /tags/rel-1.7.0/docs/api/howto.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/howto.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/howto.rst	(revision 942)
@@ -0,0 +1,42 @@
+.. _api-howto:
+
+Using ZOO-API
+==================
+
+This section will help you to get started using :ref:`ZOO-API<api-what>`.
+
+Prerequisites
+----------------------
+
+ZOO-API relies on the following software:
+
+- :ref:`kernel_index` (`http://zoo-project.org
+  <http://zoo-project.org>`__), the ZOO-Project WPS Server.
+- SpiderMonkey (`https://developer.mozilla.org/en/SpiderMonkey
+  <https://developer.mozilla.org/en/SpiderMonkey>`__ ), the Mozilla
+  `JavaScript <https://developer.mozilla.org/en/JavaScript>`__ engine.
+
+
+.. warning::
+
+     The ZOO-Kernel  :ref:`optional JavaScript support <js-support>` is required for using ZOO-API
+
+     
+Download
+-----------------------
+
+    * `zoo-api.js <http://zoo-project.org/trac/export/1/trunk/zoo-api/js/ZOO-api.js>`__
+    * `zoo-proj4js.js <http://zoo-project.org/trac/export/1/trunk/zoo-api/js/ZOO-proj4js.js>`__
+
+
+      
+If you did not :ref:`download <install-download>` the ZOO-Project
+source code already, please proceed to a svn checkout with the
+following command:
+
+::
+
+  svn checkout http://svn.zoo-project.org/svn/trunk/zoo-project/zoo-api
+
+
+
Index: /tags/rel-1.7.0/docs/api/index.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/index.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/index.rst	(revision 942)
@@ -0,0 +1,17 @@
+.. _api-index:
+
+ZOO-API 
+=====================
+
+
+This section provides information on **ZOO-API**, the `ZOO-Project
+<http://zoo-project.org>`__ server-side JavaScript API.
+
+.. toctree::
+   :maxdepth: 2
+   
+   what
+   howto
+   classes
+   examples
+
Index: /tags/rel-1.7.0/docs/api/what.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/what.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/what.rst	(revision 942)
@@ -0,0 +1,16 @@
+.. _api-what:
+
+What is ZOO-API ?
+==============
+
+ZOO-API is a server-side Javascript library for creating and chaining :ref:`services_index`. It lets you script on the server-side to execute WPS *Processes*, and thus to use common JavaScript controls and logic for WPS chaining.
+
+
+Server-side JavaScript WPS
+---------------------
+
+ZOO-API  :ref:`js-support`  works on the server-side using the Mozilla foundation `JavaScript <https://developer.mozilla.org/en/JavaScript>`__
+engine,  `SpiderMonkey <https://developer.mozilla.org/en/SpiderMonkey>`__. 
+It uses a  `Proj4js <http://proj4js.org/>`__ adaptation for server-side reprojection. It also allows to easily 
+convert vector formats (such as `GML <http://www.opengeospatial.org/standards/gml>`__,  `KML <http://www.opengeospatial.org/standards/kml>`__,  
+`GeoJSON <http://geojson.org/geojson-spec.html>`__, etc).
Index: /tags/rel-1.7.0/docs/api/zoo-bounds.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-bounds.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-bounds.txt	(revision 942)
@@ -0,0 +1,254 @@
+.. _api-zoo-bounds:
+
+ZOO.Bounds
+==========
+
+Instances of this class represent bounding boxes.
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`left <left>`
+     - {Number} Minimum horizontal coordinate.
+   * - :ref:`bottom <bottom>`
+     - {Number} Minimum vertical coordinate. 
+   * - :ref:`right <right>` 
+     - {Number} Maximum horizontal coordinate.
+   * - :ref:`top <top>`
+     - {Number} Maximum vertical coordinate.   
+     
+Functions
+---------  
+
+.. list-table::
+   :widths: 20 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Bounds <ZOO.Bounds>`
+     - Construct a new bounds object.
+   * - :ref:`clone <clone>`
+     - Create a cloned instance of this bounds.
+   * - :ref:`equals <equals>` 
+     - Test a two bounds for equivalence.
+   * - :ref:`toString <toString>`
+     - {String} String representation of bounds object.
+   * - :ref:`toBBOX <toBBOX>`
+     - 
+   * - :ref:`toGeometry <toGeometry>`
+     - Create a new polygon geometry based on this bounds.
+   * - :ref:`getWidth <getWidth>` 
+     - {Float} The width of the bounds
+   * - :ref:`getHeight <getHeight>`
+     - {Float} The height of the bounds (top minus bottom)  
+   * - :ref:`add <add>`
+     - 
+   * - :ref:`extend <extend>`
+     - Extend the bounds to include the point, lonlat, or bounds specified.
+   * - :ref:`intersectsBounds <intersectsBounds>` 
+     - Determine whether the target bounds intersects this bounds.
+   * - :ref:`containsBounds <containsBounds>`
+     - Determine whether the target bounds is contained within this bounds.     
+
+**Properties**
+   
+.. _left:   
+   
+left	
+  ``{Number}`` Minimum horizontal coordinate.
+  
+.. _bottom:     
+  
+bottom	
+  ``{Number}`` Minimum vertical coordinate.
+
+.. _right:     
+
+right	
+  ``{Number}`` Maximum horizontal coordinate.
+
+.. _top:     
+
+top	
+  ``{Number}`` Maximum vertical coordinate.
+
+**Functions**
+
+.. _ZOO.Bounds:     
+
+ZOO.Bounds	
+  Construct a new bounds object.
+  
+  *Parameters*
+
+  | ``left {Number}`` The left bounds of the box.  Note that for width calculations, this is assumed to be less than the right value.
+  | ``bottom {Number}`` The bottom bounds of the box.  Note that for height calculations, this is assumed to be more than the top value.
+  | ``right {Number}`` The right bounds.
+  | ``top {Number}`` The top bounds.  
+  
+.. _clone:       
+
+clone	
+  ::
+  
+    clone:function()
+
+  Create a cloned instance of this bounds.
+
+  *Returns*
+
+  :ref:`{ZOO.Bounds} <api-zoo-bounds>` A fresh copy of the bounds
+
+.. _equals:       
+
+equals	
+  ::
+  
+    equals:function(bounds)
+
+  Test a two bounds for equivalence.
+
+  *Parameters*
+  
+  | ``bounds {ZOO.Bounds}``
+  
+  *Returns*
+
+  ``{Boolean}`` The passed-in bounds object has the same left, right, top, bottom components as this.  Note 
+  that if bounds passed in is null, returns false.
+
+.. _toString: 
+
+toString	
+  :: 
+  
+    toString:function()
+
+  *Returns*
+
+  ``{String}`` String representation of bounds object.  (ex. *<i>"left-bottom=(5,42) right-top=(10,45)"</i>*)
+  
+.. _toBBOX:   
+  
+toBBOX	
+  ::
+  
+    toBBOX:function(decimal)
+
+  *Parameters*
+  
+  ``decimal {Integer}`` How many significant digits in the bbox coords?  Default is 6
+
+  *Returns*
+
+  ``{String}`` Simple String representation of bounds object.  (ex. *<i>"5,42,10,45"</i>*)  
+
+.. _toGeometry:   
+
+toGeometry	
+  ::
+  
+    toGeometry: function()
+
+  Create a new polygon geometry based on this bounds.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A new polygon with the coordinates of this bounds.
+  
+.. _getWidth:     
+
+getWidth	
+  ::    
+  
+    getWidth:function()
+
+  *Returns*
+
+  ``{Float}`` The width of the bounds
+  
+.. _getHeight:       
+  
+getHeight	
+  ::
+  
+    getHeight:function()
+
+  *Returns*
+
+  ``{Float}`` The height of the bounds (top minus bottom).
+
+.. _add:       
+
+add
+  ::
+  
+    add:function(x,y)
+
+  *Parameters*
+
+  | ``x	{Float}``
+  | ``y	{Float}``
+
+  *Returns*
+
+  :ref:`{ZOO.Bounds} <api-zoo-bounds>` A new bounds whose coordinates are the same as this, but shifted by the passed-in x and y values.
+
+.. _extend:       
+
+extend	
+  ::
+  
+    extend:function(object)
+
+  Extend the bounds to include the point, lonlat, or bounds specified.  Note, this function assumes that left 
+  < right and bottom < top.
+  
+  *Parameters*
+  
+  ``object {Object}`` Can be Point, or Bounds.
+  
+.. _intersectsBounds:         
+  
+intersectsBounds	
+  ::
+  
+    intersectsBounds:function(bounds,inclusive)
+
+  Determine whether the target bounds intersects this bounds.  Bounds are considered intersecting if any 
+  of their edges intersect or if one bounds contains the other.
+
+  *Parameters*
+  
+  | ``bounds`` :ref:`{ZOO.Bounds} <api-zoo-bounds>` The target bounds.
+  | ``inclusive	{Boolean}`` Treat coincident borders as intersecting.  Default is true.  If false, bounds that do not overlap but only touch at the border will not be considered as intersecting.
+
+  *Returns*
+
+  ``{Boolean}`` The passed-in bounds object intersects this bounds.
+ 
+.. _containsBounds:          
+ 
+containsBounds	
+  ::
+  
+    containsBounds:function(bounds,partial,inclusive)
+
+  Determine whether the target bounds is contained within this bounds.
+
+  *Parameters*
+  
+  | ``bounds`` :ref:`{ZOO.Bounds} <api-zoo-bounds>` The target bounds.
+  | ``partial {Boolean}`` If any of the target corners is within this bounds consider the bounds contained.  Default is false.  If true, the entire target bounds must be contained within this bounds.
+  | ``inclusive	{Boolean}`` Treat shared edges as contained.  Default is true.
+
+  *Returns*
+
+  ``{Boolean}`` The passed-in bounds object is contained within this bounds.
Index: /tags/rel-1.7.0/docs/api/zoo-feature.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-feature.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-feature.txt	(revision 942)
@@ -0,0 +1,107 @@
+.. _api-zoo-feature:
+
+ZOO.Feature
+===========
+
+Vector features use the ZOO.Geometry classes as geometry description.
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`fid <fid>`
+     - {String}
+   * - :ref:`geometry <geometry>`
+     - {ZOO.Geometry}
+   * - :ref:`attributes <attributes>`
+     - {Object} This object holds arbitrary properties that describe the feature.
+   * - :ref:`bounds <bounds>`
+     - {ZOO.Bounds} The box bounding that feature's geometry, that property can be set by an ZOO.Format object when deserializing the feature, so in most cases it represents an information set by the server.
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Feature <ZOO.Feature>`
+     - Create a vector feature.
+   * - :ref:`destroy <destroy>`
+     - nullify references to prevent circular references and memory leaks
+   * - :ref:`clone <clone>`
+     - Create a clone of this vector feature.
+   * - :ref:`move <move>`
+     - Moves the feature and redraws it at its new location
+   
+     
+**Properties**
+       
+.. _fid: 
+
+fid	
+  ``{String}``
+  
+.. _geometry:   
+  
+geometry	
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+  
+.. _attributes:     
+  
+attributes	
+  ``{Object}`` This object holds arbitrary properties that describe the feature.
+  
+.. _bounds:       
+  
+bounds	
+  :ref:`{ZOO.Bounds} <api-zoo-bounds>` The box bounding that feature's geometry, that 
+  property can be set by an ZOO.Format object when deserializing the feature, so in most cases 
+  it represents an information set by the server.
+
+**Functions**
+       
+.. _ZOO.Feature: 
+
+ZOO.Feature
+  Create a vector feature.
+
+
+  *Parameters*
+  
+  | ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` The geometry that this feature represents.
+  | ``attributes {Object}`` An optional object that will be mapped to the attributes property. 
+  
+.. _destroy:   
+  
+destroy	
+  ::
+  
+    destroy: function()
+
+  nullify references to prevent circular references and memory leaks  
+  
+.. _clone:     
+  
+clone	
+  ::
+  
+    clone: function ()
+
+  Create a clone of this vector feature.  Does not set any non-standard properties.
+
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` An exact clone of this vector feature.  
+  
+.. _move:       
+  
+move	
+  Moves the feature and redraws it at its new location
Index: /tags/rel-1.7.0/docs/api/zoo-format-geojson.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-format-geojson.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-format-geojson.txt	(revision 942)
@@ -0,0 +1,455 @@
+.. _api-zoo-format-geojson:
+
+ZOO.Format.GeoJSON
+==================
+
+Read and write GeoJSON.
+
+Inherits from
+
+- :ref:`ZOO.Format.JSON <api-zoo-format-json>`
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 20 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Format.GeoJSON <ZOO.Format.GeoJSON>`
+     - Create a new parser for GeoJSON.
+   * - :ref:`read <read>`
+     - Deserialize a GeoJSON string.
+   * - :ref:`isValidType <isValidType>`
+     - Check if a GeoJSON object is a valid representative of the given type.
+   * - :ref:`parseFeature <parseFeature>`
+     - Convert a feature object from GeoJSON into an ZOO.Feature. 
+   * - :ref:`parseGeometry <parseGeometry>`
+     - Convert a geometry object from GeoJSON into an ZOO.Geometry.   
+     
+parseCoords Properties	
+----------------------
+
+.. list-table::
+   :widths: 20 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`parseCoords <parseCoords>`
+     - Object with properties corresponding to the GeoJSON geometry types.  
+     
+parseCoords Functions	
+---------------------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`parseCoords.point <parseCoords.point>`
+     - Convert a coordinate array from GeoJSON into an ZOO.Geometry.Point.
+   * - :ref:`parseCoords.multipoint <parseCoords.multipoint>`
+     - Convert a coordinate array from GeoJSON into an ZOO.Geometry.MultiPoint.
+   * - :ref:`parseCoords.linestring <parseCoords.linestring>`
+     - Convert a coordinate array from GeoJSON into an ZOO.Geometry.LineString.
+   * - :ref:`parseCoords.multilinestring <parseCoords.multilinestring>`
+     - Convert a coordinate array from GeoJSON into an ZOO.Geometry.MultiLineString.
+   * - :ref:`parseCoords.polygon <parseCoords.polygon>`
+     - Convert a coordinate array from GeoJSON into an ZOO.Geometry.Polygon.  
+   * - :ref:`parseCoords.multipolygon <parseCoords.multipolygon>`
+     - Convert a coordinate array from GeoJSON into an ZOO.Geometry.MultiPolygon.
+   * - :ref:`parseCoords.box <parseCoords.box>`
+     - Convert a coordinate array from GeoJSON into an ZOO.Geometry.Polygon.
+   * - :ref:`write <write>`
+     - Serialize a feature, geometry, array of features into a GeoJSON string.
+   * - :ref:`createCRSObject <createCRSObject>`
+     - Create the CRS object for an object.     
+     
+extract Properties
+------------------
+
+.. list-table::
+   :widths: 20 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`extract <extract>`
+     - Object with properties corresponding to the GeoJSON types.   
+     
+extract Functions	
+-----------------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`extract.feature <extract.feature>`
+     - Return a partial GeoJSON object representing a single feature.
+   * - :ref:`extract.geometry <extract.geometry>`
+     - Return a GeoJSON object representing a single geometry.
+   * - :ref:`extract.point <extract.point>`
+     - Return an array of coordinates from a point.
+   * - :ref:`extract.multipoint <extract.multipoint>`
+     - Return an array of coordinates from a multipoint.  
+   * - :ref:`extract.linestring <extract.linestring>`
+     - Return an array of coordinate arrays from a linestring.
+   * - :ref:`extract.multilinestring <extract.multilinestring>`
+     - Return an array of linestring arrays from a linestring.
+   * - :ref:`extract.polygon <extract.polygon>`
+     - Return an array of linear ring arrays from a polygon.
+   * - :ref:`extract.multipolygon <extract.multipolygon>`
+     - Return an array of polygon arrays from a multipolygon.  
+   * - :ref:`extract.collection <extract.collection>`
+     - Return an array of geometries from a geometry collection.      
+     
+**Functions**	
+  
+.. _ZOO.Format.GeoJSON:                         
+  
+ZOO.Format.GeoJSON	
+  Create a new parser for GeoJSON.
+
+
+  *Parameters*
+
+  ``options {Object}`` An optional object whose properties will be set on this instance.
+  
+.. _read:                           
+  
+read	
+  ::
+  
+    read: function(json,type,filter)
+
+  Deserialize a GeoJSON string.
+
+  *Parameters*
+
+  | ``json {String}`` A GeoJSON string
+  | ``type {String}`` Optional string that determines the structure of the output.  Supported values are "Geometry", "Feature", and "FeatureCollection".  If absent or null, a default of "FeatureCollection" is assumed.
+  | ``filter {Function}`` A function which will be called for every key and value at every level of the final result.  Each value will be replaced by the result of the filter function.  This can be used to reform generic objects into instances of classes, or to transform date strings into Date objects.
+
+  *Returns*
+
+  ``{Object}`` The return depends on the value of the type argument.  If type is "FeatureCollection" (the default), 
+  the return will be an array of :ref:`ZOO.Feature <api-zoo-feature>`.  If type is "Geometry", the input json must 
+  represent a single geometry, and the return will be an :ref:`ZOO.Geometry <api-zoo-geometry>`.  If type 
+  is "Feature", the input json must represent a single feature, and the return will be an :ref:`ZOO.Feature <api-zoo-feature>`.
+  
+.. _isValidType:                             
+  
+isValidType	
+  ::
+  
+    isValidType: function(obj,type)
+
+  Check if a GeoJSON object is a valid representative of the given type.
+
+  *Returns*
+
+  ``{Boolean}`` The object is valid GeoJSON object of the given type.
+  
+.. _parseFeature:                               
+  
+parseFeature	
+  ::
+  
+    parseFeature: function(obj)
+
+  Convert a feature object from GeoJSON into a :ref:`ZOO.Feature <api-zoo-feature>`.
+
+  *Parameters*
+  
+  ``obj	{Object}`` An object created from a GeoJSON object
+
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A feature.  
+  
+.. _parseGeometry:                                 
+  
+parseGeometry	
+  ::
+  
+    parseGeometry: function(obj)
+
+  Convert a geometry object from GeoJSON into a :ref:`ZOO.Geometry <api-zoo-geometry>`.
+
+  *Parameters*
+  
+  ``obj {Object}`` An object created from a GeoJSON object
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>` A geometry.
+  
+**parseCoords Properties**
+
+.. _parseCoords:                                 
+
+parseCoords	
+  Object with properties corresponding to the GeoJSON geometry types. Property 
+  values are functions that do the actual parsing.
+  
+**parseCoords Functions**
+
+.. _parseCoords.point:                                 
+
+parseCoords.point	
+  Convert a coordinate array from GeoJSON into a :ref:`ZOO.Geometry.Point <api-zoo-geometry-point>`.
+
+  *Parameters*
+
+  ``array {Object}`` The coordinates array from the GeoJSON fragment.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` A geometry.
+  
+.. _parseCoords.multipoint:                                   
+  
+parseCoords.multipoint	
+  Convert a coordinate array from GeoJSON into a :ref:`ZOO.Geometry.MultiPoint <api-zoo-geometry-multipoint>`.
+
+  *Parameters*
+  
+  ``array {Object}`` The coordinates array from the GeoJSON fragment.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.MultiPoint} <api-zoo-geometry-multipoint>` A geometry.
+  
+.. _parseCoords.linestring:                                     
+  
+parseCoords.linestring	
+  Convert a coordinate array from GeoJSON into a :ref:`ZOO.Geometry.LineString <api-zoo-geometry-linestring>`.
+
+  *Parameters*
+  
+  ``array {Object}`` The coordinates array from the GeoJSON fragment.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.LineString} <api-zoo-geometry-linestring>` A geometry. 
+  
+.. _parseCoords.multilinestring: 
+  
+parseCoords.multilinestring	
+  Convert a coordinate array from GeoJSON into a :ref:`ZOO.Geometry.MultiLineString <api-zoo-geometry-multilinestring>`.
+
+  *Parameters*
+  
+  ``array {Object}`` The coordinates array from the GeoJSON fragment.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.MultiLineString} <api-zoo-geometry-multilinestring>` A geometry.
+  
+.. _parseCoords.polygon:  
+  
+parseCoords.polygon	
+  Convert a coordinate array from GeoJSON into a :ref:`ZOO.Geometry.Polygon <api-zoo-geometry-polygon>`.
+
+  *Parameters*
+  
+  ``array {Object}`` The coordinates array from the GeoJSON fragment.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A geometry.
+  
+.. _parseCoords.multipolygon:  
+
+parseCoords.multipolygon	
+  Convert a coordinate array from GeoJSON into a :ref:`ZOO.Geometry.MultiPolygon <api-zoo-geometry-multipolygon>`.
+  
+  *Parameters*
+
+  ``array {Object}`` The coordinates array from the GeoJSON fragment.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.MultiPolygon} <api-zoo-geometry-multipolygon>` A geometry.  
+  
+.. _parseCoords.box:  
+  
+parseCoords.box	
+  Convert a coordinate array from GeoJSON into a :ref:`ZOO.Geometry.Polygon <api-zoo-geometry-polygon>`.
+
+  *Parameters*
+  
+  ``array {Object}`` The coordinates array from the GeoJSON fragment.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A geometry.  
+  
+.. _write:  
+  
+write	
+  ::
+  
+    write: function(obj,pretty)
+
+  Serialize a feature, geometry, array of features into a GeoJSON string.
+
+  *Parameters*
+  
+  | ``obj {Object}`` A :ref:`{ZOO.Feature} <api-zoo-feature>`, :ref:`{ZOO.Geometry} <api-zoo-geometry>`, or an array of features.
+  | ``pretty {Boolean}`` Structure the output with newlines and indentation.  Default is false.
+
+  *Returns*
+
+  ``{String}`` The GeoJSON string representation of the input geometry, features, or array of features. 
+  
+.. _createCRSObject:    
+  
+createCRSObject	
+  ::
+  
+    createCRSObject: function(object)
+
+  Create the CRS object for an object.
+  
+  *Parameters*
+  
+  ``object`` :ref:`{ZOO.Feature} <api-zoo-feature>`
+
+  *Returns*
+
+  ``{Object}`` An object which can be assigned to the crs property of a GeoJSON object. 
+  
+**extract Properties**
+
+.. _extract:    
+
+extract	
+  Object with properties corresponding to the GeoJSON types. Property values are 
+  functions that do the actual value extraction.
+  
+**extract Functions**
+
+.. _extract.feature:    
+
+extract.feature	
+  Return a partial GeoJSON object representing a single feature.
+
+
+  *Parameters*
+  
+  ``feature`` :ref:`{ZOO.Feature} <api-zoo-feature>`
+
+  *Returns*
+
+  ``{Object}`` An object representing the point.  
+  
+.. _extract.geometry:      
+  
+extract.geometry	
+  Return a GeoJSON object representing a single geometry.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+  
+  *Returns*
+
+  ``{Object}`` An object representing the geometry. 
+  
+.. _extract.point:        
+  
+extract.point	
+  Return an array of coordinates from a point.
+
+  *Parameters*
+  
+  ``point`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>`
+
+  *Returns*
+
+  ``{Array}`` An array of coordinates representing the point. 
+  
+.. _extract.multipoint:          
+  
+extract.multipoint	
+  Return an array of coordinates from a multipoint.
+
+  *Parameters*
+  
+  ``multipoint`` :ref:`{ZOO.Geometry.MultiPoint} <api-zoo-geometry-multipoint>`
+
+  *Returns*
+
+  ``{Array}`` An array of point coordinate arrays representing the multipoint.
+  
+.. _extract.linestring:            
+  
+extract.linestring	
+  Return an array of coordinate arrays from a linestring.
+
+  *Parameters*
+  
+  ``linestring`` :ref:`{ZOO.Geometry.LineString} <api-zoo-geometry-linestring>`
+
+  *Returns*
+
+  ``{Array}`` An array of coordinate arrays representing the linestring. 
+  
+.. _extract.multilinestring:              
+  
+extract.multilinestring	
+  Return an array of linestring arrays from a linestring.
+
+  *Parameters*
+  
+  ``multilinestring`` :ref:`{ZOO.Geometry.MultiLineString} <api-zoo-geometry-multilinestring>`
+
+  *Returns*
+
+  ``{Array}`` An array of linestring arrays representing the multilinestring. 
+  
+.. _extract.polygon:             
+  
+extract.polygon	
+  Return an array of linear ring arrays from a polygon.
+
+  *Parameters*
+  
+  ``polygon`` :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>`
+  
+  *Returns*
+
+  ``{Array}`` An array of linear ring arrays representing the polygon. 
+  
+.. _extract.multipolygon:                 
+  
+extract.multipolygon	
+  Return an array of polygon arrays from a multipolygon.
+  
+  *Parameters*
+  
+  ``multipolygon`` :ref:`{ZOO.Geometry.MultiPolygon} <api-zoo-geometry-multipolygon>`
+
+  *Returns*
+
+  ``{Array}`` An array of polygon arrays representing the multipolygon  
+  
+.. _extract.collection:  
+  
+extract.collection	
+  Return an array of geometries from a geometry collection.
+
+  *Parameters*
+
+  ``collection`` :ref:`{ZOO.Geometry.Collection} <api-zoo-geometry-collection>`
+
+  *Returns*
+
+  ``{Array}`` An array of geometry objects representing the geometry collection.
Index: /tags/rel-1.7.0/docs/api/zoo-format-gml.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-format-gml.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-format-gml.txt	(revision 942)
@@ -0,0 +1,446 @@
+.. _api-zoo-format-gml:
+
+ZOO.Format.GML
+==============
+
+Read/Write GML.
+
+Inherits from
+
+- :ref:`ZOO.Format <api-zoo-format>`
+
+Properties and Functions	
+------------------------
+
+.. list-table::
+   :widths: 20 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`schemaLocation <schemaLocation>`
+     - {String} Schema location for a particular minor version.
+   * - :ref:`namespaces <namespaces>`
+     - {Object} Mapping of namespace aliases to namespace URIs.
+   * - :ref:`defaultPrefix <defaultPrefix>`
+     - 
+   * - :ref:`collectionName <collectionName>`
+     - {String} Name of featureCollection element. 
+   * - :ref:`featureName <featureName>`
+     - {String} Element name for features. 
+   * - :ref:`geometryName <geometryName>`
+     - {String} Name of geometry element.
+   * - :ref:`xy <xy>`
+     - {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x) Changing is not recommended, a new Format should be instantiated.
+   * - :ref:`extractAttributes <extractAttributes>`
+     - {Boolean} Could we extract attributes
+   * - :ref:`ZOO.Format.GML <ZOO.Format.GML>`
+     - Create a new parser for GML.
+   * - :ref:`read <read>`
+     - Read data from a string, and return a list of features. 
+   * - :ref:`parseFeature <parseFeature>`
+     - This function is the core of the GML parsing code in ZOO.
+   * - :ref:`parseGeometry <parseGeometry>`
+     - Properties of this object are the functions that parse geometries based on their type.
+   * - :ref:`parseGeometry.point <parseGeometry.point>`
+     - Given a GML node representing a point geometry, create a ZOO point geometry.  
+   * - :ref:`parseGeometry.multipoint <parseGeometry.multipoint>`
+     - Given a GML node representing a point geometry, create a ZOO multipoint geometry.     
+   * - :ref:`parseGeometry.linestring <parseGeometry.linestring>`
+     - Given a GML node representing a linestring geometry, create a ZOO linestring geometry.
+   * - :ref:`parseGeometry.polygon <parseGeometry.polygon>`
+     - Given a GML node representing a polygon geometry, create a ZOO polygon geometry.
+   * - :ref:`parseGeometry.multigeometry <parseGeometry.multigeometry>`
+     - Given a GML node representing a multigeometry, create a ZOO geometry collection.
+   * - :ref:`parseAttributes <parseAttributes>`
+     -  
+   * - :ref:`parseExtendedData <parseExtendedData>`
+     - Parse ExtendedData from GML.  
+   * - :ref:`write <write>`
+     - Accept Feature Collection, and return a string.
+   * - :ref:`createFeature <createFeature>`
+     - Accept an ZOO.Feature, and build a GML node for it.
+   * - :ref:`buildGeometryNode <buildGeometryNode>`
+     - Builds and returns a GML geometry node with the given geometry.
+   * - :ref:`buildGeometry <buildGeometry>`
+     - Object containing methods to do the actual geometry node building based on geometry type.
+   * - :ref:`buildGeometry.point <buildGeometry.point>`
+     - Given a ZOO point geometry, create a GML point.     
+   * - :ref:`buildGeometry.multipoint <buildGeometry.multipoint>`
+     - Given a ZOO multipoint geometry, create a GML GeometryCollection.
+   * - :ref:`buildGeometry.linestring <buildGeometry.linestring>`
+     -  Given a ZOO linestring geometry, create a GML linestring.
+   * - :ref:`buildGeometry.multilinestring <buildGeometry.multilinestring>`
+     - Given a ZOO multilinestring geometry, create a GML GeometryCollection. 
+   * - :ref:`buildGeometry.linearring <buildGeometry.linearring>`
+     - Given a ZOO linearring geometry, create a GML linearring.
+   * - :ref:`buildGeometry.polygon <buildGeometry.polygon>`
+     - Given a ZOO polygon geometry, create a GML polygon.
+   * - :ref:`buildGeometry.multipolygon <buildGeometry.multipolygon>`
+     - Given a ZOO multipolygon geometry, create a GML GeometryCollection.
+   * - :ref:`buildGeometry.collection <buildGeometry.collection>`
+     - Given a ZOO geometry collection, create a GML MultiGeometry.
+   * - :ref:`buildCoordinatesNode <buildCoordinatesNode>`
+     - builds the coordinates XmlNode 
+
+.. _schemaLocation:  
+  		
+schemaLocation	
+  ``{String}`` Schema location for a particular minor version.
+  
+.. _namespaces:    
+  
+namespaces	
+  ``{Object}`` Mapping of namespace aliases to namespace URIs.
+
+.. _defaultPrefix:    
+
+defaultPrefix
+
+.. _collectionName:    
+
+collectionName	
+  ``{String}`` Name of featureCollection element.
+  
+.. _featureName:      
+  
+featureName	
+  ``{String}`` Element name for features. Default is "sql_statement".
+  
+.. _geometryName:        
+  
+geometryName	
+  ``{String}`` Name of geometry element. Defaults to "geometryProperty".
+  
+.. _xy:          
+  
+xy	
+  ``{Boolean}`` Order of the GML coordinate true:(x,y) or false:(y,x) Changing is not recommended, a new Format should be instantiated.
+
+.. _extractAttributes:          
+
+extractAttributes	
+  ``{Boolean}`` Could we extract attributes
+  
+.. _ZOO.Format.GML:            
+  
+ZOO.Format.GML	
+  Create a new parser for GML.
+
+  *Parameters*
+  
+  ``options {Object}`` An optional object whose properties will be set on this instance.  
+  
+.. _read:              
+  
+read	
+  ::
+  
+    read: function(data)
+
+  Read data from a string, and return a list of features.
+
+  *Parameters*
+  
+  ``data {String}`` data to read/parse.
+
+  *Returns*
+
+  :ref:`{Array(ZOO.Feature)} <api-zoo-feature>` An array of features.  
+  
+.. _parseFeature:  
+  
+parseFeature	
+  ::
+  
+    parseFeature: function(node)
+
+  This function is the core of the GML parsing code in ZOO.  It creates the geometries 
+  that are then attached to the returned feature, and calls parseAttributes() to get 
+  attribute data out.
+  
+  *Parameters*
+  
+  ``node {E4XElement}``
+
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A vector feature.  
+  
+.. _parseGeometry:    
+  
+parseGeometry	
+  Properties of this object are the functions that parse geometries based on their type.
+  
+.. _parseGeometry.point:      
+  
+parseGeometry.point	
+  Given a GML node representing a point geometry, create a ZOO point geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A GML node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` A point geometry. 
+  
+.. _parseGeometry.multipoint:        
+  
+parseGeometry.multipoint	
+  Given a GML node representing a multipoint geometry, create a ZOO multipoint geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A GML node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` A multipoint geometry.   
+  
+.. _parseGeometry.linestring:          
+  
+parseGeometry.linestring	
+  Given a GML node representing a linestring geometry, create a ZOO linestring geometry.
+  
+  *Parameters*
+    
+  ``node {E4XElement}`` A GML node.
+  
+  *Returns*
+  
+  :ref:`{ZOO.Geometry.LineString} <api-zoo-geometry-linestring>` A linestring geometry. 
+
+.. _parseGeometry.multilinestring:          
+
+parseGeometry.multilinestring	
+  Given a GML node representing a multilinestring geometry, create a ZOO multilinestring geometry.
+  
+  *Parameters*
+    
+  ``node {E4XElement}`` A GML node.
+  
+  *Returns*
+  
+  :ref:`{ZOO.Geometry.MultiLineString} <api-zoo-geometry-multilinestring>` A multilinestring geometry.   
+
+.. _parseGeometry.polygon:          
+
+parseGeometry.polygon	
+  Given a GML node representing a polygon geometry, create a ZOO polygon geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A GML node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A polygon geometry.   
+
+.. _parseGeometry.multipolygon:          
+
+parseGeometry.multipolygon	
+  Given a GML node representing a multipolygon geometry, create a ZOO multipolygon geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A GML node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.MultiPolygon} <api-zoo-geometry-multipolygon>` A multipolygon geometry.  
+
+.. _parseGeometry.envelope:          
+
+parseGeometry.envelope	
+  Given a GML node representing an envelope, create a ZOO polygon geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A GML node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A polygon geometry.  
+
+.. _parseAttributes:          
+
+parseAttributes	
+  ::
+  
+    parseAttributes: function(node)
+
+  *Parameters*
+  
+  ``node {E4XElement}``
+  
+  *Returns*
+
+  ``{Object}`` An attributes object.
+
+.. _write:          
+
+write	
+  ::
+  
+    write: function(features)
+
+  Generate a GML document string given a list of features.
+  
+  *Parameters*
+  
+  ``features`` :ref:`{Array(ZOO.Feature)} <api-zoo-feature>` List of features to serialize into a string.
+
+  *Returns*
+
+  ``{String}`` A string representing the GML document.
+  
+.. _createFeature:          
+
+createFeature	
+  ::
+  
+    createFeature: function(feature)
+
+  Accept an ZOO.Feature, and build a GML node for it.
+  
+  *Parameters*
+  
+  ``feature`` :ref:`{ZOO.Feature} <api-zoo-feature>` The feature to be built as GML.
+  
+  *Returns*
+
+  ``{E4XElement}`` A node reprensting the feature in GML.
+  
+.. _buildGeometryNode:          
+
+buildGeometryNode
+  ::
+  
+    buildGeometryNode: function(geometry)
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` The geometry to be built as GML.
+  
+  *Returns*
+
+  ``{E4XElement}`` A node reprensting the geometry in GML.
+
+.. _buildGeometry:          
+
+buildGeometry	
+  Object containing methods to do the actual geometry node building based on geometry type.
+
+.. _buildGeometry.point:          
+
+buildGeometry.point	
+  Given a ZOO point geometry, create a GML point.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` A point geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A GML point node.
+  
+.. _buildGeometry.multipoint:          
+
+buildGeometry.multipoint	
+  Given a ZOO multipoint geometry, create a GML multipoint.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.MultiPoint} <api-zoo-geometry-multipoint>` A multipoint geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A GML multipoint node.  
+
+.. _buildGeometry.linestring:          
+
+buildGeometry.linestring	
+  Given a ZOO linestring geometry, create a GML linestring.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.LineString} <api-zoo-geometry-linestring>` A linestring geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A GML linestring node.
+  
+.. _buildGeometry.multilinestring:          
+
+buildGeometry.multilinestring	
+  Given a ZOO multilinestring geometry, create a GML multilinestring.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.MultiLineString} <api-zoo-geometry-multilinestring>` A multilinestring geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A GML multilinestring node.  
+
+.. _buildGeometry.linearring:          
+
+buildGeometry.linearring	
+  Given a ZOO linearring geometry, create a GML linearring.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.LinearRing} <api-zoo-geometry-linearring>` A linearring geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A GML linearring node.
+  
+.. _buildGeometry.polygon:          
+
+buildGeometry.polygon	
+  Given an ZOO polygon geometry, create a GML polygon.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A polygon geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A GML polygon node.
+  
+.. _buildGeometry.multipolygon:          
+
+buildGeometry.multipolygon	
+  Given a ZOO multipolygon geometry, create a GML multipolygon.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.MultiPolygon} <api-zoo-geometry-multipolygon>` A multipolygon geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A GML multipolygon node.  
+
+.. _buildCoordinatesNode:          
+
+buildCoordinatesNode	
+  ::
+  
+    buildCoordinatesNode: function(geometry)
+
+  builds the coordinates XmlNode
+
+    ::
+    
+      <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates>
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+
+  *Returns*
+
+  ``{E4XElement}`` created E4XElement  
+  
Index: /tags/rel-1.7.0/docs/api/zoo-format-json.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-format-json.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-format-json.txt	(revision 942)
@@ -0,0 +1,287 @@
+.. _api-zoo-format-json:
+
+ZOO.Format.JSON
+===============
+
+A parser to read/write JSON safely.
+
+Inherits from
+
+- :ref:`ZOO.Format <api-zoo-format>`
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`indent <indent>`
+     - {String} For "pretty" printing, the indent string will be used once for each indentation level.
+   * - :ref:`space <space>`
+     - {String} For "pretty" printing, the space string will be used after the ":" separating a name/value pair.
+   * - :ref:`newline <newline>`
+     - {String} For "pretty" printing, the newline string will be used at the end of each name/value pair or array item.
+   * - :ref:`level <level>`
+     - {Integer} For "pretty" printing, this is incremented/decremented during serialization.  
+   * - :ref:`pretty <pretty>`
+     - {Boolean} Serialize with extra whitespace for structure.    
+     
+Functions	
+---------
+
+.. list-table::
+   :widths: 14 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Format.JSON <ZOO.Format.JSON>`
+     - Create a new parser for JSON.
+   * - :ref:`read <read>`
+     - Deserialize a json string.
+   * - :ref:`write <write>`
+     - Serialize an object into a JSON string.
+   * - :ref:`writeIndent <writeIndent>`
+     - Output an indentation string depending on the indentation level.  
+   * - :ref:`writeNewline <writeNewline>`
+     - Output a string representing a newline if in pretty printing mode.   
+   * - :ref:`writeSpace <writeSpace>`
+     - Output a string representing a space if in pretty printing mode. 
+     
+Serialize Properties	
+--------------------
+
+.. list-table::
+   :widths: 14 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`serialize <serialize>`
+     - Object with properties corresponding to the serializable data types. 
+     
+Serialize Functions	
+-------------------
+
+.. list-table::
+   :widths: 14 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`serialize.object <serialize.object>`
+     - Transform an object into a JSON string.
+   * - :ref:`serialize.array <serialize.array>`
+     - Transform an array into a JSON string.
+   * - :ref:`serialize.string <serialize.string>`
+     - Transform a string into a JSON string.
+   * - :ref:`serialize.number <serialize.number>`
+     - Transform a number into a JSON string.  
+   * - :ref:`serialize.boolean <serialize.boolean>`
+     - Transform a boolean into a JSON string.   
+   * - :ref:`serialize.date <serialize.date>`
+     - Transform a date into a JSON string.     
+       
+**Properties**
+
+.. _indent:   
+
+indent	
+  ``{String}`` For "pretty" printing, the indent string will be used once for each indentation level.
+  
+.. _space:     
+  
+space	
+  ``{String}`` For "pretty" printing, the space string will be used after the ":" separating a name/value pair.
+  
+.. _newline:       
+  
+newline	
+  ``{String}`` For "pretty" printing, the newline string will be used at the end of each name/value pair or array item.
+  
+.. _level:        
+  
+level	
+  ``{Integer}`` For "pretty" printing, this is incremented/decremented during serialization.
+  
+.. _pretty:          
+  
+pretty	
+  ``{Boolean}`` Serialize with extra whitespace for structure. This is set by the :ref:`write <write>` method.
+  
+**Functions**
+
+.. _ZOO.Format.JSON:          
+
+ZOO.Format.JSON	
+  Create a new parser for JSON.
+
+  *Parameters*
+  
+  ``options {Object}`` An optional object whose properties will be set on this instance. 
+  
+.. _read:            
+  
+read	
+  ::
+  
+    read: function(json,filter)
+
+  Deserialize a json string.
+
+  *Parameters*
+  
+  | ``json {String}`` A JSON string
+  | ``filter {Function}`` A function which will be called for every key and value at every level of the final result.  Each value will be replaced by the result of the filter function.  This can be used to reform generic objects into instances of classes, or to transform date strings into Date objects.
+
+  *Returns*
+
+  ``{Object}`` An object, array, string, or number.
+  
+.. _write:              
+  
+write	
+  ::
+  
+    write: function(value,pretty)
+
+  Serialize an object into a JSON string.
+
+  *Parameters*
+  
+  | ``value {String}`` The object, array, string, number, boolean or date to be serialized.
+  | ``pretty {Boolean}`` Structure the output with newlines and indentation.  Default is false.
+
+  *Returns*
+
+  ``{String}`` The JSON string representation of the input value.  
+  
+.. _writeIndent:               
+  
+writeIndent	
+  ::
+  
+    writeIndent: function()
+
+  Output an indentation string depending on the indentation level.
+  
+  *Returns*
+
+  ``{String}`` An appropriate indentation string.
+  
+.. _writeNewline:               
+  
+writeNewline	
+  ::
+  
+    writeNewline: function()
+
+  Output a string representing a newline if in pretty printing mode.
+  
+  *Returns*
+
+  ``{String}`` A string representing a new line.
+  
+.. _writeSpace:               
+  
+writeSpace	
+  ::
+  
+    writeSpace: function()
+
+  Output a string representing a space if in pretty printing mode.  
+
+  *Returns*
+
+  ``{String}`` A space.
+  
+**Serialize Properties**
+
+.. _serialize:               
+
+serialize	
+  Object with properties corresponding to the serializable data types. Property 
+  values are functions that do the actual serializing.
+  
+**Serialize Functions**
+
+.. _serialize.object:               
+
+serialize.object	
+  Transform an object into a JSON string.
+
+  *Parameters*
+
+  ``object {Object}`` The object to be serialized.
+  
+  *Returns*
+
+  ``{String}`` A JSON string representing the object. 
+  
+.. _serialize.array:                 
+  
+serialize.array	
+  Transform an array into a JSON string.
+
+  *Parameters*
+  
+  ``array {Array}`` The array to be serialized
+
+  *Returns*
+
+  ``{String}`` A JSON string representing the array. 
+  
+.. _serialize.string:                   
+  
+serialize.string	
+  Transform a string into a JSON string.
+
+  *Parameters*
+  
+  ``string {String}`` The string to be serialized
+
+  *Returns*
+
+  ``{String}`` A JSON string representing the string. 
+  
+.. _serialize.number:                     
+  
+serialize.number	
+  Transform a number into a JSON string.
+
+  *Parameters*
+  
+  ``number {Number}`` The number to be serialized.
+  
+  *Returns*
+
+  ``{String}`` A JSON string representing the number.  
+  
+.. _serialize.boolean:                       
+  
+serialize.boolean	
+  Transform a boolean into a JSON string.
+
+  *Parameters*
+  
+  ``bool {Boolean}`` The boolean to be serialized.
+
+  *Returns*
+
+  ``{String}`` A JSON string representing the boolean. 
+  
+.. _serialize.date:                         
+  
+serialize.date	
+  Transform a date into a JSON string.
+
+  *Parameters*
+  
+  ``date {Date}`` The date to be serialized.
+
+  *Returns*
+
+  ``{String}`` A JSON string representing the date.
Index: /tags/rel-1.7.0/docs/api/zoo-format-kml.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-format-kml.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-format-kml.txt	(revision 942)
@@ -0,0 +1,412 @@
+.. _api-zoo-format-kml:
+
+ZOO.Format.KML
+==============
+
+Read/Write KML.
+
+Inherits from
+
+- :ref:`ZOO.Format <api-zoo-format>`
+
+Properties and Functions	
+------------------------
+
+.. list-table::
+   :widths: 20 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`kmlns <kmlns>`
+     - {String} KML Namespace to use.
+   * - :ref:`foldersName <foldersName>`
+     - {String} Name of the folders.
+   * - :ref:`foldersDesc <foldersDesc>`
+     - {String} Description of the folders.
+   * - :ref:`placemarksDesc <placemarksDesc>`
+     - {String} Name of the placemarks. 
+   * - :ref:`extractAttributes <extractAttributes>`
+     - {Boolean} Extract attributes from KML.   
+   * - :ref:`ZOO.Format.KML <ZOO.Format.KML>`
+     - Create a new parser for KML.
+   * - :ref:`parseFeatures <parseFeatures>`
+     - Loop through all Placemark nodes and parse them.
+   * - :ref:`parseFeature <parseFeature>`
+     - This function is the core of the KML parsing code in ZOO.
+   * - :ref:`parseGeometry <parseGeometry>`
+     - Properties of this object are the functions that parse geometries based on their type.
+   * - :ref:`parseGeometry.point <parseGeometry.point>`
+     - Given a KML node representing a point geometry, create a ZOO point geometry.  
+   * - :ref:`parseGeometry.linestring <parseGeometry.linestring>`
+     - Given a KML node representing a linestring geometry, create a ZOO linestring geometry.
+   * - :ref:`parseGeometry.polygon <parseGeometry.polygon>`
+     - Given a KML node representing a polygon geometry, create a ZOO polygon geometry.
+   * - :ref:`parseGeometry.multigeometry <parseGeometry.multigeometry>`
+     - Given a KML node representing a multigeometry, create a ZOO geometry collection.
+   * - :ref:`parseAttributes <parseAttributes>`
+     -  
+   * - :ref:`parseExtendedData <parseExtendedData>`
+     - Parse ExtendedData from KML.  
+   * - :ref:`write <write>`
+     - Accept Feature Collection, and return a string.
+   * - :ref:`createPlacemark <createPlacemark>`
+     - Creates and returns a KML placemark node representing the given feature.
+   * - :ref:`buildGeometryNode <buildGeometryNode>`
+     - Builds and returns a KML geometry node with the given geometry.
+   * - :ref:`buildGeometry <buildGeometry>`
+     - Object containing methods to do the actual geometry node building based on geometry type.
+   * - :ref:`buildGeometry.point <buildGeometry.point>`
+     - Given a ZOO point geometry, create a KML point.     
+   * - :ref:`buildGeometry.multipoint <buildGeometry.multipoint>`
+     - Given a ZOO multipoint geometry, create a KML GeometryCollection.
+   * - :ref:`buildGeometry.linestring <buildGeometry.linestring>`
+     -  Given a ZOO linestring geometry, create a KML linestring.
+   * - :ref:`buildGeometry.multilinestring <buildGeometry.multilinestring>`
+     - Given a ZOO multilinestring geometry, create a KML GeometryCollection. 
+   * - :ref:`buildGeometry.linearring <buildGeometry.linearring>`
+     - Given a ZOO linearring geometry, create a KML linearring.
+   * - :ref:`buildGeometry.polygon <buildGeometry.polygon>`
+     - Given a ZOO polygon geometry, create a KML polygon.
+   * - :ref:`buildGeometry.multipolygon <buildGeometry.multipolygon>`
+     - Given a ZOO multipolygon geometry, create a KML GeometryCollection.
+   * - :ref:`buildGeometry.collection <buildGeometry.collection>`
+     - Given a ZOO geometry collection, create a KML MultiGeometry.
+   * - :ref:`buildCoordinatesNode <buildCoordinatesNode>`
+     - Builds and returns the KML coordinates node with the given geometry <coordinates>...</coordinates> 
+
+.. _kmlns:  
+  	
+kmlns	
+  ``{String}`` KML Namespace to use. Defaults to 2.2 namespace.
+  
+.. _foldersName:  
+  
+foldersName	
+  ``{String}`` Name of the folders. Default is "ZOO export".  If set to null, no name element will be created.
+  
+.. _foldersDesc:    
+  
+foldersDesc	
+  ``{String}`` Description of the folders. Default is "Exported on [date]."  If set to null, no description element will be created.
+  
+.. _placemarksDesc:      
+  
+placemarksDesc	
+  ``{String}`` Name of the placemarks. Default is "No description available".
+  
+.. _extractAttributes:        
+  
+extractAttributes	
+  ``{Boolean}`` Extract attributes from KML. Default is true.  Extracting styleUrls requires this to be set to true
+  
+.. _ZOO.Format.KML:          
+  
+ZOO.Format.KML	
+  Create a new parser for KML.
+
+  *Parameters*
+  
+  ``options {Object}`` An optional object whose properties will be set on this instance.
+  
+.. _parseFeatures:            
+  
+parseFeatures	
+  ::
+  
+    parseFeatures: function(nodes)
+
+  Loop through all Placemark nodes and parse them.  Will create a list of features
+
+  *Parameters*
+  
+  | ``nodes {Array}`` of {E4XElement} data to read/parse.
+  | ``options {Object}`` Hash of options
+  
+.. _parseFeature:              
+  
+parseFeature	
+  ::
+  
+    parseFeature: function(node)
+
+  This function is the core of the KML parsing code in ZOO.  It creates the geometries 
+  that are then attached to the returned feature, and calls parseAttributes() to get 
+  attribute data out.
+  
+  *Parameters*
+  
+  ``node {E4XElement}``
+
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A vector feature.  
+  
+.. _parseGeometry:                
+  
+parseGeometry	
+  Properties of this object are the functions that parse geometries based on their type.
+  
+.. _parseGeometry.point:                  
+  
+parseGeometry.point	
+  Given a KML node representing a point geometry, create a ZOO point geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A KML Point node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` A point geometry. 
+  
+.. _parseGeometry.linestring:                    
+  
+parseGeometry.linestring	
+  Given a KML node representing a linestring geometry, create a ZOO linestring geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A KML LineString node.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.LineString} <api-zoo-geometry-linestring>` A linestring geometry. 
+  
+.. _parseGeometry.polygon:                      
+  
+parseGeometry.polygon	
+  Given a KML node representing a polygon geometry, create a ZOO polygon geometry.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A KML Polygon node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A polygon geometry. 
+  
+.. _parseGeometry.multigeometry:                        
+  
+parseGeometry.multigeometry	
+  Given a KML node representing a multigeometry, create a ZOO geometry collection.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A KML MultiGeometry node.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Collection} <api-zoo-geometry-collection>` A geometry collection.  
+  
+.. _parseAttributes:                          
+  
+parseAttributes	
+  ::
+  
+    parseAttributes: function(node)
+
+  *Parameters*
+  
+  ``node {E4XElement}``
+  
+  *Returns*
+
+  ``{Object}`` An attributes object.
+
+.. _parseExtendedData:
+
+parseExtendedData	
+  ::
+  
+    parseExtendedData: function(node)
+
+  Parse ExtendedData from KML.  Limited support for schemas/datatypes.  See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata 
+  for more information on extendeddata.
+  
+  *Parameters*
+  
+  ``node {E4XElement}``
+  
+  *Returns*
+
+  ``{Object}`` An attributes object. 
+  
+.. _write:  
+  
+write	
+  ::
+  
+    write: function(features)
+
+  Accept Feature Collection, and return a string.
+
+  *Parameters*
+  
+  ``features`` :ref:`{Array(ZOO.Feature)} <api-zoo-feature>` An array of features.
+  
+  *Returns*
+
+  ``{String}`` A KML string.  
+  
+.. _createPlacemark:   
+  
+createPlacemark	
+  ::
+  
+    createPlacemark: function(feature)
+
+  Creates and returns a KML placemark node representing the given feature.
+
+  *Parameters*
+  
+  ``feature`` :ref:`{ZOO.Feature} <api-zoo-feature>`
+  
+  *Returns*
+
+  ``{E4XElement}``
+  
+.. _buildGeometryNode:     
+  
+buildGeometryNode	
+  ::
+  
+    buildGeometryNode: function(geometry)
+
+  Builds and returns a KML geometry node with the given geometry.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+
+  *Returns*
+
+  ``{E4XElement}``
+  
+.. _buildGeometry:       
+  
+buildGeometry	
+  Object containing methods to do the actual geometry node building based on geometry type.
+  
+.. _buildGeometry.point:         
+  
+buildGeometry.point	
+  Given a ZOO point geometry, create a KML point.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` A point geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A KML point node.  
+  
+.. _buildGeometry.multipoint:           
+  
+buildGeometry.multipoint	
+  Given a ZOO multipoint geometry, create a KML GeometryCollection.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.MultiPoint} <api-zoo-geometry-multipoint>` A multipoint geometry.
+  
+  *Returns*
+
+  ``{E4XElement}`` A KML GeometryCollection node. 
+  
+.. _buildGeometry.linestring:             
+  
+buildGeometry.linestring	
+  Given a ZOO linestring geometry, create a KML linestring.
+  
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.LineString} <api-zoo-geometry-linestring>` A linestring geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A KML linestring node.
+  
+.. _buildGeometry.multilinestring:               
+  
+buildGeometry.multilinestring	
+  Given a ZOO multilinestring geometry, create a KML GeometryCollection.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.MultiLineString} <api-zoo-geometry-multilinestring>` A multilinestring geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A KML GeometryCollection node. 
+  
+.. _buildGeometry.linearring:                 
+  
+buildGeometry.linearring	
+  Given a ZOO linearring geometry, create a KML linearring.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.LinearRing} <api-zoo-geometry-linearring>` A linearring geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A KML linearring node.  
+  
+.. _buildGeometry.polygon:                   
+  
+buildGeometry.polygon	
+  Given a ZOO polygon geometry, create a KML polygon.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.Polygon} <api-zoo-geometry-polygon>` A polygon geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A KML polygon node.  
+  
+.. _buildGeometry.multipolygon:                     
+  
+buildGeometry.multipolygon	
+  Given a ZOO multipolygon geometry, create a KML GeometryCollection.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` A multipolygon geometry.
+
+  *Returns*
+
+  ``{E4XElement}`` A KML GeometryCollection node.  
+  
+.. _buildGeometry.collection:                       
+  
+buildGeometry.collection	
+  Given a ZOO geometry collection, create a KML MultiGeometry.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry.Collection} <api-zoo-geometry-collection>` A geometry collection.
+
+  *Returns*
+
+  ``{E4XElement}`` A KML MultiGeometry node.  
+  
+.. _buildCoordinatesNode:                         
+  
+buildCoordinatesNode	
+  ::
+  
+    buildCoordinatesNode: function(geometry)
+
+  Builds and returns the KML coordinates node with the given geometry <coordinates>...</coordinates>
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+
+  *Return*
+
+  ``{E4XElement}`` 
+  
+  
Index: /tags/rel-1.7.0/docs/api/zoo-format-wkt.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-format-wkt.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-format-wkt.txt	(revision 942)
@@ -0,0 +1,196 @@
+.. _api-zoo-format-wkt:
+
+ZOO.Format.WKT
+==============
+
+Class for reading and writing Well-Known Text.
+
+Inherits from
+
+- :ref:`ZOO.Format <api-zoo-format>`
+
+Functions and Properties	
+------------------------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Format.WKT <ZOO.Format.WKT>`
+     - Create a new parser for WKT
+   * - :ref:`read <read>`
+     - Deserialize a WKT string and return a vector feature or an array of vector features.
+   * - :ref:`write <write>`
+     - Serialize a feature or array of features into a WKT string.
+   * - :ref:`extract <extract>`
+     - Object with properties corresponding to the geometry types.   
+   * - :ref:`parse <parse>`
+     - Object with properties corresponding to the geometry types.
+   * - :ref:`parse.point <parse.point>`
+     - Return point feature given a point WKT fragment.   
+   * - :ref:`parse.multipoint <parse.multipoint>`
+     - Return a multipoint feature given a multipoint WKT fragment.
+   * - :ref:`parse.linestring <parse.linestring>`
+     - Return a linestring feature given a linestring WKT fragment. 
+   * - :ref:`parse.multilinestring <parse.multilinestring>`
+     - Return a multilinestring feature given a multilinestring WKT fragment.
+   * - :ref:`parse.polygon <parse.polygon>`
+     - Return a polygon feature given a polygon WKT fragment.
+   * - :ref:`parse.multipolygon <parse.multipolygon>`
+     - Return a multipolygon feature given a multipolygon WKT fragment.
+   * - :ref:`parse.geometrycollection <parse.geometrycollection>`
+     - Return an array of features given a geometrycollection WKT fragment.     
+       
+.. _ZOO.Format.WKT:   
+
+ZOO.Format.WKT	
+  Create a new parser for WKT
+
+  *Parameters*
+  
+  ``options {Object}`` An optional object whose properties will be set on this instance
+
+  *Returns*
+
+  :ref:`{ZOO.Format.WKT} <api-zoo-format-wkt>` A new WKT parser. 
+  
+.. _read:     
+  
+read	
+  ::
+  
+    read: function(wkt)
+
+  Deserialize a WKT string and return a vector feature or an array of vector features.  
+  Supports WKT for POINT, MULTIPOINT, LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, 
+  and GEOMETRYCOLLECTION.
+  
+  *Parameters*
+  
+  ``wkt	{String}`` A WKT string
+  
+  *Returns*
+
+  {<ZOO.Feature.Vector>|Array} A feature or array of features for GEOMETRYCOLLECTION WKT. 
+  
+.. _write:       
+  
+write	
+  ::
+  
+    write: function(features)
+
+  Serialize a feature or array of features into a WKT string.
+  
+  *Parameters*
+  
+  ``features {<ZOO.Feature.Vector>|Array}`` A feature or array of features
+
+  *Returns*
+
+  ``{String}`` The WKT string representation of the input geometries 
+  
+.. _extract:         
+  
+extract	
+  Object with properties corresponding to the geometry types. Property values are 
+  functions that do the actual data extraction.
+  
+.. _parse:           
+  
+parse	
+  Object with properties corresponding to the geometry types. Property values are 
+  functions that do the actual parsing.
+  
+.. _parse.point:             
+  
+parse.point	
+  Return point feature given a point WKT fragment.
+  
+  *Parameters*
+  
+  ``str	{String}`` A WKT fragment representing the point 
+  
+  *Returns*
+  
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A point feature  
+  
+.. _parse.multipoint:               
+  
+parse.multipoint	
+  Return a multipoint feature given a multipoint WKT fragment.
+
+  *Parameters*
+  
+  ``str	{String}`` A WKT fragment representing the multipoint
+
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A multipoint feature 
+  
+.. _parse.linestring:                
+ 
+parse.linestring	
+  Return a linestring feature given a linestring WKT fragment.
+
+  *Parameters*
+  
+  ``str	{String}`` A WKT fragment representing the linestring
+
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A linestring feature
+  
+.. _parse.multilinestring:                  
+  
+parse.multilinestring	
+  Return a multilinestring feature given a multilinestring WKT fragment.
+  
+  *Parameters*
+  
+  ``str	{String}`` A WKT fragment representing the multilinestring
+  
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A multilinestring feature  
+  
+.. _parse.polygon:                  
+  
+parse.polygon	
+  Return a polygon feature given a polygon WKT fragment.
+
+  *Parameters*
+  
+  ``str	{String}`` A WKT fragment representing the polygon
+  
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A polygon feature 
+  
+.. _parse.multipolygon:                    
+  
+parse.multipolygon	
+  Return a multipolygon feature given a multipolygon WKT fragment.
+
+  *Parameters*
+  
+  ``str	{String}`` A WKT fragment representing the multipolygon
+
+  *Returns*
+
+  :ref:`{ZOO.Feature} <api-zoo-feature>` A multipolygon feature  
+  
+.. _parse.geometrycollection:                      
+  
+parse.geometrycollection	
+  Return an array of features given a geometrycollection WKT fragment.
+
+  *Parameters*
+  
+  ``str	{String}`` A WKT fragment representing the geometrycollection
+
+  *Returns*
+
+  ``{Array}`` An array of ZOO.Feature
Index: /tags/rel-1.7.0/docs/api/zoo-format-wps.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-format-wps.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-format-wps.rst	(revision 942)
@@ -0,0 +1,120 @@
+.. _api-zoo-format-wps:
+
+ZOO.Format.WPS
+==============
+
+Read/Write WPS.
+
+Inherits from
+
+- :ref:`ZOO.Format <api-zoo-format>`
+
+Functions and Properties	
+------------------------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`schemaLocation <schemaLocation>`
+     - {String} Schema location for a particular minor version.
+   * - :ref:`namespaces <namespaces>`
+     - {Object} Mapping of namespace aliases to namespace URIs.
+   * - :ref:`read <read>`
+     - 
+   * - :ref:`parseExecuteResponse <parseExecuteResponse>`
+     -   
+   * - :ref:`parseData <parseData>`
+     - Object containing methods to analyse data response.
+   * - :ref:`parseData.complexdata <parseData.complexdata>`
+     - Given an Object representing the WPS complex data response.   
+   * - :ref:`parseData.literaldata <parseData.literaldata>`
+     - Given an Object representing the WPS literal data response.
+   * - :ref:`parseData.reference <parseData.reference>`
+     - Given an Object representing the WPS reference response. 
+       
+.. _schemaLocation:   
+
+schemaLocation	
+  ``{String}`` Schema location for a particular minor version.
+  
+.. _namespaces:   
+  
+namespaces	
+  ``{Object}`` Mapping of namespace aliases to namespace URIs.
+  
+.. _read:     
+  
+read
+  ::
+  
+    read:function(data)
+
+  *Parameters*
+  
+  ``data {String}`` A WPS xml document
+  
+  *Returns*
+
+  ``{Object}`` Execute response.
+
+.. _parseExecuteResponse:     
+
+parseExecuteResponse	
+  ::
+  
+    parseExecuteResponse: function(node)
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A WPS ExecuteResponse document
+
+  *Returns*
+
+  ``{Object}`` Execute response.
+
+.. _parseData:     
+
+parseData	
+  Object containing methods to analyse data response.
+  
+.. _parseData.complexdata:       
+  
+parseData.complexdata	
+  Given an Object representing the WPS complex data response.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A WPS node.
+  
+  *Returns*
+
+  ``{Object}`` A WPS complex data response.  
+  
+.. _parseData.literaldata:         
+  
+parseData.literaldata	
+  Given an Object representing the WPS literal data response.\
+  
+  *Parameters*
+  
+  ``node {E4XElement}`` A WPS node.
+  
+  *Returns*
+
+  ``{Object}`` A WPS literal data response.  
+  
+.. _parseData.reference:         
+  
+parseData.reference	
+  Given an Object representing the WPS reference response.
+
+  *Parameters*
+  
+  ``node {E4XElement}`` A WPS node.
+  
+  *Returns*
+
+  ``{Object}`` A WPS reference response.
Index: /tags/rel-1.7.0/docs/api/zoo-format.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-format.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-format.txt	(revision 942)
@@ -0,0 +1,143 @@
+.. _api-zoo-format:
+
+ZOO.Format
+==========
+
+Base class for format reading/writing a variety of formats.
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`options <options>`
+     - {Object} A reference to options passed to the constructor.
+   * - :ref:`externalProjection <externalProjection>`
+     - {ZOO.Projection} When passed a externalProjection and internalProjection, the format will reproject the geometries it reads or writes.
+   * - :ref:`internalProjection <internalProjection>`
+     - {ZOO.Projection} When passed a externalProjection and internalProjection, the format will reproject the geometries it reads or writes.
+   * - :ref:`data <data>`
+     - {Object} When keepData is true, this is the parsed string sent to read.
+   * - :ref:`keepData <keepData>`
+     - {Object} Maintain a reference (data) to the most recently read data.   
+     
+Functions	
+---------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Format <ZOO.Format>`
+     - Instances of this class are not useful.
+   * - :ref:`destroy <destroy>`
+     - Clean up.
+   * - :ref:`read <read>`
+     - Read data from a string, and return an object whose type depends on the subclass.
+   * - :ref:`data <data>`
+     - {Object} When keepData is true, this is the parsed string sent to read.
+   * - :ref:`write <write>`
+     - Accept an object, and return a string.     
+        
+**Properties**
+
+.. _options:   
+
+options	
+  ``{Object}`` A reference to options passed to the constructor.
+  
+.. _externalProjection:   
+
+externalProjection	
+  :ref:`{ZOO.Projection} <api-zoo-projection>` When passed a externalProjection and internalProjection, 
+  the format will reproject the geometries it reads or writes. The externalProjection is the projection 
+  used by the content which is passed into read or which comes out of write.  In order to reproject, 
+  a projection transformation function for the specified projections must be available.  This support 
+  is provided via zoo-proj4js.
+
+.. _internalProjection:   
+
+internalProjection	
+  :ref:`{ZOO.Projection} <api-zoo-projection>` When passed a externalProjection and internalProjection, 
+  the format will reproject the geometries it reads or writes. The internalProjection is the projection 
+  used by the geometries which are returned by read or which are passed into write.  In order to reproject, 
+  a projection transformation function for the specified projections must be available.  This support 
+  is provided via zoo-proj4js.
+
+.. _data:   
+
+data	
+  ``{Object}`` When :ref:`keepData <keepData>` is true, this is the parsed string sent to :ref:`read <read>`.
+
+.. _keepData:   
+
+keepData	
+  ``{Object}`` Maintain a reference (:ref:`data <data>`) to the most recently read data.  Default is false.
+
+**Functions**
+
+.. _ZOO.Format:   
+
+ZOO.Format	
+  Instances of this class are not useful.  See one of the subclasses.
+
+  *Parameters*
+  
+  ``options {Object}`` An optional object with properties to set on the format
+  
+  *Valid options*
+
+  ``keepData {Boolean}`` If true, upon read, the data property will be set to the parsed object (e.g. the json or xml object).
+
+  *Returns*
+
+  An instance of ZOO.Format
+  
+.. _destroy:     
+  
+destroy	
+  ::
+  
+    destroy: function()
+
+  Clean up.
+
+.. _read:     
+  
+read	
+  ::
+  
+    read: function(data)
+
+  Read data from a string, and return an object whose type depends on the subclass.
+
+  *Parameters*
+  
+  ``data {string}`` Data to read/parse.
+
+  *Returns*
+
+  Depends on the subclass
+
+.. _write:     
+
+write	
+  ::
+  
+    write: function(data)
+
+  Accept an object, and return a string.   
+
+  *Parameters*
+  
+  ``object {Object}`` Object to be serialized
+  
+  *Returns*
+
+  ``{String}`` A string representation of the object.  
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-collection.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-collection.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-collection.txt	(revision 942)
@@ -0,0 +1,355 @@
+.. _api-zoo-geometry-collection:
+
+ZOO.Geometry.Collection
+=======================
+
+A Collection is exactly what it sounds like: A collection of different Geometries.  
+These are stored in the local parameter :ref:`components <components>` (which can 
+be passed as a parameter to the constructor).
+
+As new geometries are added to the collection, they are NOT cloned.  When removing geometries, 
+they need to be specified by reference (ie you have to pass in the exact geometry to be removed).
+
+The <getArea> and :ref:`getLength <getLength>` functions here merely iterate through the components, 
+summing their respective areas and lengths.
+
+Create a new instance with the :ref:`ZOO.Geometry.Collection <ZOO.Geometry.Collection>` constructor.
+
+Inherits from
+
+- :ref:`ZOO.Geometry <api-zoo-geometry>`
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`components <components>`
+     - {Array(ZOO.Geometry)} The component parts of this geometry
+   * - :ref:`componentTypes <componentTypes>`
+     - {Array(String)} An array of class names representing the types of components that the collection can include.
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Geometry.Collection <ZOO.Geometry.Collection>`
+     - Creates a Geometry Collection -- a list of geoms.
+   * - :ref:`destroy <destroy>`
+     - Destroy this geometry.
+   * - :ref:`clone <clone>`
+     - Clone this geometry.
+   * - :ref:`getComponentsString <getComponentsString>`
+     - Get a string representing the components for this collection.
+   * - :ref:`calculateBounds <calculateBounds>`
+     - Recalculate the bounds by iterating through the components and calling extendBounds() on each item.
+   * - :ref:`addComponent <addComponent>`
+     - Add a new component (geometry) to the collection.
+   * - :ref:`removeComponents <removeComponents>`
+     - Remove components from this geometry.
+   * - :ref:`removeComponent <removeComponent>`
+     - Remove a component from this geometry.
+   * - :ref:`getLength <getLength>`
+     - Calculate the length of this geometry. 
+   * - :ref:`getCentroid <getCentroid>`
+     - {ZOO.Geometry.Point} The centroid of the collection.
+   * - :ref:`getGeodesicLength <getGeodesicLength>`
+     - Calculate the approximate length of the geometry were it projected onto the earth.
+   * - :ref:`move <move>`
+     - Moves a geometry by the given displacement along positive x and y axes.
+   * - :ref:`rotate <rotate>`
+     - Rotate a geometry around some origin.
+   * - :ref:`resize <resize>`
+     - Resize a geometry relative to some origin.
+   * - :ref:`equals <equals>`
+     - Determine whether another geometry is equivalent to this one.
+   * - :ref:`transform <transform>`
+     - Reproject the components geometry from source to dest.
+   * - :ref:`intersects <intersects>`
+     - Determine if the input geometry intersects this one.
+   * - :ref:`getVertices <getVertices>`
+     - Return a list of all points in this geometry.      
+   
+     
+**Properties**
+       
+.. _components: 
+
+components	
+  {Array(:ref:`ZOO.Geometry <api-zoo-geometry>`)} The component parts of this geometry
+  
+.. _componentTypes:   
+  
+componentTypes	
+  ``{Array(String)}`` An array of class names representing the types of components that the collection can include.
+  A null value means the component types are not restricted.
+
+**Functions**
+       
+.. _ZOO.Geometry.Collection:
+
+ZOO.Geometry.Collection	
+  Creates a Geometry Collection -- a list of geoms.
+
+  *Parameters*
+  
+  ``components`` {Array(:ref:`ZOO.Geometry <api-zoo-geometry>`)} Optional array of geometries 
+  
+.. _destroy: 
+ 
+destroy	
+  ::
+  
+    destroy: function ()
+
+Destroy this geometry. 
+
+.. _clone:   
+  
+clone	
+  ::
+  
+    clone: function()
+
+  Clone this geometry.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Collection} <api-zoo-geometry-collection>` An exact clone of this collection.
+  
+.. _getComponentsString:     
+  
+getComponentsString	
+  ::
+  
+    getComponentsString: function()
+
+  Get a string representing the components for this collection.
+  
+  *Returns*
+
+  ``{String}`` A string representation of the components of this geometry.
+  
+.. _calculateBounds:  
+  
+calculateBounds	
+  ::
+  
+    calculateBounds: function()
+
+  Recalculate the bounds by iterating through the components and calling extendBounds() on each item.
+  
+.. _addComponent:    
+  
+addComponent	
+  ::
+  
+    addComponent: function(component,index)
+
+  Add a new component (geometry) to the collection.  If this.componentTypes is set, then the 
+  component class name must be in the componentTypes array.  The bounds cache is reset.
+  
+  *Parameters*
+  
+  | ``component`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` A geometry to add
+  | ``index {int}`` Optional index into the array to insert the component
+  
+  *Returns*
+
+  ``{Boolean}`` The component geometry was successfully added 
+  
+.. _removeComponents:      
+  
+removeComponents	
+  ::
+  
+    removeComponents: function(components)
+
+  Remove components from this geometry.\
+  
+  *Parameters*
+  
+  ``components`` {Array(:ref:`ZOO.Geometry <api-zoo-geometry>`)} The components to be removed  
+  
+.. _removeComponent:  
+  
+removeComponent	
+  ::
+  
+    removeComponent: function(component)
+
+  Remove a component from this geometry.
+  
+  *Parameters*
+  
+  ``component`` :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+  
+.. _getLength:    
+  
+getLength	
+  ::
+  
+    getLength: function()
+
+  Calculate the length of this geometry
+ 
+  *Returns*
+
+  ``{Float}`` The length of the geometry  
+  
+.. _getCentroid:      
+  
+getCentroid	
+  ::
+  
+    getCentroid: function()
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` The centroid of the collection 
+  
+.. _getGeodesicLength:        
+  
+getGeodesicLength	
+  ::
+  
+    getGeodesicLength: function(projection)
+
+  Calculate the approximate length of the geometry were it projected onto the earth.
+
+  *Parameters*
+  
+  ``projection`` :ref:`{ZOO.Projection} <api-zoo-projection>` The spatial 
+  reference system for the geometry coordinates.  If not provided, Geographic/WGS84 is assumed.
+  
+  *Returns*
+
+  ``{Float}`` The appoximate geodesic length of the geometry in meters. 
+  
+.. _move:          
+  
+move	
+  ::
+  
+    move: function(x,y)
+
+  Moves a geometry by the given displacement along positive x and y axes.  This modifies the 
+  position of the geometry and clears the cached bounds.
+  
+  *Parameters*
+  
+  | ``x	{Float}`` Distance to move geometry in positive x direction.
+  | ``y	{Float}`` Distance to move geometry in positive y direction.  
+  
+.. _rotate:            
+  
+rotate	
+  ::
+  
+    rotate: function(angle,origin)
+
+  Rotate a geometry around some origin
+  
+  *Parameters*
+  
+  | ``angle {Float}`` Rotation angle in degrees (measured counterclockwise from the positive x-axis)
+  | ``origin`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Center point for the rotation 
+  
+.. _resize:              
+  
+resize	
+  ::
+  
+    resize: function(scale,origin,ratio)
+
+  Resize a geometry relative to some origin.  Use this method to apply a uniform scaling to a geometry.
+
+  *Parameters*
+  
+  | ``scale {Float}`` Factor by which to scale the geometry.  A scale of 2 doubles the size of the geometry in each dimension (lines, for example, will be twice as long, and polygons will have four times the area).
+  | ``origin`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Point of origin for resizing
+  | ``ratio {Float}`` Optional x:y ratio for resizing.  Default ratio is 1.
+
+  *Returns*
+  
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>`  The current geometry.  
+
+.. _equals:                
+  
+equals	
+  ::
+  
+    equals: function(geometry)
+
+  Determine whether another geometry is equivalent to this one.  Geometries are considered equivalent if 
+  all components have the same coordinates.
+  
+  *Parameters*
+  
+  ``geom`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` The geometry to test.
+
+  *Returns*
+
+  ``{Boolean}`` The supplied geometry is equivalent to this geometry. 
+  
+.. _transform:                  
+  
+transform	
+  ::
+  
+    transform: function(source,dest)
+
+  Reproject the components geometry from source to dest.
+
+  *Parameters*
+  
+  | ``source`` :ref:`{ZOO.Projection} <api-zoo-projection>`
+  | ``dest`` :ref:`{ZOO.Projection} <api-zoo-projection>`
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+  
+.. _intersects:                    
+  
+intersects	
+  ::
+  
+    intersects: function(geometry)
+
+  Determine if the input geometry intersects this one.
+
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` Any type of geometry.
+
+  *Returns*
+
+  ``{Boolean}`` The input geometry intersects this one. 
+  
+.. _getVertices:                      
+  
+getVertices	
+  ::
+  
+    getVertices: function(nodes)
+
+  Return a list of all points in this geometry.
+  
+  *Parameters*
+  
+  ``nodes {Boolean}`` For lines, only return vertices that are endpoints.  If false, for lines, 
+  only vertices that are not endpoints will be returned.  If not provided, all vertices will be returned.
+
+  *Returns*
+
+  ``{Array}`` A list of all vertices in the geometry.
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-curve.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-curve.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-curve.txt	(revision 942)
@@ -0,0 +1,68 @@
+.. _api-zoo-geometry-curve:
+
+ZOO.Geometry.Curve
+==================
+
+A Curve is a MultiPoint, whose points are assumed to be connected.  To this end, 
+we provide a "getLength()" function, which iterates through the points, summing the 
+distances between them.
+
+Inherits from
+
+- :ref:`ZOO.Geometry.MultiPoint <api-zoo-geometry-multipoint>`
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`componentTypes <componentTypes>`
+     - {Array(String)} An array of class names representing the types of components that the collection can include.
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.Curve <ZOO.Geometry.Curve>`
+     - 
+   * - :ref:`getLength <getLength>`
+     - {Float} The length of the curve        
+     
+**Properties**
+       
+.. _componentTypes: 
+
+componentTypes	
+  ``{Array(String)}`` An array of class names representing the types of components that the 
+  collection can include.  A null value means the component types are not restricted.  
+  
+**Functions** 
+
+.. _ZOO.Geometry.Curve: 
+
+ZOO.Geometry.Curve
+
+  *Parameters*
+  
+  ``point`` {Array(:ref:`ZOO.Geometry.Point <api-zoo-geometry-point>`)}
+  
+.. _getLength: 
+
+getLength
+
+  ::
+  
+    getLength: function()
+
+  *Returns*
+
+  ``{Float}`` The length of the curve
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-linearring.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-linearring.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-linearring.txt	(revision 942)
@@ -0,0 +1,231 @@
+.. _api-zoo-geometry-linearring:
+
+ZOO.Geometry.LinearRing
+=======================
+
+A Linear Ring is a special LineString which is closed.  It closes itself automatically 
+on every addPoint/removePoint by adding a copy of the first point as the last point.
+
+Also, as it is the first in the line family to close itself, a getArea() function is 
+defined to calculate the enclosed area of the linearRing
+
+Inherits from
+
+- :ref:`ZOO.Geometry.LineString <api-zoo-geometry-linestring>`
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`componentTypes <componentTypes>`
+     - {Array(String)} An array of class names representing the types of components that the collection can include.
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.LinearRing <ZOO.Geometry.LinearRing>`
+     - Linear rings are constructed with an array of points.
+   * - :ref:`addComponent <addComponent>`
+     - Adds a point to geometry components.  
+   * - :ref:`move <move>`
+     - Moves a geometry by the given displacement along positive x and y axes.
+   * - :ref:`rotate <rotate>`
+     - Rotate a geometry around some origin   
+   * - :ref:`resize <resize>`
+     - Resize a geometry relative to some origin.
+   * - :ref:`transform <transform>`
+     - Reproject the components geometry from source to dest. 
+   * - :ref:`getCentroid <getCentroid>`
+     - {ZOO.Geometry.Point} The centroid of the ring
+   * - :ref:`getArea <getArea>`
+     -     
+   * - :ref:`getGeodesicArea <getGeodesicArea>`
+     - Calculate the approximate area of the polygon were it projected onto the earth.   
+   * - :ref:`containsPoint <containsPoint>`
+     - Test if a point is inside a linear ring.     
+     
+**Properties**
+       
+.. _componentTypes: 
+
+componentTypes	
+  ``{Array(String)}`` An array of class names representing the types of components that the 
+  collection can include.  A null value means the component types are not restricted.  
+  
+**Functions** 
+
+.. _ZOO.Geometry.LinearRing: 
+
+ZOO.Geometry.LinearRing	
+  Linear rings are constructed with an array of points.  This array can represent a closed 
+  or open ring.  If the ring is open (the last point does not equal the first point), 
+  the constructor will close the ring.  If the ring is already closed (the last point does 
+  equal the first point), it will be left closed.
+  
+  *Parameters*
+  
+  ``points`` {Array(:ref:`ZOO.Geometry.Point <api-zoo-geometry-point>`)} points  
+  
+.. _addComponent:   
+  
+addComponent	
+  ::
+  
+    addComponent: function(point,index)
+
+  Adds a point to geometry components.  If the point is to be added to the end of the 
+  components array and it is the same as the last point already in that array, the 
+  duplicate point is not added.  This has the effect of closing the ring if it is not 
+  already closed, and doing the right thing if it is already closed.  This behavior can be 
+  overridden by calling the method with a non-null index as the second argument.
+  
+  *Parameter*
+  
+  | ``point`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>`
+  | ``index {Integer}`` Index into the array to insert the component
+
+  *Returns*
+
+  ``{Boolean}`` Was the Point successfully added?  
+  
+.. _move:     
+  
+move	
+  ::
+  
+    move: function(x,y)
+
+  Moves a geometry by the given displacement along positive x and y axes.  This 
+  modifies the position of the geometry and clears the cached bounds.
+  
+  *Parameters*
+  
+  | ``x {Float}`` Distance to move geometry in positive x direction.
+  | ``y	{Float}`` Distance to move geometry in positive y direction.  
+
+.. _rotate:       
+  
+rotate	
+  ::
+  
+    rotate: function(angle,origin)
+
+  Rotate a geometry around some origin
+
+  *Parameters*
+  
+  | ``angle {Float}`` Rotation angle in degrees (measured counterclockwise from the positive x-axis)
+  | ``origin`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Center point for the rotation  
+
+.. _resize:         
+  
+resize	
+  ::
+  
+    resize: function(scale,origin,ratio)
+
+  Resize a geometry relative to some origin.  Use this method to apply a uniform scaling to a geometry.
+
+  *Parameters*
+  
+  | ``scale {Float}`` Factor by which to scale the geometry.  A scale of 2 doubles the size of the geometry in each dimension (lines, for example, will be twice as long, and polygons will have four times the area).
+  | ``origin`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Point of origin for resizing
+  | ``ratio {Float}`` Optional x:y ratio for resizing.  Default ratio is 1.
+
+  *Returns*
+  
+  ``{ZOO.Geometry}`` The current geometry.
+  
+.. _transform:           
+  
+transform	
+  ::
+  
+    transform: function(source,dest)
+
+  Reproject the components geometry from source to dest.
+
+  *Parameters*
+  
+  | ``source`` :ref:`{ZOO.Projection} <api-zoo-projection>`
+  | ``dest`` :ref:`{ZOO.Projection} <api-zoo-projection>`
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>` 
+  
+.. _getCentroid:             
+  
+getCentroid	
+  ::
+  
+    getCentroid: function()
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` The centroid of the ring  
+
+.. _getArea:               
+  
+getArea	
+  ::
+  
+    getArea: function()
+
+  .. note:: The area is positive if the ring is oriented CW, otherwise it will be negative.
+
+  *Returns*
+
+  ``{Float}`` The signed area for a ring.
+
+.. _getGeodesicArea:               
+
+getGeodesicArea	
+  ::
+  
+    getGeodesicArea: function(projection)
+
+  Calculate the approximate area of the polygon were it projected onto the earth.  Note that 
+  this area will be positive if ring is oriented clockwise, otherwise it will be negative.
+
+  *Parameters*
+  
+  ``projection`` :ref:`{ZOO.Projection} <api-zoo-projection>` The spatial reference system for the geometry coordinates.  If not provided, Geographic/WGS84 is assumed.
+
+  *Reference*
+
+  Robert.  G. Chamberlain and William H.  Duquette, "Some Algorithms for Polygons on a Sphere", 
+  JPL Publication 07-03, Jet Propulsion Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
+
+  *Returns*
+
+  ``{float}`` The approximate signed geodesic area of the polygon in square meters.  
+
+.. _containsPoint:                 
+  
+containsPoint	
+  ::
+  
+    containsPoint: function(point)
+
+  Test if a point is inside a linear ring.  For the case where a point is coincident with a 
+  linear ring edge, returns 1.  Otherwise, returns boolean.
+
+  *Parameters*
+
+  ``point`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>`
+
+  *Returns*
+
+  ``{Boolean | Number}`` The point is inside the linear ring.  Returns 1 if the point is coincident with an edge.  Returns boolean otherwise.
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-linestring.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-linestring.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-linestring.txt	(revision 942)
@@ -0,0 +1,180 @@
+.. _api-zoo-geometry-linestring:
+
+ZOO.Geometry.LineString
+=======================
+
+A LineString is a Curve which, once two points have been added to it, can never be less than two points long.
+
+Inherits from
+
+- :ref:`ZOO.Geometry.Curve <api-zoo-geometry-curve>`
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.LineString <ZOO.Geometry.LineString>`
+     - Create a new LineString geometry
+   * - :ref:`removeComponent <removeComponent>`
+     - Only allows removal of a point if there are three or more points in the linestring.  
+   * - :ref:`intersects <intersects>`
+     - Test for instersection between two geometries.
+   * - :ref:`getSortedSegments <getSortedSegments>`
+     - {Array} An array of segment objects.  
+   * - :ref:`splitWithSegment <splitWithSegment>`
+     - Split this geometry with the given segment.
+   * - :ref:`split <split>`
+     - Use this geometry (the source) to attempt to split a target geometry. 
+   * - :ref:`splitWith <splitWith>`
+     - Split this geometry (the target) with the given geometry (the source).
+   * - :ref:`getVertices <getVertices>`
+     - Return a list of all points in this geometry.       
+     
+.. _ZOO.Geometry.LineString: 
+
+ZOO.Geometry.LineString	
+  Create a new LineString geometry
+
+  *Parameters*
+  
+  ``points`` {Array(:ref:`ZOO.Geometry.Point <api-zoo-geometry-point>`)} An array of points used to generate the linestring  
+
+.. _removeComponent:  
+  
+removeComponent	
+  ::
+  
+    removeComponent: function(point)
+
+  Only allows removal of a point if there are three or more points in the linestring. (otherwise 
+  the result would be just a single point)
+
+  *Parameters*
+  
+  ``point`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` The point to be removed  
+  
+.. _intersects:  
+  
+intersects	
+  ::
+  
+    intersects: function(geometry)
+
+  Test for instersection between two geometries.  This is a cheapo implementation of the 
+  Bently-Ottmann algorigithm.  It doesn't really keep track of a sweep line data structure.  
+  It is closer to the brute force method, except that segments are sorted and potential intersections 
+  are only calculated when bounding boxes intersect.
+  
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+  
+  *Returns*
+
+  ``{Boolean}`` The input geometry intersects this geometry.  
+  
+.. _getSortedSegments:    
+  
+getSortedSegments	
+  ::
+  
+    getSortedSegments: function()
+
+  *Returns*
+
+  ``{Array}`` An array of segment objects.  Segment objects have properties x1, y1, x2, and y2.  
+  The start point is represented by x1 and y1.  The end point is represented by x2 and y2.  
+  Start and end are ordered so that x1 < x2.  
+  
+.. _splitWithSegment:      
+  
+splitWithSegment	
+  ::
+  
+    splitWithSegment: function(seg,options)
+
+  Split this geometry with the given segment.
+  
+  *Parameters*
+  
+  | ``seg {Object}`` An object with x1, y1, x2, and y2 properties referencing segment endpoint coordinates.
+  | ``options {Object}`` Properties of this object will be used to determine how the split is conducted.
+
+  *Valid options*
+  
+  | ``edge {Boolean}`` Allow splitting when only edges intersect.  Default is true.  If false, a vertex on the source segment must be within the tolerance distance of the intersection to be considered a split.
+  | ``tolerance	{Number}`` If a non-null value is provided, intersections within the tolerance distance of one of the source segment's endpoints will be assumed to occur at the endpoint.
+
+  *Returns*
+
+  ``{Object}`` An object with lines and points properties.  If the given segment intersects this linestring, the lines array will reference geometries that result from the split.  The points array will contain all intersection points.  Intersection points are sorted along the segment (in order from x1,y1 to x2,y2).  
+
+.. _split:        
+  
+split	
+  ::
+  
+    split: function(target,options)
+
+  Use this geometry (the source) to attempt to split a target geometry.
+  
+  *Parameters*
+  
+  | ``target`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` The target geometry.
+  | ``options {Object}`` Properties of this object will be used to determine how the split is conducted.
+
+  *Valid options*
+  
+  | ``mutual {Boolean}`` Split the source geometry in addition to the target geometry.  Default is false.
+  | ``edge {Boolean}`` Allow splitting when only edges intersect.  Default is true.  If false, a vertex on the source must be within the tolerance distance of the intersection to be considered a split.
+  | ``tolerance	{Number}`` If a non-null value is provided, intersections within the tolerance distance of an existing vertex on the source will be assumed to occur at the vertex.
+
+  *Returns*
+
+  ``{Array}`` A list of geometries (of this same type as the target) that result from splitting the target with the source geometry.  The source and target geometry will remain unmodified.  If no split results, null will be returned.  If mutual is true and a split results, return will be an array of two arrays - the first will be all geometries that result from splitting the source geometry and the second will be all geometries that result from splitting the target geometry.  
+
+.. _splitWith:          
+  
+splitWith	
+  ::
+  
+    splitWith: function(geometry,options)
+
+  Split this geometry (the target) with the given geometry (the source).
+  
+  *Parameters*
+  
+  | ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` A geometry used to split this geometry (the source).
+  | ``options {Object}`` Properties of this object will be used to determine how the split is conducted.
+
+  *Valid options*
+  
+  | ``mutual {Boolean}`` Split the source geometry in addition to the target geometry.  Default is false.
+  | ``edge {Boolean}`` Allow splitting when only edges intersect.  Default is true.  If false, a vertex on the source must be within the tolerance distance of the intersection to be considered a split.
+  | ``tolerance {Number}`` If a non-null value is provided, intersections within the tolerance distance of an existing vertex on the source will be assumed to occur at the vertex.
+
+  *Returns*
+
+  ``{Array}`` A list of geometries (of this same type as the target) that result from splitting the target with the source geometry.  The source and target geometry will remain unmodified.  If no split results, null will be returned.  If mutual is true and a split results, return will be an array of two arrays - the first will be all geometries that result from splitting the source geometry and the second will be all geometries that result from splitting the target geometry.  
+
+.. _getVertices:            
+  
+getVertices	
+  ::
+  
+    getVertices: function(nodes)
+
+  Return a list of all points in this geometry.
+  
+  *Parameters*
+  
+  ``nodes {Boolean}`` For lines, only return vertices that are endpoints.  If false, for lines, only vertices that are not endpoints will be returned.  If not provided, all vertices will be returned.
+
+  *Returns*
+
+  ``{Array}`` A list of all vertices in the geometry.
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-multilinestring.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-multilinestring.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-multilinestring.txt	(revision 942)
@@ -0,0 +1,31 @@
+.. _api-zoo-geometry-multilinestring:
+
+ZOO.Geometry.MultiLineString
+============================
+
+A MultiLineString is a geometry with multiple ZOO.Geometry.LineString components.
+
+Inherits from
+
+- :ref:`ZOO.Geometry.Collection <api-zoo-geometry-collection>`
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.MultiLineString <ZOO.Geometry.MultiLineString>`
+     - Constructor for a MultiLineString Geometry.     
+     
+.. _ZOO.Geometry.MultiLineString: 
+
+ZOO.Geometry.MultiLineString	
+  Constructor for a MultiLineString Geometry.
+
+  *Parameters*
+  
+  ``components`` {Array(:ref:`ZOO.Geometry.LineString <api-zoo-geometry-linestring>`)}
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-multipoint.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-multipoint.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-multipoint.txt	(revision 942)
@@ -0,0 +1,90 @@
+.. _api-zoo-geometry-multipoint:
+
+ZOO.Geometry.MultiPoint
+=======================
+
+MultiPoint is a collection of Points.  Create a new instance with the 
+:ref:`ZOO.Geometry.MultiPoint <ZOO.Geometry.MultiPoint>` constructor.
+
+Inherits from
+
+- :ref:`ZOO.Geometry.Collection <api-zoo-geometry-collection>`
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`componentTypes <componentTypes>`
+     - {Array(String)} An array of class names representing the types of components that the collection can include.
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.MultiPoint <ZOO.Geometry.MultiPoint>`
+     - Create a new MultiPoint Geometry
+   * - :ref:`addPoint <addPoint>`
+     - rapper for ZOO.Geometry.Collection.addComponent  
+   * - :ref:`removePoint <removePoint>`
+     - Wrapper for ZOO.Geometry.Collection.removeComponent       
+     
+**Properties**
+       
+.. _componentTypes: 
+
+componentTypes	
+  ``{Array(String)}`` An array of class names representing the types of components that the collection can include.  
+  A null value means the component types are not restricted.
+  
+**Functions**  
+
+.. _ZOO.Geometry.MultiPoint: 
+
+ZOO.Geometry.MultiPoint	
+  Create a new MultiPoint Geometry
+
+
+  *Parameters*
+  
+  ``components`` {Array(:ref:`ZOO.Geometry.Point <api-zoo-geometry-point>`)}
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry.MultPoint} <api-zoo-geometry-multipoint>` 
+  
+.. _addPoint:   
+  
+addPoint	
+  ::
+  
+    addPoint: function(point,index)
+
+  Wrapper for :ref:`ZOO.Geometry.Collection.addComponent <addComponent>`
+
+  *Parameters*
+  
+  | ``point`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Point to be added
+  | ``index {Integer}`` Optional index  
+  
+.. _removePoint:     
+  
+removePoint	
+  ::
+  
+    removePoint: function(point)
+
+  Wrapper for :ref:`ZOO.Geometry.Collection.removeComponent <removeComponent>`
+  
+  *Parameters*
+  
+  ``point`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Point to be removed
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-multipolygon.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-multipolygon.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-multipolygon.txt	(revision 942)
@@ -0,0 +1,32 @@
+.. _api-zoo-geometry-multipolygon:
+
+ZOO.Geometry.MultiPolygon
+=========================
+
+MultiPolygon is a geometry with multiple :ref:`ZOO.Geometry.Polygon <api-zoo-geometry-polygon>` components.  
+Create a new instance with the :ref:`ZOO.Geometry.MultiPolygon <ZOO.Geometry.MultiPolygon>` constructor.
+
+Inherits from
+
+- :ref:`ZOO.Geometry.Collection <api-zoo-geometry-collection>`
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.MultiPolygon <ZOO.Geometry.MultiPolygon>`
+     - Create a new MultiPolygon geometry        
+     
+.. _ZOO.Geometry.MultiPolygon: 
+
+ZOO.Geometry.MultiPolygon
+  Create a new MultiPolygon geometry
+
+  *Parameters*
+  
+  ``components`` {Array(:ref:`ZOO.Geometry.Polygon <api-zoo-geometry-polygon>`)} An array of polygons used to generate the MultiPolygon
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-point.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-point.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-point.txt	(revision 942)
@@ -0,0 +1,246 @@
+.. _api-zoo-geometry-point:
+
+ZOO.Geometry.Point
+==================
+
+Point geometry class.
+
+Inherits from
+
+- :ref:`ZOO.Geometry <api-zoo-geometry>`
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`x <x>`
+     - {float}
+   * - :ref:`y <y>`
+     - {float}
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.Point <ZOO.Geometry.Point>`
+     - Construct a point geometry.
+   * - :ref:`clone <clone>`
+     - {ZOO.Geometry.Point} An exact clone of this ZOO.Geometry.Point   
+   * - :ref:`calculateBounds <calculateBounds>`
+     - Create a new Bounds based on the x/y
+   * - :ref:`equals <equals>`
+     - Determine whether another geometry is equivalent to this one.
+   * - :ref:`toShortString <toShortString>`
+     - {String} Shortened String representation of Point object.
+   * - :ref:`move <move>`
+     - Moves a geometry by the given displacement along positive x and y axes.
+   * - :ref:`rotate <rotate>`
+     - Rotate a point around another.
+   * - :ref:`getCentroid <getCentroid>`
+     - {ZOO.Geometry.Point} The centroid of the collection 
+   * - :ref:`resize <resize>`
+     - Resize a point relative to some origin.
+   * - :ref:`intersects <intersects>`
+     - Determine if the input geometry intersects this one.  
+   * - :ref:`transform <transform>`
+     - Translate the x,y properties of the point from source to dest.
+   * - :ref:`getVertices <getVertices>`
+     - Return a list of all points in this geometry.      
+   
+     
+**Properties**
+       
+.. _x: 
+
+x	
+  ``{float}``
+  
+.. _y:  
+  
+y	
+  ``{float}``
+  
+**Functions**  
+
+.. _ZOO.Geometry.Point:  
+
+ZOO.Geometry.Point	
+  Construct a point geometry.
+
+  *Parameters*
+  
+  | ``x	{float}``
+  | ``y	{float}``
+  
+.. _clone:  
+  
+clone	
+  ::
+  
+    clone: function(obj)
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` An exact clone of this ZOO.Geometry.Point 
+  
+.. _calculateBounds:    
+  
+calculateBounds	
+  ::
+  
+    calculateBounds: function ()
+
+  Create a new Bounds based on the x/y  
+  
+.. _equals:      
+  
+equals	
+  ::
+  
+    equals: function(geom)
+
+  Determine whether another geometry is equivalent to this one.  Geometries are considered 
+  equivalent if all components have the same coordinates.
+  
+  *Parameters*
+  
+  ``geom`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` The geometry to test.
+  
+  *Returns*
+
+  ``{Boolean}`` The supplied geometry is equivalent to this geometry.
+  
+.. _toShortString:        
+  
+toShortString	
+  ::
+  
+    toShortString: function()
+
+  *Returns*
+
+  ``{String}`` Shortened String representation of Point object.  (ex.  <i>"5, 42"</i>)  
+  
+.. _move:          
+  
+move	
+  ::
+  
+    move: function(x,y)
+
+  Moves a geometry by the given displacement along positive x and y axes.  This modifies 
+  the position of the geometry and clears the cached bounds.
+
+  *Parameters*
+  
+  | ``x {Float}`` Distance to move geometry in positive x direction.
+  | ``y	{Float}`` Distance to move geometry in positive y direction. 
+  
+.. _rotate:            
+  
+rotate	
+  ::
+  
+    rotate: function(angle,origin)
+
+  Rotate a point around another.
+  
+  *Parameters*
+  
+  | ``angle {Float}`` Rotation angle in degrees (measured counterclockwise from the positive x-axis)
+  | ``origin`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Center point for the rotation 
+
+.. _getCentroid:             
+ 
+getCentroid	
+  ::
+  
+    getCentroid: function()
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` The centroid of the collection  
+  
+.. _resize:               
+  
+resize	
+  ::
+  
+    resize: function(scale,origin,ratio)
+
+  Resize a point relative to some origin.  For points, this has the effect of scaling a 
+  vector (from the origin to the point).  This method is more useful on geometry collection 
+  subclasses.
+  
+  *Parameters*
+  
+  | ``scale {Float}`` Ratio of the new distance from the origin to the old distance from the origin.  A scale of 2 doubles the distance between the point and origin.
+  | ``origin`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` Point of origin for resizing
+  | ``ratio {Float}`` Optional x:y ratio for resizing.  Default ratio is 1.
+
+  *Returns*
+  
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>` The current geometry.  
+  
+.. _intersects:                 
+  
+intersects	
+  ::
+  
+    intersects: function(geometry)
+
+  Determine if the input geometry intersects this one.
+  
+  *Parameters*
+  
+  ``geometry`` :ref:`{ZOO.Geometry} <api-zoo-geometry>` Any type of geometry.
+
+  *Returns*
+
+  ``{Boolean}`` The input geometry intersects this one. 
+  
+.. _transform:                   
+  
+transform	
+  ::
+  
+    transform: function(source,dest)
+
+  Translate the x,y properties of the point from source to dest.
+  
+  *Parameters*
+  
+  | ``source`` :ref:`{ZOO.Projection} <api-zoo-projection>`
+  | ``dest`` :ref:`{ZOO.Projection} <api-zoo-projection>`
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>`
+  
+.. _getVertices:                     
+  
+getVertices	
+  ::
+  
+    getVertices: function(nodes)
+
+  Return a list of all points in this geometry.
+  
+  *Parameters*
+  
+  ``nodes {Boolean}`` For lines, only return vertices that are endpoints.  If false, for lines, 
+  only vertices that are not endpoints will be returned.  If not provided, all vertices will be returned.
+
+  *Returns*
+
+  ``{Array}`` A list of all vertices in the geometry.
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-polygon.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-polygon.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-polygon.txt	(revision 942)
@@ -0,0 +1,87 @@
+.. _api-zoo-geometry-polygon:
+
+ZOO.Geometry.Polygon
+====================
+
+Polygon is a collection of :ref:`ZOO.Geometry.LinearRing <api-zoo-geometry-linearring>`.
+
+Inherits from
+
+- :ref:`ZOO.Geometry.Collection <api-zoo-geometry-collection>`
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`ZOO.Geometry.Polygon <ZOO.Geometry.Polygon>`
+     - Constructor for a Polygon geometry.   
+   * - :ref:`getArea <getArea>`
+     - Calculated by subtracting the areas of the internal holes from the area of the outer hole.  
+   * - :ref:`containsPoint <containsPoint>`
+     - Test if a point is inside a polygon.  
+   * - :ref:`createRegularPolygon <createRegularPolygon>`
+     - Create a regular polygon around a radius.       
+     
+.. _ZOO.Geometry.Polygon: 
+
+ZOO.Geometry.Polygon	
+  Constructor for a Polygon geometry.  The first ring (*this.component[0]*) is the outer 
+  bounds of the polygon and all subsequent rings (*this.component[1-n]*) are internal holes.
+
+  *Parameters*
+  
+  ``components`` {Array(:ref:`ZOO.Geometry.LinearRing <api-zoo-geometry-linearring>`)}  
+
+.. _getArea:  
+  
+getArea	
+  ::
+  
+    getArea: function()
+
+  Calculated by subtracting the areas of the internal holes from the area of the outer hole.
+
+  *Returns*
+
+  ``{float}`` The area of the geometry  
+  
+.. _containsPoint:    
+  
+containsPoint	
+  ::
+  
+    containsPoint: function(point)
+
+  Test if a point is inside a polygon.  Points on a polygon edge are considered inside.
+
+  *Parameters*
+  
+  ``point`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>`
+
+  *Returns*
+
+  ``{Boolean | Number}`` The point is inside the polygon.  Returns 1 if the point is on an edge.  Returns boolean otherwise.  
+
+.. _createRegularPolygon:      
+  
+createRegularPolygon	
+  ::
+  
+    ZOO.Geometry.Polygon.createRegularPolygon = function( origin,
+    	                                                  radius,
+                                                          sides,
+    	                                                  rotation	)
+
+  Create a regular polygon around a radius.  Useful for creating circles and the like.
+
+  *Parameters*
+  
+  | ``origin`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` center of polygon.
+  | ``radius {Float}`` distance to vertex, in map units.
+  | ``sides {Integer}`` Number of sides.  20 approximates a circle.
+  | ``rotation {Float}`` original angle of rotation, in degrees.
Index: /tags/rel-1.7.0/docs/api/zoo-geometry-surface.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry-surface.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry-surface.txt	(revision 942)
@@ -0,0 +1,10 @@
+.. _api-zoo-geometry-surface:
+
+ZOO.Geometry.Surface
+====================
+
+Surface geometry class.
+
+Inherits from
+
+- :ref:`ZOO.Geometry <api-zoo-geometry>`
Index: /tags/rel-1.7.0/docs/api/zoo-geometry.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-geometry.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-geometry.txt	(revision 942)
@@ -0,0 +1,173 @@
+.. _api-zoo-geometry:
+
+ZOO.Geometry
+============
+
+A Geometry is a description of a geographic object.
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`id <id>`
+     - {String} A unique identifier for this geometry.
+   * - :ref:`parent <parent>`
+     - {ZOO.Geometry}This is set when a Geometry is added as component of another geometry
+   * - :ref:`bounds <bounds>`
+     - {ZOO.Bounds} The bounds of this geometry
+
+Functions	
+---------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Geometry <ZOO.Geometry>`
+     - Creates a geometry object.
+   * - :ref:`destroy <destroy>`
+     - nullify references to prevent circular references and memory leaks
+   * - :ref:`clone <clone>`
+     - Create a clone of this vector feature.
+   * - :ref:`extendBounds <extendBounds>`
+     - Moves the feature and redraws it at its new location
+   * - :ref:`clearBounds <clearBounds>`
+     - Nullify this components bounds and that of its parent as well.
+   * - :ref:`getBounds <getBounds>`
+     - Get the bounds for this Geometry.
+   * - :ref:`calculateBounds <calculateBounds>`
+     - Recalculate the bounds for the geometry.
+   * - :ref:`toString <toString>`
+     - Returns the Well-Known Text representation of a geometry
+   * - :ref:`ZOO.Geometry.fromWKT <ZOO.Geometry.fromWKT>`
+     - Generate a geometry given a Well-Known Text string.   
+   
+     
+**Properties**
+       
+.. _id: 
+
+id	
+  ``{String}`` A unique identifier for this geometry.
+  
+.. _parent:  
+  
+parent	
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>` This is set when a Geometry is added as component of another geometry
+  
+.. _bounds:    
+  
+bounds	
+  :ref:`{ZOO.Bounds} <api-zoo-bounds>` The bounds of this geometry
+
+**Functions**
+       
+.. _ZOO.Geometry: 
+
+ZOO.Geometry	
+  Creates a geometry object.
+  
+.. _destroy:   
+  
+destroy	
+  ::
+  
+    destroy: function()
+
+  Destroy this geometry.
+  
+.. _clone:     
+  
+clone	
+  ::
+  
+    clone: function()
+
+  Create a clone of this geometry.  Does not set any non-standard properties of the cloned geometry.
+  
+  *Returns*
+
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>` An exact clone of this geometry.  
+  
+.. _extendBounds:       
+  
+extendBounds	
+  ::
+  
+    extendBounds: function(newBounds)
+
+  Extend the existing bounds to include the new bounds.  If geometry's bounds is not yet set, 
+  then set a new Bounds.
+  
+  *Parameters*
+  
+  ``newBounds``	:ref:`{ZOO.Bounds} <api-zoo-bounds>`
+  
+.. _clearBounds:         
+  
+clearBounds	
+  ::
+  
+    clearBounds: function()
+
+  Nullify this components bounds and that of its parent as well. 
+  
+.. _getBounds:           
+  
+getBounds	
+  ::
+  
+    getBounds: function()
+
+  Get the bounds for this Geometry.  If bounds is not set, it is calculated again, this 
+  makes queries faster.
+  
+  *Returns*
+
+  ``newBounds``	:ref:`{ZOO.Bounds} <api-zoo-bounds>`
+  
+.. _calculateBounds:             
+  
+calculateBounds	
+  ::
+  
+    calculateBounds: function()
+
+  Recalculate the bounds for the geometry. 
+  
+.. _toString:               
+  
+toString	
+  ::
+  
+    toString: function()
+
+  Returns the Well-Known Text representation of a geometry
+  
+  *Returns*
+
+  ``{String}`` Well-Known Text  
+  
+.. _ZOO.Geometry.fromWKT:                 
+  
+ZOO.Geometry.fromWKT	
+  ::
+  
+    ZOO.Geometry.fromWKT = function(wkt)
+
+  Generate a geometry given a Well-Known Text string.
+  
+  *Parameters*
+  
+  ``wkt	{String}`` A string representing the geometry in Well-Known Text.
+
+  *Returns*
+
+  :ref:`{ZOO.Geometry} <api-zoo-geometry>` A geometry of the appropriate class.
Index: /tags/rel-1.7.0/docs/api/zoo-process.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-process.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-process.rst	(revision 942)
@@ -0,0 +1,149 @@
+.. _api-zoo-process:
+
+ZOO.Process
+===========
+
+Used to query OGC WPS process defined by its URL and its identifier.  Useful for chaining localhost process.
+
+Properties and Functions	
+------------------------
+
+.. list-table::
+   :widths: 15 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION   
+   * - :ref:`schemaLocation <schemaLocation>`
+     - {String} Schema location for a particular minor version. 
+   * - :ref:`namespaces <namespaces>`
+     - {Object} Mapping of namespace aliases to namespace URIs.
+   * - :ref:`url <url>`
+     - {String} The OGC's Web PRocessing Service URL, default is http://localhost/zoo.
+   * - :ref:`identifier <identifier>`
+     - {String} Process identifier in the OGC's Web Processing Service. 
+   * - :ref:`ZOO.Process <ZOO.Process>`
+     - Create a new Process 
+   * - :ref:`Execute <Execute>`
+     - Query the OGC's Web PRocessing Servcie to Execute the process.
+   * - :ref:`buildInput <buildInput>`
+     - Object containing methods to build WPS inputs. 
+   * - :ref:`buildInput.complex <buildInput.complex>`
+     - Given an E4XElement representing the WPS complex data input.   
+   * - :ref:`buildInput.reference <buildInput.reference>`
+     - Given an E4XElement representing the WPS reference input.
+   * - :ref:`buildInput.literal <buildInput.literal>`
+     - Given an E4XElement representing the WPS literal data input.
+   * - :ref:`buildDataInputsNode <buildDataInputsNode>`
+     - Method to build the WPS DataInputs element.     
+     
+.. _schemaLocation: 
+
+schemaLocation	
+  ``{String}`` Schema location for a particular minor version.
+  
+.. _namespaces:   
+  
+namespaces	
+  ``{Object}`` Mapping of namespace aliases to namespace URIs.
+  
+.. _url:     
+  
+url	
+  ``{String}`` The OGC's Web PRocessing Service URL, default is http://localhost/zoo.
+  
+.. _identifier:       
+  
+identifier	
+  ``{String}`` Process identifier in the OGC's Web Processing Service.
+  
+.. _ZOO.Process:         
+  
+ZOO.Process	
+  Create a new Process
+
+  *Parameters*
+  
+  | ``url {String}`` The OGC's Web Processing Service URL.
+  | ``identifier {String}`` The process identifier in the OGC's Web Processing Service.  
+
+.. _Execute:           
+  
+Execute	
+  ::
+  
+    Execute: function(inputs)
+
+  Query the OGC's Web PRocessing Servcie to Execute the process.
+
+  *Parameters*
+  
+  ``inputs {Object}``
+  
+  *Returns*
+
+  ``{String}`` The OGC's Web processing Service XML response.  The result needs to be interpreted. 
+  
+.. _buildInput:             
+  
+buildInput	
+  Object containing methods to build WPS inputs.
+  
+.. _buildInput.complex:               
+  
+buildInput.complex	
+  Given an E4XElement representing the WPS complex data input.
+
+  *Parameters*
+  
+  | ``identifier {String}`` the input indetifier
+  | ``data {Object}`` A WPS complex data input.
+
+  *Returns*
+
+  ``{E4XElement}`` A WPS Input node.
+  
+.. _buildInput.reference:                 
+  
+buildInput.reference	
+  Given an E4XElement representing the WPS reference input.
+
+  *Parameters*
+  
+  | ``identifier {String}`` the input indetifier
+  | ``data {Object}`` A WPS reference input.
+
+  *Returns*
+
+  ``{E4XElement}`` A WPS Input node.  
+  
+.. _buildInput.literal:                   
+  
+buildInput.literal	
+  Given an E4XElement representing the WPS literal data input.
+
+  *Parameters*
+  
+  | ``identifier {String}`` the input indetifier
+  | ``data {Object}`` A WPS literal data input.
+
+  *Returns*
+
+  ``{E4XElement}`` The WPS Input node.  
+  
+.. _buildDataInputsNode:                     
+  
+buildDataInputsNode	
+  ::
+  
+    buildDataInputsNode:function(inputs)
+
+  Method to build the WPS DataInputs element.
+
+  *Parameters*
+  
+  ``inputs {Object}``
+  
+  *Returns*
+
+  ``{E4XElement}`` The WPS DataInputs node for Execute query.
Index: /tags/rel-1.7.0/docs/api/zoo-projection.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-projection.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-projection.txt	(revision 942)
@@ -0,0 +1,153 @@
+.. _api-zoo-projection:
+
+ZOO.Projection
+==============
+
+Class for coordinate transforms between coordinate systems.
+
+Properties	
+----------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`proj <proj>`
+     - {Number} Proj4js.Proj instance.
+   * - :ref:`projCode <projCode>`
+     - {String} 
+       
+Functions	
+---------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`ZOO.Projection <ZOO.Projection>`
+     - This class offers several methods for interacting with a wrapped zoo-pro4js projection object.
+   * - :ref:`getCode <getCode>`
+     - Get the string SRS code.
+   * - :ref:`getUnits <getUnits>`
+     - Get the units string for the projection -- returns null if zoo-proj4js is not available.
+   * - :ref:`toString <toString>`
+     - Convert projection to string (getCode wrapper).
+   * - :ref:`equals <equals>`
+     - Test equality of two projection instances.   
+   * - :ref:`destroy <destroy>`
+     - Destroy projection object.
+   * - :ref:`transform <transform>`
+     - Transform a point coordinate from one projection to another.       
+
+**Properties**
+
+.. _proj:   
+
+proj	
+  ``{Object}`` Proj4js.Proj instance.
+  
+.. _projCode:     
+  
+projCode	
+  ``{String}``
+
+**Functions**
+
+.. _ZOO.Projection:     
+
+ZOO.Projection	
+  This class offers several methods for interacting with a wrapped zoo-pro4js projection object.
+
+  *Parameters*
+  
+  | ``projCode {String}`` A string identifying the Well Known Identifier for the projection.
+  | ``options {Object}`` An optional object to set additional properties.
+
+  *Returns*
+
+  :ref:`{ZOO.Projection} <api-zoo-projection>` A projection object.
+  
+.. _getCode:     
+
+getCode	
+  ::
+  
+    getCode: function()
+
+  Get the string SRS code.
+  
+  *Returns*
+
+  ``{String}`` The SRS code. 
+  
+.. _getUnits:       
+
+getUnits	
+  ::
+  
+    getUnits: function()
+
+  Get the units string for the projection -- returns null if zoo-proj4js is not available.
+
+  *Returns*
+
+  ``{String}`` The units abbreviation.
+  
+.. _toString:       
+
+toString	
+  ::
+  
+    toString: function()
+
+  Convert projection to string (getCode wrapper).
+  
+  *Returns*
+
+  ``{String}`` The projection code.  
+  
+.. _equals:         
+  
+equals	
+  ::
+  
+    equals: function(projection)
+
+  Test equality of two projection instances.  Determines equality based soley on the projection code.
+
+  *Returns*
+
+  ``{Boolean}`` The two projections are equivalent. 
+  
+.. _destroy:           
+  
+destroy	
+  ::
+  
+    destroy: function()
+
+  Destroy projection object. 
+  
+.. _transform:             
+  
+transform	
+  ::
+  
+    ZOO.Projection.transform = function(point,source,dest)
+
+  Transform a point coordinate from one projection to another.  Note that the input point is 
+  transformed in place.
+  
+  *Parameters*
+  
+  | ``point {{ZOO.Geometry.Point> | Object}`` An object with x and y properties representing coordinates in those dimensions.
+  | ``sourceProj {ZOO.Projection}`` Source map coordinate system
+  | ``destProj {ZOO.Projection}`` Destination map coordinate system
+
+  *Returns*
+  
+  ``point {object}`` A transformed coordinate.  The original point is modified.
Index: /tags/rel-1.7.0/docs/api/zoo-request.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-request.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-request.rst	(revision 942)
@@ -0,0 +1,49 @@
+.. _api-zoo-request:
+
+ZOO.Request
+===========
+
+Contains convenience methods for working with ZOORequest which replace XMLHttpRequest.
+
+Functions
+---------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`GET <GET>`
+     - Send an HTTP GET request.
+   * - :ref:`POST <POST>`
+     - Send an HTTP POST request. 
+     
+.. _GET:
+
+GET	
+  Send an HTTP GET request.
+
+  *Parameters*
+  
+  | ``url {String}`` The URL to request.
+  | ``params {Object}`` Params to add to the url
+
+  *Returns*
+
+  ``{String}`` Request result.
+  
+.. _POST:
+
+POST	
+  Send an HTTP POST request.
+
+  *Parameters*
+  
+  | ``url {String}`` The URL to request.
+  | ``body {String}`` The request's body to send.
+  | ``headers {Object}`` A key-value object of headers to push to the request's head
+
+  *Returns*
+
+  ``{String}`` Request result.
Index: /tags/rel-1.7.0/docs/api/zoo-string.txt
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo-string.txt	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo-string.txt	(revision 942)
@@ -0,0 +1,147 @@
+.. _api-zoo-string:
+
+ZOO.String
+==========
+
+Contains convenience methods for string manipulation:
+
+Functions and Properties
+------------------------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`startsWith <startsWith>`
+     - Test whether a string starts with another string.
+   * - :ref:`contains <contains>`
+     - Test whether a string contains another string.  
+   * - :ref:`trim <trim>` 
+     - Removes leading and trailing whitespace characters from a string.
+   * - :ref:`camelize <camelize>`
+     - Camel-case a hyphenated string.    
+   * - :ref:`tokenRegEx <tokenRegEx>`
+     - Used to find tokens in a string.     
+   * - :ref:`numberRegEx <numberRegEx>` 
+     - Used to test strings as numbers.
+   * - :ref:`isNumeric <isNumeric>`
+     - Determine whether a string contains only a numeric value. 
+   * - :ref:`numericIf <numericIf>`
+     - Converts a string that appears to be a numeric value into a number.        
+
+.. _startsWith:
+
+startsWith
+  ::
+  
+    startsWith: function(str,sub)
+
+  Test whether a string starts with another string.
+
+  *Parameters*
+  
+  | ``str {String}`` The string to test.
+  | ``sub {Sring}`` The substring to look for.
+
+  *Returns*
+
+  ``{Boolean}`` The first string starts with the second.
+  
+.. _contains:
+
+contains	
+  ::
+  
+    contains: function(str,sub)
+
+  Test whether a string contains another string.
+
+  *Parameters*
+  
+  | ``str {String}`` The string to test.
+  | ``sub {String}`` The substring to look for.
+
+  *Returns*
+
+  ``{Boolean}`` The first string contains the second.
+  
+.. _trim:
+
+trim	
+  ::
+  
+    trim: function(str)
+
+  Removes leading and trailing whitespace characters from a string.
+
+  *Parameters*
+  
+  ``str	{String}`` The (potentially) space-padded string. This string is not modified.
+
+  *Returns*
+
+  ``{String}`` A trimmed version of the string with all leading and trailing spaces removed.
+
+.. _camelize:
+
+camelize	
+  ::
+  
+    camelize: function(str)
+
+  Camel-case a hyphenated string. Ex. "chicken-head" becomes "chickenHead", and "-chicken-head" becomes "ChickenHead".
+
+  *Parameters*
+  
+  ``str	{String}`` The string to be camelized.  The original is not modified.
+
+  *Returns*
+
+  ``{String}`` The string, camelized  
+  
+.. _tokenRegEx:  
+  
+tokenRegEx	
+  Used to find tokens in a string.  Examples: *${a}, ${a.b.c}, ${a-b}, ${5}*
+  
+.. _numberRegEx:    
+  
+numberRegEx	
+  Used to test strings as numbers.
+  
+.. _isNumeric:  
+  
+isNumeric	
+  ::
+  
+    isNumeric: function(value)
+
+  Determine whether a string contains only a numeric value.
+
+  *Examples*
+
+  ::
+  
+    ZOO.String.isNumeric("6.02e23") // true
+    ZOO.String.isNumeric("12 dozen") // false
+    ZOO.String.isNumeric("4") // true
+    ZOO.String.isNumeric(" 4 ") // false
+
+  *Returns*
+
+  ``{Boolean}`` String contains only a number. 
+  
+.. _numericIf:  
+
+numericIf	
+  ::
+  
+    numericIf: function(value)
+
+  Converts a string that appears to be a numeric value into a number.
+
+  *Returns*
+  
+  ``{Number|String}`` a Number if the passed value is a number, a String otherwise.
Index: /tags/rel-1.7.0/docs/api/zoo.rst
===================================================================
--- /tags/rel-1.7.0/docs/api/zoo.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/api/zoo.rst	(revision 942)
@@ -0,0 +1,188 @@
+.. _api-zoo:
+
+ZOO
+===
+
+The following constants and functions are available for the ZOO class:
+
+Constants
+---------
+
+.. list-table::
+   :widths: 30 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`SERVICE_ACCEPTED <service_accepted>`
+     - {Integer} used for 
+   * - :ref:`SERVICE_STARTED <service_started>`
+     - {Integer} used for   
+   * - :ref:`SERVICE_PAUSED <service_paused>` 
+     - {Integer} used for 
+   * - :ref:`SERVICE_SUCCEEDED <service_succeeded>`
+     - {Integer} used for      
+   * - :ref:`SERVICE_FAILED <service_failed>`
+     - {Integer} used for        
+
+Functions
+---------
+
+.. list-table::
+   :widths: 12 50
+   :header-rows: 1
+
+   * - NAME
+     - DESCRIPTION
+   * - :ref:`removeItem <removeItem>`
+     - Remove an object from an array.   
+   * - :ref:`indexOf <indexOf>` 
+     - 
+   * - :ref:`extend <extend>` 
+     - Copy all properties of a source object to a destination object.  
+   * - :ref:`rad <rad>`  
+     -     
+   * - :ref:`distVincenty <distVincenty>`
+     - Given two objects representing points with geographic coordinates, 
+       this calculates the distance between those points on the surface of an  
+       ellipsoid. 
+   * - :ref:`Class <Class>` 
+     - Method used to create ZOO classes. 
+   * - :ref:`UpdateStatus <UpdateStatus>`
+     - Method used to update the status of the process      
+
+**Constants**
+
+.. _service_accepted:
+
+SERVICE_ACCEPTED	
+  ``{Integer}`` used for
+  
+.. _service_started:
+
+SERVICE_STARTED
+  ``{Integer}`` used for
+  
+.. _service_paused:  
+
+SERVICE_PAUSED	
+  ``{Integer}`` used for
+  
+.. _service_succeeded:  
+
+SERVICE_SUCCEEDED
+  ``{Integer}`` used for
+  
+.. _service_failed:    
+  
+SERVICE_FAILED	
+  ``{Integer}`` used for
+
+**Functions**
+
+.. _removeItem:
+
+removeItem	
+  ::
+  
+    removeItem: function(array,item)
+  
+  Remove an object from an array.  Iterates through the array to find the item, then removes it.
+  
+  *Parameters*
+  
+  | ``array {Array}``
+  | ``item {Object}``
+  
+  *Returns*
+   
+  ``{Array}`` A reference to the array
+  
+.. _indexOf:
+
+indexOf	
+  ::
+  
+    indexOf: function(array,obj)
+
+  *Parameters*
+   
+  | ``array {Array}``
+  | ``obj {Object}``
+
+  *Returns*
+
+  ``{Integer}`` The index at, which the first object was found in the array.  If not found, returns -1.
+
+.. _extend:
+
+extend
+  ::
+  
+    extend: function(destination,source)
+
+  Copy all properties of a source object to a destination object.  Modifies the passed in destination object.  
+  Any properties on the source object that are set to undefined will not be (re)set on the destination object.
+
+  *Parameters*
+  
+  | ``destination {Object}`` The object that will be modified
+  | ``source {Object}`` The object with properties to be set on the destination
+
+  *Returns*
+
+  ``{Object}`` The destination object.
+  
+.. _rad:  
+  
+rad	
+  ::
+  
+    rad: function(x)
+
+  *Parameters*
+  
+  | ``x {Float}``
+
+  *Returns*
+
+  ``{Float}``
+
+.. _distVincenty:
+
+distVincenty
+  ::
+
+    distVincenty: function(p1,p2)
+
+  Given two objects representing points with geographic coordinates, this calculates the distance between 
+  those points on the surface of an ellipsoid.
+
+  *Parameters:*
+
+  | ``p1`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` (or any object with both .x, .y properties)
+  | ``p2`` :ref:`{ZOO.Geometry.Point} <api-zoo-geometry-point>` (or any object with both .x, .y properties)
+
+.. _Class:
+
+Class	
+  ::
+  
+    Class: function()
+
+  Method used to create ZOO classes.  Includes support for multiple inheritance.
+  
+.. _UpdateStatus:  
+  
+UpdateStatus	
+  ::
+  
+    UpdateStatus: function(env,value)
+
+  Method used to update the status of the process
+
+  *Parameters*
+  
+  | ``env {Object}`` The environment object
+  | ``value {Float}`` The status value between 0 to 100
+
Index: /tags/rel-1.7.0/docs/client/example.rst
===================================================================
--- /tags/rel-1.7.0/docs/client/example.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/client/example.rst	(revision 942)
@@ -0,0 +1,181 @@
+.. _client-example:
+
+Example application
+=====================
+
+This section gives a detailed example of ZOO-Client based JavaScript appliclation.
+
+.. note::
+   For this example application, first setup a ``/zoo-client-demo`` directory accessible from your web server at `http://localhost/zoo-client-demo`.
+
+The following subdirectories must be created in the ``/zoo-client-demo`` directory:
+
+:: 
+
+    assets
+    assets/js
+    assets/js/lib
+    assets/js/lib/hogan
+    assets/js/lib/jquery
+    assets/js/lib/query-string
+    assets/js/lib/xml2json
+    assets/js/lib/zoo
+    assets/tpl
+
+You will need to copy your node_modules javascript files copied in the
+`hogan` and `query-string` directories. First, you wil need to install
+query-string.
+
+:: 
+
+    npm install query-string
+
+Then you will copy `query-string.js` and `hogan-3.0.2.js` files in
+your `zoo-client-demo` web directory. Those files are located in your
+`~/node_modules` directory.
+
+For other libraries, you will need to download them from their
+official web sites and uncompress them in the corresponding
+directories.
+
+Loading the modules from your web application
+*********************************************
+
+Before using the ZOO-Client, you will first have to include the
+javascript files from your web page. With the use of requirejs you
+will need only one line in your HTML page to include everything at
+once. This line will look like the following:
+
+::
+
+    <script data-main="assets/js/first" src="assets/js/lib/require.js"></script>
+
+In this example, we suppose that you have created a `first.js` file
+in the `assets/js` directory containing your main application
+code. First, you define there the required JavaScript libraries and
+potentially their configuration, then you can add any relevant code.
+
+.. code-block:: javascript
+    :linenos:
+
+    requirejs.config({
+        baseUrl: 'assets/js',
+        paths: {
+            jquery: 'lib/jquery/jquery-1.11.0.min',
+            hogan: 'lib/hogan/hogan-3.0.2',
+            xml2json: 'lib/xml2json/xml2json.min',
+            queryString: 'lib/query-string/query-string',
+            wpsPayloads: 'lib/zoo/payloads',
+            wpsPayload: 'lib/zoo/wps-payload',
+            utils: 'lib/zoo/utils',
+            zoo: 'lib/zoo/zoo',
+            domReady: 'lib/domReady',
+            app: 'first-app',
+        },
+        shim: {
+            wpsPayloads: {
+                deps: ['hogan'],
+            },
+            wpsPayload: {
+                deps: ['wpsPayloads'],
+                exports: 'wpsPayload',
+            },
+            hogan: {
+                exports: 'Hogan',
+            },
+            xml2json: {
+              exports: "X2JS",
+            },
+            queryString: {
+                exports: 'queryString',
+            },
+        },
+    });
+    
+    requirejs.config({ 
+        config: {
+            app: {
+                url: '/cgi-bin/zoo_loader.cgi',
+                delay: 2000,
+            }
+        } 
+    });
+    
+    require(['domReady', 'app'], function(domReady, app) {
+        domReady(function() {
+            app.initialize();
+        });
+    });
+
+On line 2, you define the url where your files are located on the web
+server, in `assets/js`. From line 3 to 14, you define the JavaScript
+files to be loaded. From line 15 to 21, you configure the dependencies
+and exported symbols. From line 35 to 42, you configure your main
+application.
+
+In this application, we use the `domReady
+<http://github.com/requirejs/domReady>`__ module to call the
+`initialize` function defined in the `app` module, which is defined in
+the `first-app.js` file as defined on line 13.
+
+
+
+.. code-block:: javascript
+    :linenos:
+
+    define([
+        'module','zoo','wpsPayload'
+    ], function(module, ZooProcess, wpsPayload) {
+        
+        var myZooObject = new ZooProcess({
+            url: module.config().url,
+            delay: module.config().delay,
+        });
+        
+        var initialize = function() {
+            self = this;        
+            myZooObject.getCapabilities({
+               type: 'POST',
+                 success: function(data){
+                         console.log(data);
+                }
+            });
+
+            myZooObject.describeProcess({
+                type: 'POST',
+                identifier: "all",
+                success: function(data){
+                    console.log(data);
+                }
+            });
+
+           myZooObject.execute({
+               identifier: "Buffer",
+               dataInputs: [{"identifier":"InputPolygon","href":"XXX","mimeType":"text/xml"}],
+               dataOutputs: [{"identifier":"Result","mimeType":"application/json","type":"raw"}],
+               type: 'POST',
+               success: function(data) {
+                    console.log(data);
+               },
+               error: function(data){
+                    console.log(data);
+               }
+            });
+        }
+    
+        // Return public methods
+        return {
+            initialize: initialize
+        };
+    
+    });
+
+On line 5 you create a "global" `ZooProcess` instance named
+`myZooObject`, you set the `url` and `delay` to the values defined in
+`first.js` on line 35. From line 10 to 40,  you define a simple
+`initialize` function which will invoke the `getCapabilities` (line
+12 to 18), `describeProcess` (from line 20 to 26) and `execute` (from
+line 28 to 39) methods. For each you define a callback function which
+will simply display the resulting data in the browser's console.
+
+
Index: /tags/rel-1.7.0/docs/client/howto.rst
===================================================================
--- /tags/rel-1.7.0/docs/client/howto.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/client/howto.rst	(revision 942)
@@ -0,0 +1,89 @@
+.. _client-howto:
+
+Using ZOO-Client
+==================
+
+This section will help you to get started using :ref:`ZOO-Client <client-what>`.
+
+Prerequisites
+----------------------
+
+ZOO-Client is based on the following Javascript libraries
+
+- jQuery (`http://www.jquery.com <http://www.jquery.com>`_)
+- x2js (`https://code.google.com/p/x2js <https://code.google.com/p/x2js/>`_)
+- Require.js (`http://requirejs.org <http://requirejs.org/>`_ )
+- Hogan.js (`http://twitter.github.io/hogan.js <http://twitter.github.io/hogan.js>`_ )
+- query-string (`https://github.com/sindresorhus/query-string <https://github.com/sindresorhus/query-string/>`_ )
+
+.. warning::
+
+     `Node.js <http://nodejs.org/>`__ is also required on your system
+     for compiling ZOO-Client templates. 
+
+Download
+-----------------------
+
+If you did not :ref:`download <install-download>` the ZOO-Project
+source code already, please proceed to a svn checkout with the
+following command:
+
+::
+
+  svn checkout http://svn.zoo-project.org/svn/trunk/zoo-project/zoo-client
+
+
+.. warning::
+   You do not necessarily need to :ref:`install <install-installation>` the ZOO-Project server for using ZOO-Client. The corresponding svn `directory <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-client>`__ is needed only.
+
+
+Compiling ZOO-Client templates
+------------------------------
+
+In order to work with ZOO-Client, you will first need to compile the
+provided `Mustache <http://mustache.github.io/>`_ templates using
+`Node.js <http://nodejs.org/>`__. The ZOO-Client templates are located
+in the ``/zoo-project/zoo-client/lib/tpl`` directory downloaded from
+svn.
+
+* Install Node.js (see related `documentation <https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager>`__.)
+* Install Hogan, the JavaScript templating engine, using the following command:
+
+  ::
+ 
+     sudo npm install hogan
+
+
+*  Use Hulk (Hogan's command line utility) for compiling the tempaltes
+   using the following command:
+
+   ::
+ 
+     hulk zoo-client/lib/tpl/*mustache > \ zoo-client/lib/js/wps-client/payloads.js
+
+.. warning:: Using different versions of Hogan to compile and to use in a web application may lead to compatibility issue.
+
+Everything is now ready to work with :ref:`ZOO-Client
+<client-what>`. Read the :ref:`next section <client-example>` for an
+example JavaScript application. 
+
+Building ZOO-Client API documentation
+-------------------------------------
+
+You may also build the ZOO-Client API documentation using `jsDoc
+<http://usejsdoc.org/>`__, with the following command:
+
+::
+
+    npm install jsdoc
+    ~/node_modules/.bin/jsdoc zoo-client/lib/js/wps-client/* -p
+
+This will build HTML documentation in a new directory named ``/out`` in
+your working directory. 
+
+.. note:: 
+    Building the ZOO-Client API documentation is optional, please
+    refer to `the up-to-date ZOO-Client API Documentation
+    <http://www.zoo-project.org/jsDoc/index.html>`__ for the current
+    API version. 
+
Index: /tags/rel-1.7.0/docs/client/index.rst
===================================================================
--- /tags/rel-1.7.0/docs/client/index.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/client/index.rst	(revision 942)
@@ -0,0 +1,16 @@
+.. _client-index:
+
+ZOO-Client 
+========================
+
+This section provides information on **ZOO-Client**, the `ZOO-Project
+<http://zoo-project.org>`__ WPS JavaScript client.
+
+.. toctree::
+   :maxdepth: 2
+   
+   what
+   howto
+   example
+   
+
Index: /tags/rel-1.7.0/docs/client/what.rst
===================================================================
--- /tags/rel-1.7.0/docs/client/what.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/client/what.rst	(revision 942)
@@ -0,0 +1,67 @@
+.. _client-what:
+
+What is ZOO-Client ?
+=========================
+
+ZOO-Client is a client-side JavaScript API which provides simple methods
+for interacting with `WPS
+<http://www.opengeospatial.org/standards/wps/>`__ server from web
+applications. It is helpful for sending requests to any WPS compliant
+server (such as :ref:`kernel_index`) and to parse the output responses
+using simple JavaScript.
+
+
+JavaScript
+-------------------------------
+
+ZOO-Client relies on modern JavaScript libraries and can be seamlessly
+integrated in new or existing web platforms or
+applications. ZOO-Client works by expanding the tags available in WPS
+specific templates using values provided by a JavaScript hash or
+object. It allows to build valid WPS requests and to send them to a
+WPS server. It also provides functions to easily parse and reuse the
+output XML responses. Read the :ref:`next section <client-howto>` to
+get started.
+
+Please, refer to the `ZOO-Client API documentation
+<http://www.zoo-project.org/jsDoc/index.html>`__ for accessing the
+up-to-date documentation.
+
+
+Templates
+-------------------------------
+
+ZOO-Client uses logic-less `Mustache <http://mustache.github.io/>`__
+templates for creating well-formed WPS requests. Please, refer to the
+`ZOO-Client API documentation
+<http://www.zoo-project.org/jsDoc//module-wpsPayload.html>`__ for more
+details about the functions using the templates. 
+
+
+GetCapabilities
+..........................................................
+
+*GetCapabilities* requests are created using the following template:
+
+.. include:: ../../zoo-project/zoo-client/lib/tpl/payload_GetCapabilities.mustache
+    :code: xml
+
+
+
+DescribeProcess
+..........................................................
+
+*DescribeProcess* requests are created using the following template:
+
+.. include:: ../../zoo-project/zoo-client/lib/tpl/payload_DescribeProcess.mustache
+    :code: xml
+
+
+Execute
+..........................................................
+
+*Execute* requests are created using a more complex template, as shown bellow:
+
+.. include:: ../../zoo-project/zoo-client/lib/tpl/payload_Execute.mustache
+    :code: xml
+
Index: /tags/rel-1.7.0/docs/conf.py
===================================================================
--- /tags/rel-1.7.0/docs/conf.py	(revision 942)
+++ /tags/rel-1.7.0/docs/conf.py	(revision 942)
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+#
+# ZOO Project documentation build configuration file
+
+import re
+import sphinx
+
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo','sphinx.ext.autosummary', 'sphinx.ext.extlinks','sphinx.ext.viewcode']
+master_doc = 'index'
+templates_path = ['_templates']
+exclude_patterns = ['_build']
+
+# General information
+
+project = 'ZOO-Project'
+copyright = '2009-2019, ZOO-Project team'
+version = '1.0'
+release = '1.5'
+show_authors = True
+
+# Options for HTML output
+
+html_theme = 'sphinx_rtd_theme'
+html_theme_path = ['_themes']
+modindex_common_prefix = ['sphinx.']
+html_static_path = ['_static']
+html_sidebars = {'index': ['indexsidebar.html', 'searchbox.html']}
+#html_additional_pages = {'index': 'index.html'}
+html_use_opensearch = 'http://sphinx-doc.org'
+htmlhelp_basename = 'Sphinxdoc'
+
+# Options for epub output
+
+epub_theme = 'epub'
+epub_basename = 'ZOO-Project'
+epub_author = 'ZOO-Project team'
+epub_publisher = 'http://zoo-project.org/'
+epub_scheme = 'url'
+epub_identifier = 'http://zoo-project.org'
+epub_pre_files = [('index.html', 'ZOO-Project documentation')]
+#epub_post_files = [('install.html', 'Installing Sphinx'),('develop.html', 'Sphinx development')]
+epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js','_static/jquery.js', '_static/searchtools.js','_static/underscore.js', '_static/basic.css','search.html', '_static/websupport.js']
+epub_fix_images = False
+epub_max_image_width = 0
+epub_show_urls = 'inline'
+epub_use_index = False
+epub_guide = (('toc', 'index.html', u'Table of Contents'),)
+
+# Options for LaTeX output
+
+latex_documents = [('contents', 'ZOO-Project.tex', 'ZOO-Project Documentation','ZOO-Project team', 'manual', 1)]
+latex_logo = '_static/zoo-simple.png'
+latex_elements = {'fontpkg': '\\usepackage{palatino}'}
+latex_show_urls = 'footnote'
+todo_include_todos = True
+man_pages = [('index', 'zooproject', 'ZOO-Project Documentation','ZOO-Project team', 1)]
+
+# -- Extension interface -------------------------------------------------------
+
+from sphinx import addnodes  # noqa
+
+event_sig_re = re.compile(r'([a-zA-Z-]+)\s*\((.*)\)')
+
+
+def parse_event(env, sig, signode):
+    m = event_sig_re.match(sig)
+    if not m:
+        signode += addnodes.desc_name(sig, sig)
+        return sig
+    name, args = m.groups()
+    signode += addnodes.desc_name(name, name)
+    plist = addnodes.desc_parameterlist()
+    for arg in args.split(','):
+        arg = arg.strip()
+        plist += addnodes.desc_parameter(arg, arg)
+    signode += plist
+    return name
+
+
+def setup(app):
+    from sphinx.ext.autodoc import cut_lines
+    from sphinx.util.docfields import GroupedField
+    app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
+    app.add_object_type('confval', 'confval',
+                        objname='configuration value',
+                        indextemplate='pair: %s; configuration value')
+    fdesc = GroupedField('parameter', label='Parameters',
+                         names=['param'], can_collapse=True)
+    app.add_object_type('event', 'event', 'pair: %s; event', parse_event,
+                        doc_field_types=[fdesc])
Index: /tags/rel-1.7.0/docs/contribute/code.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/code.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/code.rst	(revision 942)
@@ -0,0 +1,76 @@
+.. _contribute_code:
+
+Contribute code
+===============
+
+Anybody can take part to the `ZOO-Project <http://zoo-project.org>`__ developement and is welcome to:
+
+ * Share new source code or correction
+   
+ * Create tickets to report bugs
+   
+ * Write a new feature request.
+
+Submit new code
+---------------
+
+For new comers
+**************
+
+New source code or existing source code corrections (patches) should
+be submitted using the ZOO-Project bug tracking system (`ZOO-Trac
+<http://zoo-project.org/trac>`__ ).
+
+Create a `new ticket <http://zoo-project.org/trac/newticket>`__ in
+order to describe your code or patch and attach it to the ticket
+(attach all the files required to use your code or patch). It will
+then be checked and discussed with the developers, and can potentially
+be integrated and merged with the trunk.
+
+For registered developers
+***************************
+
+ZOO-Project registered developers have direct svn access and can:
+
+* Commit fixes, enhancement and new source directly to trunk
+  
+* Create and commit to a new branch of the svn
+
+ZOO-Project registered developers must accept and respect the :ref:`contribute_dev` when contributing code.
+
+Bug tracking
+--------------------------
+
+General information
+*********************
+
+Bug reports and wishes can be submitted using the `ZOO-Trac <http://zoo-project.org/trac>`__ . This requires you to setup a user account (userid) using this section.
+
+The following trackers are available:
+
+* *defects* to report bugs and 'bad' features
+* *enhancement* to describe feature wishes
+* *task* to describe any different but relevant topic.
+
+The following components are available:
+
+* *Developemnt platform* to report bugs and 'bad' features
+* *ZOO-Kernel* to report a bug or problem with the ZOO-Project WPS server
+* *ZOO-Services* to report a bug or problem with the ZOO-Project WPS services
+* *ZOO-API* to report a bug or problem with the ZOO-Project API
+* *ZOO-Client* to report a bug or problem with the ZOO-Project Client
+* *Documentation* to report a problem or suggest an enhancement to the documentation
+  
+Best practices
+*********************
+
+Please consider the following when submitting bugs or feature requests:
+
+* Check if the bug is still persistent in svn trunk before reporting. If you use an older version, please consider upgrading.
+* Before reporting a bug, please search if it is yet unknown in the bug tracking system.
+* Give an appropriate, starightforward and understandable title to your ticket using the *Summary* field   
+* Make sure the developers get all the needed information to recreate the bug using the *Description* field (e.g. tell about your configuration and explain every step to reproduce the bug).
+* Select at least a *Type* of tracker and a *Component* for your new ticket.
+* Report only one single bug by ticket.
+
+
Index: /tags/rel-1.7.0/docs/contribute/contributors.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/contributors.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/contributors.rst	(revision 942)
@@ -0,0 +1,74 @@
+.. _contribute_contributors:
+
+List of contributors
+================================
+
+.. _zoo_founder:
+ 
+ZOO-Project founders
+------------------
+
+The ZOO-Project concept, architecture and source code implementation was initiated in 2008 by the following individuals:
+
+   * Gérald FENOY (aka djay)
+   * Nicolas BOZON (aka nbozon)
+   * Venkatesh RAGHAVAN (aka venka)
+
+.. _zoo_psc:
+
+ZOO-Project Project Steering Commitee
+-------------------------------------
+
+The ZOO Project Steering Comitee is responsible to manage the project
+which is maintained, improved, and supported by a small but growing
+developer community. The PSC is composed of the following people (by
+alphabetical order):
+
+    * Nicolas BOZON (`GeoLabs SARL <http://geolabs.fr>`_), FR
+    * Maria Antonia BROVELLI (`Politecnico di Milano
+      <http://www.polimi.it>`_), IT
+    * Massimiliano CANNATA (`SUPSI <http://www.ist.supsi.ch/>`_), CH
+    * Gérald FENOY (`GeoLabs <http://www.geolabs.fr/>`_), FR **(Chair)**
+    * Hirofumi HAYASHI (`AppTech <http://www.apptec.co.jp/>`_), JP
+    * Daniel KASTL (`Georepublic <http://georepublic.de/en/>`_), DE
+    * Jeff McKENNA (`Gateway Geomatics
+      <http://www.gatewaygeomatics.com/>`_), CA
+    * Markus NETELER (`Fondazione Edmund Mach
+      <http://gis.fem-environment.eu/>`_), IT
+    * Venkatesh RAGHAVAN (`Osaka City University
+      <http://www.osaka-cu.ac.jp/index-e.html>`_), JP
+    * Angelos TZOTSOS (`National Technical University of Athens
+      <http://users.ntua.gr/tzotsos/>`_), GR
+
+
+.. _zoo_developers:
+
+ZOO-Project Commiters
+---------------------
+
+The following individuals will be considered authorized ZOO-Project
+committers as long as they each review the commiter guidelines, and
+agree to adhere to them. The ZOO-Project commiters are listed here by alphabetical order.
+
+   * Nicolas BOZON (aka nbozon)
+   * Trevor CLARKE (aka tclarke)
+   * Luca DELUCCHI (aka lucadelu)
+   * René-Luc D'HONT  (aka reluc)
+   * Gérald FENOY (aka djay) **Admin**
+   * Knut LANDMARK (aka knut)
+   * Jeff MCKENNA (aka jmckenna)
+   * Markus NETELER (aka neteler)
+   * Marco NEGRETTI (aka nmarco)
+   * David SAGGIORATO (aka david)
+   * Angelos TZOTSOS (aka kalxas)
+
+Other contributors
+----------------
+
+The following individuals have also contributed to the ZOO-Project
+source code or documentation.
+
+   * Thomas GRATIER 
+   * Guillaume SUEUR
+   * Daisuke YOSHIDA
+   
Index: /tags/rel-1.7.0/docs/contribute/dev.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/dev.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/dev.rst	(revision 942)
@@ -0,0 +1,78 @@
+.. _contribute_dev:
+
+Committer guidelines
+================================
+
+This section gathers information to the registered ZOO-Project developers.
+
+Election to SVN Commit Access
+-----------------------------
+
+Permission for SVN commit access shall be provided to new developers only if accepted by the :ref:`zoo_psc`. A proposal should be written to the PSC for new committers and voted.
+
+Removal of SVN commit access should be handled by the same process.
+
+The new committer should have demonstrated commitment to ZOO-Project and knowledge of the ZOO-Project source code and processes to the committee's satisfaction, usually by reporting bugs, submitting patches, and/or actively participating in the ZOO-Project mailing list(s).
+
+The new committer should also be prepared to support any new feature or changes that he/she commits to the ZOO-Project source tree in future releases, or to find someone to which to delegate responsibility for them if he/she stops being available to support the portions of code that he/she is responsible for.
+
+All committers should also be a member of the zoo-discuss mailing list so they can stay informed on policies, technical developments and release preparation.
+
+New commiters are responsible for having read, and understood this document.
+
+Committer Tracking
+------------------
+
+A list of all project committers will be kept in the main zoo-project directory (called `COMMITTERS <http://zoo-project.org/trac/browser/trunk/zoo-project/COMMITTERS>`__) listing for each SVN committer:
+
+    * Userid: the id that will appear in the SVN logs for this person.
+    * Full name: the users actual name.
+    * Email address: A current email address at which the committer can be reached. It may be altered in normal ways to make it harder to auto-harvest.
+
+
+SVN Administrator
+-----------------
+
+One member of the Project Steering Committee will be designed the SVN Administrator. That person will be responsible for giving SVN commit access to folks, updating the COMMITTERS file, and other SVN related management. That person will need login access on the SVN server of course.
+
+
+SVN Commit Practices
+--------------------
+
+The following are considered good SVN commit practices for the ZOO-Project project.
+
+   * Use meaningful descriptions for SVN commit log entries.
+   * Add a bug reference like "(#1234)" at the end of SVN commit log entries when committing changes related to a ticket in Trac. The '#' character enables Trac to create a hyperlink from the changeset to the mentionned ticket.
+   * After commiting changes related to a ticket in Trac, write the tree and revision in which it was fixed in the ticket description. Such as "Fixed in trunk (r12345) and in branches/1.7 (r12346)". The 'r' character enables Trac to create a hyperlink from the ticket to the changeset.
+   * Changes should not be committed in stable branches without a corresponding bug id. Any change worth pushing into the stable version is worth a bug entry.
+   * Never commit new features to a stable branch without permission of the PSC or release manager. Normally only fixes should go into stable branches.
+   * New features go in the main development trunk.
+   * Only bug fixes should be committed to the code during pre-release code freeze, without permission from the PSC or release manager. 
+   * Significant changes to the main development version should be discussed on the zoo-discuss list before you make them, and larger changes will require a to be discussed and approved on zoo-psc list by the PSC.
+   * Do not create new branches without the approval of the PSC. Release managers are assumed to have permission to create a branch.
+   * All source code in SVN should be in Unix text format as opposed to DOS text mode.
+   * When committing new features or significant changes to existing source code, the committer should take reasonable measures to insure that the source code continues to build and work on the most commonly supported platforms (currently Linux and Windows), either by testing on those platforms directly, running Buildbot tests, or by getting help from other developers working on those platforms. If new files or library dependencies are added, then the configure.in, Makefile.in, Makefile.vc and related documentations should be kept up to date. 
+
+Legal
+-----
+
+Committers are the front line gatekeepers to keep the code base clear of improperly contributed code. It is important to the ZOO-Project users, developers and the OSGeo foundation to avoid contributing any code to the project without it being clearly licensed under the project license.
+
+Generally speaking the key issues are that those providing code to be included in the repository understand that the code will be released under the MIT/X license, and that the person providing the code has the right to contribute the code. For the commiter themselves understanding about the license is hopefully clear. For other contributors, the commiter should verify the understanding unless the commiter is very comfortable that the contributor understands the license (for instance frequent contributors).
+
+If the contribution was developed on behalf of an employer (on work time, as part of a work project, etc) then it is important that an appropriate representative of the employer understand that the code will be contributed under the MIT/X license. The arrangement should be cleared with an authorized supervisor/manager, etc.
+
+The code should be developed by the contributor, or the code should be from a source which can be rightfully contributed such as from the public domain, or from an open source project under a compatible license.
+
+All unusual situations need to be discussed and/or documented.
+
+Committers should adhere to the following guidelines, and may be personally legally liable for improperly contributing code to the source repository:
+
+   * Make sure the contributor (and possibly employer) is aware of the contribution terms.
+   * Code coming from a source other than the contributor (such as adapted from another project) should be clearly marked as to the original source, copyright holders, license terms and so forth. This information can be in the file headers, but should also be added to the project licensing file if not exactly matching normal project licensing (zoo-project/zoo-kernel/LICENSE).
+   * Existing copyright headers and license text should never be stripped from a file. If a copyright holder wishes to give up copyright they must do so in writing to the foundation before copyright messages are removed. If license terms are changed it has to be by agreement (written in email is ok) of the copyright holders.
+   * Code with licenses requiring credit, or disclosure to users should be added to /trunk/zoo-project/zoo-kernel/LICENSE.
+   * When substantial contributions are added to a file (such as substantial patches) the author/contributor should be added to the list of copyright holders for the file.
+   * If there is uncertainty about whether a change it proper to contribute to the code base, please seek more information from the project steering committee, or the foundation legal counsel. 
+
+
Index: /tags/rel-1.7.0/docs/contribute/doc.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/doc.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/doc.rst	(revision 942)
@@ -0,0 +1,187 @@
+.. _contribute_doc:
+
+.. include:: <xhtml1-lat1.txt>
+.. include:: <xhtml1-symbol.txt>
+
+Contribute documentation
+========================
+
+ZOO Documentation is a collaborative process managed by the ZOO developers. Anybody is welcome to contribute to the ZOO-Project documentation. Please consider the following instructions before doing so.
+
+General information
+------------------------
+
+Heading syntaxe
+...............
+
+Tere are various title heading used in the documentation, when you
+create a new document, you're invited to follow the following heading
+underline syntaxe:
+
+ * for Heading 1, use ``=``,
+ *  for Heading 2, use ``-``,
+ *  for Heading 3, use ``.``,
+ *  for Heading 4, use ``*``,
+ *  for Heading 5, use ``#``.
+ 
+
+For new comers
+..........................
+
+New users are encouraged to contribute documentation using the following ways:
+
+* Download the ZOO-Project svn, edit the documentation files
+  located /docs directory and share the modifications through a new
+  ticket set to 'Documentation' tracker
+  
+* Create a wiki page containg new or corrected documentation text, and create a new ticket to report its creation. 
+
+The ZOO developers responsible for the documentation will then review the contributions to add them into the official docs.
+
+For registered developers
+........................................
+
+The current structure of the ZOO Project documentation process is for
+developers with :ref:`SVN <svn>` commit access to maintain their
+documents in reStructuredText format, and therefore all documents live
+in the /docs directory in SVN.  The `Sphinx
+<http://sphinx.pocoo.org/>`__ documentation generator is used to
+convert the reStructuredText files to html, and the live website is
+then updated on an hourly basis.
+
+
+Installing and using Sphinx
+---------------------------
+
+On Linux
+.................
+
+* Make sure you have the Python dev and setuptools packages installed. For example on Ubuntu:
+
+   ::
+
+       sudo apt-get install python-dev
+       sudo apt-get install python-setuptools
+
+* Install sphinx using easy_install:
+
+   ::
+
+       sudo easy_install Sphinx==1.3.1
+       
+   .. note::
+    
+      Make sure you install Sphinx 1.3.1 or more recent. 
+      
+* Checkout the /docs directory from SVN, such as:
+
+   ::
+  
+       svn checkout http://svn.zoo-project.org/svn/trunk zoo-project      
+
+* To process the docs, from the ZOO /docs directory, run:
+
+   ::
+
+       make html
+
+   or
+
+   ::
+
+       make latex
+
+   The HTML output will be written to the build/html sub-directory.
+
+.. note::
+
+    If there are more than one translation, the above commands will automatically
+    build all translations.
+
+
+On Mac OS X |trade|
+..................................
+
+* Install sphinx using easy_install:
+
+   ::
+
+       sudo easy_install-2.7 Sphinx==1.3.1
+       
+   .. note::
+   
+      Make sure you install Sphinx 1.3.1 or more recent. 
+
+* Install `MacTex <http://www.tug.org/mactex/2009/>`__ if you want to build pdfs
+
+* Checkout the /docs directory from SVN, such as:
+
+   ::
+  
+       svn checkout http://svn.zoo-project.org/svn/trunk zoo-project
+
+* To process the docs, from the ZOO /docs directory, run:
+
+   ::
+
+       make html
+
+   or
+
+   ::
+
+       make latex
+
+   The HTML output will be written to the build/html sub-directory.
+
+
+On Windows |trade|
+................................
+
+* Install `Python 2.X <http://www.python.org/>`__
+* Download `setuptools <http://pypi.python.org/pypi/setuptools#windows>`__
+* Make sure that the ``C:/Python2X/Scripts`` directory is your path
+* Execute the following at commandline:
+
+   ::
+
+       easy_install Sphinx==1.3.1
+
+   ...you should see message: "Finished processing dependencies for Sphinx"
+
+   .. note::
+   
+      Make sure you install Sphinx 1.3.1 or more recent.  See note above.
+      
+* Install `MiKTeX <http://miktex.org>`__ if you want to build pdfs
+      
+* Checkout the /docs directory from SVN, such as:
+
+   ::
+  
+       svn checkout http://svn.zoo-project.org/svn/trunk zoo-project
+      
+* Inside the /docs directory, execute:
+
+   ::
+
+       make html
+
+   or
+
+   ::
+
+       make latex
+
+   The HTML output will be written to the _build/html sub-directory.
+
+
+reStructuredText Reference Guides
+***************************************
+
+The following resources are considered as useful for editing and creating new ZOO-Project documentation files.
+
+- Docutils `Quick reStructuredText <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`__
+- Docutils `reStructuredText Directives <http://docutils.sourceforge.net/docs/ref/rst/directives.html>`__
+- Sphinx's `reStructuredText Primer <http://sphinx.pocoo.org/rest.html>`__
+- search Sphinx's `mailing list <http://groups.google.com/group/sphinx-dev>`__
Index: /tags/rel-1.7.0/docs/contribute/howto.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/howto.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/howto.rst	(revision 942)
@@ -0,0 +1,58 @@
+How to contribute ?
+===================
+
+Please consider the following simple rules if you would like to contribute to  the `ZOO-Project <http://zoo-project.org>`__  open source software.
+
+Community 
+-------------------
+
+Anybody is welcome to share and contribute ideas, code, documentation or any relevant resource. This should be done according to the directives stated in the ZOO-Project :ref:`contribute_index`.
+
+Governance
+......................................
+
+`ZOO-Project <http://zoo-project.org>`__ activities are directed by the Project Steering Committee (PSC) and the software itself is being developed, maintained and documented by an international community of users and developers (aka `ZOO-Tribe <http://zoo-project.org/new/ZOO-Project/ZOO%20Tribe>`_).
+
+Contributions are moderated and integrated in trunk at the discretion of the `ZOO-Project <http://zoo-project.org>`__ PSC. Commit access are usually granted to active contributors by vote from the PSC members. 
+
+Licensing
+......................................
+
+`ZOO-Project <http://zoo-project.org>`__ source code is open source and made available under the `MIT/X-11 <http://opensource.org/licenses/MITlicense>`__  `license
+<http://zoo-project.org/trac/browser/trunk/zoo-project/LICENSE>`__. You must agree to the terms of that same license when creating, submiting and releasing new source code.
+
+`ZOO-Project <http://zoo-project.org>`__ documentation is open source and made available under the `Creative Commons Attribution-ShareAlike 4.0 International Public License
+<https://creativecommons.org/licenses/by-sa/4.0/legalcode>`__ . You must agree to the terms of that same license when creating, submiting and releasing a new documentation file.
+
+Available media
+-------------------
+
+Discussions and contributions to `ZOO-Project <http://zoo-project.org>`__ are encouraged using the following public media.
+
+Mailing lists
+......................................
+
+Feel free to post any question, feedback, comment or idea to the general public mailing list. For project managment or governance topics, please use the PSC list.
+
+..   csv-table::
+     
+  Name,Description
+    `zoo-discuss <http://lists.osgeo.org/cgi-bin/mailman/listinfo/zoo-discuss>`__,General mailing list for ZOO-Project users and developers
+    `zoo-psc <http://lists.osgeo.org/cgi-bin/mailman/listinfo/zoo-psc>`__,Project Steering Committe mailing list
+    
+
+IRC
+......................................
+
+Join the **#zoo-project** channel on irc.freenode.net to discuss with the ZOO-Tribe at any time.
+
+
+Tracker
+......................................
+
+Bug reports and code patches should be shared using the `ZOO-Project <http://zoo-project.org>`__ bug tracking system, as specified in the :ref:`contribute-code` section. 
+
+Wiki
+......................................
+
+Wiki pages can also be created by registered users. They can be used in order to describe any concept, contribution and or action that benefits or is related to the project.
Index: /tags/rel-1.7.0/docs/contribute/index.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/index.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/index.rst	(revision 942)
@@ -0,0 +1,20 @@
+.. _contribute_index:
+
+Contributor Guide
+=================
+
+This is the `ZOO-Project <http://zoo-project.org>`__ **Contributor
+Guide**. This document provides information and guidelines to anyone
+willing to contribute to the `ZOO-Project <http://zoo-project.org>`__
+open source software project and help making it better.
+
+.. toctree::
+   :maxdepth: 2
+
+   howto
+   code
+   doc
+   dev
+   release
+   translate
+   contributors
Index: /tags/rel-1.7.0/docs/contribute/release.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/release.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/release.rst	(revision 942)
@@ -0,0 +1,93 @@
+.. _contribute_release:
+
+Release Procedure
+=================
+
+The ZOO-Project release procedure is commonly defined by the following
+rules:
+
+* Any of the :ref:`zoo_developers` can ask for a release by asking the
+  :ref:`zoo_psc` and pointing a release manager. This last will then
+  vote for accepting both the manager and the release procedure to
+  happen.
+* If not already created, create  a wiki page (like this `one
+  <http://zoo-project.org/trac/wiki/Release/1.3.0/Notes>`_ using this
+  scheme: Release/M.m.r/Notes), summarizing changes from the previous
+  release (extracted from the `revision log
+  <http://zoo-project.org/trac/browser/trunk/zoo-project/HISTORY.txt>`_).
+* That file should include new features, changed features, and
+  deprecated features if any. Changes to the official documentation
+  should be specifically noted along with other items that will cause
+  breaking changes during upgrades. 
+* Read the documentation and remove outdated parts.
+* Create release candidate as .zip and .tar.bz2  then add them on this
+  `page <http://zoo-project.org/new/Code/Download>`_ (by editing this
+  `wiki page <http://zoo-project.org/trac/wiki/ZooWebSite/2015/Code/Download>`_)
+* Cut a release candidate once you think that everything is in
+  order. Announce the release candidate for review for at least 1
+  week. In this period of time, it is also appropriate for you to
+  deploy in production since you are asserting that it is stable and
+  (significant) bug free. Publish a specific revision with this.
+* If significant bugs are reported, fix and cut a new release
+  candidate. If no major bugs, then announce that the release
+  candidate has officially been promoted to the official release (if
+  you want, you can do this with a motion and support of the PSC).
+* Ensure that release exactly matches something in SVN. Tag and branch
+  appropriately.
+* Update documentation as needed.
+* Announce on various email list and other locations
+  (news_item@osgeo.org, SlashGeo, etc)
+
+Creating an Official Release
+----------------------------
+
+Release versions lead to an update in documentation and standard tarballs. This is to help future administrators repeatably create releases.
+
+* Double check that the pages from `the ZOO-Project.org web site <http://zoo-project.org/>`_ match the current version.
+* Double check that the latest build file matches the current revisions number.
+* If this is a new major release create a branch and a tag.
+
+.. code::
+
+    cd zoo-project-svn/
+    svn cp trunk branches/branch-1.6
+    svn cp trunk tags/rel-1.6.0
+
+* If this is a major or minor relase, create a tag.
+
+.. code::
+
+    svn cp branches/branch-1.6 tags/rel-1.6.1
+
+* Commit the tags or branches with the version numbers.
+
+.. code::
+
+    svn commit -m 'Created branch/tags for the X.Y.Z release'
+
+* Create version archives
+
+.. code::
+
+    export VERSION=2.6.0
+    cd zoo-propject-svn
+    cp -r trunk zoo-project-$VERSION
+    cd zoo-project-$VERSION
+    rm -rf $(find ./ -name ".svn") 
+    cd zoo-project/zoo-kernel
+    autoconf
+    # In case you did not build ZOO-Kernel
+    cd ../../..
+    # In case you built ZOO-Kernel, then remove the generated file from the archive
+    make clean
+    rm -f  {Makefile,ZOOMakefile.opts}
+    cd ../../..
+    # In case you built one or more ZOO-Services, then remove the generated file from the archive
+    rm $(find ./zoo-project-$VERSION/zoo-project/zoo-services -name "*zo")
+    # Remove documentation from the archive
+    rm -rf ./zoo-project-$VERSION/{docs,workshop}
+    tar -cvjf ./zoo-project-$VERSION.tar.bz2 ./zoo-project-$VERSION
+    zip -r ./zoo-project-$VERSION.zip ./zoo-project-$VERSION
+    scp -P 1046 ./zoo-project-$VERSION.{zip,tar.bz2} zoo-project.org:/var/www/localhost/htdocs/dl/
+
+* Update the `Downloads page <http://zoo-project.org/new/Code/Download>`_ to add the latest release (by editing `this wiki page <http://zoo-project.org/trac/wiki/ZooWebSite/2015/Code/Download>`_).
Index: /tags/rel-1.7.0/docs/contribute/translate.rst
===================================================================
--- /tags/rel-1.7.0/docs/contribute/translate.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/contribute/translate.rst	(revision 942)
@@ -0,0 +1,82 @@
+.. _contribute_trans:
+
+Contribute translation
+======================
+
+Introduction
+------------
+
+This chapter aims to explain how to help translating the internal
+ZOO-Kernel messages into  another language than English. Some
+languages are already enabled for translating and some are not. Please
+see :ref:`documentation_translation_newlang` if needed.
+
+This chapter describes how to add a new language, how to join a language group, 
+and how to translate the internal ZOO-Kernel messages.
+
+
+What is Transifex for?
+----------------------------------------
+
+`Transifex <https://www.transifex.com/signup/contributor/>`_ is a croudsourcing
+translation web application. It allows projects to  let people easily
+translate documentation, websites, and applications.
+
+It offers a graphic interface for those of you who don't like command
+line but also some features for those who love them.
+
+Transifex helps the translator to improve their translation with
+suggestions, glossary and proofreading process.
+
+Starting with Transifex
+-----------------------
+
+Subscribe to Transifex
+......................
+
+You need to subscribe to Transifex before translating. Go to
+`Transifex subscribing page
+<https://www.transifex.com/signup/contributor/>`_ and create a new
+account.
+
+Access the project
+..................
+
+The project can be found here: `ZOO-Project Dashboard <https://www.transifex.com/organization/zoo-project/dashboard>`_
+
+Each project has a news page to send some information to you, so please, take 
+some time to read them. You can also send some messages to others to discuss on 
+a topic.
+
+Ask to join the Translator group
+................................
+
+Click on the link to access the dashboard of the ZOO-Project project
+in Transifex (link above),  find the button *Join team*. You  should
+now wait for the manager accept you in the group (given them time to
+read  your request and act in consequence).
+
+.. _documentation_translation_newlang:
+
+Request a new language
+----------------------
+
+Go to the ZOO-Project dashboard on Transifex (see link above) and
+click on 'Request language'.
+
+Creating a new language by the manager should not be too long, actually as long 
+as to accept you in the team.
+
+
+Translate messages
+------------------
+
+Once you are a member of the Translator team, go on the ZOO-Project
+Dashboard you can translate and click on the language you want to
+translate, then press the button 'Translate' and you can start
+translating strings by using the online editor. Please refer to this `documentation
+<http://docs.transifex.com/tutorials/txeditor/>`_ if you need details
+on how to use this editor.
+
+
+
Index: /tags/rel-1.7.0/docs/index.rst
===================================================================
--- /tags/rel-1.7.0/docs/index.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/index.rst	(revision 942)
@@ -0,0 +1,31 @@
+.. _contents:
+
+ZOO-Project documentation 
+=============================
+
+This is the `ZOO-Project <http://zoo-project.org>`__ Open WPS Platform official documentation.
+
+.. note::
+    The entire documentation is also available as a single `PDF
+    document <./ZOO-Project.pdf>`__ and `ePub document
+    <./ZOO-Project.epub>`__
+
+.. toctree::
+   :maxdepth: 2
+
+   intro
+   install/index
+   kernel/index
+   services/index
+   api/index
+   client/index
+   contribute/index
+
+This document is released under the Creative Commons
+Attribution-ShareAlike 4.0 International Public License (`CC-BY-SA
+<https://creativecommons.org/licenses/by-sa/4.0/legalcode>`__).
+
+.. image:: _static/by-sa.png
+   :width: 103px
+   :scale: 50 %
+   :alt: CC-BY-SA license
Index: /tags/rel-1.7.0/docs/install/centos.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/centos.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/centos.rst	(revision 942)
@@ -0,0 +1,52 @@
+.. _install-centos:
+
+Installation on CentOS
+======================
+
+Use the following instructions to install `ZOO-Project <http://zoo-project.org>`__ on CentOS distributions. 
+
+Prerequisites
+----------------------
+
+First you should add the `ELGIS Repository <http://elgis.argeo.org>`__ then install the
+dependencies by using `yum` commands.
+
+.. code-block:: guess
+
+  rpm -Uvh http://elgis.argeo.org/repos/6/elgis-release-6-6_0.noarch.rpm
+  rpm -Uvh \
+    http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
+  wget\
+    http://proj.badc.rl.ac.uk/cedaservices/raw-attachment/ticket/670/armadillo-3.800.2-1.el6.x86_64.rpm
+  yum install armadillo-3.800.2-1.el6.x86_64.rpm
+  yum install hdf5.so.6
+  yum install gcc-c++ zlib-devel libxml2-devel bison openssl \
+    python-devel subversion libxslt-devel libcurl-devel \
+    gdal-devel proj-devel libuuid-devel openssl-devel fcgi-devel
+  yum install java-1.7.0-openjdk-devel
+
+
+Installation
+----------------------
+
+Now refer to general instructions from :ref:`install-installation` to
+setup your ZOO-Kernel and the ZOO-Services of your choice.
+
+.. note:: 
+   In case you use the Java support, please, make sure to use the
+   correct version of both java and javac using the following
+   commands:
+   
+   .. code-block:: guess
+   
+     update-alternatives --config java
+     update-alternatives --config javac
+   
+   Also, make sure to add the following to your `main.cfg` file before
+   trying to execute any Java service:
+
+   .. code-block:: guess
+   
+     [javax]
+     ss=2m
+
Index: /tags/rel-1.7.0/docs/install/debian.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/debian.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/debian.rst	(revision 942)
@@ -0,0 +1,144 @@
+.. _install-debian:
+
+Installation on Debian / Ubuntu
+===============================
+
+Use the following instructions to install `ZOO-Project <http://zoo-project.org>`__ on Debian or Ubuntu distributions. 
+
+Prerequisites
+-------------
+
+Using Debian
+......................
+
+The following command should install all the required dependancies on Debian. See the :ref:`install-prereq` section for additional information.
+
+.. code-block:: guess
+
+   apt-get install flex bison libfcgi-dev libxml2 libxml2-dev curl openssl autoconf apache2 python-software-properties subversion python-dev libgdal1-dev build-essential libmozjs185-dev libxslt1-dev
+
+Using Ubuntu
+......................
+
+On Ubuntu, use the following command first to install the required dependancies :
+
+.. code-block:: guess
+
+   sudo apt-get install flex bison libfcgi-dev libxml2 libxml2-dev curl openssl autoconf apache2 python-software-properties subversion libmozjs185-dev python-dev build-essential libxslt1-dev
+
+Then add the *UbuntuGIS* repository in order to get the latest versions of libraries
+
+.. code-block:: guess
+
+   sudo add-apt-repository ppa:ubuntugis/ppa
+   sudo apt-get update
+
+Install the geographic library as follow:
+
+.. code-block:: guess
+
+   sudo apt-get install libgdal1-dev
+
+
+Installation
+------------
+
+:ref:`install-download` ZOO-Project latest version from svn using the following command:
+
+.. code-block:: guess
+
+  svn checkout http://svn.zoo-project.org/svn/trunk zoo-project
+
+Install the *cgic* library from packages using the following command:
+
+.. code-block:: guess
+
+  cd zoo-project/thirds/cgic206/
+  make
+
+Head to the :ref:`kernel_index` directory
+
+.. code-block:: guess
+
+  cd ../../zoo-project/zoo-kernel/
+
+Create a configure file as follow:
+
+.. code-block:: guess
+
+  autoconf
+
+Run configure with the desired options, for example with the following command:
+
+.. code-block:: guess
+
+  ./configure --with-js --with-python
+
+.. note::
+   Refer to the :ref:`installation` section for the full list of available options
+
+Compile ZOO-Kernel as follow:
+
+.. code-block:: guess
+
+  make
+
+Install the ``libzoo_service.so.1.5`` by using the following command:
+
+.. code-block:: guess
+
+      sudo make install
+
+
+Copy the necessary files to the `cgi-bin` directory (as administrator
+user):
+
+.. code-block:: guess
+
+  cp main.cfg /usr/lib/cgi-bin
+  cp zoo_loader.cgi /usr/lib/cgi-bin
+
+Install ZOO ServiceProviders, for example the basic Python service (as administrator user)
+
+.. code-block:: guess
+
+  cp ../zoo-services/hello-py/cgi-env/*.zcfg /usr/lib/cgi-bin
+  cp ../zoo-services/hello-py/cgi-env/*.py /usr/lib/cgi-bin/
+
+Edit the *main.cfg* file as follow (example configuration):
+
+.. code-block:: guess
+
+  nano /usr/lib/cgi-bin/main.cfg
+  - serverAddress = http://127.0.0.1
+
+
+Test the ZOO-Kernel installation with the following requests:
+
+.. code-block:: guess
+
+   http://127.0.0.1/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=GetCapabilities&Version=1.0.0
+
+.. code-block:: guess
+
+   http://127.0.0.1/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=DescribeProcess&Version=1.0.0&Identifier=HelloPy
+
+.. code-block:: guess
+
+   http://127.0.0.1/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=Execute&Version=1.0.0&Identifier=HelloPy&DataInputs=a=myname
+
+
+.. note:: 
+
+   Such request should return well formed XML documents (OWS documents responses).
+
+.. warning:: 
+
+   The URLs provided here suppose that you have previously setup a web
+   server and defined cgi-bin as a location where you can run cgi
+   application.
+
+.. warning:: 
+
+   If ZOO-Kernel returns an error please check the :ref:`kernel_config` and beware of the :ref:`install-prereq`.
+
Index: /tags/rel-1.7.0/docs/install/download.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/download.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/download.rst	(revision 942)
@@ -0,0 +1,55 @@
+.. _install-download:
+
+Download
+=============
+
+Several ways to download the `ZOO-Project <http://zoo-project.org>`_ source code are available and explained in this section.
+
+.. warning::
+    The ZOO-Project svn is the place where developement
+    happens. Checking out svn is the best way to be always up-to-date.
+
+
+ZOO-Project releases archives
+-------------------------------
+
+Each new `ZOO-Project <http://zoo-project.org>`_ major release are
+available on the project official website as .zip and .tar.bz2
+archives. Head to the `Downloads
+<http://zoo-project.org/site/Downloads>`_ section to get the latest or
+older ZOO-Project releases. 
+
+.. warning::
+    Don't use older versions of ZOO-Project if you want to use new
+    features and avoid older code issues. Prefer svn or github
+    instead.
+
+
+
+ZOO-Project SVN
+-------------------------------
+
+.. _svn:
+
+Download the `latest <http://zoo-project.org/trac/browser/trunk>`_ `ZOO-Project <http://zoo-project.org>`_  source code using the following *svn* command:
+
+::
+
+  svn checkout http://svn.zoo-project.org/svn/trunk zoo-src
+
+Registered ZOO-Project developers would prefer the following:
+
+::
+
+  sed "s:\[tunnels\]:\[tunnels\]\nzoosvn = /usr/bin/ssh -p 1046:g" -i ~/.subversion/config
+  svn co svn+zoosvn://svn.zoo-project.org/var/svn/repos/trunk zoo-src
+  
+.. note::
+    The ZOO-Project svn server listens on the 1046 (1024+22) port
+    (instead of 22 by default), so please use a specific tunnel to
+    access the svn server, as shown in the command above.
+
+ZOO-Project Github
+-------------------------------
+
+The ZOO-Project svn is mirrored in this Github `repository <https://github.com/kalxas/zoo-project/>`_ in case you would like to fork it.
Index: /tags/rel-1.7.0/docs/install/index.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/index.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/index.rst	(revision 942)
@@ -0,0 +1,21 @@
+.. _install:
+
+ZOO-Project installation
+========================
+
+The following sections will help you to install the `ZOO-Project <http://zoo-project.org>`_ Open WPS Platform on various
+operating systems.
+
+.. toctree::
+   :maxdepth: 2
+   
+   prerequisites
+   download
+   installation
+   debian
+   opensuse
+   centos
+   windows
+
+
+
Index: /tags/rel-1.7.0/docs/install/installation.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/installation.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/installation.rst	(revision 942)
@@ -0,0 +1,533 @@
+.. _install-installation:
+
+Installation on Unix/Linux
+==========================
+
+To build and install ZOO-Project on your Web Server you will need 4
+steps :
+
+.. contents:: 
+    :local:
+    :depth: 1
+    :backlinks: top
+
+
+Build cgic
+----------
+
+Run the following commands from the ``thirds/cgic`` directory to build
+the cgic library.
+
+::
+
+   cd thirds/cgic
+   make
+
+The cgic library originaly come from `http://www.boutell.com/cgic
+<http://www.boutell.com/cgic>`_.
+
+.. warning:: 
+
+   You may need to edit the ``Makefile`` in case you are using a 64 bits
+   platform for building and your fcgi library is not located in ``/usr/lib64``.
+
+Install ZOO-Kernel
+------------------
+
+
+For the impatient
+.................
+
+Run the following commands from the directory where you :ref:`install-download` and extracted the ZOO Kernel source code in order to build the ``zoo_loader.cgi`` CGI program with default options.
+
+::
+
+   cd zoo-project/zoo-kernel
+   autoconf  
+   ./configure
+   make
+   make install
+
+This should produce executables for the *zoo_loader.cgi* CGI program
+(located per default in ``/usr/lib/cgi-bin/``) and a shared library
+``libzoo_service``  (located per default in ``/usr/local/lib``).
+
+.. warning:: 
+
+   Edit ZOO-Kernel installation settings in the ``main.cfg`` file (set
+   ``tmpPath`` and ``tmpUrl`` to fit your web server configuration).
+
+
+Configure options
+.................
+
+This section provides information on :ref:`kernel_index` configure options. It is recommanded to also read the :ref:`kernel_config` section for configuration technical details.
+
+
+Here is the list of available options in the same order as returned by
+``./configure --help`` command:
+
+.. contents:: 
+    :local:
+    :depth: 2
+    :backlinks: top
+
+Specific CGI Directory
+**********************
+
+In the case your ``cgi-bin`` is not located in ``/usr/lib/`` as it is
+assumed per default, then you can specify a specific target location
+by using the following option:
+
+.. code::
+
+    ./configure --with-cgi-dir=/Lbrary/WebServer/CGI-Executables
+
+This way, when you will run the ``make install`` command, the
+ZOO-Kernel will be deployed in the specified directory (so,
+`/Lbrary/WebServer/CGI-Executables`` in this example).
+
+Specific main.cfg location  (Optional)
+**************************************
+
+Per default, the ZOO-Kernel search for the ``main.cfg`` file from its
+installation directory but, in case you want to store this file in
+another place, then you can use the ``--with-etc-dir`` option so it
+will search for the ``main.cfg`` file in the ``sysconfdir`` directory.
+
+For instance, you can define that the directory to store the
+``main.cfg`` file is the ``/etc/zoo-project`` directory, by using the
+following command:
+
+.. code::
+
+    ./configure --with-etc-dir=yes --sysconfdir=/etc/zoo-project
+
+
+.. _zoo_install_db_backend:
+
+Use a Database Backend (Optional) 
+**********************************
+
+If you want to share the ongoing informations of running services
+between various ZOO-Kernel instances then you should use this
+option: ``--with-db-backend``. This way, both the *GetStatus*,
+*GetResult* and *Dismiss* requests can be run from any host accessing
+the same database. Obviously, this will require that the ZOO-Kernel is
+able to access the Database server. To learn how to configure this
+connection and how to create this database please refer to :ref:`[1]
+<zoo_activate_db_backend>` and :ref:`[2] <zoo_create_db_backend>`
+respectively.
+
+.. note::
+    By now, the ZOO-Kernel is not able to handle correctly the
+    *Dismiss* request from any host. Nevertheless, it will provide
+    valid response from any host, but only the host which is really
+    handling the service will be able to stop it and remove all the
+    linked files.
+
+.. _zoo_create_db_backend:
+
+To create a new database to be used by the ZOO-Kernel, you have
+to load the `schema.sql
+<http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel/sql/schema.sql>`_ 
+file. For instance, you may run the following:
+
+.. code::
+
+    createdb zoo_project
+    psql zoo_project -f zoo-project/zoo-kernel/sql/schema.sql
+
+.. note::
+    You can choose another schema to store ZOO-Kernel specific
+    informations. In such a case, you would need to edit the
+    schema.sql file to uncomment line `33
+    <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel/sql/schema.sql#L33>`_
+    and `34
+    <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel/sql/schema.sql#L34>`_.
+
+.. _zoo_create_metadb:
+
+Metadata Database (Optional)
+*****************************
+
+
+It is possible to use a PostgreSQL database to store metadata
+information about WPS Services. This support is optional and require
+to be activated by using the ``--with-metadb=yes`` option.
+
+To create the database for storing the metadata informations about the
+WPS Services, you may use the following command:
+
+.. code::
+
+    createdb zoo_metadb
+    psql zoo_metadb -f zoo-project/zoo-kernel/sql/zoo_collectiondb.sql
+
+In case you want to convert an existing zcfg file then, you can use
+the ``zcfg2sql`` tool from the command line. It can be found in
+``thirds/zcfg2sql`` and can be build simply by running the ``make``
+command. After compilation you only need to give it the path of the
+zcfg file you want to obtain the SQL queries required to store the
+metadata informations in the database rather than in zcfg file.
+
+For instance you may use the following command:
+
+.. code::
+
+    #Direct import in the zoo_metadb database
+    ./zcfg2sql /Path/To/MyZCFGs/myService.zcfg | psql zoo_metadb
+    #Create a SQL file for a futur import
+    ./zcfg2sql /Path/To/MyZCFGs/myService.zcfg > myService.sql
+
+
+
+YAML Support (Optional) 
+************************
+
+If ``yaml.h`` file is not found in your ``/usr/include`` directory and
+``libyaml.so`` is not found in ``/usr/lib``, a ``--with-yaml`` option
+can be used to specify its location. For instance, if the header file
+lies in ``/usr/local/include`` and the shared library is located in
+``/usr/local/lib``, you may use the following command:
+
+::
+
+  $ ./configure --with-yaml=/usr/local
+
+
+FastCGI Support (Required) 
+***************************
+
+If your FastCGI library is not available in the default search path, a
+``--with-fastcgi`` option can be used to specify its location. For
+instance, if ``libfcgi.so`` lies in ``/usr/local/lib`` which is not in
+your ``LD_SEARCH_PATH``, you may use the following command:
+
+::
+
+  $ ./configure --with-fastcgi=/usr/local
+
+
+
+GDAL Support (Required) 
+************************
+
+If gdal-config program is not found in your ``PATH``, a
+``--with-gdal-config`` option can be used to specify its location. For
+instance, if ``gdal-config`` lies in ``/usr/local/bin`` which is not in
+your ``PATH``, you may use the following command:
+
+::
+
+  $ ./configure --with-gdal-config=/usr/local/bin/gdal-config
+
+
+GEOS Support (Optional) 
+************************
+
+If ``geos-config`` program is not found in your ``PATH``, a
+``--with-geosconfig`` option can be used to specify its location. For
+instance, if ``geos-config`` lies in ``/usr/local/bin`` which is not in
+your ``PATH``, you may use the following command:
+
+::
+
+  $ ./configure --with-geosconfig=/usr/local/bin/geos-config
+
+
+CGAL Support (Optional) 
+************************
+
+If ``CGAL/Delaunay_triangulation_2.h`` program is not found in your
+``/usr/include`` directory, a ``--with-cgal`` option can be used to
+specify its location. For instance, if the file lies in
+``/usr/local/include`` which is not in your PATH, you may use the
+following command:
+
+::
+
+  $ ./configure --with-cgal=/usr/local
+
+
+
+MapServer Support (Optional) 
+*****************************
+
+
+In order to activate the WMS, WFS and WCS output support using
+MapServer, the ``--with-mapserver`` option must be used. The path to
+``mapserver-config`` which is located in the source code of MapServer
+must also be set, using the following command:
+
+::
+
+  $ ./configure --with-mapserver=/path/to/your/mapserver_config/
+
+
+Read more about the :ref:`kernel-mapserver`.
+
+XML2 Support (Required) 
+************************
+
+If xml2-config program is not found in PATH, a *--with-xml2config* option can be used  to specify its location. For instance, if xml2-config is installed in ``/usr/local/bin`` which is not in PATH, you may use the following command:
+
+::
+
+  $ ./configure --with-xml2config=/usr/local/bin/xml2-config
+
+Python Support (Optional) 
+**************************
+
+The ``--with-python=yes`` option is required to activate the :ref:`kernel_index` Python support, using the following command:
+
+::
+
+  $ ./configure --with-python=yes
+
+This assumes that python-config is found in your ``PATH``. If not,
+then you can specify the Python installation directory using the
+following command (with Python installed in the ``/usr/local``
+directory):
+
+::
+
+  $ ./configure --with-python=/usr/local
+
+
+Python Version
+##############
+
+If multiple Python versions are available and you want to use a
+specific one, then you can use the ``--with-pyvers`` option as shown
+bellow:
+
+::
+
+  $ ./configure --with-pyvers=2.7
+
+
+.. _js-support:
+
+JavaScript Support (Optional) 
+******************************
+
+In order to activate the JavaScript support for ZOO-Kernel,
+the ``--with-js=yes`` configure option must be specified. If you are using
+a "Debian-like" GNU/Linux distribution then  dpkg will be used to
+detect if the required packages are installed and you don't have to
+specify anything here. The following command is only needed (assuming
+that js_api.h and libmozjs.so are found in default directories):
+
+
+::
+
+  $ ./configure --with-js=yes
+
+If you want to use a custom installation of `SpiderMonkey
+<https://developer.mozilla.org/en/SpiderMonkey>`__ , or if you are not
+using a Debian packaging  system, then you'll have to specify the
+directory where it is installed. For  instance, if SpiderMonkey is in
+``/usr/local/``, then the following command must be used:
+
+::
+
+  $ ./configure --with-js=/usr/local
+
+
+PHP Support (Optional) 
+***********************
+
+The ``--with-php=yes`` option is required to activate the
+:ref:`kernel_index` PHP support`, using the following command:
+
+::
+
+  $ ./configure --with-php=yes
+
+This assumes that ``php-config`` can be found in the ``<PATH>/bin``
+directory . So, supposing the your ``php-config`` can be found in
+``/usr/local/bin``, then use the following command:
+
+::
+
+  $ ./configure --with-php=/usr/local
+
+.. warning::
+    ZOO-Kernel optional PHP support requires a local PHP Embedded installation. Read more `here <http://zoo-project.org/trac/wiki/ZooKernel/Embed/PHP>`__.
+
+
+Java Support (Optional) 
+************************
+
+In order to activate the Java support for ZOO-Kernel, the
+`--with-java` configure option must be specified and sets the
+installation path of your Java SDK. For instance,  if Java SDK is
+installed in the ``/usr/lib/jvm/java-6-sun-1.6.0.22/`` directory,
+then the following command can be used:
+
+::
+
+  $ ./configure --with-java=/usr/lib/jvm/java-6-sun-1.6.0.22/
+
+This assumes that the ``include/linux`` and ``jre/lib/i386/client/``
+subdirectories exist in ``/usr/lib/jvm/java-6-sun-1.6.0.22/``, and
+that the ``include/linux`` directory contains the ``jni.h`` headers file
+and that the ``jre/lib/i386/client/`` directory contains the ``libjvm.so``
+file.
+
+.. note:: 
+   You can use the `--with-java-rpath` option to produce a binary
+   aware of the libjvm location.
+
+
+.. note:: 
+   With Mac OS X you only have to set *macos* as the value for the
+   ``--with-java`` option to activate Java support. For example:
+
+   ::
+
+     $ ./configure --with-java=macos
+
+
+Perl Support (Optional) 
+************************
+
+The ``--with-perl=yes`` option can be used for activating the
+ZOO-Kernel Perl support, as follow:
+
+::
+
+  $ ./configure --with-perl=yes
+
+This assumes that perl is found in your PATH. For instance, if Perl is
+installed in ``/usr/local`` and ``/usr/local/bin`` is not found in
+your ``PATH``, then the following command can be used (this assumes
+that ``/usr/local/bin/perl`` exists):
+
+::
+
+  $ ./configure --with-perl=/usr/local
+
+
+Orfeo Toolbox Support (Optional) 
+*********************************
+
+In order to activate the optional Orfeo Toolbox support, the
+``--with-otb`` option must be used, using the following command:
+
+::
+
+  $ ./configure --with-otb=/path/to/your/otb/
+
+
+Read more about the :ref:`kernel-orfeotoolbox`.
+
+.. warning::
+    To build the Orfeo Toolbox support you will require ITK, the
+    default version of ITK is 4.5, in case you use another version,
+    please make sure to use the ``--with-itk-version`` to specificy
+    what is the version available on your system.
+
+SAGA GIS Support (Optional) 
+****************************
+
+
+In order to activate the optional SAGA GIS support, the *--with-saga* option must be used, using the following command:
+
+::
+
+  $ ./configure --with-saga=/path/to/your/saga/
+
+
+Read more about the :ref:`kernel-sagagis`.
+
+.. warning::
+    In case wx-config is not in your ``PATH`` please, make sure to use
+    the ``--with-wx-config``  to specify its location.
+
+Translation support (Optional)
+******************************
+
+The ZOO-Kernel is able to translate the messages it produces in different
+natural languages. This requires that you download `the messages file
+<https://www.transifex.com/projects/p/zoo-kernel-internationalization/>`_
+translated in your language, if any. Then, for this translation
+support to work, you have to generate manually the requested file on
+your system. For instance for the French translation, you may use the
+following command:
+
+.. code::
+
+    msgfmt messagespo_fr_FR.utf8.po -o /usr/share/locale/fr/LC_MESSAGES/zoo-kernel.mo
+
+The ZOO-Kernel is also able to handle translation of
+ZOO-Services. Please, refer to :ref:`this document
+<service_translation>` for more details on the procedure to add new
+ZOO-Service translation files.
+
+.. warning::
+    The location of the final ``.mo`` file may vary depending on your
+    system setup.
+
+
+Install ZOO-Services
+--------------------
+
+.. warning::
+    We present here a global installation procedure for basics
+    ZOO-Services, for details about automatic installation of services
+    provided by :ref:`kernel-orfeotoolbox` or :ref:`kernel-sagagis`,
+    please refer to there specific documentations.
+
+Depending on the programming language used to implement the
+ZOO-Services you want to install, you will need to build a
+Services Provider. In the case of *C* and *Fotran*, you would create a
+shared library exporting the functions corresponding to all the
+ZOO-Services provided by this Services Provider. In case of *Java*,
+you will need to build a Java Class. In any other programming
+language, you should simply have to install the ServiceProvider and
+the zcfg files.
+
+If building a Shared library or a Java class is required, then you
+should find a ``Makefile`` in the service directory which is
+responsible to help you build this Services Provider. So you should
+simply run the `make` command from the Service directory to generate
+the required file.
+
+Then you simply need to copy the content of the ``cgi-env`` directory
+in ``cgi-bin``.
+
+To install the ``ogr/base-vect-ops`` Services Provider, supposing that
+your ``cgi-bin`` directory is ``/usr/local/lib`` use the following
+commands:
+
+.. code::
+
+    cd zoo-project/zoo-services/ogr/base-vect-ops
+    make
+    cp cgi-env/*.* /usr/lib/cgi-bin
+
+.. note::
+    You may also run ``make install`` directly after ``make``.
+
+
+To install the hello-py Services Provider, use the following commands:
+
+.. code::
+
+    cd zoo-project/zoo-services/hello-py/
+    cp cgi-env/* /usr/lib/cgi-bin
+
+
+Testing your installation
+-------------------------
+
+To test your installation yous should first be able to run the
+following command from the ``cgi-bin`` directory:
+
+.. code::
+
+    ./zoo_loader.cgi "request=GetCapabilities&service=WPS"
+
+
Index: /tags/rel-1.7.0/docs/install/opensuse.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/opensuse.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/opensuse.rst	(revision 942)
@@ -0,0 +1,53 @@
+.. _install-opensuse:
+
+Install on OpenSUSE
+===================
+
+:ref:`kernel_index` is maintained as a package in `OpenSUSE Build Service (OBS) <https://build.opensuse.org/package/show?package=zoo-kernel&project=Application%3AGeo>`__. RPM are thus provided for all versions of OpenSUSE Linux (11.2, 11.3, 11.4, Factory).
+
+Stable release
+----------------------
+
+Use the following instructions to install ZOO-Project latetst release on OpenSUSE distribution.
+
+One-click installer
+...................
+
+A one-click installer is available `here <http://software.opensuse.org/search?q=zoo-kernel&baseproject=openSUSE%3A11.4&lang=en&exclude_debug=true>`__. 
+For openSUSE 11.4, follow this direct `link <http://software.opensuse.org/ymp/Application:Geo/openSUSE_11.4/zoo-kernel.ymp?base=openSUSE%3A11.4&query=zoo-kernel>`__.
+
+Yast software manager
+.....................
+
+Add the `Application:Geo <http://download.opensuse.org/repositories/Application:/Geo/>`__ repository to the software repositories and then ZOO-Kernel can then be found in Software Management using the provided search tool.
+
+Command line (as root for openSUSE 11.4)
+........................................
+
+Install ZOO-Kernel package by yourself using the following command:
+
+.. code-block:: guess
+
+  zypper ar http://download.opensuse.org/repositories/Application:/Geo/openSUSE_11.4/
+  zypper refresh
+  zypper install zoo-kernel
+
+Developement version
+********************
+
+The latest development version of ZOO-Kernel can be found in OBS under the project `home:tzotsos <https://build.opensuse.org/project/show?project=home%3Atzotsos>`__. ZOO-Kernel packages are maintained and tested there before being released to the Application:Geo repository. Installation methods are identical as for the stable version. Make sure to use `this <http://download.opensuse.org/repositories/home:/tzotsos/>`__ repository instead.
+
+Command line (as root for openSUSE 11.4)
+********************************************
+
+Install latest ZOO-Kernel trunk version with the following command:
+
+.. code-block:: guess
+
+  zypper ar http://download.opensuse.org/repositories/home:/tzotsos/openSUSE_11.4/
+  zypper refresh
+  zypper install zoo-kernel
+  zypper install zoo-kernel-grass-bridge
+
+Note that there is the option of adding the zoo-wps-grass-bridge package. This option will automatically install grass7 (svn trunk).
+
Index: /tags/rel-1.7.0/docs/install/prerequisites.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/prerequisites.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/prerequisites.rst	(revision 942)
@@ -0,0 +1,49 @@
+.. _install-prereq:
+
+Prerequisites
+=============
+
+Mandatory
+-----------------
+
+The following libraries are required to install :ref:`kernel_index`. Please make sure they are available on your system before anything else.
+
+- autoconf (`http://www.gnu.org/software/autoconf/
+  <http://www.gnu.org/software/autoconf/>`_)
+- gettext (`https://www.gnu.org/software/gettext/
+  <https://www.gnu.org/software/gettext/>`_ )
+- cURL (`http://curl.haxx.se <http://curl.haxx.se>`_ )
+- FastCGI (`http://www.fastcgi.com <http://www.fastcgi.com>`_ )
+- Flex & Bison (`http://flex.sourceforge.net/
+  <http://flex.sourceforge.net/>`_ |
+  `http://www.gnu.org/software/bison/
+  <http://www.gnu.org/software/bison/>`_ )
+- libxml2 (  http://xmlsoft.org )
+- OpenSSL (  http://www.openssl.org )
+- GDAL (http://gdal.org/) 
+
+ .. warning::
+    It is mandatory to install every library listed above before
+    compiling and installing ZOO-Kernel
+
+Optional
+-----------------
+
+You may also consider the following optional libraries:
+
+- MapServer (for ZOO-Kernel optional WMS, WFS and WCS support)
+  ( http://mapserver.org )
+- Python (  http://www.python.org )
+- PHP Embedded (for ZOO-Kernel optional PHP support)
+  ( http://www.php.net )
+- Java SDK (for ZOO-Kernel optional Java support) (
+  http://java.sun.com )
+- SpiderMonkey (for ZOO-Kernel optional Javascript support) (
+  http://www.mozilla.org/js/spidermonkey/ )
+- SAGA GIS (for ZOO-Kernel optional SAGA support) (
+  http://www.saga-gis.org/en/index.html/ )
+- OrfeoToolbox (for ZOO-Kernel optional OTB support) (
+  https://www.orfeo-toolbox.org/ )
+- GRASS GIS (for using it through WPSGrassBridge) (
+  http://grass.osgeo.org )
+- PostgreSQL support activated in GDAL to :ref:`zoo_install_db_backend`
Index: /tags/rel-1.7.0/docs/install/windows.rst
===================================================================
--- /tags/rel-1.7.0/docs/install/windows.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/install/windows.rst	(revision 942)
@@ -0,0 +1,406 @@
+.. include:: <xhtml1-lat1.txt>
+.. include:: <xhtml1-symbol.txt>
+
+.. _install-onwindows:
+
+	     
+Installation on Windows |trade|
+====================
+
+Install ZOO-Project binaries
+-------------------------------
+
+.. note::
+   The content of the ZOO-Project Windows-Binaries is based on
+   `GISInternals SDK <http://www.gisinternals.com/release.php>`__,
+   make sure to refer to license informations. 
+
+.. note::
+   When using the ZOO-Project Windows-Binaries, you can decide if you
+   want the Java support activated or not (which is the case per
+   default). Indeed, once your installation has been done, you will
+   have both a `zoo_loader.cgi` and `zoo_loader_java.cgi` which
+   correspond respectively to the ZOO-Kernel without and with Java
+   support activated. So, in case you want to use the Java support,
+   simply rename the `zoo_loader_jave.cgi` file located in
+   `c:\\inetpub\\cgi-bin` to `zoo_loader.cgi` and make sure the
+   `jvm.dll` can be found.
+
+
+Using the installer
+...................
+
+Prior to run the ZOO-Project-Installer, please make sure you have IIS
+and `Python <https://www.python.org/downloads/windows/>`__ setup on
+your machine. Then download the `ZOO-Project-Installer
+<https://bintray.com/gfenoy/ZOO-Project/Windows-Binaries/view>`__
+corresponding to your platform. The first time you will run the
+installer binary, you may be prompted to authorize it to run. Once the
+installer has been run, simply access the following link:
+http://localhost/zoo-demo/ to access your local demo application.
+
+Install by hand
+...................
+
+Prior to run the ZOO-Project-Installer, please make sure you have IIS
+and `Python <https://www.python.org/downloads/windows/>`__ setup on
+your machine. Then download the `ZOO-Project
+<https://bintray.com/gfenoy/ZOO-Project/Windows-Binaries/view>`__
+archive corresponding to your platform. Uncompress it, then move
+`cgi-bin`, `data` and `tmp` from uncompressed folder to `c:\\inetpub`,
+also move `wwwroot\\zoo-demo` and `wwwroot\\tmp` to
+`c:\\inetpub\\wwwroot`. To finish the installation, run the folllowing
+command as administrator to allow the `zoo_loader.cgi` to run from
+http://localhost/cgi-bin/zoo_loader.cgi:
+
+   ::
+   
+     cd C:\Windows\System32\inetsrv
+     appcmd.exe add vdirs /app.name:"Default Web Site/" /path:/cgi-bin /physicalPath:c:\inetpub\cgi-bin
+     appcmd set config /section:handlers /+[name='CGI-exe1',path='*.cgi',verb='*',modules='CgiModule']
+     appcmd.exe set config /section:isapiCgiRestriction /+[path='c:\inetpub\cgi-bin\zoo_loader.cgi',description='ZOO-Project',allowed='True'] 
+
+
+
+Compile ZOO-Project from source
+-------------------------------
+
+.. warning::
+   Ensure to first perform the :ref:`prerequisite steps
+   <install-prereq>` before compiling the ZOO Kernel.
+
+The following steps are for use with the Microsoft Visual Studio
+compiler (and tested with MSVC 2010).
+
+1. Make sure the gnuwin32 tools ``bison.exe``  and ``flex.exe`` are found
+   in your path.  You can download the GNUwin32 tools `here
+   <http://www.zoo-project.org/dl/tool-win32.zip>`__.
+
+2. Modify the ``nmake.opt`` file to point to your local libraries. Note
+   that you can also use definition directly in the command line if
+   you prefer. See :ref:`win_configure_options` for details about this
+   options.
+
+   
+3. Execute:
+
+   ::
+   
+     nmake /f makefile.vc
+     
+4. A file ``zoo_loader.cgi`` and ``libzoo_service.dll`` should be
+   created.  Note that if another file named
+   ``zoo_loader.cgi.manifest`` is also created, you will have to run
+   another command:
+
+   ::
+   
+     nmake /f makefile.vc embed-manifest
+     
+5. Copy the files ``zoo_loader.cgi``, ``libzoo_service.dll``  and
+   ``main.cfg`` into your cgi-bin directory.
+
+6. Using the command prompt, test the ZOO-Kernel by executing the
+   following command:
+
+   ::
+   
+     D:\ms4w\Apache\cgi-bin> zoo_loader.cgi
+     
+   which should display a message such as:
+   
+   ::
+   
+     Content-Type: text/xml; charset=utf-8
+     Status: 200 OK
+     
+     <?xml version="1.0" encoding="utf-8"?>
+     <ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd" xml:lang="en-US" version="1.1.0">
+       <ows:Exception exceptionCode="MissingParameterValue">
+         <ows:ExceptionText>Parameter &lt;request&gt; was not specified</ows:ExceptionText>
+       </ows:Exception>
+     </ows:ExceptionReport>
+     
+7. Edit the ``main.cfg`` file so that it contains values describing
+   your WPS service.  An example of such a file running on Windows is:
+   
+   ::
+   
+     [main]
+     encoding = utf-8
+     version = 1.0.0
+     serverAddress = http://localhost/
+     lang = en-CA
+     tmpPath=/ms4w/tmp/ms_tmp/
+     tmpUrl = /ms_tmp/
+     
+     [identification]
+     title = The Zoo WPS Development Server
+     abstract = Development version of ZooWPS. See http://www.zoo-project.org
+     fees = None
+     accessConstraints = none
+     keywords = WPS,GIS,buffer
+     
+     [provider]
+     providerName=Gateway Geomatics
+     providerSite=http://www.gatewaygeomatics.com
+     individualName=Jeff McKenna
+     positionName=Director
+     role=Dev
+     adressDeliveryPoint=1101 Blue Rocks Road
+     addressCity=Lunenburg
+     addressAdministrativeArea=False
+     addressPostalCode=B0J 2C0
+     addressCountry=ca
+     addressElectronicMailAddress=info@gatewaygeomatics.com
+     phoneVoice=False
+     phoneFacsimile=False
+     
+8. Open a web browser window, and execute a GetCapababilites request on your WPS service: http://localhost/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS
+
+   The response should be displayed in your browser, such as:
+   
+   ::
+   
+     <wps:Capabilities xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsGetCapabilities_response.xsd" service="WPS" xml:lang="en-US" version="1.0.0">
+     <ows:ServiceIdentification>
+       <ows:Title>The Zoo WPS Development Server</ows:Title>
+       <ows:Abstract>
+         Development version of ZooWPS. See http://www.zoo-project.org
+       </ows:Abstract>
+       <ows:Keywords>
+         <ows:Keyword>WPS</ows:Keyword>
+         <ows:Keyword>GIS</ows:Keyword>
+         <ows:Keyword>buffer</ows:Keyword>
+       </ows:Keywords>
+       <ows:ServiceType>WPS</ows:ServiceType>
+       <ows:ServiceTypeVersion>1.0.0</ows:ServiceTypeVersion>
+       ...
+       
+
+.. _win_configure_options:
+
+Build options
+.............
+
+Various build options can be set in the ``nmake.opt`` file to define
+the location of the built libraries you want to use to build your
+ZOO-Kernel. Some are optional and some are required, they are listed
+below exhaustively:
+
+.. contents:: 
+    :local:
+    :depth: 1
+    :backlinks: top
+
+
+gettext (Required)
+******************
+
+The location of the libintl (built when building gettext) should be
+specified by defining the ``INTL_DIR`` environment variable. It
+supposes that the header and the ``intl.lib`` file are available.
+
+So for instance, in case you build the gettext in
+``\buildkit\srcs\gettext-0.14.6``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set INTL_DIR=\buildkit\srcs\gettext-0.14.6\gettext-runtime\intl
+
+
+libCURL (Required)
+******************
+
+The location of the libCURL should be specified by defining
+the ``CURL_DIR`` environment variable. It supposes that there are 2
+sub-directory ``include`` containing the libCURL header and ``lib``
+which contains the ``libcurl.lib`` file.
+
+So for instance, in case you build the libCURL in
+``\buildkit\srcs\curl-7.38.0``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set CURL_DIR=\buildkit\srcs\curl-7.38.0\builds\libcurl-vc10-x86-release-dll-ssl-dll-zlib-dll-ipvs6-sspi
+
+
+libFCGI (Required)
+******************
+
+The location of the libFCGI should be specified by defining the
+``FCGI_DIR`` environment variable. It supposes that there are 2
+sub-directory ``include`` containing the FastCGI header and
+``libfcgi/Release`` which contains the ``libfcgi.lib`` file.
+
+So for instance, in case you build the libXML2 library in
+``\buildkit\srcs\fcgi-2.4.1``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set FCGI_DIR=\buildkit\srcs\fcgi-2.41.1
+
+libXML2 (Required)
+******************
+
+The location of the libXML2 should be specified by defining the
+``XML2_DIR`` environment variable. It supposes that there are 2
+sub-directory ``include`` containing the libXML2 header and
+``win32\bin.msvc`` which contains the ``libxml2.lib`` file.
+
+So for instance, in case you build the libXML2 library in
+``\buildkit\srcs\libxml2-2.9.0``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set XML2_DIR=\buildkit\srcs\libxml2-2.9.0
+
+OpenSSL (Required)
+******************
+
+The location of the OpenSSL library should be specified by defining
+the ``SSL_DIR`` environment variable. It supposes that there are 2
+sub-directory ``inc32`` containing the header files and
+``out32dll`` which contains the ``ssleay32.lib`` file.
+
+So for instance, in case you build the libXML2 library in
+``\buildkit\srcs\openssl-1.0.2c``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set SSL_DIR=\buildkit\srcs\openssl-1.0.2c
+
+GDAL (Required)
+******************
+
+The location of the GDAL library should be specified by defining
+the ``GDAL_DIR`` environment variable. It corresponds to the path
+where you uncompress and built GDAL, it supposes that you have the
+``gdal_i.lib`` file available in this directory.
+
+So for instance, in case you build the libXML2 library in
+``\buildkit\srcs\gdal-1.10.1``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set GDAL_DIR=\buildkit\srcs\gdal-1.10.1
+
+MapServer (Optional)
+********************
+
+The location of the MapServer library path should be specified by
+defining the ``MS_DIR`` environment variable. It corresponds to the
+path where you build MapServer on your system, this directory should
+contain the ``nmake.opt`` file used. 
+
+So for instance, in case you build Python in
+``\buildkit\srcs\mapserver-6.2.0``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set MS_DIR=\buildkit\srcs\mapserver-6.2.0
+
+
+Python (Optional)
+*****************
+
+The location of the Python binaries path should be specified by
+defining the ``PY_DIR`` environment variable. It corresponds to the
+path where you build Python on your system. The location of the
+``pythonXX.lib`` files should be specified by setting the
+``PY_LIBRARY`` environment variable.
+
+So for instance, in case you build Python in
+``\buildkit\srcs\Python-2.7``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set PY_DIR=\buildkit\srcs\Python-2.7
+    set PY_LIBRARY=\buildkit\srcs\Python-2.7\PCBuild\python27.lib
+
+JavaScript (Optional)
+*********************
+
+The location of libmozjs should be specified by defining the
+``JS_DIR`` environment variable. It corresponds to the path where you
+build libmozjs on your system, it supposes that the header and
+the ``mozjs185-1.0.lib`` file are available in this directory.
+
+So for instance, in case you build libmozjs in
+``\buildkit\srcs\js-1.8.5``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set JS_DIR=\buildkit\srcs\js-1.8.5
+
+PHP (Optional)
+*****************
+
+The location of PHP should be specified by defining the ``PHP_DIR``
+environment variable. It corresponds to the path where you build PHP
+on your system. The location of the ``php5embed.lib`` files should be
+specified by setting the ``PHP_LIB`` environment variable.
+
+So for instance, in case you build PHP in
+``\buildkit\srcs\php-5.5.10``, you may define the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set PHP_DIR=\buildkit\srcs\php-5.5.10
+    set PHP_LIB=\buildkit\srcs\php-5.5.10\Release_TS\php5embed.lib
+
+Database backend (Optional)
+***************************
+
+ZOO-Kernel can use a database backend to store ongoing status
+informations of running services, for activating this operation mode,
+you should define the evironment variable ``DB`` and set it to any
+value. So, to activate this option, you may use the following before
+running ``nmake /f makefile.vc``:
+
+.. code::
+
+    set DB=activated
+
+.. note:: 
+    To learn how to setup the corresponding database, please refer to
+    :ref:`this section <zoo_create_db_backend>`.
+
+
+
+
+Optionally Compile Individual Services
+.............................................................
+
+An example could be the *OGR base-vect-ops* provider located in the ``zoo-project\zoo-services\ogr\base-vect-ops`` directory.  
+
+1. First edit the *makefile.vc* located in that directory, and execute:
+
+   ::
+   
+     nmake /f makefile.vc
+     
+   Inside that same directory, the *ogr_service.zo* file should be created.
+   
+2. Copy all the files inside ``zoo-services\ogr\base-vect-ops\cgi-env`` into your ``cgi-bin`` directory
+
+3. Test this service provider through the following URL:
+
+http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Buffer&DataInputs=BufferDistance=1@datatype=interger;InputPolygon=Reference@xlink:href=http%3A%2F%2Fwww.zoo-project.org%3A8082%2Fgeoserver%2Fows%3FSERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dtopp%3Astates%26SRS%3DEPSG%3A4326%26FeatureID%3Dstates.15
+   
+   The response displayed in your browser should contain:
+   
+   ::
+   
+     <wps:ProcessSucceeded>Service "Buffer" run successfully.</wps:ProcessSucceeded>
+
Index: /tags/rel-1.7.0/docs/intro.rst
===================================================================
--- /tags/rel-1.7.0/docs/intro.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/intro.rst	(revision 942)
@@ -0,0 +1,47 @@
+Introduction
+============
+
+This is an introduction to  the `ZOO-Project
+<http://zoo-project.org>`_ open source software documentation. 
+
+
+What is ZOO-Project ?
+-------------------
+
+`ZOO-Project <http://zoo-project.org>`__  is a WPS (Web Processing Service) implementation written in C, Python and JavaScript. It is an open source platform which implements the `WPS 1.0.0 <http://www.opengeospatial.org/standards/wps/>`_ and  `WPS 2.0.0 <http://www.opengeospatial.org/standards/wps/>`_ standards edited by the `Open Geospatial Consortium <http://www.opengeospatial.org/>`__ (OGC).
+
+`ZOO-Project <http://zoo-project.org>`__ provides a developer-friendly framework for creating and chaining WPS compliant Web Services. Its main goal is to provide generic and standard-compliant methods for using existing open source librairies and algorithms as WPS. It also offers efficient tools for creating new innovative web services and applications.
+
+`ZOO-Project <http://zoo-project.org>`_ is able to process geospatial or non geospatial data online. Its core processing engine (aka :ref:`kernel_index`) lets you execute a number of existing :ref:`ZOO-Services <services-available>` based on reliable software and libraries. It also gives you the ability to create your own WPS Services from new or existing source code, which can be written in seven different programming languages. That lets you compose or turn code as WPS Services simply, with straightforward configuration and standard coding methods.
+
+`ZOO-Project <http://zoo-project.org>`_ is very flexible with data input and output so you can process almost any kind of data stored locally or accessed from remote servers and databases. ZOO-Project excels in data processing and integrates new or existing spatial data infrastructures, as it is able to communicate with map servers and can integrate webmapping clients.
+
+
+ZOO-Project components
+----------------------
+
+The `ZOO-Project <http://zoo-project.org>`__ platform is made up of the following components:
+
+* :ref:`kernel_index`: A  WPS compliant implementation written in C offering a powerful WPS server able to manage and chain WPS services. by loading dynamic libraries and code written in different languages.
+
+* :ref:`services_index`: A growing collection of ready to use Web Processing Services built on top of reliable open source libraries such as GDAL, GRASS GIS, OrfeoToolbox, CGAL and SAGA GIS. 
+* :ref:`api-index`: A server-side JavaScript API for creating, chaining and orchestrating the available WPS Services.
+
+* :ref:`client-index`: A client side JavaScript API for interacting with WPS servers and executing standard requests from web applications.
+  
+
+Open Source
+-------------------
+
+`ZOO-Project <http://zoo-project.org>`__  is open source and released under the terms of the `MIT/X-11 <http://opensource.org/licenses/MITlicense>`__  `license <http://zoo-project.org/trac/browser/trunk/zoo-project/LICENSE>`__ . ZOO-Project activities are directed by the Project Steering Committee (PSC) and the software itself is being developed, maintained and documented by an international community of users and developers (aka `ZOO-Tribe <http://zoo-project.org/new/ZOO-Project/ZOO%20Tribe>`_).
+
+Please refer to the ZOO-Project :ref:`contribute_index` if you want to participate and contribute. It is easy to :ref:`get involved <contribute_index>`  on source code, documentation or translation. Everybody is welcome to join the `ZOO-Tribe <http://zoo-project.org/new/ZOO-Project/ZOO%20Tribe/>`__.
+
+`ZOO-Project <http://zoo-project.org>`__  is an incubating software at the Open Source Geospatial Foundation (`OSGeo <http://osgeo.org>`__).
+
+.. image:: _static/OSGeo_incubation.png
+   :height: 92px
+   :width: 225px
+   :scale: 75 %
+   :alt: OSGeo incubation
+
Index: /tags/rel-1.7.0/docs/kernel/configuration.rst
===================================================================
--- /tags/rel-1.7.0/docs/kernel/configuration.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/kernel/configuration.rst	(revision 942)
@@ -0,0 +1,416 @@
+.. _kernel_config:
+
+ZOO-Kernel configuration
+========================
+
+Main configuration file
+-----------------------
+
+ZOO-Kernel general settings are defined in a configuration file called
+``main.cfg``. This file is stored in the same directory as ZOO-Kernel
+(``/usr/lib/cgi-bin/`` in most cases). It provides usefull metadata information on your ZOO-Kernel installation.     
+
+.. warning:: 
+  ZOO-Kernel (``/usr/lib/cgi-bin/zoo_loader.cgi``) and its
+  configuration file (``/usr/lib/cgi-bin/main.cfg``) must be in the
+  same directory.
+  
+.. note:: 
+  Information contained by ``/usr/lib/cgi-bin/main.cfg`` is accessible from WPS Services at runtime, so when *Execute* requests are used.
+
+Default main.cfg
+...............................
+
+An example *main.cfg* file is given here as reference.
+
+.. code-block:: guess
+    :linenos:
+    
+    [headers]
+    X-Powered-By=ZOO@ZOO-Project
+    
+    [main]
+    version=1.0.0
+    encoding=utf-8
+    dataPath=/var/data
+    tmpPath=/var/www/temp
+    cacheDir=/var/www/cache
+    sessPath=/tmp
+    serverAddress=http://localhost/cgi-bin/zoo_loader.cgi
+    lang=fr-FR,ja-JP
+    language=en-US
+    mapserverAddress=http://localhost/cgi-bin/mapserv.cgi
+    msOgcVersion=1.0.0
+    tmpUrl=http:/localhost/temp/
+    cors=false
+    
+    [identification]
+    keywords=t,ZOO-Project, ZOO-Kernel,WPS,GIS
+    title=ZOO-Project demo instance
+    abstract= This is ZOO-Project, the Open WPS platform. 
+    accessConstraints=none
+    fees=None
+    
+    [provider]
+    positionName=Developer
+    providerName=GeoLabs SARL
+    addressAdministrativeArea=False
+    addressDeliveryPoint=1280, avenue des Platanes
+    addressCountry=fr
+    phoneVoice=+33467430995
+    addressPostalCode=34970
+    role=Dev
+    providerSite=http://geolabs.fr
+    phoneFacsimile=False
+    addressElectronicMailAddress=gerald@geolabs.fr
+    addressCity=Lattes
+    individualName=Gerald FENOY
+
+
+Main section 
+...............................
+
+The main.cfg ``[main]`` section parameters are explained bellow.
+
+ * ``version``: Supported WPS version.
+ * ``encoding``: Default encoding of WPS Responses.
+ * ``dataPath``: Path to the directory where data files are stored (used to store mapfiles and data when MapServer support is activated).
+ * ``tmpPath``: Path to the directory where temporary files are stored (such as *ExecuteResponse* when *storeExecuteResponse* is set to true).
+ * ``tmpUrl``: URL to access the temporary files directory (cf. ``tmpPath``).
+ * ``cacheDir``: Path to  the directory where cached request files [#f1]_ are stored (optional).
+ * ``serverAddress``: URL to the ZOO-Kernel instance.
+ * ``mapservAddress``: URL to the MapServer instance (optional).
+ * ``msOgcVersion``: Version of all supported OGC Web Services output [#f2]_
+   (optional).
+ * ``lang``: Supported natural languages separated by a coma (the first is the default one),
+ * ``cors``: Define if the ZOO-Kernel should support `Cross-Origin
+   Resource Sharing <https://www.w3.org/TR/cors/>`__. If this
+   parameter is not defined, then the ZOO-Kernel won't support CORS.
+ * ``servicePath``: Define a specific location to search for services
+   rather than using the ZOO-Kernel directory. If this parameter is
+   not defined, then the ZOO-Kernel will search for services using its
+   directory.
+ * ``libPath``: (Optional) Path to a directory where the ZOO-kernel should search for
+   service providers, e.g., shared libraries with service implementations 
+   (the ``serviceProvider`` parameter in the service configuration (.zcfg) file).   
+ * ``memory``: (Optional) can take the value ``load`` to ensure that
+   the value field of the inputs data will be filled by the ZOO-Kernel
+   or ``protected`` to have only the ``cache_file`` filled.
+
+
+.. warning:: 
+  The ``libPath`` parameter is currently only recognized by services implemented
+  in C/C++ or PHP, and may be moved to another section in future versions.
+
+
+.. warning:: 
+  Depending on the ``memory`` parameter the WPS Service will receive
+  different fields (``value`` or ``cache_file``).
+   
+In case you have activated the MapServer support, please refer to
+:ref:`this specific section <kernel-mapserver-main.cfg>`. 
+
+
+Identification and Provider 
+..........................................
+
+The ``[identification]`` and ``[provider]`` sections are not ZOO-Project
+specific. They provide OGC metadata [#f3]_ and should be set according
+to the `XML Schema Document
+<http://schemas.opengis.net/ows/1.1.0/ows19115subset.xsd>`__ which
+encodes the parts of ISO 19115 used by the common
+*ServiceIdentification* and *ServiceProvider* sections of the
+*GetCapabilities* operation response, known as the service metadata
+XML document.
+
+Details of the common OWS 1.1.0 *ServiceIdentification* section can be
+found in this `XML Schema Document
+<http://schemas.opengis.net/ows/1.1.0/owsServiceIdentification.xsd>`__.
+
+Details of the common OWS 1.1.0 *ServiceProvider* section can be
+found in this `XML Schema Document
+<http://schemas.opengis.net/ows/1.1.0/owsServiceProvider.xsd>`__.
+
+
+Additional sections
+--------------------------------
+
+All the additional sections discribed in the following section are
+optional.
+
+Headers section
+...............................
+
+The ``[headers]`` section can be set in order to define a specific HTTP
+Response header, which will be used for every response. As an example,
+you can check http://zoo-project.org using *curl* command line tool
+and notice the specific header *X-Powered-By: Zoo-Project@Trac*.
+
+In case you want to allow CORS support for POST requests coming from
+``myhost.net``, then you should define the following minimal
+parameters in this section:
+
+.. code-block:: guess
+    :linenos:
+    
+    Access-Control-Allow-Origin=myhost.net
+    Access-Control-Allow-Methods=POST
+    Access-Control-Allow-Headers=content-type
+
+
+env section
+...............................
+
+The ``[env]`` section can be used to store specific environment
+variables to be set prior the loading of *Services Provider* and Service execution.
+
+A typical example is when a Service requires the access to a X server
+running on *framebuffer*, which takes to set the DISPLAY environnement
+variable, as follow:
+
+.. code-block:: guess
+    :linenos:
+    
+    [env]
+    DISPLAY=:1
+
+In case you have activated the OTB support, please refer to :ref:`this
+specific section <kernel-orfeotoolbox-main.cfg>`. 
+
+lenv section
+...............................
+
+The ``lenv`` section is used by the ZOO-Kernel to store runtime informations
+before the execution of a WPS service, it contains the following
+parameters:
+
+ * ``sid`` (r): The WPS Service unique identifier,
+ * ``status`` (rw): The current progress value ( a value between 0 and
+   100 in percent (**%**) ),
+ * ``cwd`` (r): The current working directory of ZOO-Kernel,
+ * ``message`` (rw): An error message used when ``SERVICE_FAILED`` is returned (optional),
+ * ``cookie`` (rw): The cookie to be returned to the client (for
+   example for authentication purpose).
+ * ``file.pid`` (r): The file used by the ZOO-Kernel to store process identifier.
+ * ``file.sid`` (r): The file used by the ZOO-Kernel to store service identifier.
+ * ``file.responseInit`` (r): The file used by the ZOO-Kernel to store
+   the initial (then final) WPS response.
+ * ``file.responseFinal`` (r): The file used by the ZOO-Kernel to
+   temporary store the final WPS response.
+
+renv section
+...............................
+
+The ``renv`` section is automatically created by the ZOO-Kernel before
+the execution of a WPS service, it contains all the environment
+variables available at runtime (so including the header fields in case
+it is used through http, refer to [https://tools.ietf.org/html/rfc3875
+rfc3875] for more details).
+
+
+senv section
+...............................
+
+The ``senv`` section can be used to store sessions information on the
+server side. Such information can then be accessed automatically from
+the Service if the server is requested using a valid cookie (as
+defined in ``lenv`` section). ZOO-Kernel will store the values set in the
+``senv`` maps on disk, load it and dynamically replace its content to
+the one in the ``main.cfg``. The ``senv`` section must contain the
+following parameter at least:
+
+ * ``XXX``: The session unique identifier where ``XXX`` is the name
+   included in the cookie which is returned.
+
+.. _cookie_example:
+
+For instance, adding the following in the Service source code  :
+
+.. code:: python
+    
+    conf["lenv"]["cookie"]="XXX=XXX1000000; path=/" 
+    conf["senv"]={"XXX": "XXX1000000","login": "demoUser"}
+
+means that ZOO-Kernel will create a file named ``sess_XXX1000000.cfg``
+in the ``cacheDir`` directory, and will return the specified cookie to the client. Each time the client will 
+request ZOO-Kernel using this cookie, it will automatically load the
+value stored before the Service execution.
+
+Security section
+...............................
+
+The ``[security]`` section can be used to define what headers, the
+ZOO-Kernel has initially received in the request, should be passed
+to other servers for accessing resources (such as WMS, WFS, WCS
+or any other file passed as a reference). This section contains two
+parameters:
+
+ * ``attributes``: The header to pass to other servers (such as
+   Authorization, Cookie, User-Agent ...),
+ * ``hosts``: The host for wich the restriction apply (can be "*" to
+   forward header to every server or a coma separated list of host
+   names, domain, IP).
+
+Both parameters are mandatory.
+
+Suppose you need to share Authorization, Cookie and User-Agent to
+every server for accessing ressources, then yo ucan use the following
+section definition:
+
+.. code:: 
+
+    [security]
+    attributes=Authorization,Cookie,User-Agent
+    hosts=*
+
+In case only local servers require such header forwarding, you may use
+the following definition:
+
+.. code:: 
+
+    [security]
+    attributes=Authorization,Cookie,User-Agent
+    hosts=localhost,127.0.0.1
+
+Optionaly, you can also define the shared url(s), meaning that even if
+the ressource requires authentication to be accessed, this
+authentifcation won't be used to define the name for storing the
+file. Hence, two user with different authentication will use the same
+file as it is considerated as shared. You can find bellow a sample
+security section containing the shared parameter. In this example,
+every requests to access the coverage using the url defined in the
+shared parameter (``myHost/cgi-bin/WCS_Server``) will be shared
+between users.
+
+.. code::
+
+    [security]
+    attributes=Authorization,Cookie,User-Agent
+    hosts=localhost,127.0.0.1
+    shared=myHost/cgi-bin/WCS_Server
+
+.. _zoo_activate_db_backend:
+
+Database section
+...............................
+
+The database section allows to configure the
+:ref:`ZOO-Kernel optional database support <zoo_install_db_backend>`. 
+
+.. code-block:: guess
+
+	[database]
+	dbname=zoo_project
+	port=5432
+	user=username
+	host=127.0.0.1
+	type=PG
+	schema=public
+
+This will generate strings to be passed to GDAL to connect the
+database server:
+
+.. code-block:: guess
+   
+    <type>:host=<host> port=<port>  user=<user> dbname=<dbname>
+
+
+With the previous database section, it will give the following:
+
+.. code-block:: guess
+
+    PG:"dbname=zoo_project host=127.0.0.1 port=5432 user=username"
+
+Please refer to this `section <zoo_create_db_backend>`_ to learn how
+to setup the database.
+
+.. _zoo_activate_metadb:
+
+Metadb section
+...............................
+
+The metadb section allows to configure the ZOO-Kernel to access :ref:`the
+metadata information about WPS Services <zoo_create_metadb>` by using
+a PostgreSQL database in addition to the zcfg files.
+
+.. code-block:: guess
+
+	[metadb]
+	dbname=zoo_metadb
+	port=5432
+	user=username
+	host=127.0.0.1
+	type=PG
+
+This will generate strings to be passed to GDAL to connect the
+database server:
+
+.. code-block:: guess
+   
+    <type>:host=<host> port=<port>  user=<user> dbname=<dbname>
+
+
+With the previous database section, it will give the following:
+
+.. code-block:: guess
+
+    PG:"dbname=zoo_metadb host=127.0.0.1 port=5432 user=username"
+
+Please refer to this `section <zoo_create_metadb>`_ to learn how
+to setup the database.
+
+Include section
+...............................
+
+The ``[include]`` section (optional) lists explicitely a set of service configuration files
+the the ZOO-Kernel should parse, e.g.,
+
+
+.. code-block:: guess
+    :linenos:
+    
+    [include]
+    servicename1 = /my/service/repository/service1.zcfg
+    servicename2 = /my/service/repository/service2.zcfg
+
+The ``[include]`` section may be used to control which services are exposed to particular user groups.
+While service configuration files (.zcfg) may be located in a common repository or in arbitrary folders,
+main.cfg files at different URLs may include different subsets of services. 
+
+When the ZOO-Kernel handles a request, it will first check if there is an ``[include]`` 
+section in main.cfg and then search for other .zcfg files in the current working directory (CWD) and 
+subdirectories. If an included service happens to be located in a CWD (sub)directory, 
+it will be published by its name in the ``[include]`` section. For example, the service
+``/[CWD]/name/space/myService.zcfg``
+would normally be published as name.space.myService, but if it is listed in the ``[include]`` section 
+it will be published simply as myService: 
+
+.. code-block:: guess
+    :linenos:
+    
+    [include]
+    myService =  /[CWD]/name/space/myService.zcfg
+
+On the other hand, with
+
+.. code-block:: guess
+    :linenos:
+    
+    [include]
+    myService =  /some/other/dir/myService.zcfg
+
+there would be two distinct services published as myService and name.space.myService, respectively, 
+with two different zcfg files.
+
+.. note:: 
+  As currently implemented, the ZOO-Kernel searches the CWD for the library files of 
+  included services if the ``libPath`` parameter is not set.
+
+      
+.. rubric:: Footnotes
+
+.. [#f1] If GET requests are passed through ``xlink:href`` to the ZOO-Kernel , the latter will execute the request the first time and store the result  on disk. The next time the same request is executed, the cached file will be used and this will make your process run much faster. If ``cachedir`` was not specified in the ``main.cfg`` then the ``tmpPath`` value will be used.
+.. [#f2] Usefull when the :ref:`kernel-mapserver` is activated (available since ZOO-Project version 1.3.0).
+.. [#f3] ZOO-Kernel and MapServer are sharing the same metadata for OGC Web Services if the :ref:`kernel-mapserver` is activated.
+
+   
Index: /tags/rel-1.7.0/docs/kernel/hpc.rst
===================================================================
--- /tags/rel-1.7.0/docs/kernel/hpc.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/kernel/hpc.rst	(revision 942)
@@ -0,0 +1,339 @@
+.. _kernel-hpc:
+    
+Optional HPC support
+======================
+
+The optional ZOO-Kernel HPC support gives you the opportunity to use
+OGC WPS for invoking remote execution of OTB applications. The current
+implementation rely on `OpenSSH <https://www.openssh.com/>`_ and the
+`Slurm <http://slurm.schedmd.com/>`_  scheduler. 
+
+.. note:: 
+
+   |slurm| `Slurm <http://slurm.schedmd.com/>`_ is an acronym for Simple Linux Utility for Resource Management. Learn more on official `website <https://slurm.schedmd.com/overview.html>`__.
+
+For executing an OGC WPS Service using this HPC support, one should
+use the OGC WPS version 2.0.0 and asynchornous request. Any tentative
+to execute synchronously a HPC service will fail with the message "The
+synchronous mode is not supported by this type of service". The
+ZOO-Kernel is not the only responsible for the execution and will wait
+for the execution on the HPC server to end before being able to
+continue its execution. Also, transfering the data from the WPS server
+to the cluster and downloading the data produced by the execution will
+take time. Hence, when OGC WPS Client will request for GetCapabilities
+or DescribeProcess only the "async-execute" mode will be present in
+the jobControlOptions attribute for the HPC services.
+
+You can see in the sequence diagram below the interactions between
+the OGC WPS Server (ZOO-Kernel), the mail daemon (running on the OGC
+WPS server), the Callback Service and, the HPC Server during an
+execution of a HPC Service. The dashed lines represent the behavior in
+case the optional callback service invocation has been activated. These 
+invocations are made asynchronously for lowering their impact over the
+whole process in case of failure of the callback service for instance.
+
+By now, the callback service is not a WPS service but an independent server.
+
+|hpc_support|
+
+.. |slurm| image:: https://slurm.schedmd.com/slurm_logo.png
+       :height: 100px
+       :width: 100px
+       :scale: 45%
+       :alt: Slurm logo
+
+.. |hpc_support| image:: ../_static/hpc_schema.svg
+       :scale: 65%
+       :alt: HPC Support schema
+
+
+Installation and configuration
+------------------------------
+
+Follow the step described below in order to activate the ZOO-Project optional HPC support.
+
+Prerequisites
+.....................
+
+   * latest `ZOO-Kernel
+     <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel>`_
+     trunk version
+   * `libssh2 <https://www.libssh2.org/>`_
+   * `MapServer <http://www.mapserver.org>`_
+   * an access to a server with `Slurm  <http://slurm.schedmd.com>`_
+     and `OrfeoToolBox <https://www.orfeo-toolbox.org>`_.
+
+Installation steps
+...........................
+
+ZOO-Kernel
+****************************
+
+Compile ZOO-Kernel using the configuration options as shown below:
+
+.. code-block:: guess
+
+     cd zoo-kernel
+     autoconf
+     ./configure  --with-hpc=yes --with-ssh2=/usr --with-mapserver=/usr --with-ms-version=7
+     make
+     sudo make install
+
+Optionally, you can ask your ZOO-Kernel to invoke a callback service
+which is responsible to record execution history and data
+produced. In such a case you can add the ``--with-callback=yes``
+option to the configure command. 
+
+.. note::
+
+   In case you need other languages to be activated, such as Python
+   for exemple, please use the corresponding option(s).
+
+FinalizeHPC WPS Service
+****************************
+
+For being informed that the remote OTB application ends on the
+cluster, one should invoke the FinalizeHPC service. It is responsible
+to connect using SSH to the HPC server to run an ``sacct`` command for
+extracting detailled informations about the sbatch that has been
+run. If the ``sacct`` command succeed, and the service is no more
+running on the cluster, then the informations are stored in a local
+conf file containing a ``[henv]`` section definition, the service
+connect to unix domain socket (opened by the ZOO-Kernel that has
+initially schedduled the service through Slurm) to inform about the
+end of the service run on the cluster. This makes the initial
+ZOO-Kernel to continue its execution by downloading output data
+produced over the execution of the OTB application on the cluster. So,
+this service should be build and deployed on your WPS server. You can
+use the following commands to do so. 
+
+.. code-block:: guess
+
+     cd zoo-service/utils/hpc
+     make
+     cp cgi-env/* /usr/lib/cgi-bin
+     mkdir -p /var/data/xslt/
+     cp xslt/updateExecute.xsl /var/data/xslt/
+     
+You should also copy the 
+.. note::
+
+   FinalizeHPC should be called from a daemon, responsible for reading
+   mails sent by the cluster to the WPS server.
+
+
+Configuration steps
+...............................
+
+Main configuration file
+****************************
+
+When HPC support is activated, you can use different HPC configuration
+by adding ``confId`` to your usual ``serviceType=HPC`` in your zcfg
+file. For being able to find which configuration a service should
+use, the ZOO-Kernel require to know what are the options for creating
+the relevant sbatch.
+
+Also, you can define multiple configuration to run the OTB application
+on the cluster(s) depending on the size of the inputs. You should
+define in the section corresponding to your ``ServiceType`` the
+treshold for both raster (``preview_max_pixels``) and vector
+(``preview_max_features``) input. In case the raster or the vector
+dataset is upper the defined limit, then the ``fullres_conf`` will
+be used, in other case the ``preview_conf`` will be.
+
+For each of this configurations, you will have define the parameters
+to connect the HPC server, by providing ``ssh_host``, ``ssh_port``,
+``ssh_user`` and, ``ssh_key``. Also, you should set where the input
+data will be stored on the HPC server, by defining
+``remote_data_path`` (the default directory to store data),
+``remote_presistent_data_path`` (the directory to store data
+considerated as shared data, see below)  and, ``remote_work_path`` the
+directory used to store the SBATCH script created locally then,
+uploaded by the ZOO-Kernel.
+
+Also, there are multiple options you can use to run your applications
+using  SBATCH. You can define them using ``jobscript_header``,
+``jobscript_body`` and ``jobscript_footer`` or by using
+``sbatch_options_<SBATCH_OPTION>`` where ``<SBATCH_OPTION>`` should be
+replaced by a real option name, like ``workdir`` in the following
+example. For creating the SBATCH file, the ZOO-Kernel create a file
+starting with the content of the file pointed by ``jobscript_header``
+(if any, a default header is set in other case), then, any option
+defined in ``sbatch_options_*`` and a specific one: ``job-name``,
+then, ``jobscript_body`` is added (if any, usually to load required
+modules), then the ZOO-Kernel add the invocation of the OTB
+application then, optionally the ``jobscript_footer`` is added, if
+any.
+
+Finally, ``remote_command_opt`` should contains all the informations
+you want to be extracted by the ``sacct`` command run by the
+FinalizeHPC service. ``billing_nb_cpu`` is used for billing purpose to
+define a cost for using a specific option (preview or fullres).
+
+In addition to the specific ``HPC_<ID>`` section and the corresponding
+fullres and preview ones, you should define in the ``[security]``
+section using the ``shared`` parameter to set the URLs from where the
+downloaded data should be considerated as shared, meaning that even if
+this ressources requires authentication to be accessed, any
+authenticated user will be allowed to access the cache file even if
+it was created by somebody else. Also, this shared cache won't contain
+any authentication informations in the cache file name as it is
+usually the case.
+
+.. code-block:: guess
+
+     [HPC_Sample]
+     preview_max_pixels=820800
+     preview_max_features=100000
+     preview_conf=hpc-config-2
+     fullres_conf=hpc-config-1
+     
+     [hpc-config-1]
+     ssh_host=mycluster.org
+     ssh_port=22
+     ssh_user=cUser
+     ssh_key=/var/www/.ssh/id_rsa.pub
+     remote_data_path=/home/cUser/wps_executions/data
+     remote_persitent_data_path=/home/cUser/wps_executions/datap
+     remote_work_path=/home/cUser/wps_executions/script
+     jobscript_header=/usr/lib/cgi-bin/config-hpc1_header.txt
+     jobscript_body=/usr/lib/cgi-bin/config-hpc1_body.txt
+     sbatch_options_workdir=/home/cUser/wps_executions/script
+     sbatch_substr=Submitted batch job 
+     billing_nb_cpu=1
+     remote_command_opt=AllocCPUS,AllocGRES,AllocNodes,AllocTRES,Account,AssocID,AveCPU,AveCPUFreq,AveDiskRead,AveDiskWrite,AvePages,AveRSS,AveVMSize,BlockID,Cluster,Comment,ConsumedEnergy,ConsumedEnergyRaw,CPUTime,CPUTimeRAW,DerivedExitCode,Elapsed,Eligible,End,ExitCode,GID,Group,JobID,JobIDRaw,JobName,Layout,MaxDiskRead,MaxDiskReadNode,MaxDiskReadTask,MaxDiskWrite,MaxDiskWriteNode,MaxDiskWriteTask,MaxPages,MaxPagesNode,MaxPagesTask,MaxRSS,MaxRSSNode,MaxRSSTask,MaxVMSize,MaxVMSizeNode,MaxVMSizeTask,MinCPU,MinCPUNode,MinCPUTask,NCPUS,NNodes,NodeList,NTasks,Priority,Partition,QOS,QOSRAW,ReqCPUFreq,ReqCPUFreqMin,ReqCPUFreqMax,ReqCPUFreqGov,ReqCPUS,ReqGRES,ReqMem,ReqNodes,ReqTRES,Reservation,ReservationId,Reserved,ResvCPU,ResvCPURAW,Start,State,Submit,Suspended,SystemCPU,Timelimit,TotalCPU,UID,User,UserCPU,WCKey,WCKeyID
+     
+     [hpc-config-2]
+     ssh_host=mycluster.org
+     ssh_port=22
+     ssh_user=cUser
+     ssh_key=/var/www/.ssh/id_rsa.pub
+     remote_data_path=/home/cUser/wps_executions/data
+     remote_persitent_data_path=/home/cUser/wps_executions/datap
+     remote_work_path=/home/cUser/wps_executions/script
+     jobscript_header=/usr/lib/cgi-bin/config-hpc2_header.txt
+     jobscript_body=/usr/lib/cgi-bin/config-hpc2_body.txt
+     sbatch_options_workdir=/home/cUser/wps_executions/script
+     sbatch_substr=Submitted batch job 
+     billing_nb_cpu=4
+     remote_command_opt=AllocCPUS,AllocGRES,AllocNodes,AllocTRES,Account,AssocID,AveCPU,AveCPUFreq,AveDiskRead,AveDiskWrite,AvePages,AveRSS,AveVMSize,BlockID,Cluster,Comment,ConsumedEnergy,ConsumedEnergyRaw,CPUTime,CPUTimeRAW,DerivedExitCode,Elapsed,Eligible,End,ExitCode,GID,Group,JobID,JobIDRaw,JobName,Layout,MaxDiskRead,MaxDiskReadNode,MaxDiskReadTask,MaxDiskWrite,MaxDiskWriteNode,MaxDiskWriteTask,MaxPages,MaxPagesNode,MaxPagesTask,MaxRSS,MaxRSSNode,MaxRSSTask,MaxVMSize,MaxVMSizeNode,MaxVMSizeTask,MinCPU,MinCPUNode,MinCPUTask,NCPUS,NNodes,NodeList,NTasks,Priority,Partition,QOS,QOSRAW,ReqCPUFreq,ReqCPUFreqMin,ReqCPUFreqMax,ReqCPUFreqGov,ReqCPUS,ReqGRES,ReqMem,ReqNodes,ReqTRES,Reservation,ReservationId,Reserved,ResvCPU,ResvCPURAW,Start,State,Submit,Suspended,SystemCPU,Timelimit,TotalCPU,UID,User,UserCPU,WCKey,WCKeyID
+     
+     [security]
+     attributes=Cookie,Cookies
+     hosts=*
+     shared=myhost.net/WCS
+
+You can see below an example of ``jobscript_header`` file.
+
+.. code-block:: guess
+
+     #!/bin/sh
+     #SBATCH --ntasks=1
+     #SBATCH --ntasks-per-node=1
+     #SBATCH --exclusive
+     #SBATCH --distribution=block:block
+     #SBATCH --partition=partName
+     #SBATCH --mail-type=END              # Mail events (NONE, BEGIN, END, FAIL, ALL)
+     #SBATCH --mail-user=user@wps_server.net   # Where to send mail
+
+You can see below an example of ``jobscript_body`` file.
+
+
+.. code-block:: guess
+
+     # Load all the modules
+     module load cv-standard
+     module load cmake/3.6.0
+     module load gcc/4.9.3
+     module load use.own
+     module load OTB/6.1-serial-24threads
+
+In casse you have activated the callback service, then you should also
+have a ``[callback]`` section, in which you will define ``url`` to
+invoke the callback service, ``prohibited`` to list the services that
+should not require invocation of the callback sercvice if any and,
+``template`` pointing to the local ``updateExecute.xsl`` file used to
+replace any inputs provided by value to the reference to the locally
+published OGC WFS/WCS web services. This execute request is provided
+to the callback service.
+
+.. code-block:: guess
+
+     [callback]
+     url=http://myhost.net:port/callbackUpdate/
+     prohibited=FinalizeHPC,Xml2Pdf,DeleteData
+     template=/home/cUser/wps_dir/updateExecute.xsl
+
+
+OGC WPS Services metadata
+****************************
+
+To produce the zcfg files corresponding to the metadata definition of
+the WPS services, you can use the otb2zcfg tool to produce them. You
+will need to replace ``serviceType=OTB`` by ``serviceType=HPC`` and,
+optionally, add one line containing ``confId=HPC_Sample`` for
+instance.
+
+Please refer to `otb2zcfg
+<./orfeotoolbox.html#services-configuration-file>`_ documentation to
+know how to use this tool.
+
+Using the HPC support, when you define one output, there will be
+automatically 1 to 3 inner outputs created for the defined output:
+
+download_link
+   URL to download to generated output 
+
+wms_link
+   URL to access the OGC WMS for this output (only in case
+   `useMapserver=true`)
+
+wcs_link/wfs_link
+   URL to access the OGC WCS or WFS for this output (only in case
+   `useMapserver=true`) 
+
+You can see below an example of Output node resulting of the
+definition of one output named out and typed as geographic imagery.
+
+
+.. code-block:: guess
+
+      <wps:Output>
+        <ows:Title>Outputed Image</ows:Title>
+        <ows:Abstract>Image produced by the application</ows:Abstract>
+        <ows:Identifier>out</ows:Identifier>
+        <wps:Output>
+          <ows:Title>Download link</ows:Title>
+          <ows:Abstract>The download link</ows:Abstract>
+          <ows:Identifier>download_link</ows:Identifier>
+          <wps:ComplexData>
+            <wps:Format default="true" mimeType="image/tiff"/>
+            <wps:Format mimeType="image/tiff"/>
+          </wps:ComplexData>
+        </wps:Output>
+        <wps:Output>
+          <ows:Title>WMS link</ows:Title>
+          <ows:Abstract>The WMS link</ows:Abstract>
+          <ows:Identifier>wms_link</ows:Identifier>
+          <wps:ComplexData>
+            <wps:Format default="true" mimeType="image/tiff"/>
+            <wps:Format mimeType="image/tiff"/>
+          </wps:ComplexData>
+        </wps:Output>
+        <wps:Output>
+          <ows:Title>WCS link</ows:Title>
+          <ows:Abstract>The WCS link</ows:Abstract>
+          <ows:Identifier>wcs_link</ows:Identifier>
+          <wps:ComplexData>
+            <wps:Format default="true" mimeType="image/tiff"/>
+            <wps:Format mimeType="image/tiff"/>
+          </wps:ComplexData>
+        </wps:Output>
+      </wps:Output>
+
+   
+
+
+
+
Index: /tags/rel-1.7.0/docs/kernel/index.rst
===================================================================
--- /tags/rel-1.7.0/docs/kernel/index.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/kernel/index.rst	(revision 942)
@@ -0,0 +1,16 @@
+.. _kernel_index:
+
+ZOO-Kernel
+========
+
+This section provides information on **ZOO-Kernel** , the `ZOO-Project <http://zoo-project.org>`__ WPS server. It will help you to configure and compile ZOO-Kernel.
+
+.. toctree::
+   :maxdepth: 2
+   
+   what
+   configuration
+   mapserver
+   orfeotoolbox
+   sagagis
+   hpc
Index: /tags/rel-1.7.0/docs/kernel/mapserver.rst
===================================================================
--- /tags/rel-1.7.0/docs/kernel/mapserver.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/kernel/mapserver.rst	(revision 942)
@@ -0,0 +1,347 @@
+.. _kernel-mapserver:
+    
+Optional MapServer support
+==========================
+
+Processing geospatial data using WPS Services is usefull. Publishing their results directly as WMS, WFS or WCS ressources is even more convenient. This is possible since `ZOO-Project 1.3 <http://zoo-project.org>`__ using the **optional MapServer support**. The latter thus allows for automatic publication of WPS Service output as WMS/WFS or WCS using a :ref:`kernel_index` specific internal mechanism which is detailed in this section. 
+
+
+.. note:: 
+
+  |mapserver| `MapServer <http://mapserver.org>`__ is an open source WMS/WFS/WCS server. Learn more by reading its `documentation <http://mapserver.org/documentation.html>`__.
+ 
+
+.. |mapserver| image:: ../_static/mapserver.png
+       :height: 74px
+       :width: 74px
+       :scale: 50%
+       :alt: MapServer logo
+
+
+How does it work ?
+-------------------------
+
+If a request with ``mimeType=image/png`` is sent to :ref:`kernel_index`, the latter will detect that the *useMapServer* option is set to true an it will automatically:
+
+   * Execute the service using the *<Default>* block definition (these values must be understood by `GDAL <http:/gdal.org>`__)
+   * Store the resulting output on disk (in the ``[main]`` > ``dataPath`` directory)
+   * Write a `mapfile <http://mapserver.org/mapfile/index.html>`__ (in the ``[main]`` > ``dataPath`` directory) using the `MapServer <http://mapserver.org>`__ C-API (this sets up both WMS and WFS services).
+
+Existing WPS Services source code doesn't need to be modified once the MapServer support is activated. It only takes to edit their respective :ref:`services-zcfg` files accordingly.
+
+.. note:: In case of a vector data source output, both WMS and WFS configuration are included by default in the resulting mapfile.
+
+.. note:: In case of a raster data source output, both WMS and WCS configuration are included by default in the resulting mapfile.
+
+Depending on the requests, ZOO-Kernel is able to return a location header and different request types:
+
+    * ResponseDocument=XXXX@asReference=true
+
+In this case, ZOO-Kernel will return the GetMap/GetFeature/GetCoverage request as KVP in the *href* of the result.
+
+    * ResponseDocument=XXXX@asReference=false
+
+In this case, ZOO-Kernel will return the result of the GetMap/GetFeature/GetCoverage request as KVP of the href used in the previous case.
+
+    * RawDataOutput=XXXX@asReference=true/false
+
+In this case, ZOO-Kernel will return the GetMap/GetFeature/GetCoverage request as KVP in a specific location header, which implies that the browser is supposed to request MapServer directly.
+
+Whatever the default output *mimeType* returned by a WPS service is, it is used if the *useMapserver* option is found at runtime. As an example, if ``<Default>`` and ``<Supported>`` blocks are found in the ZOO Service configuration file as shown bellow, this means that the service returns GML 3.1.0 features by default.
+
+.. code-block:: guess
+
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = image/png
+     useMapserver = true
+    </Supported>
+
+Installation and configuration
+------------------------------
+
+Follow the step described bellow in order to activate the ZOO-Project optional MapServer support.
+
+Prerequisites
+.............
+
+   * latest `ZOO-Kernel <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel>`__ trunk version
+   * `MapServer <http://mapserver/org>`__ version >= 6.0.1
+
+First download the lastest zoo-kernel by checking out the svn. Use the following command from do the directory where your previously checked out (in this example we will use ``$PREV_SVN_CO`` to design this directory).
+
+.. code-block:: guess
+
+    svn checkout http://svn.zoo-project.org/svn/trunk/ $PREV_SVN_CO
+    cd $PREV_SVN_CO
+    
+Then uncompress the MapServer archive (ie. ``mapserver-6.0.1.tar.bz2``) into ``/tmp/zoo-ms-src``, and compile it using the following command:
+
+.. code-block:: guess
+
+     cd /tmp/zoo-ms-src/mapserver-6.0.1
+     ./configure --with-ogr=/usr/bin/gdal-config --with-gdal=/usr/bin/gdal-config \
+                    --with-proj --with-curl --with-sos --with-wfsclient --with-wmsclient \
+                    --with-wcs --with-wfs --with-postgis --with-kml=yes --with-geos \
+                    --with-xml --with-xslt --with-threads --with-cairo
+     make
+     cp mapserv /usr/lib/cgi-bin
+
+Once done, compile ZOO-Kernel with MapServer support from the ``$PREV_SVN_CO`` directory, using the following command:
+
+.. code-block:: guess
+
+     cd zoo-kernel
+     autoconf
+     ./configure --with-python --with-mapserver=/tmp/zoo-ms-src/mapserver-6.0.1
+     make
+     sudo make install
+
+
+.. _kernel-mapserver-main.cfg:
+
+Main configuration file
+........................
+
+Open and edit the ``/usr/lib/cgi-bin/main.cfg`` file, by adding the following content in the ``[main]`` section:
+
+.. code-block:: guess
+
+      dataPath = /var/www/temp/
+      mapserverAddress=http://localhost/cgi-bin/mapserv
+
+You can also add the following lines to the ``[main]`` section, in case
+you want to use a default style for Polygon, Lines and Points vector
+layer.
+
+.. code-block:: guess
+
+      msStylePoly=STYLE COLOR 202 109 19 OUTLINECOLOR 105 105 105 WIDTH 3 END
+      msStyleLine=STYLE OUTLINECOLOR 202 109 19 WIDTH 3 END
+      msStylePoint=STYLE COLOR 202 109 19 OUTLINECOLOR 105 105 105 SYMBOL 0 SIZE 14 END
+
+The ``dataPath`` directory is mandatory and must belong to the Apache user.
+
+.. code-block:: guess
+
+     mkdir /var/www/temp/
+     chown -r apache:apache /var/www/temp/
+
+A ``symbols.sym`` file is required in this directory. Create it and add the following content in it:
+
+.. code-block:: guess
+
+      SYMBOLSET
+      SYMBOL
+        NAME "circle"
+        TYPE ellipse
+        FILLED true
+        POINTS
+          1 1
+        END
+      END
+      END
+
+.. note::
+  Only one symbol definition is required (with any name) for the WMS service output.
+
+The ZOO-Project optional MapServer support is activated at this step. Don't forget to add the ``mapserverAddress`` and  ``msOgcVersion`` parameters to the ``main.cfg`` file in order to  to specify the path to MapServer and the OGC WebService version used by the Services.
+
+.. code-block:: guess
+     mapserverAddress=http://localhost/cgi-bin/mapserv.cgi
+     msOgcVersion=1.0.0
+
+.. warning::
+   ZOO-kernel will segfault (checking ``NULL`` value should correct this behavior) if the ``mapserverAddress`` parameter is not found
+
+
+Service configuration file
+............................
+
+useMapserver
+*************
+
+In order to activate the MapServer WMS/WFS/WCS output for a specific service, the ``useMapserver`` parameter must be added to the ``<Default>`` or ``<Supported>`` blocks of the Service `services-zcfg`. If ``useMapserver=true``, this means that the output result of the Service is a GDAL compatible datasource and that you want it to be automatically published by MapServer as WMS,WFS or WCS.
+
+When the useMapserver option is used in a ``<Default>`` or ``<Supported>`` block, then you have to know what are the corresponding mimeType:
+
+   * text/xml: Implies that the output data will be accessible through a WFS GetFeature request (default protocol version 1.1.0)
+   * image/tiff: Implies that the output data will be accessible through a WCS GetCoverage request (default protocol version 2.0.0)
+   * any other mimeType coupled with useMapserver option: Implies that the output data will be accessible through a WMS GetMap request (default protocol version 1.3.0). You can check the supported output mimeType by sending a GetCapabilities request to MapServer.
+
+
+You get the same optional parameter ``msOgcVersion`` as for the ``main.cfg``. This will specify that this is the specific protocol version the service want to use (so you may set also locally to service rather than globally).
+
+Styling
+*************
+
+You have different options to define the style of the layer created
+using the data returned by your service.
+
+msStyle
++++++++
+
+The optional ``msStyle`` parameter can also be used to define a custom MapServer style block (used for vector datasource only), as follow:
+
+.. code-block:: guess
+
+     msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 3 END
+
+msClassify
+++++++++++
+
+If a WPS service outputs a one band raster file, then it is possible
+to add a ``msClassify`` parameter and set it to ``true`` in the output
+ComplexData ``<Default>`` or ``<Supported>`` nodes of its zcfg
+file. This allows ZOO-Kernel to use its own default style definitions
+in order to classify the raster using equivalent intervals.  
+
+.. code-block:: guess
+
+     msClassify = true
+
+
+msInclude
++++++++++
+
+In case you want to use another layer which use the result of your
+service, for instance to produce a `heatmap
+<https://mapserver.org/output/kerneldensity.html>`_, then you can use
+the 
+``msInclude`` and ``msLayer`` options in the output ``ComplexData``
+``<Default>`` or ``<Supported>`` nodes of its zcfg file. You can see below an
+example of use of this two options with the associated mapfile.
+
+.. code-block:: guess
+
+     msInclude = /var/data/template.map
+     msLayer = heatmap
+
+You can find below a sample ``/var/data/template.map``:
+
+.. code-block:: guess
+
+     MAP
+       SIZE 1000 500
+       EXTENT -180 -90 180 90
+       NAME "test heat"
+       IMAGETYPE "png"
+
+       WEB
+         METADATA
+           "ows_srs" "epsg:4326  epsg:3857 epsg:900913"
+           "ows_enable_request" "*"
+	 END # METADATA
+       END # WEB
+       
+       PROJECTION
+         "+init=epsg:4326"
+       END # PROJECTION
+
+       LAYER
+         NAME "heatmap" # Corresponding to the msLayer defined
+	 TYPE raster
+	 CONNECTIONTYPE kerneldensity
+	 CONNECTION "Result"
+	 STATUS on
+	 PROCESSING "RANGE_COLORSPACE=HSL"
+	 PROCESSING "KERNELDENSITY_RADIUS=20"
+	 PROCESSING "KERNELDENSITY_COMPUTE_BORDERS=ON"
+	 PROCESSING "KERNELDENSITY_NORMALIZATION=AUTO"
+	 OFFSITE 0 0 0
+	 CLASS
+	   STYLE
+	     COLORRANGE  "#0000ff00"  "#0000ffff"
+	     DATARANGE 0 32
+	   END # STYLE
+	   STYLE
+	     COLORRANGE  "#0000ffff"  "#ff0000ff"
+	     DATARANGE 32 255
+	   END # STYLE
+	 END # CLASS
+       END # LAYER
+       
+       LAYER
+         NAME "points"
+	 STATUS on
+	 TYPE POINT
+	 #DATA "/Library/WebServer/cache//ef76ee6642c1ea704e847e28120ba1ca.zca"
+       END # LAYER
+     END # MAPFILE
+
+
+
+
+Example
+**************
+
+An example :ref:`services-zcfg` file configured for the optional MapServer support is shown bellow: 
+
+.. code-block:: guess
+
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     useMapserver = true
+    </Default>
+    <Supported>
+     mimeType = image/png
+     useMapserver = true
+     asReference = true
+     msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 3 END
+    </Supported>
+    <Supported>
+     mimeType = application/vnd.google-earth.kmz
+     useMapserver = true
+     asReference = true
+     msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 3 END
+    </Supported>
+    <Supported>
+     mimeType = image/tif
+     useMapserver = true
+     asReference = true
+     msClassify = true
+    </Supported>
+
+In this example, the default output ``mimeType`` is ``image/png``, so a WMS GetMap request will be returned, or the resulting ``image/tiff`` will be returned as WCS GetCoverage request.
+
+
+Test requests
+--------------
+
+The optional MapServer support can be tested using any service. The
+simple *HelloPy* Service is used in the following example requests.
+
+.. note::
+  The following examples require a zip file containing a Shapefile (http://localhost/data/data.zip) and a tif file (http://localhost/data/demo.tif)
+
+Accessing a remote Zipped Shapefile as WFS GetFeatures Request:
+
+.. code-block:: guess
+
+     http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=HelloPy&DataInputs=a=Reference@xlink:href=http://localhost/data/data.zip&ResponseDocument=Result@asReference=true@mimetype=text/xml
+
+Accessing a remote Zipped Shapefile as WMS GetMap Request:
+
+.. code-block:: guess
+
+     http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=HelloPy&DataInputs=a=Reference@xlink:href=http://localhost/data/data.zip&ResponseDocument=Result@asReference=true@mimetype=image/png
+
+Accessing a remote tiff as WMS GetMap Request:
+
+.. code-block:: guess
+
+     http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=HelloPy&DataInputs=a=Reference@xlink:href=http://localhost/data/data.tiff&ResponseDocument=Result@asReference=true@mimetype=image/png
+
+Accessing a remote tiff as WCS GetMap Request:
+
+.. code-block:: guess
+
+     http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=HelloPy&DataInputs=a=Reference@xlink:href=http://localhost/data/data.tiff&ResponseDocument=Result@asReference=true@mimetype=image/tiff
+
+
Index: /tags/rel-1.7.0/docs/kernel/orfeotoolbox.rst
===================================================================
--- /tags/rel-1.7.0/docs/kernel/orfeotoolbox.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/kernel/orfeotoolbox.rst	(revision 942)
@@ -0,0 +1,132 @@
+.. _kernel-orfeotoolbox:
+    
+Optional Orfeo Toolbox support
+======================
+
+`Orfeo Toolbox <http://orfeo-toolbox.org/otb/>`_ provides simple to advanced algorithms for processing imagery available from remote sensors.
+The optional Orfeo Toolbox support is available since `ZOO-Project 1.5 <http://zoo-project.org>`__. It allows to execute the `OTB Applications <http://orfeo-toolbox.org/otb/otb-applications.html>`_ directly as ZOO WPS Services thanks to a :ref:`kernel_index` specific internal mechanism which is detailed in this section.
+
+.. note:: 
+
+   |otb| `Orfeo Toolbox <https://www.orfeo-toolbox.org>`__ is an open source image processing library. Learn more by reading its `documentation <https://www.orfeo-toolbox.org/documentation/>`__.
+ 
+
+.. |otb| image:: ../_static/orfeotoolbox.png
+       :height: 115px
+       :width: 150px
+       :scale: 30%
+       :alt: Orfeo Toolbox logo
+
+
+Installation and configuration
+------------------------------
+
+Follow the step described bellow in order to activate the ZOO-Project optional Orfeo Toolbox support.
+
+Prerequisites
+.....................
+
+   * latest `ZOO-Kernel <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel>`_ trunk version
+   * Orfeo Toolbox (`OTB 4.2.1 <http://orfeo-toolbox.org/otb/>`_)
+   * Insight Segmentation and Registration Toolkit  (`ITK-4.7 <http://itk.org/ITK/resources/software.html/>`_)
+
+Installation steps
+...........................
+
+.. Note:: These installation steps were successfully tested on Ubuntu 14.4 LTS 
+
+.. Note:: For OTB and ITK, the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS must first be set to ``-fPIC``
+
+Download lastest ZOO-Kernel code from SVN.
+
+.. code-block:: guess
+
+    svn checkout http://svn.zoo-project.org/svn/trunk/zoo-kernel zoo-kernel
+
+Then compile ZOO-Kernel using the needed configuration options as shown bellow:
+
+.. code-block:: guess
+
+     cd zoo-kernel
+     autoconf
+     ./configure  --with-otb=/usr/local --with-itk=/usr/local --with-itk-version=4.7 
+     make
+     cp zoo_loader.cgi /usr/lib/cgi-bin
+
+Configuration steps
+....................................
+
+.. _kernel-orfeotoolbox-main.cfg:
+    
+Main configuration file
+*************************
+
+Add the following content to your ``/usr/lib/cgi-bin/main.cfg`` file 
+in the ``[env]`` section:
+
+.. code-block:: guess
+
+       ITK_AUTOLOAD_PATH=/usr/local/lib/otb/applications
+
+Services configuration file
+****************************
+
+The build of the `otb2zcfg  <http://zoo-project.org/trac/browser/trunk/thirds/otb2zcfg>`_ utility is required to activate the available OTB Applications as WPS services. This can be done using the following command: 
+
+.. code-block:: guess
+	
+	 mkdir build
+	 cd build
+	 ccmake ..
+	 make
+	
+Run the following command to generate all the needed zcfg files for the available OTB Application:
+
+.. code-block:: guess
+	
+	 mkdir zcfgs
+	 cd zcfgs
+	 export ITK_AUTOLOAD_PATH=/your/path/to/otb/applications
+	 ../build/otb2zcfg
+         mkdir /location/to/your/cgi-bin/OTB
+	 cp *zcfg /location/to/your/cgi-bin/OTB
+	
+.. warning 
+
+     The ITK_AUTOLOAD_PATH environment variable is required in the [env] section of your main.cfg.
+
+Test requests
+****************************
+
+Once done, OTB Applications should be listed as available WPS Services when runing a GetCapabilities request
+
+.. code-block:: guess 
+
+        http://localhost/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS 
+
+Each OTB Service can then be described individually using the DescribeProcess request, as for example:
+
+.. code-block:: guess
+
+   http://localhost/cgi-bin/zoo_loader.cgi?request=DescribeProcess&service=WPS&version=1.0.0&Identifier=OTB.BandMath
+
+Here is an example request executing the *OTB.BandMath* Application with the `OTB Cookbook <https://www.orfeo-toolbox.org/CookBook/CookBook.html>`_ sample data as input
+
+.. code-block:: guess
+
+   http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=OTB.BandMath&DataInputs=il=Reference@xlink:href=http://hg.orfeo-toolbox.org/OTB-Data/raw-file/ca154074b282/Examples/verySmallFSATSW.tif;il=Reference@xlink:href=http://hg.orfeo-toolbox.org/OTB-Data/raw-file/ca154074b282/Examples/verySmallFSATSW_nir.tif;out=float;exp=im1b3*cos%28im1b1%29,im1b2*cos%28im1b1%29,im1b1*cos%28im1b1%29&RawDataOutput=out@mimeType=image/png
+
+
+.. note::
+
+   The usual ZOO GetStatus requests also work when using the OTB Applications as WPS Services.
+
+
+
+    
+
+
+
+
+
+
Index: /tags/rel-1.7.0/docs/kernel/sagagis.rst
===================================================================
--- /tags/rel-1.7.0/docs/kernel/sagagis.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/kernel/sagagis.rst	(revision 942)
@@ -0,0 +1,103 @@
+.. _kernel-sagagis:
+    
+Optional SAGA GIS support
+======================
+
+`SAGA GIS <http://www.saga-gis.org/>`_ provides a comprehensive set of geoscientific methods and spatial algorithms. The optional SAGA GIS support is available since `ZOO-Project 1.5 <http://zoo-project.org>`__. It allows to execute the `SAGA Modules <http://www.saga-gis.org/saga_module_doc/2.1.4/index.html>`_ directly as ZOO WPS Services thanks to a :ref:`kernel_index` specific internal mechanism which is detailed in this section.
+
+.. note:: 
+
+   |saga| `SAGA GIS <http://www.saga-gis.org/>`__ is the System for Automated Geoscientific Analyses. Learn more on official `website <http://www.saga-gis.org/en/index.html>`__.
+ 
+
+.. |saga| image:: ../_static/sagagis.png
+       :height: 100px
+       :width: 100px
+       :scale: 45%
+       :alt: SAGA GIS logo
+
+
+Installation and configuration
+------------------------------
+
+Follow the step described bellow in order to activate the ZOO-Project optional SAGA GIS support.
+
+Prerequisites
+.....................
+
+   * latest `ZOO-Kernel <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-kernel>`_ trunk version
+   * `SAGA GIS  <http://saga-gis.org>`_  (7.2.0)
+
+Installation steps
+...........................
+
+Compile ZOO-Kernel using the configuration options as shown bellow:
+
+.. code-block:: guess
+
+     cd zoo-kernel
+     autoconf
+     ./configure  --with-saga=/usr/local/ --with-saga-version=7
+     make
+
+And copy the newly created zoo_loader.cgi to ``/usr/lib/cgi-bin``.
+     
+.. note::
+   
+    The ``--with-saga-version`` option let you set the major
+    version number of SAGA-GIS.  
+     
+.. code-block:: guess
+
+     cp zoo_loader.cgi /usr/lib/cgi-bin
+
+Configuration steps
+...............................
+
+Services configuration file
+****************************
+
+Building the
+`saga2zcfg <http://zoo-project.org/trac/browser/trunk/thirds/saga2zcfg>`_
+utility is required to activate the available SAGA-GIS Modules as WPS
+Services. This can be done using the following command: 
+
+.. code-block:: guess
+
+    cd thirds/saga2zcfg
+    make
+
+The following commands will then generate all the needed zcfg files for the available SAGA-GIS Modules:
+
+.. code-block:: guess
+		
+    mkdir zcfgs
+    cd zcfgs
+    ../saga2zcfg
+    mkdir /location/to/your/cgi-bin/SAGA
+    cp *zcfg /location/to/your/cgi-bin/SAGA
+
+
+Test requests
+*****************
+
+The SAGA-GIS Modules should be listed as available WPS Services when
+runing a GetCapabilities request, as follow:
+
+http://localhost/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS
+
+Each SAGA-GIS Service can then be described individually using the DescribeProcess request, as for example:
+
+http://localhost/cgi-bin/zoo_loader.cgi?request=DescribeProcess&service=WPS&version=1.0.0&Identifier=SAGA.garden_fractals.1
+
+And executed according to your needs. The following example executes *SAGA.garden_fractals.1* with no optional parameter:
+
+http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=SAGA.garden_fractals.1&DataInputs=&ResponseDocument=RESULT@mimeType=application/json@asReference=true
+
+.. note::
+   
+  The common ZOO GetStatus requests also work when using the SAGA-GIS Modules as WPS Services.
+
+
+
+
Index: /tags/rel-1.7.0/docs/kernel/what.rst
===================================================================
--- /tags/rel-1.7.0/docs/kernel/what.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/kernel/what.rst	(revision 942)
@@ -0,0 +1,107 @@
+.. kernel-what:
+
+.. include:: <xhtml1-lat1.txt>
+.. include:: <xhtml1-symbol.txt>
+
+What is ZOO-Kernel ?
+====================
+
+ZOO-Kernel is the heart of the `ZOO-Project <http://zoo-project.org>`_ WPS platform. It is a WPS compliant implementation written in C language which provides a powerful and extensible WPS server. 
+
+ZOO-Kernel is an extensible WPS server that makes your system more
+powerful. It provides a full-featured processing engine which runs on
+Linux, Mac OSX |trade| and Windows |trade| operating
+systems. ZOO-Kernel is a CGI program which works on common web servers
+(namely `Apache <http://httpd.apache.org/>`_ or `IIS
+<http://www.iis.net/>`_ |trade|). It can be seamlessly integrated to
+new or existing web platforms.
+
+ZOO-Kernel lets you process geospatial or non geospatial data using
+well formed WPS requests. The WPS server is able to manage and chain
+WPS Services (see ZOO-Services for examples) by loading dynamic
+libraries and source code written in different programming languages.  
+
+First class WPS server
+-----------------------
+
+Simple
+......
+
+The ZOO-Kernel rely on simple principles and tends to ease the
+implementation of new services by sharing similar data structures for
+every supported programming languages. The ZOO-Kernel is responsible
+to parse the requests it receives and return the corresponding WPS
+response. 
+
+In case of an *Execute* request, the ZOO-Kernel stores informations in
+a basic KVP data structure for the programming language used to
+implement the service, dynamically load the Service Provider defined
+in the zcfg file and run a specific function corresponding to the
+service, passing three arguments. Once the function return, ZOO-Kernel
+knows if the service run succeessfuly or failed by checking the
+returned value. In the case it succeeded, the ZOO-Kernel then parse
+the third arguments containing the result and produce the output in
+the desired format.
+
+
+
+Compliant
+........................................................
+
+ZOO-Kernel implements and complies with the `WPS 1.0.0
+<http://www.opengeospatial.org/standards/wps/>`_ and the `WPS 2.0.0
+<http://www.opengeospatial.org/standards/wps/>`_ standards edited by
+the `Open Geospatial Consortium <http://www.opengeospatial.org/>`_. It
+is able to perform the WPS operations defined in the OpenGIS |reg|
+specification, such as:
+
+* **GetCapablities**: Returns service-level metadata information.It
+  provides the list of available processing services.
+* **DescribeProcess**: Returns a description of a process, including
+  its supported input and output.
+* **Execute**:  Launches computation and returns the output produced
+  by a particular process.
+* **GetStatus**:  only available in WPS 2.0.0, it lets the client fetch
+  the ongoing status of a running service.
+* **GetResult**: only available in WPS 2.0.0, it lets the client fetch
+  the final result of a running service.
+* **Dismiss**: only available in WPS 2.0.0, it lets the client ask
+  the server to stop a running service and remove any file it created.
+
+ZOO-Kernel compliancy and performances can be tested using the
+following tools:
+ * `cptesting <https://github.com/WPS-Benchmarking/cptesting>`_ 
+ * WPS Test Suite provided by the `OGC compliancy program <http://cite.opengeospatial.org/>`_
+ * XML responses validity can also be simply tested using `XMLint <http://xmlsoft.org/xmllint.html/>`_.
+
+Polyglot
+........................................................
+
+ZOO-Kernel is a **polyglot**. The software is written in a valid form
+of multiple programming languages, which performs the same operations
+independent of the programming language used to compile or interpret
+it. The supported programming languages are listed bellow:
+
+============ =================== ========================= ============
+**Language** **ServiceProvider** **DataStructure**         **Return**
+------------ ------------------- ------------------------- ------------
+C / C++      Shared Library      maps* M 	           integer
+Java 	     Class File 	 `HashMap`_ 	           integer
+C# 	     Class File 	 `ZMaps`_	           integer
+Python 	     Module File 	 `Dictionary`_ 	           integer
+PHP 	     Script File 	 `Array`_ 	           integer
+Perl 	     Script File 	  	                   integer
+Ruby 	     Script File 	 `Hash`_	           integer
+Fortran      Shared Library      CHARACTER*(1024) M(10,30) integer
+R	     Script file 	 `R List`_	           integer
+JavaScript   Script file 	 `Object`_ or Array	   Object/Array
+============ =================== ========================= ============
+
+.. _`HashMap`: http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html
+.. _`dictionary`: http://docs.python.org/tutorial/datastructures.html#dictionaries
+.. _`Array`: http://php.net/manual/language.types.array.php
+.. _`Object`: http://www.json.org/
+.. _`Hash`: http://ruby-doc.org/core-2.2.0/Hash.html
+.. _`ZMaps`: https://docs.microsoft.com/fr-fr/dotnet/api/system.collections.generic.dictionary-2?view=netframework-4.8
+.. _`R List`: https://cran.r-project.org/doc/manuals/r-release/R-lang.html#List-objects
+
Index: /tags/rel-1.7.0/docs/services/debug.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/debug.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/debug.rst	(revision 942)
@@ -0,0 +1,110 @@
+.. _services-debug:
+
+Debugging ZOO Services
+=========================
+
+Several methods can be used in order to debug :ref:`services_index`. The most common solutions are web or command line.
+
+Web
+----
+
+Any problem can be checked in the Apache server log file when using http WPS requests.
+
+On Unix, the log files is usually located in ``/var/log/apache2`` and
+the relevant one is named *error_log*. A simple way to read this file is to use the ``tail`` command,
+as it allows to see the file updates for each request ::
+
+  tail -f /var/log/apache2/error_log
+
+If the log is not clear enough, you still have the possibility to add
+more debug information to your source code, writing to standard errors.
+
+Python
+********
+Using Python, you can for example do this:
+
+.. code-block:: python
+
+  import sys
+  
+  #add this line when you want see an own message
+  sys.stderr.write("My message")
+
+.. _web_javascript:
+
+Javascript
+************
+
+Using JavaScript, you can use ``alert`` to print a string to standard error, for example:
+
+.. code-block:: javascript
+
+  // add this line when you want to see own message
+  alert('My message')
+  // you can debug value of inputs, outputs or conf
+  alert(inputs["S"]["value"])
+
+.. note:: If you try to pass an object it will only return ``[object Object]``
+
+Command line
+--------------
+
+:ref:`kernel_index` (*zoo_loader.cgi*) can also be used from command line. This is really useful for debugging services in a deeper way, for example:.
+
+.. code-block:: bash
+
+  # in order to use it you have to copy test_service.py and HelloPy.zcfg from
+  # the example services
+  ./zoo_loader.cgi "service=wps&version=1.0.0&request=execute&identifier=HelloPy&datainputs=a=your name&responsedocument=Result"
+
+Working this way you can use the standard debug system of the actual
+programming language used to develop your service.
+
+In case you should simulate POST requests, you can use the following
+command to tell the ZOO-Kernel to use the file ``/tmp/req.xml`` as the
+input XML request:
+
+.. code-block:: guess
+
+    # Define required environment settings
+    export REQUEST_METHOD=POST
+    export CONTENT_TYPE=text/xml
+    # Run the request stored in a file
+    ./zoo_loader.cgi < /tmp/req.xml
+
+
+GDB
+*****
+From command line you can use also the command line tool `GDB <http://www.gnu.org/software/gdb/>`_
+to debug ``zoo_loader.cgi``, you have to run:
+
+.. code-block:: bash
+
+  # launch zoo_loader.cgi from gdb
+  gdb zoo_loader.cgi
+  # now run your request
+  run "service=wps&version=1.0.0&request=execute&identifier=HelloPy&datainputs=a=your name&responsedocument=Result"
+
+.. note::
+    You can use the same parameter used before to simulate POST
+    requests when running from gdb.
+
+If nothing helped, you can ask help at the `ZOO mailing list
+<http://lists.osgeo.org/cgi-bin/mailman/listinfo/zoo-discuss>`_
+copying the result of the command.
+
+Python
+**********
+For Python, you can use ``pdb``, more info at http://docs.python.org/2/library/pdb.html
+
+.. code-block:: python
+
+  import pdb
+  
+  # add this line when you want investigate your code in more detail
+  pdb.set_trace()
+
+Javascript
+************
+
+You can use ``alert`` also to print in the console, more info in the :ref:`web_javascript` web section
Index: /tags/rel-1.7.0/docs/services/howtos.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/howtos.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/howtos.rst	(revision 942)
@@ -0,0 +1,514 @@
+.. _services-create:
+
+Create your own ZOO-Services
+=========================
+
+:ref:`services_index` are quite easy to create once you have installed the ZOO Kernel and have 
+chosen code (in the language of your choice) to turn into a ZOO service. Here are some 
+HelloWorlds in Python, PHP, Java, C#  and JavaScript with links to their corresponding 
+``.zcfg`` files.
+
+
+.. contents:: :depth: 3
+
+
+General information
+----------------------
+
+The function of the process for each programming language take three arguments: the main
+configuration, inputs and outputs.
+
+.. note:: The service must return **3** if the process run successfully
+	  
+.. note:: The service must return **4** if the process ended with an error
+
+Python
+------
+
+You'll find here information needed to deploy your own Python Services Provider.
+
+Python ZCFG requirements
+************************
+
+.. Note:: For each Service provided by your ZOO Python Services Provider, the ZCFG File 
+          must be named the same as the Python module function name (also the case of
+          characters is important).
+
+The ZCFG file should contain the following :
+
+
+serviceType
+    Python 
+serviceProvider
+    The name of the Python module to use as a ZOO Service Provider. For instance, if your
+    script, located in the same directory as your ZOO Kernel, was named ``my_module.py`` then
+    you should use ``my_module`` (the Python module name) for the serviceProvider value in ZCFG file.
+
+Python Data Structure used
+**************************
+The three parameters of the function are passed to the Python module as dictionaries.
+
+Following you'll find an example for each parameters
+
+Main configuration
+^^^^^^^^^^^^^^^^^^^^^
+Main configuration contains several informations, some of them are really useful to develop your service.
+Following an example ::
+
+  {
+  'main': {'lang': 'en-UK',
+	   'language': 'en-US',
+	   'encoding': 'utf-8',
+	   'dataPath': '/var/www/tmp',
+	   'tmpPath': '/var/www/tmp',
+	   'version': '1.0.0',
+	   'mapserverAddress': 'http://localhost/cgi-bin/mapserv',
+	   'isSoap': 'false',
+	   'tmpUrl': 'http://localhost/tmp/',
+	   'serverAddress': 'http://localhost/zoo'
+	  },
+  'identification': {'keywords': 'WPS,GIS',
+		     'abstract': 'WPS services for testing ZOO',
+		     'fees': 'None',
+		     'accessConstraints': 'none',
+		     'title': 'testing services'
+		    },
+  'lenv': {'status': '0',
+	   'soap': 'false',
+	   'cwd': '/usr/lib/cgi-bin',
+	   'sid': '24709'
+	  },
+  'env': {'DISPLAY': 'localhost:0'},
+  'provider': {'addressCountry': 'it',
+	       'positionName': 'Developer',
+	       'providerName': 'Name of provider',
+	       'addressAdministrativeArea': 'False',
+	       'phoneVoice': 'False',
+	       'addressCity': 'City',
+	       'providerSite': 'http://www.your.site',
+	       'addressPostalCode': '38122',
+	       'role': 'Developer',
+	       'addressDeliveryPoint': 'False',
+	       'phoneFacsimile': 'False', 
+	       'addressElectronicMailAddress': 'your@email.com',
+	       'individualName': 'Your Name'
+	      }
+  }
+
+Inputs
+^^^^^^^^^^^^
+The inputs are somethings like this ::
+
+  {
+  'variable_name': {'minOccurs': '1',
+		    'DataType': 'string',
+		    'value': 'this_is_the_value',
+		    'maxOccurs': '1',
+		    'inRequest': 'true'
+		   }
+  }
+
+The access to the value you have to require for the ``value`` parameter, something like this ::
+
+  yourVariable = inputs['variable_name']['value']
+
+Outputs
+^^^^^^^^^^^^^
+The outputs data as a structure really similar to the inputs one ::
+
+  {
+  'result': {'DataType': 'string',
+	     'inRequest': 'true',
+	    }
+  }
+
+There is no ``'value'`` parameter before you assign it ::
+
+  inputs['result']['value'] = yourOutputDataVariable
+
+The return statement has to be an integer: corresponding to the service status code.
+
+To add a message for the wrong result you can add the massage to ``conf["lenv"]["message"]``,
+for example:
+
+.. code-block:: python
+
+  conf["lenv"]["message"] = 'Your module return an error'
+
+Sample ZOO Python Services Provider
+***********************************
+
+The following code represents a simple ZOO Python Services Provider which provides only one 
+Service, the HelloPy one.
+
+.. code-block:: python
+
+  import zoo
+  import sys
+  def HelloPy(conf,inputs,outputs):
+     outputs["Result"]["value"]="Hello "+inputs["a"]["value"]+" from Python World !"
+     return zoo.SERVICE_SUCCEEDED
+
+PHP
+---
+
+ZOO-API
+*******
+
+The ZOO-API for the PHP language is automatically available from your
+service code. Tthe following functions are defined in the ZOO-API:
+
+int zoo_SERVICE_SUCCEEDED()
+    return the value of SERVICE_SUCCEEDED
+int zoo_SERVICE_FAILED()
+    return the value of SERVICE_FAILED
+string zoo_Translate(string a)
+    return the translated string (using the "zoo-service" `textdomain
+    <http://www.gnu.org/software/libc/manual/html_node/Locating-gettext-catalog.html#index-textdomain>`__)
+
+void zoo_UpdateStatus(Array conf,string message,int pourcent)
+    update the status of the running service
+
+PHP ZCFG requirements
+**********************************
+
+The ZCFG file should contain the following :
+
+serviceType
+    PHP 
+serviceProvider
+    The name of the php script (ie. service.php) to use as a ZOO Service Provider.
+
+PHP Data Structure used
+********************************
+
+The three parameters are passed to the PHP function as 
+`Arrays <php.net/manual/language.types.array.php>`__.
+
+Sample ZOO PHP Services Provider
+******************************************
+
+.. code-block:: php
+
+  <?
+  function HelloPHP(&$main_conf,&$inputs,&$outputs){
+     $tmp="Hello ".$inputs[S][value]." from PHP world !";
+     $outputs["Result"]["value"]=zoo_Translate($tmp);
+     return zoo_SERVICE_SUCCEEDED();
+  }
+  ?>
+
+Java
+----
+
+Specifically for the Java support, you may add the following three
+sections to your ``main.cfg`` file:
+
+:[java]:
+   This section is used to pass -D* parameters to the JVM  created by the
+   ZOO-Kernel to handle your ZOO-Service (see `ref. 1
+   <http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#BehavioralOptions>`__
+   or `ref. 2
+   <http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#PerformanceTuning>`__
+   for sample available). 
+   For each map ``a = b`` available in the ``[java]`` section, the
+   option ``-Da=b`` will be passed to the JVM. 
+:[javax]:
+   The section is used to pass -X* options to the JVM (see
+   `ref. <http://docs.oracle.com/cd/E22289_01/html/821-1274/configuring-the-default-jvm-and-java-arguments.html>`__). For
+   each map ``a = b`` available in the ``[javax]`` section, the option
+   ``-Xab`` will be passed to the JVM (ie. set ``mx=2G`` to pass
+   ``-Xmx2G``).
+:[javaxx]:
+   This section is used to pass -XX:* parameters to the JVM  created by the
+   ZOO-Kernel to handle your ZOO-Service (see `ref. 1
+   <http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#BehavioralOptions>`__
+   or `ref. 2
+   <http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#PerformanceTuning>`__
+   for sample available). 
+   For each map ``a = b`` available in the ``[javaxx]`` section, the
+   option ``-XX:a=b`` will be passed to the JVM. In case of a map ``a =
+   minus`` (respectively ``a=plus``) then the option ``-XX:-a``
+   (respectivelly ``-XX:+a``) will be passed.
+
+ZOO-API
+*******
+
+Before you build your first ZOO-Service implemented in Java, it is
+recommended that you first build the ZOO class of the Java ZOO-API.
+
+.. Note:: You should build ZOO-Kernel prior to follow this instructions.
+
+To build the ZOO.class of the ZOO-API for Java, use the following
+command:
+
+.. code-block:: guess
+
+  cd zoo-api/java
+  make
+
+.. Note:: running the previous commands will require that both
+          ``javac`` and ``javah`` are in your PATH.
+
+You should copy the ``libZOO.so`` in a place Java can find it. In case you
+have defined the ``java.library.path`` key as ``/usr/lib/cgi-bin``
+(in the ``[java]`` section), then you should copy it there. 
+
+.. code-block:: guess
+
+  cp libZOO.so /usr/lib/cgi-bin
+
+The ZOO-API provides the following functions:
+
+:String translate(String s):
+   This function call the internal ZOO-Kernel function responsible for
+   searching a translation of ``s`` in the zoo-services dictionary.
+
+:void updateStatus(Hashmap conf,String pourcent,String message):
+   This function call the updateStatus ZOO-Kernel function responsible
+   for updating the status of the running service (only usefull when
+   the service has been called asynchronously).
+
+
+
+Java ZCFG requirements
+**********************************
+
+.. Note:: For each Service provided by your ZOO Java Services Provider
+          (your corresponding Java class), the ZCFG File should have
+          the name of the Java public method corresponding to the
+          service (case-sensitive).
+
+The ZCFG file should contain the following :
+
+serviceType
+    Java 
+serviceProvider
+    The name of the Java class to use as a ZOO Service Provider. For instance, if your
+    java class, located in the same directory as your ZOO-Kernel, was
+    named ``HelloJava.class`` then you should use ``HelloJava``.
+
+Java Data Structure used
+********************************
+
+The three parameters are passed to the Java function as 
+`java.util.HashMap <http://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html>`__.
+
+Sample ZOO Java Services Provider
+******************************************
+
+.. code-block:: java
+
+  import java.util.*;
+  public class HelloJava {
+    public static int HelloWorldJava(HashMap conf,HashMap inputs, HashMap outputs) {
+       HashMap hm1 = new HashMap();
+       hm1.put("dataType","string");
+       HashMap tmp=(HashMap)(inputs.get("S"));
+       java.lang.String v=tmp.get("value").toString();
+       hm1.put("value","Hello "+v+" from JAVA WOrld !");
+       outputs.put("Result",hm1);
+       System.err.println("Hello from JAVA WOrld !");
+       return ZOO.SERVICE_SUCCEEDED;
+    }
+  }
+
+C#
+----
+
+Specifically for the C# support, you should add the following
+section to your ``main.cfg`` file.
+
+
+:[mono]:
+   This section is used to define both ``libPath`` and ``etcPath``
+   required by the Mono .NET Framework.
+
+ZOO-API
+*******
+
+Before you build your first ZOO-Service implemented in Mono, you
+should first build the ``ZMaps.dll`` containing the Mono ZOO-API.
+
+.. Note:: You should build ZOO-Kernel prior to follow this instructions.
+
+.. code-block:: guess
+
+  cd zoo-api/mono
+  make
+
+Then you should copy the ``ZMaps.dll`` in your ``servicePath`` or in
+the directory where your ``zoo_loader.cgi`` file is stored.
+
+The ZOO-API is available from a C# class named ZOO_API and provides
+the following static variables:
+
+:int SERVICE_SUCCEEDED:
+   Value to return in case your service end successfully.
+:int SERVICE_FAILED:
+   Value to retrun in case of failure.
+
+The ZOO-API provides the following static functions:
+
+:string Translate(String s):
+   This function call the internal ZOO-Kernel function responsible for
+   searching a translation of ``s`` in the zoo-services dictionary.
+
+:void UpdateStatus(ZMaps conf,String pourcent,String message):
+   This function call the updateStatus ZOO-Kernel function responsible
+   for updating the status of the running service (only usefull when
+   the service has been called asynchronously).
+
+
+C# ZCFG requirements
+**********************************
+
+.. Note:: For each Service provided by your ZOO Mono Services Provider
+          (your corresponding Mono class), the ZCFG File should have
+          the name of the Mono public static function corresponding to the
+          service (case-sensitive).
+
+The ZCFG file should contain the following :
+
+serviceType
+    Mono 
+serviceProvider
+    The full name of the C# dll containing the ZOO-Service Provider
+    (including ``.dll``).
+serviceNameSpace
+    The namespace of the C# class containing the ZOO-Service Provider.
+serviceClass
+    The name of the C# class containing the ZOO-Service Provider definition.
+
+C# Data Structure used
+********************************
+
+The three parameters of the function are passed to the Mono static
+function as ``ZMaps`` which are basically
+``Dictionary<String,_ZMaps>``.
+
+Sample ZOO C# Services Provider
+******************************************
+
+.. literalinclude:: ../../zoo-project/zoo-services/hello-mono/test.cs
+   :language: csharp
+   :lines: 24-100
+
+Javascript
+----------
+
+ZOO API
+*********
+
+If you need to use :ref:`ZOO API <api>` in your service, you have first to copy ``zoo-api.js``
+and ``zoo-proj4js.js`` where your services are located (for example in Unix system probably in
+``/usr/lib/cgi-bin/``
+
+Javascript ZCFG requirements
+**********************************
+
+.. Note:: For each Service provided by your ZOO Javascript Services Provider, the ZCFG File 
+          must be named the same as the Javascript function name (also the case of
+          characters is important).
+
+The ZCFG file should contain the following :
+
+serviceType
+    JS 
+serviceProvider
+    The name of the JavaScript file to use as a ZOO Service Provider. For instance, if your
+    script, located in the same directory as your ZOO Kernel, was named ``my_module.js`` then
+    you should use ``my_module.js``.
+
+
+Javascript Data Structure used
+********************************
+
+The three parameters of the function are passed to the JavaScript function as Object.
+
+Sample ZOO Javascript Services Provider
+******************************************
+
+.. code-block:: javascript
+
+  function hellojs(conf,inputs,outputs){
+     outputs=new Array();
+     outputs={};
+     outputs["result"]["value"]="Hello "+inputs["S"]["value"]+" from JS World !";
+     return Array(3,outputs);
+  }
+
+
+R
+----------
+
+ZOO API
+*********
+
+For using the R language from the ZOO-Project, you have first to copy
+``minimal.r`` in the same directory as the ZOO-Kernel.
+
+The ZOO-API is available from a R script and provide access to a
+global zoo environment which contains both static variables and also
+the dictionaries for outputs and conf:
+
+:int zoo[["SERVICE_SUCCEEDED"]]:
+   Value to return in case your service end successfully.
+:int zoo[["SERVICE_FAILED"]]:
+   Value to retrun in case of failure.
+
+The ZOO-API provides the following functions:
+
+:string ZOOTranslate(String s):
+   This function call the internal ZOO-Kernel function responsible for
+   searching a translation of ``s`` in the zoo-services dictionary.
+
+:void ZOOUpdateStatus(ZMaps conf,String pourcent):
+   This function call the updateStatus ZOO-Kernel function responsible
+   for updating the status of the running service (only usefull when
+   the service has been called asynchronously).
+
+
+R ZCFG requirements
+**********************************
+
+.. Note:: For each Service provided by your ZOO R Services Provider,
+	  the ZCFG File must be named the same as the R function name
+	  (it is case-sensitive).
+
+The ZCFG file should contain the following :
+
+serviceType
+   R 
+serviceProvider
+    The name of the R file to use as a ZOO Service Provider. For instance, if your
+    script, located in the same directory as your ZOO Kernel, was named ``my_module.r`` then
+    you should use ``my_module.r``.
+
+
+R Data Structure used
+********************************
+
+The three parameters of the function are passed to the R function as
+R dictionaries.
+
+The specificity of the R language make that it was easier to use
+global variales than passing parameters by reference as we do in
+other progamming languages. It is the reason why you will have to
+access outpus by using the global variable as for the main
+configuration dictionary. 
+
+Sample ZOO R Services Provider
+******************************************
+
+.. code-block:: javascript
+
+    source("minimal.r")
+		
+    hellor <- function(a,b,c) {
+        # Set the result
+        zoo[["outputs"]][["Result"]][["value"]] <<- ZOOTranslate(paste("Hello",b[["S"]][["value"]],"from the R World!",sep=" "))
+        # Return SERVICE_SUCCEEDEED
+        return(zoo[["SERVICE_SUCCEEDEED"]])
+    }
+
Index: /tags/rel-1.7.0/docs/services/index.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/index.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/index.rst	(revision 942)
@@ -0,0 +1,21 @@
+.. _services_index:
+
+ZOO-Services 
+==========
+
+This section will guide you for creating your own WPS
+Services using the `ZOO-Project <http://zoo-project.org>`__
+platform. It also gives usefull information for taking advantage of the ready-to-use
+**ZOO-Services** which are available in the ZOO-Project svn.
+
+.. toctree::
+   :maxdepth: 2
+   
+   what
+   zcfg-reference
+   process-profiles
+   howtos
+   translation
+   status
+   debug
+   zoo-services
Index: /tags/rel-1.7.0/docs/services/process-profiles.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/process-profiles.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/process-profiles.rst	(revision 942)
@@ -0,0 +1,260 @@
+.. _process-profiles:
+    
+Process profiles registry
+=========================
+
+WPS Services belonging to the same Services provider often share the
+same inputs and outputs. In such a case, every :ref:`ZCFG
+<services-zcfg>` file would contain the same metadata information and
+this may be a waste of time to write them all.
+
+:ref:`ZOO-Kernel <kernel_index>` is able to handle metadata
+inheritance from `rev. 607
+<http://www.zoo-project.org/trac/changeset/607>`__, and this solves
+the issue of writing many ZCFG with same input and output. A registry
+can be loaded by the ZOO-Kernel (before any other ZCFG files) and
+contain a set of Process Profiles organized in hierarchic levels
+according to the following rules:
+
+  * *Concept*: The higher level in the hierarchy. *Concepts* are basic
+    text files containing an abstract description of a WPS Service
+    (see `the OGC definition
+    <http://docs.opengeospatial.org/is/14-065/14-065.html#33>`_ for
+    more details).
+  * *Generic*: A *Generic* profile can make reference to
+    *Concepts*. It defines inputs and outputs without data format or
+    maximum size limitation (see `the OGC definition
+    <http://docs.opengeospatial.org/is/14-065/14-065.html#34>`_ for
+    more details).
+  * *Implementation*: An *Implementation* profile can inherit from a
+    generic profile and make reference to concepts (see `the OGC definition
+    <http://docs.opengeospatial.org/is/14-065/14-065.html#35>`_ for
+    more details). It contains all the metadata information about a
+    particular WPS Service (see :ref:`ZCFG reference <services-zcfg>`
+    for more information).
+
+Both *Generic* and *Implementation* process profiles are created  from
+:ref:`ZCFG <services-zcfg>` files and stored in the registry
+sub-directories according to their level (*Concept*, *Generic* or
+*Implementation*).
+
+To activate the registry, you have to add a ``registry`` key to the
+``[main]`` section of your ``main.cfg`` file, and set its value to the
+directory path used to store the profile ZCFG files. Please see
+:ref:`install_gfr` for more details about the other services and
+parameters required.
+
+.. note::
+    Even if the profile registry was first introduced in WPS 2.0.0, it
+    can be also used in the same way for WPS 1.0.0 Services.
+
+
+
+
+Generic Process Profile
+-----------------------
+
+A Generic Process Profile is a ZCFG file located in the ``generic``
+sub-directory, it defines `main metadata information
+<zcfg-reference.html#main-metadata-information>`__, inputs and outputs
+name, basic metadata and multiplicity. It can make reference to a
+concept by defining a ``concept`` key in the `main metadata
+information <zcfg-reference.html#main-metadata-information>`__ part.
+
+You can find below the `GO.zcfg` file, a typical Generic Process
+Profile for Generic Geographic Operation, taking one InputPolygon
+input parameter and returning a result named Result, it make reference
+to the ``GOC`` concept:
+
+.. code-block:: none
+   :linenos:
+   
+   [GO]
+    Title = Geographic Operation
+    Abstract = Geographic Operation on exactly one input, returning one output
+    concept = GOC
+    level = generic
+    statusSupported = true
+    storeSupported = true
+    <DataInputs>
+     [InputPolygon]
+      Title = the geographic data
+      Abstract = the geographic data to run geographipc operation
+      minOccurs = 1
+      maxOccurs = 1
+    </DataInputs>
+    <DataOutputs>
+     [Result]
+      Title = the resulting data
+      Abstract = the resulting data after processing the operation
+    </DataOutputs>  
+
+
+.. Note:: if you need to reference more than one concept, you should
+    separate their names with a comma (ie. concept = GO,GB),
+
+Process Implementation Profile
+------------------------------
+
+A Process Implementation Profile is similar to a `ZCFG file
+<zcfg-reference.html>`__ located in the `implementation`
+sub-directory, it defines (or inherit from its parent) all the
+properties of a `Generic Process Profile <#generic-process-profile>`__
+and specify `Data Format <zcfg-reference.html#type-of-data-nodes>`__
+for both inputs and outputs. It can make reference to a concept by
+defining a ``concept`` key in the `main metadata information
+<zcfg-reference.html#main-metadata-information>`__ part.
+
+You can find below the `VectorOperation.zcfg` file, a typical Process
+Implementation Profile for Vector Geographic Operation, it inherit
+from the `GP generic profile <#generic-process-profile>`__:
+
+.. code-block:: none
+   :linenos:
+   
+   [VectorOperation]
+    Title = Vector Geographic Operation
+    Abstract = Apply a Vector Geographic Operation on a features collection and return the resulting features collection
+    extend = GO
+    level = profile
+    <DataInputs>
+     [InputPolygon]
+      Title = the vector data
+      Abstract = the vector data to run geographic operation
+      <ComplexData>
+       <Default>
+        mimeType = text/xml
+        encoding = UTF-8
+        schema = http://fooa/gml/3.1.0/polygon.xsd
+       </Default>
+       <Supported>
+        mimeType = application/json
+        encoding = UTF-8
+        extension = js
+       </Supported>
+    </DataInputs>
+    <DataOutputs>
+     [Result]
+      Title = the resulting data
+      Abstract = the resulting geographic data after processing the operation
+      <ComplexData>
+       <Default>
+        mimeType = text/xml
+        encoding = UTF-8
+        schema = http://fooa/gml/3.1.0/polygon.xsd
+       </Default>
+       <Supported>
+        mimeType = application/json
+        encoding = UTF-8
+        extension = js
+       </Supported>
+      </ComplexData>
+    </DataOutputs>  
+
+
+ZCFG inheritance
+----------------------------------
+
+For the ZCFG files at the service level, you can inherit the metadata
+from a Process Implementation Profile available in the registry. As
+before, you simply need to add a ``extend`` key refering the ZCFG you
+want to inherit from and a ``level`` key taking the `ìmplementation``
+value to your main metadata informations.
+
+So, for example, the original `ConvexHull.zcfg
+<http://www.zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/ConvexHull.zcfg?rev=491>`__
+may be rewritten as:
+
+.. code-block:: none
+   :linenos:
+   
+   [ConvexHull]
+    Title = Compute convex hull.
+    Abstract = Return a feature collection that represents the convex hull of each geometry from the input collection.
+    serviceProvider = ogr_service.zo
+    serviceType = C
+    extend = VectorOperation
+    level = implementation
+
+Now, suppose that your service is able to return the result in KML
+format, then you may write the following:
+
+.. code-block:: none
+   :linenos:
+   
+   [ConvexHull]
+    Title = Compute convex hull.
+    Abstract = Return a feature collection that represents the convex hull of each geometry from the input collection.
+    serviceProvider = ogr_service.zo
+    serviceType = C
+    extend = VectorOperation
+    level = implementation
+    <DataOutputs>
+     [Result]
+        <Supported>
+         mimeType = application/vnd.google-earth.kml+xml
+         encoding = utf-8
+        </Supported>
+    </DataOutputs>
+
+.. _install_gfr:
+
+Setup registry browser
+----------------------
+
+In the ``zoo-project/zoo-services/utils/registry``  you can find the
+source code and the ``Makefile`` required to build the Registry Browser
+Services Provider. To build and install this service, use the
+following comands:
+
+.. code::
+
+     cd zoo-project/zoo-services/utils/registry
+     make
+     cp cgi-env/* /usr/lib/cgi-bin
+
+
+To have valid
+``href`` in the metadata children of a ``wps:Process``, you have to
+define the ``registryUrl`` to point to the path to browse the
+registry. For this you have two different options, the first one is to
+install the ``GetFromRegistry`` ZOO-Service and to use a WPS 1.0.0
+Execute request as ``registryUrl`` to dynamically generate `Process
+Concept <http://docs.opengeospatial.org/is/14-065/14-065.html#33>`__,
+`Generic Process Profile
+<http://docs.opengeospatial.org/is/14-065/14-065.html#34>`__ and
+`Process Implementation Profile
+<http://docs.opengeospatial.org/is/14-065/14-065.html#35>`__.
+You also have to add a ``registryUrl`` to the ``[main]`` section to
+inform the ZOO-Kernel that it should use the Registry Browser to
+create the href attribute of Metadata nodes. So by adding the
+following line:
+
+.. code::
+
+    registryUrl = http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=GetFromRegistry&RawDataOutput=Result&DataInputs=id=
+
+The second option is to pre-generate each level of the hierarchy by
+running shell commands then set ``registryUrl`` to the URL to browse
+the generated files. In such a case, you will also have to define the
+``registryExt`` and set it to the file extension you used to generate
+your registry cache.
+
+To generate the cache in ``/opt/zoo/registry/``, use the following command:
+
+.. code::
+
+    cd /usr/lib/cgi-bin
+    mkdir /opt/zoo/regcache/{concept,generic,implementation}
+    for i in $(find /opt/zoo/registry/ -name "*.*") ; 
+    do  
+        j=$(echo $i | sed "s:../registry//::g;s:.zcfg::g;s:.txt::g") ; 
+       if [ -z "$(echo $j | grep concept)" ]; 
+       then 
+           ext="xml" ; 
+       else 
+           ext="txt"; 
+       fi
+        ./zoo_loader.cgi "request=Execute&service=wps&version=1.0.0&Identifier=GetFromRegistry&RawDataOutput=Result&DataInputs=id=$j" | grep "<" > /opt/zoo/regcache/$j.$ext; 
+    done
+
Index: /tags/rel-1.7.0/docs/services/status.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/status.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/status.rst	(revision 942)
@@ -0,0 +1,47 @@
+.. _services-status:
+
+ZOO Status Service
+===============================
+
+The ZOO-Status Service is a `ZOO-Project <http://zoo-project.org>`__
+utility allowing to get the status of a running WPS Service.
+
+Description
+-----------------------------
+
+It returns the stage of completion of the ongoing Service in percentage
+(%). The ZOO-Status Service is usefull to monitor :ref:`services_index`. It can
+also be used to animate WPS progress bars from client-side applications.
+
+Installation
+-----------------------------
+
+To install the ``ZOO Status Service`` you have to move in 
+``/path/to/zoo/source/zoo-services/utils/status/`` and compile the source
+running the ``make`` command.
+If no errors are returned during compilation you can copy the content of ``cgi-env``
+to ``/usr/lib/cgi-bin/`` or where you have your ``zoo_loader.cgi`` working with this
+command (you need administration right):
+
+::
+
+   cp /path/to/zoo/source/zoo-services/utils/status/cgi-env/*{zcfg,zo,py} /usr/lib/cgi-bin
+
+With this command you copy the code to permit to ``ZOO Status Service`` and some
+example processes about how it works.
+
+Now you have to add these two lines to ``main.cfg`` :
+
+::
+
+  rewriteUrl=call
+  dataPath=/var/www/data
+
+Here you define the path where the service is able to find the xsl file, specified in the dataPath
+parameter. You also tell the ZOO Kernel that you want to use the `rewriteUrl <../kernel/install-debian.html#rewrite-rule-configuration>`_.
+
+The last operation is to copy the ``updateStatus.xsl`` to ``dataPath`` directory as follow:
+
+::
+
+   cp /path/to/zoo/source/zoo-services/utils/status/cgi-env/*{xsl} /var/www/data
Index: /tags/rel-1.7.0/docs/services/translation.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/translation.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/translation.rst	(revision 942)
@@ -0,0 +1,84 @@
+.. _service_translation:
+
+Translation Support
+===================
+
+ZOO-Kernel support translating internal messages it emits but it can
+also translate both the metadata informations stored in the ZCFG file
+and the messages emitted by the ZOO-Service itself. This document show
+how to create the files required to handle such a translation process
+for the ZOO-Services.
+
+
+ZCFG translation
+--------------------------
+
+First of all, use the following commands from your Services Provider
+directory in order to extract all the messages to translate from the
+ZCFG files :
+
+  ::
+  
+      #!/bin/bash
+      mkdir -p locale/{po,.cache}
+      for j in cgi-env/*zcfg ; 
+        do 
+          for i in Title Abstract; 
+           do
+            grep $i $j | sed "s:$i = :_ss(\":g;s:$:\"):g" ;
+           done;
+       done > locale/.cache/my_service_string_to_translate.c
+   
+
+Then generate the ``messages.po`` file based on the Services Provider
+source code (located in ``service.c`` in this example) using the
+following command:
+
+  ::
+  
+      #!/bin/bash
+      xgettext service.c locale/.cache/my_service_string_to_translate.c -o message.po -p locale/po/ -k_ss
+
+Once ``messages.po`` is created, use the following command to create
+the ``.po`` file for the targeted language to translate into. We will
+use the French language here as an example:
+
+  ::
+  
+      #!/bin/bash
+      cd locale/po/
+      msginit -i messages.po -o zoo_fr_FR.po -l fr
+
+Edit the ``zoo_fr_FR.po`` file with your favorite text editor or using
+one of the following tools:
+
+ * `poedit <http://www.poedit.net/>`__
+ * `virtaal <http://translate.sourceforge.net/wiki/virtaal/index>`__
+ * `transifex <https://www.transifex.net/>`__
+ 
+Once the ``zoo_fr_FR.po`` file is completed, you can generate and
+install the corresponding ``.mo`` file using the following command:
+
+  ::
+  
+      #!/bin/bash
+      msgfmt locale/po/zoo_fr_FR.po -o /usr/share/locale/fr/LC_MESSAGES/zoo-services.mo
+
+
+In order to test the Services Provider ZCFG and internal messages
+translation, please add the language argument to you request. As an
+example, such a request:
+
+http://youserver/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS
+
+would become the following:
+
+http://youserver/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS&language=fr-FR
+
+The following command may also be useful in order to pull all the translations already available for a specific language.
+
+  ::
+  
+      #!sh
+      msgcat -o compilation.po $(find ../../ -name fr_FR.utf8.po)
+      msgfmt compilation.po -o /usr/share/locale/fr/LC_MESSAGES/zoo-services.mo
Index: /tags/rel-1.7.0/docs/services/what.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/what.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/what.rst	(revision 942)
@@ -0,0 +1,27 @@
+.. _services-what:
+
+What are ZOO-Services ?
+=================
+
+ZOO-Services are WPS compliant Web Services working with :ref:`ZOO-Kernel <kernel_index>`, the `ZOO-Project <http://zoo-project.org>`_ WPS server.
+
+What is a ZOO-Service?
+----------------------
+
+A ZOO Service is a couple composed of:
+
+- Source code you want to create or reuse as WPS Service
+- A :ref:`configuration file<services-zcfg>` (.zcfg) which describes this WPS Service
+
+Learn how to  :ref:`create your own <services-create>` and how to
+configure ZOO-Services according to the :ref:`ZCFG Reference <services-zcfg>`.
+
+Available ZOO-Services
+--------------------
+
+`ZOO-Project <http://zoo-project.org>`_ includes ready-to-use WPS Services based on reliable open source libraries such as `GDAL <http://gdal.org>`_, `GRASS GIS <http://grass.osgeoorg>`_, `OrfeoToolbox <http://orfeo-toolbox.org>`_ and `CGAL <http://gcal.org>`_. The so-called ZOO-Services aim at reusing existing geospatial algorithms through standard WPS, with no or minor modification of the involved software or library source codes. 
+
+Available ZOO-Services provide a number of significant examples to
+build your own.
+
+
Index: /tags/rel-1.7.0/docs/services/zcfg-reference.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/zcfg-reference.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/zcfg-reference.rst	(revision 942)
@@ -0,0 +1,313 @@
+.. _services-zcfg:
+    
+ZOO-Service configuration file
+=========================================  
+
+The ZOO-Service configuration file (.zcfg) describes a
+WPS service. It provides metadata information on a particular WPS
+Service and it is parsed by ZOO-Kernel when *DescribeProcess* and
+*Execute* request are sent.
+
+The ZOO-Service configuration file is divided into three distinct sections :
+
+ * Main Metadata information
+ * List of Inputs metadata information (optional since `rev. 469 <http://zoo-project.org/trac/changeset/469>`__)
+ * List of Outputs metadata information
+
+.. warning:: The ZOO-Service configuration file is case sensitive.
+
+.. note:: There are many example ZCFG files in the ``cgi-env``
+	  directory of the `ZOO-Project svn
+	  <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services>`__.
+
+.. note:: A ZCFG file can be converted to the YAML syntaxe by using
+	  the zcfg2yaml command line tool.
+
+Main section
+-------------------------
+
+The fist part of the ZOO-Service configuration file is the ``main`` section,
+which contains general metadata information on the related WPS
+Service.
+
+Note that the "name of your service" between brackets on the first line has to be the exact same name 
+as the function you defined in your services provider code. In most cases, this name is also the name 
+of the ZCFG file without the "``.zcfg``" extension.
+
+An example of the ``main`` section  is given bellow as reference.
+
+.. code-block:: none
+   :linenos:
+
+   [Name of WPS Service]
+   Title = Title of the WPS Service
+   Abstract = Description of the WPS Service
+   processVersion = Version number of the WPS Service
+   storeSupported = true/false
+   statusSupported = true/false
+   serviceType = Pprogramming language used to implement the service (C|Fortran|Python|Java|PHP|Ruby|Javascript)
+   serviceProvider = Name of the Services provider (shared library|Python Module|Java Class|PHP Script|JavaScript Script)
+   <MetaData>
+     title = Metadata title of the WPS Service
+   </MetaData>
+
+.. warning::  'Name of WPS Service' must be the exact same name as the function defined in the WPS Service source code.
+
+.. note:: An ``extend`` parameter may be used for the `Process profile registry <process-profiles.html>`__.
+
+List of Inputs
+--------------
+
+The second part of the ZOO-Service configuration file is the ``<DataInputs>``
+section which lists the supported inputs. Each input is defined as :
+
+ * Name (between brackets as for the name of the service before)
+ * Various medata properties (``Title``, ``Abstract``, ``minOccurs``, ``maxOccurs`` and, in case of ComplexData, the optional ``maximumMegabytes``)
+ * :ref:`Type Of Data Node  <typeDataNodes>` 
+
+A typical list of inputs (``<DataInputs>``) looks like the following:
+
+.. code-block:: none
+   :linenos:
+   
+   <DataInputs>
+     [Name of the first input]
+       Title = Title of the first input
+       Abstract = Abstract describing the first input
+       minOccurs = Minimum occurence of the first input
+       maxOccurs = Maximum occurence of the first input
+       <Type Of Data Node />
+     [Name of the second input]
+       Title = Title of the second input
+       Abstract = Abstract describing the second input
+       minOccurs = Minimum occurence of the second input
+       maxOccurs = Maximum occurence of the second input
+       <Type Of Data Node />
+   </DataInputs>
+   
+.. note:: A ``<MetaData>`` node can also be added, as in the main metadata information.
+
+List of Outputs
+---------------
+
+The third part of the ZOO Service configuration file is the ``<DataOutputs>``
+section, which lists the supported outputs and is is very similar to a
+list of inputs.
+
+A typical list of outputs (``<DataOutputs>``) looks like the
+following:
+
+.. code-block:: none
+   :linenos:
+   
+   <DataOutputs>
+     [Name of the output]
+       Title = Title of the output
+       Abstract = Description of the output
+       <Type Of Data Node />
+   </DataOutputs>
+
+.. _typeDataNodes:
+
+Type Of Data Nodes
+------------------
+
+The *Type Of Data Nodes* describes data types for inputs and
+outputs. There are three different types which are described in this
+section.
+ * :ref:`LiteralData <LiteralData>`
+ * :ref:`BoundingBoxData <BoundingBoxData>`
+ * :ref:`ComplexData <ComplexData>`
+
+ .. warning:: Every *BoundingBoxData* and *ComplexData* must have at
+	      least one ``<Default>`` node (even empty like ``<Default
+	      />``)
+
+ .. warning:: In WPS 2.0.0 version, it is possible to define `nested
+	      inputs and outputs
+	      <http://docs.opengeospatial.org/is/14-065/14-065.html#13>`__. So,
+	      from revision `790 
+	      <http://www.zoo-project.org/trac/changeset/790>`__, you
+	      are allowed to use a new input/output definition here.
+
+.. _LiteralData:
+
+LiteralData node
+****************
+
+A ``<LiteralData>`` node contains:
+
+- one (optional) ``AllowedValues`` key containing all value allowed for this input
+- one (optional) ``range`` properties containing the range (``[``, ``]``)
+- one (optional) ``rangeMin`` (``rangeMax``) properties containing the minimum (maximum) value of this range
+- one (optional) ``rangeSpacing`` properties containing the regular distance or spacing between value in this range
+- one (optional) ``rangeClosure`` properties containing the closure type (``c``, ``o``, ``oc``, ``co``)
+- one ``<Default>`` node,
+- zero or more ``<Supported>`` nodes depending on the existence or the number of supported Units Of Measure (UOM), and 
+- a ``dataType`` property. The ``dataType`` property defines the type of literal data, such as a string, an interger and so on 
+  (consult `the complete list <http://www.w3.org/TR/xmlschema-2/#built-in-datatypes>`__ of supported data types). 
+
+``<Default>`` and ``<Supported>`` nodes can contain the ``uom`` property to define which UOM has to be used for 
+this input value.
+
+For input ``<LiteralData>`` nodes, you can add the ``value`` property to the ``<Default>`` node to define a default 
+value for this input. This means that, when your Service will be run, even if the input wasn't defined, this default 
+value will be set as the current value for this input.
+
+A typical ``<LiteralData>`` node, defining a ``float`` data type using meters or degrees for its UOM, looks like the 
+following:
+
+.. code-block:: guess
+   :linenos:
+   
+   <LiteralData>
+     dataType = float
+     <Default>
+       uom = meters
+     </Default>
+     <Supported>
+       uom = feet
+     </Supported>
+   </LiteralData>
+
+
+A typical ``<LiteralData>`` node, defining a ``float`` data type which
+should take values contained in ``[0.0,100.0]``, looks like the following:
+
+.. code-block:: guess
+   :linenos:
+   
+   <LiteralData>
+     dataType = float
+     rangeMin = 0.0
+     rangeMax = 100.0
+     rangeClosure = c
+     <Default />
+   </LiteralData>
+
+Or more simply:
+
+.. code-block:: guess
+   :linenos:
+   
+   <LiteralData>
+     dataType = float
+     range = [0.0,100.0]
+     <Default />
+   </LiteralData>
+
+A typical ``<LiteralData>`` node, defining a ``string`` data type which
+support values ``hillshade``, ``slope``, ``aspect``, ``TRI``, ``TPI``
+and ``roughness``, looks like the following:
+
+.. code-block:: guess
+   :linenos:
+   
+   <LiteralData>
+     dataType = string
+     AllowedValues = hillshade,slope,aspect,TRI,TPI,roughness
+     <Default />
+   </LiteralData>
+
+Properties ``AllowedValues`` and ``range*`` can be conbined with both ``<Default>`` and
+``<Supported>`` nodes in the same was as ``<LiteralData>`` node. For
+instance, the following is supported:
+
+.. code-block:: guess
+   :linenos:
+   
+   <LiteralData>
+     dataType = int
+     <Default>
+       value = 11
+       AllowedValues = -10,-8,-7,-5,-1
+       rangeMin = 0
+       rangeMax = 100
+       rangeClosure = co
+     </Default>
+     <Supported>
+       rangeMin = 200
+       rangeMax = 600
+       rangeClosure = co
+     </Supported>
+     <Supported>
+       rangeMin = 750
+       rangeMax = 990
+       rangeClosure = co
+       rangeSpacing = 10
+     </Supported>
+   </LiteralData>
+
+.. _BoundingBoxData:
+
+BoundingBoxData node
+********************
+
+A ``<BoundingBoxData>`` node contains:
+
+- one ``<Default>`` node with a CRS property defining the default Coordinate Reference Systems (CRS), and 
+- one or more ``<Supported>`` nodes depending on the number of CRS your service supports (note that you can 
+  alternatively use a single ``<Supported>`` node with a comma-separated list of supported CRS).
+
+A typical ``<BoundingBoxData>`` node, for two supported CRS (`EPSG:4326 <http://www.epsg-registry.org/indicio/query?request=GetRepositoryItem&id=urn:ogc:def:crs:EPSG::4326>`__ 
+and `EPSG:3785 <http://www.epsg-registry.org/indicio/query?request=GetRepositoryItem&id=urn:ogc:def:crs:EPSG::3785>`__), 
+looks like the following:
+
+.. code-block:: guess
+   :linenos:
+   
+   <BoundingBoxData>
+     <Default>
+       CRS = urn:ogc:def:crs:EPSG:6.6:4326
+     </Default>
+     <Supported>
+       CRS = urn:ogc:def:crs:EPSG:6.6:4326
+     </Supported>
+     <Supported>
+       CRS = urn:ogc:def:crs:EPSG:6.6:3785
+     </Supported>
+   </BoundingBoxData>
+
+.. _ComplexData:
+
+ComplexData node
+****************
+
+A ComplexData node contains:
+
+- a ``<Default>`` node and 
+- one or more ``<Supported>`` nodes depending on the number of supported formats. A format is made up of this 
+  set of properties : ``mimeType``, ``encoding`` and optionaly ``schema``.
+
+For output ComplexData nodes, you can add the ``extension`` property to define what extension to use to name 
+the file when storing the result is required. Obviously, you'll have to add the ``extension`` property to each 
+supported format (for the ``<Default>`` and ``<Supported>`` nodes). 
+
+You can also add the ``asReference`` property to the ``<Default>`` node to define if the output should be 
+stored on server side per default. 
+
+.. Note:: the client can always modify this behavior by setting ``asReference`` attribute to ``true`` or ``false`` 
+          for this output in the request ``ResponseDocument`` parameter.
+
+You can see below a sample ComplexData node for default ``application/json`` and ``text/xml`` (encoded in UTF-8 
+or base64) mimeTypes support:
+
+.. code-block:: guess
+   :linenos:
+   
+   <ComplexData>
+     <Default>
+       mimeType = application/json
+       encoding = UTF-8
+     </Default>
+     <Supported>
+       mimeType = text/xml
+       encoding = base64
+       schema = http://fooa/gml/3.1.0/polygon.xsd
+     </Supported>
+     <Supported>
+       mimeType = text/xml
+       encoding = UTF-8
+       schema = http://fooa/gml/3.1.0/polygon.xsd
+     </Supported>
+   </ComplexData>
Index: /tags/rel-1.7.0/docs/services/zoo-services.rst
===================================================================
--- /tags/rel-1.7.0/docs/services/zoo-services.rst	(revision 942)
+++ /tags/rel-1.7.0/docs/services/zoo-services.rst	(revision 942)
@@ -0,0 +1,115 @@
+.. _services-available:
+
+Available ZOO-Services
+================
+
+`ZOO-Project <http://zoo-project.org>`__ includes some ready-to-use WPS Services based on reliable open source libraries such as such as `GDAL <http://gdal.org>`_, `CGAL <http://gcal.org>`_, `GRASS GIS <http://grass.osgeo.org>`_, `OrfeoToolbox <http://orfeo-toolbox.org>`__ and `SAGA GIS <https://www.orfeo-toolbox.org>`__.
+
+:ref:`services_index` are either developed in C/Python (with minor modifications with respect to the orginal software source code) and stored in the  ``zoo-services`` `svn <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services>`__ directory or automatically generated using some of :ref:`kernel_index` configuration options. 
+
+
+Based on GDAL 
+------------------------
+
+.. note:: 
+
+  |gdal| `GDAL <http://gdal.org>`__ is the Geospatial Data Abstraction
+  Library. Learn more on official `website <http://gdal.org>`__.
+ 
+
+.. |gdal| image:: ../_static/gdal.png
+       :height: 110px
+       :width: 100px
+       :scale: 45%
+       :alt: GDAL logo
+
+
+..   csv-table:: 
+
+    Name,Description,Language
+    `Gdal_Contour <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/gdal/contour>`__,Builds vector contour lines from a raster elevation model,C
+    `Gdal_Grid <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/gdal/grid>`__,Creates regular raster grid from the scattered data read from an OGR datasource,C
+    `Gdal_Dem <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/gdal/dem>`__,Provides tools to analyze raster elevation model,C
+    `Gdal_Ndvi <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/gdal/ndvi>`__,Computes Normalized Difference Vegetation Index on a raster file,Python
+    `Gdal_Profile <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/gdal/profile>`__,Fetches XYZ values of a raster DEM along a linestring,C
+    `Gdal_Translate <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/gdal/translate>`__,Converts raster data between different formats,C
+    `Gdal_Warp <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/gdal/translate>`__,Mosaic/Reproject/Warp a raster image,C
+    `Ogr2Ogr <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/ogr/ogr2ogr/>`__,Converts vector data from one format to another,C
+    `Base-vect-ops <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/ogr/base-vect-ops>`__,Provides tools for single and multiple geometries vector-based spatial analysis ,C
+    `Base-vect-ops <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/ogr/base-vect-ops-py>`__,Provides tools for single and multiple geometries vector-based spatial analysis ,Python
+    
+Based on CGAL
+------------------------
+
+.. note:: 
+
+  |cgal| `CGAL <http://gdal.org>`__ is the Computational Geometry Algorithms Library. Learn more on official `website <http://cgal.org>`__.
+ 
+
+.. |cgal| image:: ../_static/cgal.png
+       :height: 110px
+       :width: 112px
+       :scale: 45%
+       :alt: CGAL logo
+
+..   csv-table:: 
+
+    Name,Description,Language
+    `Cgal_Delaunay <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/cgal/delaunay.c>`__,Computes the edges of Delaunay triangulation for a set of data points,C
+    `Ggal_Voronoi <http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-services/cgal/voronoi.c>`__,Computes the edges of Voronoi diagram for a set of data points,C
+    
+Based on GRASS GIS 
+---------------------------
+
+.. note:: 
+
+  |grass| `GRASS GIS <http://grass.osgeo.org>`__ is the Geographic Resources Analysis Support System. Learn more on official `website <http://grass.osgeo.org>`__.
+ 
+
+.. |grass| image:: ../_static/grassgis.png
+       :height: 111px
+       :width: 100px
+       :scale: 45%
+       :alt: GRASS GIS logo
+	    
+..   csv-table:: 
+
+    Name,Description,Language
+   `Raster modules (r.*) <http://grass.osgeo.org/grass70/manuals/raster.html>`__,Most of the GRASS7 vector modules are supported,C
+   `Vector modules (v.*) <http://grass.osgeo.org/grass70/manuals/vector.html>`__,Most of the GRASS7 vector modules are supported,C
+   `Imagery modules (i.*) <http://grass.osgeo.org/grass70/manuals/imagery.html>`__,Most of the GRASS7 iamgery modules are supported,C
+
+`GRASS GIS 7 <http://grass.osgeo.org>`__ modules can be used as :ref:`services_index` without any modification using the `wps-grass-bridge <https://code.google.com/p/wps-grass-bridge/>`__ library. The latter includes useful tools such as `GrassXMLtoZCFG.py <https://code.google.com/p/wps-grass-bridge/source/browse/trunk/GrassXMLtoZCFG.py>`__ and `ZOOGrassModuleStarter.py <https://code.google.com/p/wps-grass-bridge/source/browse/trunk/ZOOGrassModuleStarter.py>`__ for using the supported GRASS modules directly as ZOO-Services. A step-by-step installation guide suited for ZOO-Project is available in the `wps-grass-bridge <https://code.google.com/p/wps-grass-bridge/wiki/ZOO_WPS_Integration>`__ documentation.  
+
+    
+Based on Orfeo Toolbox 
+-----------------------
+
+.. note:: 
+
+   |otb| `Orfeo Toolbox <https://www.orfeo-toolbox.org>`__ is an open
+   source image processing library. Learn more on official `website <https://www.orfeo-toolbox.org>`__.
+ 
+
+.. |otb| image:: ../_static/orfeotoolbox.png
+       :height: 115px
+       :width: 150px
+       :scale: 40%
+       :alt: Orfeo Toolbox logo
+
+`Orfeo Toolbox <https://www.orfeo-toolbox.org>`__ `Applications <http://otbcb.readthedocs.org/en/latest/Applications.html>`__ can be used as :ref:`services_index` without any modification
+using the :ref:`kernel-orfeotoolbox`.
+
+Based on SAGA GIS
+---------------------------
+
+.. note:: 
+
+   |saga| `SAGA GIS <https://www.orfeo-toolbox.org>`__ is the System for Automated Geoscientific Analyses. Learn more on official `website <http://www.saga-gis.org/en/index.html>`__.
+ 
+
+.. |saga| image:: ../_static/sagagis.png
+       :height: 100px
+       :width: 100px
+       :scale: 45%
+       :alt: SAGA GIS logo
Index: /tags/rel-1.7.0/testing/README
===================================================================
--- /tags/rel-1.7.0/testing/README	(revision 942)
+++ /tags/rel-1.7.0/testing/README	(revision 942)
@@ -0,0 +1,30 @@
+Please use the following syntaxe:
+
+  ./run.sh <WPSInstance> <ServiceName>
+
+where <WPSInstance> should be the url to a WPS Server and <ServiceName> should 
+be the service name you want to run tests with.
+
+For instance to test the Buffer service on a localhost WPS server, use the 
+following command:
+
+  ./run.sh http://localhost/cgi-bin/zoo_loader.cgi Buffer
+
+
+Important note:  sometimes XML validation failed because xmllint is unable to download
+a file required to validate. In such case, you can use the file /etc/xml/catalog on your
+local machine to use a local copy of the missing file.
+
+For instance, in case xml.xsd can't be downloaded, then you can download a copy using
+this url http://www.w3.org/2001/xml.xsd, store it in /etc/schemas directory and then 
+use the following /etc/xml/catalog file:
+
+<?xml version="1.0"?>
+<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN" "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+<rewriteSystem systemIdStartString="http://www.w3.org/2001/xml.xsd"
+                rewritePrefix="file:///etc/schemas/xml.xsd" />
+</catalog>
+
+Obviously, you can do similar manipulation for the OGC schemas to use local files 
+rather than downloading them for each tests.
Index: /tags/rel-1.7.0/testing/extractExceptionInfo.xsl
===================================================================
--- /tags/rel-1.7.0/testing/extractExceptionInfo.xsl	(revision 942)
+++ /tags/rel-1.7.0/testing/extractExceptionInfo.xsl	(revision 942)
@@ -0,0 +1,14 @@
+<?xml version="1.0"  encoding="UTF-8"?>
+
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+		xmlns:ows="http://www.opengis.net/ows/1.1"
+		xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <xsl:output method="text"/>
+
+  <xsl:template match="*/*">
+      <xsl:text>Code: </xsl:text><xsl:value-of select="@exceptionCode" /><xsl:text>, Locator: </xsl:text><xsl:value-of select="@locator" />
+  </xsl:template> 
+
+</xsl:stylesheet>
Index: /tags/rel-1.7.0/testing/extractStatusLocation.xsl
===================================================================
--- /tags/rel-1.7.0/testing/extractStatusLocation.xsl	(revision 942)
+++ /tags/rel-1.7.0/testing/extractStatusLocation.xsl	(revision 942)
@@ -0,0 +1,15 @@
+<?xml version="1.0"  encoding="UTF-8"?>
+
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+		xmlns:ows="http://www.opengis.net/ows/1.1"
+		xmlns:wps="http://www.opengis.net/wps/1.0.0"
+		xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <xsl:output method="text"/>
+
+  <xsl:template match="wps:ExecuteResponse">
+    <xsl:value-of select="@statusLocation" />
+  </xsl:template> 
+
+</xsl:stylesheet>
Index: /tags/rel-1.7.0/testing/requests/dp.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/dp.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/dp.xml	(revision 942)
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<DescribeProcess xmlns="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsDescribeProcess_request.xsd" service="WPS" version="1.0.0" language="en-US">
+	<ows:Identifier>ServiceName</ows:Identifier>
+</DescribeProcess>
Index: /tags/rel-1.7.0/testing/requests/igml_o.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/igml_o.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/igml_o.xml	(revision 942)
@@ -0,0 +1,19 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputName</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Data>
+<wps:ComplexData mimeType="text/xml"><wfs:FeatureCollection xmlns="http://www.opengis.net/wfs" xmlns:wfs="http://www.opengis.net/wfs" xmlns:topp="http://www.openplans.org/topp" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openplans.org/topp http://www.zoo-project.org:8082/geoserver/wfs?service=WFS&amp;version=1.0.0&amp;request=DescribeFeatureType&amp;typeName=topp%3Astates http://www.opengis.net/wfs http://www.zoo-project.org:8082/geoserver/schemas/wfs/1.0.0/WFS-basic.xsd"><gml:boundedBy><gml:null>unknown</gml:null></gml:boundedBy><gml:featureMember><topp:states fid="states.15"><topp:the_geom><gml:MultiPolygon srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">-105.99836,31.393818 -106.212753,31.478128 -106.383041,31.733763 -106.538971,31.786198 -106.614441,31.817728 -106.615578,31.844635 -106.643532,31.895102 -106.633202,31.913998 -106.632057,31.972118 -106.649513,31.980228 -106.623077,32.000988 -106.377846,32.000645 -106.002708,32.001553 -104.921799,32.004269 -104.850563,32.003151 -104.018814,32.007278 -103.980896,32.00589 -103.728973,32.006104 -103.332092,32.004154 -103.057968,32.0019 -103.055191,32.084995 -103.059547,32.51543 -103.048836,32.953533 -103.042603,33.377728 -103.038239,33.565742 -103.032761,33.826088 -103.029144,34.307743 -103.022156,34.745266 -103.02475,34.964718 -103.02565,35.177208 -103.021797,35.623604 -103.022118,35.742287 -103.02356,36.056026 -103.026802,36.491566 -102.996918,36.492344 -102.165222,36.490208 -102.03421,36.492954 -101.620316,36.492004 -101.089668,36.488022 -100.956909,36.489609 -100.549416,36.489449 -100.006866,36.493877 -100.001144,36.492519 -99.997154,36.057549 -99.997726,35.883793 -100,35.618809 -99.994354,35.424572 -99.997185,35.182182 -99.996071,35.030998 -99.998878,34.747185 -99.996094,34.562321 -99.972099,34.561863 -99.94474,34.579571 -99.931908,34.579109 -99.8806,34.548176 -99.860573,34.518627 -99.829933,34.501778 -99.777687,34.443993 -99.684906,34.377445 -99.601448,34.368557 -99.58522,34.384857 -99.57785,34.408913 -99.553864,34.41518 -99.502136,34.404068 -99.479439,34.383522 -99.438377,34.364704 -99.409958,34.369106 -99.394157,34.396744 -99.392792,34.428993 -99.364204,34.450195 -99.323296,34.412708 -99.267174,34.398285 -99.254105,34.368214 -99.20549,34.331993 -99.196304,34.305122 -99.204597,34.255646 -99.190483,34.223736 -99.176155,34.21273 -99.127945,34.201469 -99.07843,34.208359 -99.035217,34.198921 -98.996193,34.209496 -98.952507,34.194565 -98.891342,34.16082 -98.811066,34.145935 -98.778534,34.131962 -98.705292,34.130714 -98.682213,34.149998 -98.66172,34.147038 -98.625992,34.158436 -98.607246,34.151398 -98.576332,34.14193 -98.557579,34.105335 -98.499519,34.066414 -98.448189,34.054375 -98.421341,34.06583 -98.407135,34.082455 -98.390953,34.087231 -98.384254,34.11578 -98.350403,34.14212 -98.320488,34.13942 -98.277,34.122871 -98.172844,34.115368 -98.136864,34.138432 -98.114868,34.148987 -98.094124,34.134556 -98.110687,34.06982 -98.086205,34.005314 -98.055557,33.989799 -98.023491,33.986984 -97.982681,34.001286 -97.950226,33.971161 -97.947754,33.959751 -97.962997,33.94865 -97.950684,33.932518 -97.976128,33.912052 -97.976379,33.902504 -97.954735,33.88348 -97.909065,33.874023 -97.869751,33.855114 -97.852547,33.857071 -97.790207,33.890457 -97.756363,33.932098 -97.729019,33.939293 -97.704262,33.971546 -97.671066,33.988613 -97.600182,33.969437 -97.592354,33.917885 -97.575668,33.902531 -97.554588,33.903904 -97.518204,33.916771 -97.477531,33.907707 -97.462761,33.902382 -97.457062,33.89043 -97.452736,33.836212 -97.410118,33.820709 -97.363319,33.831024 -97.341805,33.861916 -97.314957,33.870392 -97.314087,33.89584 -97.272278,33.872574 -97.263908,33.85873 -97.250687,33.872971 -97.246063,33.894238 -97.211334,33.905689 -97.187767,33.899204 -97.164169,33.863148 -97.168594,33.847794 -97.195015,33.836159 -97.208321,33.819649 -97.189163,33.752769 -97.152473,33.728668 -97.115562,33.725933 -97.0905,33.73167 -97.083466,33.742413 -97.087669,33.807571 -97.050026,33.823448 -97.078247,33.837811 -97.082176,33.851101 -97.0709,33.856728 -97.025597,33.840561 -97.005852,33.850513 -96.987709,33.876423 -96.987862,33.944202 -96.968185,33.937321 -96.936203,33.947849 -96.929565,33.961773 -96.898453,33.950027 -96.882851,33.924591 -96.878937,33.884003 -96.861015,33.861679 -96.844009,33.858032 -96.814117,33.871769 -96.797592,33.869949 -96.748825,33.831738 -96.711678,33.83387 -96.693382,33.847904 -96.677704,33.904324 -96.666237,33.913544 -96.584488,33.896145 -96.614166,33.8629 -96.601196,33.842957 -96.562134,33.82542 -96.510574,33.815685 -96.500748,33.78809 -96.487373,33.77813 -96.419464,33.788326 -96.370819,33.740395 -96.347588,33.705528 -96.316277,33.701801 -96.300789,33.71405 -96.28968,33.761932 -96.278076,33.773388 -96.212547,33.756691 -96.187027,33.758583 -96.168816,33.769356 -96.161316,33.798229 -96.141418,33.82032 -96.154518,33.823944 -96.180725,33.808434 -96.183128,33.815792 -96.169205,33.828983 -96.148964,33.83559 -96.109444,33.829258 -96.091522,33.844578 -96.047974,33.841278 -96.026749,33.856022 -96.014069,33.844208 -96.001793,33.856979 -96.002617,33.87339 -95.994209,33.875378 -95.977394,33.857952 -95.958763,33.86504 -95.943069,33.889973 -95.933075,33.89053 -95.846558,33.841038 -95.825974,33.843025 -95.795479,33.864674 -95.768517,33.851402 -95.764252,33.879005 -95.760696,33.89344 -95.746864,33.903397 -95.699707,33.894825 -95.633492,33.920105 -95.612984,33.920238 -95.61483,33.936691 -95.606071,33.944553 -95.562775,33.936073 -95.546318,33.904034 -95.519577,33.906643 -95.526733,33.897816 -95.547493,33.893158 -95.544037,33.885742 -95.512886,33.897736 -95.498856,33.881718 -95.468124,33.886433 -95.451607,33.865753 -95.33004,33.870918 -95.336227,33.897114 -95.301956,33.886623 -95.28643,33.886902 -95.277351,33.917938 -95.263618,33.8978 -95.250992,33.905022 -95.251289,33.936443 -95.234039,33.964863 -95.148315,33.943546 -95.127968,33.940868 -95.126678,33.917145 -95.119225,33.912281 -95.09536,33.921738 -95.082268,33.918453 -95.089714,33.896915 -95.083603,33.888462 -95.063477,33.917648 -95.063141,33.896694 -95.042862,33.884445 -95.037361,33.866451 -95.012772,33.869946 -94.989281,33.856182 -94.968704,33.866215 -94.959908,33.848076 -94.939888,33.840824 -94.940399,33.815807 -94.918236,33.816196 -94.908546,33.803478 -94.913879,33.789597 -94.881638,33.774963 -94.85788,33.749321 -94.81916,33.749405 -94.803223,33.739582 -94.783508,33.753262 -94.764175,33.752842 -94.782028,33.742268 -94.783157,33.733665 -94.749771,33.736706 -94.762718,33.716797 -94.742111,33.719048 -94.754478,33.707771 -94.741653,33.701267 -94.690987,33.690289 -94.668457,33.696537 -94.655479,33.692291 -94.644325,33.67765 -94.667953,33.671459 -94.669426,33.666061 -94.658539,33.663738 -94.638763,33.670105 -94.631737,33.683899 -94.600945,33.665607 -94.585106,33.678982 -94.578506,33.670471 -94.560722,33.671913 -94.565208,33.663013 -94.585159,33.662132 -94.588387,33.655449 -94.576462,33.652157 -94.545418,33.661621 -94.541931,33.648247 -94.562195,33.64283 -94.562149,33.635536 -94.550194,33.632694 -94.51799,33.643009 -94.525055,33.621021 -94.510559,33.63081 -94.50061,33.623047 -94.476486,33.631966 -94.435913,33.636444 -94.436333,33.616844 -94.451553,33.604347 -94.443329,33.596504 -94.428467,33.597141 -94.40657,33.573486 -94.393417,33.574959 -94.379112,33.593327 -94.370628,33.590042 -94.372307,33.572662 -94.395264,33.560303 -94.370758,33.547684 -94.328751,33.573135 -94.302383,33.556934 -94.29882,33.579853 -94.278984,33.589333 -94.272079,33.584606 -94.274544,33.561737 -94.237236,33.592422 -94.223038,33.58572 -94.235367,33.561535 -94.210884,33.557987 -94.205345,33.585079 -94.159515,33.593773 -94.155167,33.567085 -94.098701,33.572998 -94.086655,33.583954 -94.061432,33.577213 -94.035927,33.555912 -94.036507,33.270325 -94.03875,33.023289 -94.041603,32.882347 -94.040199,32.694813 -94.035233,32.389225 -94.034767,32.199448 -94.035065,31.994513 -94.009888,31.989134 -94.004395,31.977942 -93.977211,31.946159 -93.969986,31.923164 -93.93573,31.909456 -93.917923,31.909702 -93.923462,31.892593 -93.899261,31.894455 -93.892525,31.870066 -93.881264,31.87142 -93.877403,31.850113 -93.864822,31.817272 -93.834328,31.802017 -93.822067,31.774637 -93.831161,31.753281 -93.80999,31.730352 -93.814949,31.712351 -93.808769,31.707565 -93.792267,31.711395 -93.811844,31.674566 -93.806427,31.653767 -93.814728,31.647966 -93.819588,31.618092 -93.835579,31.615189 -93.832619,31.590183 -93.816322,31.57711 -93.810516,31.559063 -93.780128,31.533735 -93.763306,31.530724 -93.747543,31.537718 -93.731659,31.521877 -93.705795,31.520569 -93.718994,31.495403 -93.750435,31.490557 -93.751244,31.4855 -93.726784,31.459475 -93.698418,31.461458 -93.701927,31.446251 -93.687004,31.438131 -93.696129,31.427736 -93.694443,31.415922 -93.687492,31.40613 -93.664017,31.398329 -93.661072,31.372395 -93.634857,31.373827 -93.67704,31.328386 -93.681587,31.312679 -93.656128,31.286671 -93.645592,31.290262 -93.630829,31.273903 -93.616455,31.275805 -93.611877,31.270033 -93.611,31.242188 -93.590546,31.229687 -93.602921,31.199066 -93.593941,31.180199 -93.576942,31.17214 -93.550591,31.190929 -93.528923,31.185774 -93.526932,31.178076 -93.537018,31.17634 -93.528328,31.162943 -93.544189,31.159166 -93.537506,31.132441 -93.528091,31.125925 -93.535088,31.116072 -93.556679,31.109343 -93.559982,31.100536 -93.543121,31.094751 -93.544106,31.082373 -93.516998,31.074671 -93.525742,31.05698 -93.507217,31.038908 -93.547119,31.014141 -93.564941,31.018063 -93.567894,31.012924 -93.570847,30.997271 -93.560951,30.99169 -93.572456,30.976177 -93.548676,30.97019 -93.537338,30.956884 -93.532188,30.960732 -93.52562,30.93582 -93.529984,30.926971 -93.549622,30.924885 -93.546516,30.905334 -93.564476,30.901932 -93.568497,30.886234 -93.560844,30.87188 -93.552803,30.860283 -93.566444,30.845148 -93.555641,30.842342 -93.550682,30.828344 -93.581871,30.80204 -93.585175,30.772184 -93.618454,30.745789 -93.607651,30.73201 -93.61779,30.732548 -93.612411,30.710329 -93.617607,30.686802 -93.659988,30.672859 -93.677971,30.639692 -93.692879,30.640041 -93.684586,30.623425 -93.692696,30.615795 -93.671585,30.597832 -93.69342,30.598835 -93.717812,30.587379 -93.71788,30.568153 -93.735306,30.545517 -93.70546,30.522858 -93.714638,30.505114 -93.707275,30.496241 -93.714851,30.488628 -93.697975,30.470047 -93.703423,30.462513 -93.696571,30.442633 -93.721535,30.43298 -93.742561,30.408823 -93.754944,30.381788 -93.747833,30.367411 -93.759338,30.354145 -93.759178,30.340872 -93.729774,30.304916 -93.699211,30.297388 -93.707359,30.239372 -93.714844,30.220306 -93.704361,30.180861 -93.696167,30.175676 -93.699661,30.150808 -93.683144,30.148232 -93.685959,30.141253 -93.698639,30.141226 -93.696922,30.117929 -93.708382,30.11474 -93.715858,30.095669 -93.712479,30.06052 -93.760201,30.005964 -93.857277,29.990654 -93.856331,29.964602 -93.951767,29.818363 -93.834961,29.67457 -94.065407,29.674076 -94.356995,29.5599 -94.377007,29.55197 -94.682518,29.432905 -94.766548,29.363993 -94.785248,29.383261 -94.681915,29.475111 -94.572693,29.533052 -94.501282,29.517523 -94.469795,29.55678 -94.510811,29.545147 -94.533699,29.553984 -94.564438,29.578999 -94.788086,29.538557 -94.706421,29.658516 -94.700279,29.754568 -94.735725,29.792986 -94.829414,29.759857 -94.887161,29.668539 -94.932587,29.682209 -95.088264,29.80398 -95.040398,29.711578 -94.989334,29.679701 -95.014122,29.559265 -94.911156,29.500334 -94.982811,29.460527 -94.943756,29.464682 -94.952507,29.424234 -94.913445,29.420113 -94.916992,29.447823 -94.891136,29.399324 -94.815353,29.370932 -94.891472,29.393831 -94.898788,29.308775 -94.951134,29.325922 -95.066368,29.195877 -95.160522,29.200031 -95.16478,29.117548 -95.197342,29.105223 -95.248405,28.978392 -95.526581,28.803242 -95.683029,28.726954 -95.671318,28.752682 -95.786354,28.738871 -95.937309,28.690454 -95.956146,28.622673 -95.702148,28.718987 -96.206581,28.488386 -95.991646,28.596424 -95.983749,28.653133 -96.237587,28.571321 -96.239029,28.597116 -96.157471,28.611231 -96.240456,28.634859 -96.151062,28.762672 -96.212173,28.68672 -96.285973,28.661724 -96.270378,28.708981 -96.326157,28.634089 -96.364159,28.617981 -96.391777,28.670252 -96.392731,28.726028 -96.427086,28.712013 -96.449677,28.755035 -96.432259,28.697248 -96.403397,28.719494 -96.418785,28.638664 -96.375397,28.610088 -96.491203,28.556944 -96.437157,28.596991 -96.454384,28.655933 -96.483269,28.598055 -96.511894,28.608181 -96.511734,28.649542 -96.570396,28.636267 -96.570557,28.691841 -96.572212,28.808174 -96.576485,28.690689 -96.591499,28.71736 -96.646515,28.714142 -96.660011,28.679075 -96.606705,28.623634 -96.610344,28.558941 -96.566704,28.574099 -96.48658,28.506222 -96.563194,28.469627 -96.518501,28.460827 -96.476501,28.499454 -96.390724,28.434059 -96.661308,28.306263 -96.702362,28.340197 -96.703812,28.395885 -96.740768,28.403458 -96.787094,28.477507 -96.823875,28.44964 -96.788338,28.446255 -96.759102,28.410912 -96.77536,28.39163 -96.853493,28.404997 -96.788231,28.35247 -96.78627,28.312859 -96.793335,28.271372 -96.777931,28.229349 -96.803688,28.211447 -96.950905,28.114355 -96.91272,28.256798 -96.975304,28.210751 -96.941071,28.186771 -96.975105,28.115046 -97.033615,28.137398 -97.023567,28.199797 -97.131836,28.130426 -97.135414,28.16181 -97.167992,28.15946 -97.157059,28.116381 -97.260284,28.064724 -97.241234,28.048653 -97.270294,28.025932 -97.236214,28.04052 -97.123077,28.054266 -97.026405,28.10775 -97.023804,28.020237 -97.114624,27.915386 -97.195465,27.81222 -97.247025,27.822319 -97.213341,27.83111 -97.283485,27.871145 -97.361046,27.839954 -97.345619,27.873178 -97.479355,27.852962 -97.496681,27.875469 -97.521698,27.863626 -97.499535,27.843243 -97.479813,27.820282 -97.388542,27.831427 -97.396561,27.77084 -97.317795,27.712225 -97.34951,27.715328 -97.320015,27.690634 -97.353363,27.6408 -97.399216,27.633186 -97.347504,27.631439 -97.309212,27.707863 -97.249794,27.688831 -97.331459,27.562321 -97.412262,27.321024 -97.500435,27.319668 -97.507538,27.439215 -97.528381,27.344101 -97.600113,27.300135 -97.750076,27.419666 -97.680008,27.294373 -97.784744,27.28772 -97.548157,27.230207 -97.427216,27.265133 -97.503502,27.081541 -97.478996,26.996508 -97.568565,26.977858 -97.558052,26.846052 -97.495575,26.793781 -97.451698,26.600985 -97.425858,26.518225 -97.474709,26.476805 -97.421188,26.385059 -97.368698,26.35906 -97.353363,26.182449 -97.25312,26.068316 -97.276321,26.002275 -97.213097,26.009068 -97.172226,25.954569 -97.307144,25.965124 -97.304436,25.938663 -97.380989,25.917021 -97.385643,25.845362 -97.434349,25.845198 -97.590088,25.933231 -97.574936,25.954172 -97.612923,25.962002 -97.647972,26.023445 -97.867432,26.060141 -98.04007,26.059395 -98.076347,26.034626 -98.083214,26.065758 -98.200691,26.055376 -98.291946,26.098104 -98.271355,26.120895 -98.292274,26.132809 -98.327934,26.111647 -98.347191,26.15868 -98.384521,26.156031 -98.453392,26.220911 -98.488518,26.201544 -98.599968,26.260454 -98.677917,26.242056 -98.819832,26.375071 -98.908897,26.360329 -98.93927,26.395309 -99.106728,26.419531 -99.101471,26.48834 -99.168678,26.545729 -99.165817,26.579889 -99.285522,26.857361 -99.390518,26.94663 -99.392715,26.99555 -99.455063,27.028648 -99.437157,27.199198 -99.465271,27.269884 -99.543587,27.318653 -99.490494,27.490755 -99.526741,27.504284 -99.549187,27.612627 -99.714493,27.661558 -99.815727,27.780107 -99.874733,27.797686 -99.941856,27.986881 -99.993309,28.00346 -100.096924,28.154282 -100.214073,28.201935 -100.223465,28.241457 -100.29792,28.280354 -100.292892,28.32036 -100.35157,28.394182 -100.37677,28.478651 -100.345802,28.500811 -100.419533,28.544191 -100.403175,28.589733 -100.49791,28.660988 -100.58979,28.894222 -100.647224,28.92235 -100.66877,29.080072 -100.768608,29.166571 -100.796989,29.242502 -101.009056,29.373255 -101.06736,29.473553 -101.261429,29.526474 -101.254585,29.62875 -101.308929,29.58091 -101.305862,29.652431 -101.368401,29.657162 -101.4161,29.745434 -101.401276,29.769905 -101.448425,29.760586 -101.470467,29.788691 -101.538345,29.763018 -101.543953,29.81012 -101.58149,29.76515 -101.639671,29.75696 -101.759094,29.787167 -101.805206,29.779999 -101.819099,29.814125 -101.924225,29.788502 -101.97332,29.818773 -102.063995,29.784571 -102.324333,29.880116 -102.367561,29.845289 -102.384796,29.767946 -102.503098,29.785456 -102.551949,29.7495 -102.5765,29.778248 -102.637611,29.732338 -102.676361,29.744225 -102.804726,29.530146 -102.822205,29.411844 -102.883011,29.353371 -102.908325,29.269203 -102.866173,29.229036 -102.988098,29.190863 -103.153465,28.978682 -103.266586,29.007454 -103.28035,28.986374 -103.335518,29.050339 -103.37545,29.032108 -103.474075,29.072134 -103.526237,29.146646 -103.720314,29.190632 -103.739853,29.230349 -103.782158,29.229795 -103.767761,29.28124 -103.786995,29.26726 -104.045631,29.328119 -104.164383,29.400715 -104.204735,29.484041 -104.377594,29.550611 -104.535248,29.679466 -104.57756,29.807936 -104.67437,29.909283 -104.696495,30.057302 -104.674759,30.148964 -104.702614,30.238489 -104.813957,30.35047 -104.806473,30.376448 -104.852997,30.392263 -104.890678,30.570557 -104.986931,30.641325 -104.997543,30.684334 -105.060562,30.68787 -105.21434,30.812086 -105.258186,30.797653 -105.287598,30.831949 -105.313782,30.816507 -105.390312,30.853081 -105.409065,30.90251 -105.554382,30.998285 -105.603218,31.086428 -105.76973,31.17078 -105.99836,31.393818</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">-94.913429,29.257572 -94.76738,29.342451 -94.748405,29.31949 -95.105415,29.096958 -94.913429,29.257572</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">-96.397881,28.345846 -96.834625,28.066322 -96.803841,28.172161 -96.738907,28.183535 -96.532135,28.318245 -96.463051,28.325832 -96.422554,28.391439 -96.397881,28.345846</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">-96.939964,28.045933 -96.872421,28.131405 -96.837425,28.101841 -96.853806,28.049402 -97.049606,27.840954 -97.024429,27.914381 -96.949387,27.984526 -96.973,28.000853 -96.939964,28.045933</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">-97.359116,27.283718 -97.379379,27.210453 -97.376091,27.284643 -97.335503,27.440819 -97.248672,27.581133 -97.258682,27.651749 -97.203583,27.612064 -97.170181,27.70746 -97.075294,27.811274 -97.113037,27.819216 -97.053566,27.830473 -97.223717,27.574007 -97.359116,27.283718</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">-97.301132,26.601023 -97.358025,26.706646 -97.381332,26.820375 -97.395309,26.921988 -97.400909,27.111227 -97.388786,27.201651 -97.378532,27.204449 -97.386925,27.097244 -97.381332,26.949022 -97.358025,26.802664 -97.295837,26.60067 -97.232109,26.418142 -97.194992,26.259241 -97.171799,26.077721 -97.179337,26.07192 -97.208916,26.250542 -97.226311,26.348551 -97.251251,26.419304 -97.26725,26.478905 -97.278549,26.539963 -97.301132,26.601023</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></topp:the_geom><topp:STATE_NAME>Texas</topp:STATE_NAME><topp:STATE_FIPS>48</topp:STATE_FIPS><topp:SUB_REGION>W S Cen</topp:SUB_REGION><topp:STATE_ABBR>TX</topp:STATE_ABBR><topp:LAND_KM>688219.07</topp:LAND_KM><topp:WATER_KM>17337.549</topp:WATER_KM><topp:PERSONS>1.712202E7</topp:PERSONS><topp:FAMILIES>4377106.0</topp:FAMILIES><topp:HOUSHOLD>6115966.0</topp:HOUSHOLD><topp:MALE>8433346.00000001</topp:MALE><topp:FEMALE>8688674.0</topp:FEMALE><topp:WORKERS>6192585.0</topp:WORKERS><topp:DRVALONE>5860490.0</topp:DRVALONE><topp:CARPOOL>1142908.0</topp:CARPOOL><topp:PUBTRANS>168814.0</topp:PUBTRANS><topp:EMPLOYED>7687338.0</topp:EMPLOYED><topp:UNEMPLOY>590269.0</topp:UNEMPLOY><topp:SERVICE>2139266.0</topp:SERVICE><topp:MANUAL>1042397.0</topp:MANUAL><topp:P_MALE>0.493</topp:P_MALE><topp:P_FEMALE>0.507</topp:P_FEMALE><topp:SAMP_POP>2487642.0</topp:SAMP_POP></topp:states></gml:featureMember></wfs:FeatureCollection></wps:ComplexData>
+</wps:Data>
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument>
+<wps:Output>
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/ijson_o.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/ijson_o.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/ijson_o.xml	(revision 942)
@@ -0,0 +1,19 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Data>
+<wps:ComplexData mimeType="application/json">{"type":"Polygon","coordinates":[[[-102.036758,36.988972],[-106.860657,36.989491],[-109.047821,36.996643],[-109.055199,38.24493],[-109.052864,39.518196],[-109.050591,40.210545],[-109.047638,40.998474],[-107.918037,41.00341],[-104.051201,41.003227],[-102.620789,41.000225],[-102.047279,40.998077],[-102.04557,40.697323],[-102.036758,36.988972]]]}</wps:ComplexData>
+</wps:Data>
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument>
+<wps:Output>
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/ir_o.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/ir_o.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/ir_o.xml	(revision 942)
@@ -0,0 +1,17 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows?SERVICE=WFS&amp;REQUEST=GetFeature&amp;VERSION=1.0.0&amp;typename=topp:states&amp;SRS=EPSG:4326&amp;FeatureID=states.15" />
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument>
+<wps:Output>
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/ir_o_async.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/ir_o_async.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/ir_o_async.xml	(revision 942)
@@ -0,0 +1,17 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows?SERVICE=WFS&amp;REQUEST=GetFeature&amp;VERSION=1.0.0&amp;typename=topp:states&amp;SRS=EPSG:4326&amp;FeatureID=states.15" />
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument storeExecuteResponse="true" status="true">
+<wps:Output>
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/ir_or.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/ir_or.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/ir_or.xml	(revision 942)
@@ -0,0 +1,17 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows?SERVICE=WFS&amp;REQUEST=GetFeature&amp;VERSION=1.0.0&amp;typename=topp:states&amp;SRS=EPSG:4326&amp;FeatureID=states.15" />
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument>
+<wps:Output asReference="true">
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/ir_or_async.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/ir_or_async.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/ir_or_async.xml	(revision 942)
@@ -0,0 +1,17 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows?SERVICE=WFS&amp;REQUEST=GetFeature&amp;VERSION=1.0.0&amp;typename=topp:states&amp;SRS=EPSG:4326&amp;FeatureID=states.15" />
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument storeExecuteResponse="true" status="true">
+<wps:Output asReference="true">
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/irb_o.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/irb_o.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/irb_o.xml	(revision 942)
@@ -0,0 +1,22 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows" method="POST">
+<wps:Header key="Content-type" value="text/xml" />
+<wps:Body>
+<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.1.0" maxFeatures="10" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><wfs:Query typeName="states" srsName="EPSG:4326"><ogc:Filter xmlns:ogc="http://www.opengis.net/ogc"><ogc:BBOX><ogc:PropertyName>the_geom</ogc:PropertyName><gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326"><gml:lowerCorner>-98.417969 29.498046625</gml:lowerCorner><gml:upperCorner>-97.53906275 30.376952875</gml:upperCorner></gml:Envelope></ogc:BBOX></ogc:Filter></wfs:Query></wfs:GetFeature>
+</wps:Body>
+</wps:Reference>
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument>
+<wps:Output>
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/irb_o_async.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/irb_o_async.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/irb_o_async.xml	(revision 942)
@@ -0,0 +1,22 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows" method="POST">
+<wps:Header key="Content-type" value="text/xml" />
+<wps:Body>
+<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.1.0" maxFeatures="10" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><wfs:Query typeName="states" srsName="EPSG:4326"><ogc:Filter xmlns:ogc="http://www.opengis.net/ogc"><ogc:BBOX><ogc:PropertyName>the_geom</ogc:PropertyName><gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326"><gml:lowerCorner>-98.417969 29.498046625</gml:lowerCorner><gml:upperCorner>-97.53906275 30.376952875</gml:upperCorner></gml:Envelope></ogc:BBOX></ogc:Filter></wfs:Query></wfs:GetFeature>
+</wps:Body>
+</wps:Reference>
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument storeExecuteResponse="true" status="true">
+<wps:Output>
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/irb_or.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/irb_or.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/irb_or.xml	(revision 942)
@@ -0,0 +1,22 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows" method="POST">
+<wps:Header key="Content-type" value="text/xml" />
+<wps:Body>
+<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.1.0" maxFeatures="10" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><wfs:Query typeName="states" srsName="EPSG:4326"><ogc:Filter xmlns:ogc="http://www.opengis.net/ogc"><ogc:BBOX><ogc:PropertyName>the_geom</ogc:PropertyName><gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326"><gml:lowerCorner>-98.417969 29.498046625</gml:lowerCorner><gml:upperCorner>-97.53906275 30.376952875</gml:upperCorner></gml:Envelope></ogc:BBOX></ogc:Filter></wfs:Query></wfs:GetFeature>
+</wps:Body>
+</wps:Reference>
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument>
+<wps:Output asReference="true">
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/requests/irb_or_async.xml
===================================================================
--- /tags/rel-1.7.0/testing/requests/irb_or_async.xml	(revision 942)
+++ /tags/rel-1.7.0/testing/requests/irb_or_async.xml	(revision 942)
@@ -0,0 +1,22 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd">
+<ows:Identifier>ServiceName</ows:Identifier>
+<wps:DataInputs>
+<wps:Input>
+<ows:Identifier>InputPolygon</ows:Identifier>
+<ows:Title>Playground area</ows:Title>
+<wps:Reference xlink:href="http://www.zoo-project.org:8082/geoserver/ows" method="POST">
+<wps:Header key="Content-type" value="text/xml" />
+<wps:Body>
+<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.1.0" maxFeatures="10" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><wfs:Query typeName="states" srsName="EPSG:4326"><ogc:Filter xmlns:ogc="http://www.opengis.net/ogc"><ogc:BBOX><ogc:PropertyName>the_geom</ogc:PropertyName><gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326"><gml:lowerCorner>-98.417969 29.498046625</gml:lowerCorner><gml:upperCorner>-97.53906275 30.376952875</gml:upperCorner></gml:Envelope></ogc:BBOX></ogc:Filter></wfs:Query></wfs:GetFeature>
+</wps:Body>
+</wps:Reference>
+</wps:Input>
+</wps:DataInputs>
+<wps:ResponseForm>
+<wps:ResponseDocument storeExecuteResponse="true" status="true">
+<wps:Output asReference="true">
+<ows:Identifier>Result</ows:Identifier>
+</wps:Output>
+</wps:ResponseDocument>
+</wps:ResponseForm>
+</wps:Execute>
Index: /tags/rel-1.7.0/testing/run.sh
===================================================================
--- /tags/rel-1.7.0/testing/run.sh	(revision 942)
+++ /tags/rel-1.7.0/testing/run.sh	(revision 942)
@@ -0,0 +1,255 @@
+#!/bin/bash
+
+Usage=$(cat <<EOF
+Please use the following syntaxe:
+
+  ./run.sh <WPSInstance> <ServiceName> <Request>
+
+where <WPSInstance> should be the url to a WPS Server, <ServiceName> should 
+be the service name you want to run tests with (you can use multiple service 
+names, use quote and seperate them using space), <Request> should contain the 
+requests you want to use (you can use more than one at a time).
+
+For instance to test the Buffer service on a localhost WPS server, use the 
+following command:
+
+  ./run.sh http://localhost/cgi-bin/zoo_loader.cgi Buffer "GetCapabilities DescribeProcess Execute"
+
+EOF
+)
+
+if [ -z "$1" ] || [ -z "$2" ]; then
+    echo "$Usage"
+    exit
+fi
+
+WPSInstance=$1
+ServiceName=$2
+NBRequests=1000
+NBConcurrents=50
+pstat=0
+
+iter=0
+
+function testPostRequests {
+#
+# Tests for Execute using POST requests
+#
+    for i in $1; 
+    do
+	cat requests/${i}.xml | sed "s:ServiceName:${ServiceName}:g;s:InputName:$(cat tmp/inputName.txt):g" > tmp/${i}1.xml
+	if [ -z "$(echo $i | grep async)" ]; then
+	    postRequest "${WPSInstance}" "tmp/outputE${i}.xml" "Execute" "tmp/${i}1.xml"
+	else
+	    postRequest "${WPSInstance}" "tmp/outputE${i}.xml" "Execute" "tmp/${i}1.xml" "async"
+	fi
+	echo ""
+    done
+
+}
+
+function plotStat {
+    echo " **"
+    echo " * Plot statistics ..."
+    echo " **"
+    cp run.tsv tmp/run$1.tsv
+    sed "s:\[image\]:$2:g;s:\[file\]:$3:g" -i tmp/run$1.tsv
+    gnuplot tmp/run$1.tsv
+    cp run1.tsv tmp/run1$1.tsv
+    sed "s:\[image\]:$(echo $2 | sed "s:.jpg:1.jpg:g"):g;s:\[file\]:$3:g" -i tmp/run1$1.tsv
+    gnuplot tmp/run1$1.tsv
+}
+
+
+function kvpRequest {
+    echo " **"
+    echo " <h1> Simple KVP request start on $(date) </h1>"
+    echo " <a href='$1'>$1</a>"
+    
+    RESP=$(curl -v -o "$2" "$1" 2> tmp/temp.log; grep "< HTTP" tmp/temp.log | cut -d' ' -f3)
+    if [ "${3}" == "owsExceptionReport" ]; then
+	echo " *********************************"
+	if [ "$RESP" ==	"200" ]; then
+	    echo " ! Invalid response code ($RESP)"
+	else
+	    echo " * Valid response code ($RESP)"
+	fi
+	echo " *********************************"
+	echo " * Checking for ${3} response XML validity..."
+    	echo " * Schema: [http://schemas.opengis.net/ows/1.1.0/${3}.xsd]"
+	echo " *********************************"
+	xmllint --noout --schema http://schemas.opengis.net/ows/1.1.0/${3}.xsd "$2" 2> tmp/res${iter}.txt
+	echo " *********************************"
+	echo "Verifying that the missing / wrong argument was referenced in locator and the exceptionCode take the corresponding value ..."
+	echo -n " *********************************"
+	xsltproc ./extractExceptionInfo.xsl "$2"
+	echo " *********************************"
+    else
+	if [ "$RESP" ==	"200" ]; then
+	    echo " * Valid response code ($RESP)"
+	else
+	    echo " ! Invalid response code ($RESP)"
+	fi
+	echo " * Checking for ${3} response XML validity..."
+	echo " * Schema: [http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd]"
+	xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd "$2" 2> tmp/res${iter}.txt
+	v="$(cat tmp/res${iter}.txt | grep validates)"
+	echo ""
+    fi
+    echo " **"
+    echo " * Sending $NBRequests ${3} requests starting on $(date) ..."
+    echo " **"
+    ab -g tmp/stat${3}${iter}.plot -e tmp/stat${3}${iter}.txt -n "$NBRequests" -c "$NBConcurrents" "$1"
+    if [ "$pstat" -eq 1 ]; then
+	plotStat ${iter} tmp/stat${3}${iter}.jpg tmp/stat${3}${iter}.plot
+    fi
+    iter=$(expr $iter + 1)
+    echo " ** Ending on $(date)"
+}
+
+function postRequest {
+    echo " **"
+    echo " * Simple POST request started on $(date)"
+    echo " **"
+    echo " * Checking for ${3} request XML validity..."
+    echo " * Schema: http://schemas.opengis.net/wps/1.0.0/wps${3}_request.xsd"
+    echo " *********************************"
+    xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_request.xsd "$4" 
+    echo " *********************************"
+    curl -H "Content-type: text/xml" -d@"$4" -o "$2" "$1"
+    echo " * Checking for ${3} response XML validity on $(date) ..."
+    echo " * Schema: http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd"
+    echo " *********************************"
+    xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd "$2"
+    echo " *********************************"
+    if [ -z "$5" ]; then
+	echo ""
+    else
+	echo " * Schema: http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd"
+	echo " *********************************"
+	xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd "$(xsltproc ./extractStatusLocation.xsl $2)"
+	echo " *********************************"
+    fi
+    echo " * Sending $NBRequests ${3} XML requests on $(date) ..."
+    ab -g tmp/stat${3}${iter}.plot -e tmp/stat${3}${iter}.txt -T "text/xml" -p "$4" -n "$NBRequests" -c "$NBConcurrents" "$1"
+    if [ "$pstat" -eq 1 ]; then
+	plotStat ${iter} tmp/stat${3}${iter}.jpg tmp/stat${3}${iter}.plot
+    fi
+    iter=$(expr $iter + 1)
+    echo " ** Ending on $(date)"
+}
+
+function kvpRequestWrite {
+    suffix=""
+    cnt=0
+    cnt0=0
+    for i in $2; do
+	if [ ! $1 -eq $cnt0 ]; then
+	    if [ $cnt -gt 0 ]; then
+		suffix="$suffix&$(echo $i | sed 's:\"::g')"
+	    else
+		suffix="$(echo $i | sed 's:\"::g')"
+	    fi
+	    cnt=$(expr $cnt + 1)
+	fi
+	cnt0=$(expr $cnt0 + 1)
+    done
+    echo $suffix
+}
+
+function kvpWrongRequestWrite {
+    suffix=""
+    cnt=0
+    cnt0=0
+    for i in $2; do
+	if [ ! $1 -eq $cnt0 ]; then
+	    if [ $cnt -gt 0 ]; then
+		suffix="$suffix&$(echo $i | sed 's:\"::g')"
+	    else
+		suffix="$(echo $i | sed 's:\"::g')"
+	    fi
+	    cnt=$(expr $cnt + 1)
+	else
+	    cnt1=0
+	    for j in $3; do 
+		if [ $cnt1 -eq $1 ]; then
+		    suffix="$suffix&$(echo $j | sed 's:\"::g')"
+		fi
+		cnt1=$(expr $cnt1 + 1)
+	    done
+	fi
+	cnt0=$(expr $cnt0 + 1)
+    done
+    echo $suffix
+}
+
+for i in $3; do
+    if [ "$i" == "GetCapabilities" ]; then
+#
+# Tests for GetCapabilities using KVP (including wrong requests) and POST requests
+#
+	kvpRequest "${WPSInstance}?REQUEST=GetCapabilities&SERVICE=WPS" "tmp/outputGC1.xml" "GetCapabilities"
+
+	params='"request=GetCapabilities" "service=WPS"'
+
+	suffix=$(kvpRequestWrite -1 "$params")
+	kvpRequest "${WPSInstance}?$suffix" "tmp/outputGC2.xml" "GetCapabilities"
+
+	for j in 0 1; do 
+	    suffix=$(kvpRequestWrite $j "$params")
+	    kvpRequest "${WPSInstance}?$suffix" "tmp/outputGC$(expr $j + 3).xml" "owsExceptionReport"
+	done
+
+	paramsw='"request=GetCapabilitie" "service=WXS"'
+	for j in 0 1; do 
+	    suffix=$(kvpWrongRequestWrite $j "$params" "$paramsw")
+	    kvpRequest "${WPSInstance}?$suffix" "tmp/outputGC$(expr $j + 5).xml" "owsExceptionReport"
+	done
+
+	echo "Check if differences between upper case and lower case parameter names"
+	diff -ru tmp/outputGC1.xml tmp/outputGC2.xml 
+
+	echo ""
+
+	curl -o tmp/10_wpsGetCapabilities_request.xml http://schemas.opengis.net/wps/1.0.0/examples/10_wpsGetCapabilities_request.xml
+	postRequest "${WPSInstance}" "tmp/outputGCp.xml" "GetCapabilities" "tmp/10_wpsGetCapabilities_request.xml"
+	echo ""
+    fi
+    if [ "$i" == "DescribeProcess" ]; then
+#
+# Tests for DescribeProcess using KVP and POST requests
+#
+	kvpRequest "${WPSInstance}?request=DescribeProcess&service=WPS&version=1.0.0&Identifier=ALL" "tmp/outputDPall.xml" "DescribeProcess"
+
+	params='"request=DescribeProcess" "service=WPS" "version=1.0.0" "Identifier='${ServiceName}'"'
+
+	suffix=$(kvpRequestWrite -1 "$params")
+	kvpRequest "${WPSInstance}?$suffix" "tmp/outputDPb1.xml" "DescribeProcess"
+	
+	for j in 0 1 2 3; do 
+	    suffix=$(kvpRequestWrite $j "$params")
+	    kvpRequest "${WPSInstance}?$suffix" "tmp/outputDPb$(expr $j + 2).xml" "owsExceptionReport"
+	done
+
+	paramsw='"request=DescribeProces" "service=WXS" "version=1.2.0" "Identifier=Undefined"'
+	
+	for j in 0 1 2 3; do 
+	    suffix=$(kvpWrongRequestWrite $j "$params")
+	    kvpRequest "${WPSInstance}?$suffix" "tmp/outputDPb$(expr $j + 6).xml" "owsExceptionReport"
+	done
+
+
+	cat requests/dp.xml | sed "s:ServiceName:${ServiceName}:g" > tmp/dp1.xml
+	postRequest "${WPSInstance}" "tmp/outputDPp.xml" "DescribeProcess" "tmp/dp1.xml"
+	xsltproc extractInputs.xsl tmp/outputDPp.xml > tmp/inputName.txt
+	echo "" 
+    fi
+    if [ "$i" == "ExecuteSync" ]; then
+	testPostRequests "ijson_o igml_o ir_o ir_or irb_o irb_or"
+	echo "" 
+    fi
+    if [ "$i" == "ExecuteAsync" ]; then	
+	testPostRequests "ir_o_async ir_or_async irb_o_async irb_or_async"
+	echo "" 
+    fi
+done
Index: /tags/rel-1.7.0/thirds/cgic206/Makefile
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/Makefile	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/Makefile	(revision 942)
@@ -0,0 +1,37 @@
+OS:=$(shell uname -s)
+CPU:=$(shell uname -m)
+ifeq ($(OS),Darwin)
+	MACOS_CFLAGS=-arch x86_64
+	LIBS= -L./ -lcgic /usr/local/lib/libfcgi.dylib
+else
+	LIBS= -L./ -lcgic /usr/lib/libfcgi.a
+endif
+CFLAGS=-I/usr/local/include -g -Wall ${MACOS_CFLAGS}
+CC=gcc
+AR=ar
+RANLIB=ranlib
+
+all: libcgic.a cgictest.cgi capture
+
+install: libcgic.a
+	mkdir -p ../../dist/lib
+	cp libcgic.a  ../../dist/lib
+	cp cgic.h  ../../dist/include
+	@echo libcgic.a is in  ../../dist/lib/ and cgic.h is in  ../../dist/include/
+
+libcgic.a: cgic.o cgic.h
+	rm -f libcgic.a
+	$(AR) rc libcgic.a cgic.o
+	$(RANLIB) libcgic.a
+
+#mingw32 and cygwin users: replace .cgi with .exe
+
+cgictest.cgi: cgictest.o libcgic.a
+	gcc cgictest.o -o cgictest.cgi ${LIBS}
+
+capture: capture.o libcgic.a
+	gcc capture.o -o capture ${LIBS}
+
+clean:
+	rm -f *.o *.a cgictest.cgi capture
+
Index: /tags/rel-1.7.0/thirds/cgic206/capture.c
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/capture.c	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/capture.c	(revision 942)
@@ -0,0 +1,12 @@
+#include "cgic.h"
+
+int cgiMain() {
+	cgiWriteEnvironment("/tmp/capcgi.dat");
+	cgiHeaderContentType("text/html");
+	fprintf(cgiOut, "<title>Captured</title>\n");
+	fprintf(cgiOut, "<h1>Captured</h1>\n");
+	fprintf(cgiOut, "Your form submission was captured for use in\n");
+	fprintf(cgiOut, "debugging CGI code.\n");
+	return 0;
+}
+
Index: /tags/rel-1.7.0/thirds/cgic206/cgic.c
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/cgic.c	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/cgic.c	(revision 942)
@@ -0,0 +1,2556 @@
+/* cgicTempDir is the only setting you are likely to need
+	to change in this file. */
+
+/* Used only in Unix environments, in conjunction with mkstemp(). 
+	Elsewhere (Windows), temporary files go where the tmpnam() 
+	function suggests. If this behavior does not work for you, 
+	modify the getTempFileName() function to suit your needs. */
+
+#define cgicTempDir "/tmp"
+
+#include <fcgi_stdio.h>
+#if CGICDEBUG
+#define CGICDEBUGSTART \
+	{ \
+		FILE *dout; \
+		dout = fopen("/home/boutell/public_html/debug", "a"); \
+	
+#define CGICDEBUGEND \
+		fclose(dout); \
+	}
+#else /* CGICDEBUG */
+#define CGICDEBUGSTART
+#define CGICDEBUGEND
+#endif /* CGICDEBUG */
+
+#ifdef WIN32
+#define _INC_STDIO
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+#include <io.h>
+
+/* cgic 2.01 */
+#include <fcntl.h>
+
+#else
+#include <unistd.h>
+#endif /* WIN32 */
+#include "cgic.h"
+
+#define cgiStrEq(a, b) (!strcmp((a), (b)))
+
+char *cgiServerSoftware;
+char *cgiServerName;
+char *cgiGatewayInterface;
+char *cgiServerProtocol;
+char *cgiServerPort;
+char *cgiRequestMethod;
+char *cgiPathInfo;
+char *cgiPathTranslated;
+char *cgiScriptName;
+char *cgiQueryString;
+char *cgiRemoteHost;
+char *cgiRemoteAddr;
+char *cgiAuthType;
+char *cgiRemoteUser;
+char *cgiRemoteIdent;
+char cgiContentTypeData[1024];
+char *cgiContentType = cgiContentTypeData;
+char *cgiMultipartBoundary;
+char *cgiCookie;
+int cgiContentLength;
+char *cgiAccept;
+char *cgiUserAgent;
+char *cgiReferrer;
+char *cgiSid;
+
+FILE *cgiIn;
+FILE *cgiOut;
+
+/* True if CGI environment was restored from a file. */
+static int cgiRestored = 0;
+static int cgiTreatUrlEncoding;
+
+static void cgiGetenv(char **s, char *var);
+
+typedef enum {
+	cgiParseSuccess,
+	cgiParseMemory,
+	cgiParseIO
+} cgiParseResultType;
+
+/* One form entry, consisting of an attribute-value pair,
+	and an optional filename and content type. All of
+	these are guaranteed to be valid null-terminated strings,
+	which will be of length zero in the event that the
+	field is not present, with the exception of tfileName
+	which will be null when 'in' is null. DO NOT MODIFY THESE 
+	VALUES. Make local copies if modifications are desired. */
+
+typedef struct cgiFormEntryStruct {
+        char *attr;
+	/* value is populated for regular form fields only.
+		For file uploads, it points to an empty string, and file
+		upload data should be read from the file tfileName. */ 
+	char *value;
+	/* When fileName is not an empty string, tfileName is not null,
+		and 'value' points to an empty string. */
+	/* Valid for both files and regular fields; does not include
+		terminating null of regular fields. */
+	int valueLength;
+	char *fileName;	
+	char *contentType;
+	/* Temporary file name for working storage of file uploads. */
+	char *tfileName;
+        struct cgiFormEntryStruct *next;
+} cgiFormEntry;
+
+/* The first form entry. */
+static cgiFormEntry *cgiFormEntryFirst;
+
+static cgiParseResultType cgiParseGetFormInput();
+static cgiParseResultType cgiParsePostFormInput();
+static cgiParseResultType cgiParsePostMultipartInput();
+static cgiParseResultType cgiParseFormInput(char *data, int length);
+static void cgiSetupConstants();
+static void cgiFreeResources();
+static int cgiStrEqNc(char *s1, char *s2);
+static int cgiStrBeginsNc(char *s1, char *s2);
+
+//int cgiMain_init() {}
+
+
+int main(int argc, char *argv[]) {
+	int result;
+	char *cgiContentLengthString;
+	char *e;
+	while (FCGI_Accept() >= 0) {
+	cgiSetupConstants();
+	cgiGetenv(&cgiServerSoftware, "SERVER_SOFTWARE");
+	cgiGetenv(&cgiServerName, "SERVER_NAME");
+	cgiGetenv(&cgiGatewayInterface, "GATEWAY_INTERFACE");
+	cgiGetenv(&cgiServerProtocol, "SERVER_PROTOCOL");
+	cgiGetenv(&cgiServerPort, "SERVER_PORT");
+	cgiGetenv(&cgiRequestMethod, "REQUEST_METHOD");
+	if(strcmp(cgiRequestMethod,"")==0 && argc>=1)
+		cgiRequestMethod="GET";
+	cgiGetenv(&cgiPathInfo, "PATH_INFO");
+	cgiGetenv(&cgiPathTranslated, "PATH_TRANSLATED");
+	cgiGetenv(&cgiScriptName, "SCRIPT_NAME");
+	cgiGetenv(&cgiQueryString, "QUERY_STRING");
+	cgiSid=NULL;
+	if(cgiQueryString!=NULL && argc>=2){
+		cgiQueryString=argv[1];
+		if(argc>2){
+		  cgiSid=argv[2];
+		}
+	}
+	cgiGetenv(&cgiRemoteHost, "REMOTE_HOST");
+	cgiGetenv(&cgiRemoteAddr, "REMOTE_ADDR");
+	cgiGetenv(&cgiAuthType, "AUTH_TYPE");
+	cgiGetenv(&cgiRemoteUser, "REMOTE_USER");
+	cgiGetenv(&cgiRemoteIdent, "REMOTE_IDENT");
+	/* 2.0: the content type string needs to be parsed and modified, so
+		copy it to a buffer. */
+	e = getenv("CONTENT_TYPE");
+	if (e) {
+		if (strlen(e) < sizeof(cgiContentTypeData)) {
+			strcpy(cgiContentType, e);
+		} else {
+			/* Truncate safely in the event of what is almost certainly
+				a hack attempt */
+			strncpy(cgiContentType, e, sizeof(cgiContentTypeData));
+			cgiContentType[sizeof(cgiContentTypeData) - 1] = '\0';
+		}
+	} else {
+		cgiContentType[0] = '\0';
+	}
+	/* Never null */
+	cgiMultipartBoundary = "";
+	/* 2.0: parse semicolon-separated additional parameters of the
+		content type. The one we're interested in is 'boundary'.
+		We discard the rest to make cgiContentType more useful
+		to the typical programmer. */
+	if (strchr(cgiContentType, ';')) {
+		char *sat = strchr(cgiContentType, ';');
+		while (sat) {
+			*sat = '\0';
+			sat++;
+			while (isspace(*sat)) {
+				sat++;
+			}	
+			if (cgiStrBeginsNc(sat, "boundary=")) {
+				char *s;
+				cgiMultipartBoundary = sat + strlen("boundary=");
+				s = cgiMultipartBoundary;
+				while ((*s) && (!isspace(*s))) {
+					s++;
+				}
+				*s = '\0';
+				break;
+			} else {
+				sat = strchr(sat, ';');
+			} 	
+		}
+	}
+	cgiGetenv(&cgiContentLengthString, "CONTENT_LENGTH");
+	cgiContentLength = atoi(cgiContentLengthString);	
+	if(cgiContentLength==0 && argc>=2){
+		cgiContentLength=strlen(argv[1]);
+	}
+	cgiGetenv(&cgiAccept, "HTTP_ACCEPT");
+	cgiGetenv(&cgiUserAgent, "HTTP_USER_AGENT");
+	cgiGetenv(&cgiReferrer, "HTTP_REFERER");
+	cgiGetenv(&cgiCookie, "HTTP_COOKIE");
+#ifdef CGICDEBUG
+	CGICDEBUGSTART
+	fprintf(dout, "%d\n", cgiContentLength);
+	fprintf(dout, "%s\n", cgiRequestMethod);
+	fprintf(dout, "%s\n", cgiContentType);
+	CGICDEBUGEND	
+#endif /* CGICDEBUG */
+#ifdef WIN32
+	/* 1.07: Must set stdin and stdout to binary mode */
+	/* 2.0: this is particularly crucial now and must not be removed */
+	_setmode( FCGI_fileno( stdin ), _O_BINARY );
+	_setmode( FCGI_fileno( stdout ), _O_BINARY );
+#endif /* WIN32 */
+	cgiFormEntryFirst = 0;
+	cgiIn = FCGI_stdin;
+	cgiOut = FCGI_stdout;
+	cgiRestored = 0;
+
+
+	/* These five lines keep compilers from
+		producing warnings that argc and argv
+		are unused. They have no actual function. */
+	if (argc) {
+		if (argv[0]) {
+			cgiRestored = 0;
+		}
+	}	
+
+
+	cgiTreatUrlEncoding=0;
+	if (cgiStrEqNc(cgiRequestMethod, "post")) {
+		cgiTreatUrlEncoding=0;
+#ifdef CGICDEBUG
+		CGICDEBUGSTART
+		fprintf(dout, "POST recognized\n");
+		CGICDEBUGEND
+#endif /* CGICDEBUG */
+		if (cgiStrEqNc(cgiContentType, "application/x-www-form-urlencoded")) {	
+#ifdef CGICDEBUG
+			CGICDEBUGSTART
+			fprintf(dout, "Calling PostFormInput\n");
+			CGICDEBUGEND	
+#endif /* CGICDEBUG */
+			if (cgiParsePostFormInput() != cgiParseSuccess) {
+#ifdef CGICDEBUG
+				CGICDEBUGSTART
+				fprintf(dout, "PostFormInput failed\n");
+				CGICDEBUGEND	
+#endif /* CGICDEBUG */
+				cgiFreeResources();
+				return -1;
+			}	
+#ifdef CGICDEBUG
+			CGICDEBUGSTART
+			fprintf(dout, "PostFormInput succeeded\n");
+			CGICDEBUGEND	
+#endif /* CGICDEBUG */
+		} else if (cgiStrEqNc(cgiContentType, "multipart/form-data")) {
+#ifdef CGICDEBUG
+			CGICDEBUGSTART
+			fprintf(dout, "Calling PostMultipartInput\n");
+			CGICDEBUGEND	
+#endif /* CGICDEBUG */
+			if (cgiParsePostMultipartInput() != cgiParseSuccess) {
+#ifdef CGICDEBUG
+				CGICDEBUGSTART
+				fprintf(dout, "PostMultipartInput failed\n");
+				CGICDEBUGEND	
+#endif /* CGICDEBUG */
+				cgiFreeResources();
+				return -1;
+			}	
+#ifdef CGICDEBUG
+			CGICDEBUGSTART
+			fprintf(dout, "PostMultipartInput succeeded\n");
+			CGICDEBUGEND	
+#endif /* CGICDEBUG */
+		}
+	} else if (cgiStrEqNc(cgiRequestMethod, "get")) {	
+		/* The spec says this should be taken care of by
+			the server, but... it isn't */
+		cgiContentLength = strlen(cgiQueryString);
+		if (cgiParseGetFormInput() != cgiParseSuccess) {
+#ifdef CGICDEBUG
+			CGICDEBUGSTART
+			fprintf(dout, "GetFormInput failed\n");
+			CGICDEBUGEND	
+#endif /* CGICDEBUG */
+			cgiFreeResources();
+			return -1;
+		} else {	
+#ifdef CGICDEBUG
+			CGICDEBUGSTART
+			fprintf(dout, "GetFormInput succeeded\n");
+			CGICDEBUGEND	
+#endif /* CGICDEBUG */
+		}
+	}
+	result = cgiMain();
+	cgiFreeResources();
+	}
+	FCGI_Finish();
+	return result;
+}
+
+static void cgiGetenv(char **s, char *var){
+	*s = getenv(var);
+	if (!(*s)) {
+		*s = "";
+	}
+}
+
+static cgiParseResultType cgiParsePostFormInput() {
+	char *input;
+	cgiParseResultType result;
+	if (!cgiContentLength) {
+		return cgiParseSuccess;
+	}
+	input = (char *) malloc(cgiContentLength);
+	if (!input) {
+		return cgiParseMemory;	
+	}
+	if (((int) fread(input, 1, cgiContentLength, cgiIn)) 
+		!= cgiContentLength) 
+	{
+		return cgiParseIO;
+	}	
+	result = cgiParseFormInput(input, cgiContentLength);
+	free(input);
+	return result;
+}
+
+/* 2.0: A virtual datastream supporting putback of 
+	enough characters to handle multipart boundaries easily.
+	A simple memset(&mp, 0, sizeof(mp)) is suitable initialization. */
+
+typedef struct {
+	/* Buffer for putting characters back */
+	char putback[1024];	
+	/* Position in putback from which next character will be read.
+		If readPos == writePos, then next character should
+		come from cgiIn. */
+	int readPos;
+	/* Position in putback to which next character will be put back.
+		If writePos catches up to readPos, as opposed to the other
+		way around, the stream no longer functions properly.
+		Calling code must guarantee that no more than 
+		sizeof(putback) bytes are put back at any given time. */
+	int writePos;
+	/* Offset in the virtual datastream; can be compared
+		to cgiContentLength */
+	int offset;
+} mpStream, *mpStreamPtr;
+
+int mpRead(mpStreamPtr mpp, char *buffer, int len)
+{
+	int ilen = len;
+	int got = 0;
+	while (len) {
+		if (mpp->readPos != mpp->writePos) {
+			*buffer++ = mpp->putback[mpp->readPos++];
+			mpp->readPos %= sizeof(mpp->putback);
+			got++;
+			len--;
+		} else {
+			break;
+		}	
+	}
+	/* Refuse to read past the declared length in order to
+		avoid deadlock */
+	if (len > (cgiContentLength - mpp->offset)) {
+		len = cgiContentLength - mpp->offset;
+	}
+	if (len) {
+		int fgot = fread(buffer, 1, len, cgiIn);
+		if (fgot >= 0) {
+			mpp->offset += (got + fgot);
+			return got + fgot;
+		} else if (got > 0) {
+			mpp->offset += got;
+			return got;
+		} else {
+			/* EOF or error */
+			return fgot;
+		}
+	} else if (got) {
+		return got;
+	} else if (ilen) {	
+		return EOF;
+	} else {
+		/* 2.01 */
+		return 0;
+	}
+}
+
+void mpPutBack(mpStreamPtr mpp, char *data, int len)
+{
+	mpp->offset -= len;
+	while (len) {
+		mpp->putback[mpp->writePos++] = *data++;
+		mpp->writePos %= sizeof(mpp->putback);
+		len--;
+	}
+}
+
+/* This function copies the body to outf if it is not null, otherwise to
+	a newly allocated character buffer at *outP, which will be null
+	terminated; if both outf and outP are null the body is not stored.
+	If bodyLengthP is not null, the size of the body in bytes is stored
+	to *bodyLengthP, not including any terminating null added to *outP. 
+	If 'first' is nonzero, a preceding newline is not expected before
+	the boundary. If 'first' is zero, a preceding newline is expected.
+	Upon return mpp is positioned after the boundary and its trailing 
+	newline, if any; if the boundary is followed by -- the next two 
+	characters read after this function returns will be --. Upon error, 
+	if outP is not null, *outP is a null pointer; *bodyLengthP 
+	is set to zero. Returns cgiParseSuccess, cgiParseMemory 
+	or cgiParseIO. */
+
+static cgiParseResultType afterNextBoundary(mpStreamPtr mpp,
+	FILE *outf,
+	char **outP,
+	int *bodyLengthP,
+	int first
+	);
+
+static int readHeaderLine(
+	mpStreamPtr mpp,	
+	char *attr,
+	int attrSpace,
+	char *value,
+	int valueSpace);
+
+static void decomposeValue(char *value,
+	char *mvalue, int mvalueSpace,
+	char **argNames,
+	char **argValues,
+	int argValueSpace);
+
+/* tfileName must be 1024 bytes to ensure adequacy on
+	win32 (1024 exceeds the maximum path length and
+	certainly exceeds observed behavior of _tmpnam).
+	May as well also be 1024 bytes on Unix, although actual
+	length is strlen(cgiTempDir) + a short unique pattern. */
+	
+static cgiParseResultType getTempFileName(char *tfileName);
+
+static cgiParseResultType cgiParsePostMultipartInput() {
+	cgiParseResultType result;
+	cgiFormEntry *n = 0, *l = 0;
+	int got;
+	FILE *outf = 0;
+	char *out = 0;
+	char tfileName[1024];
+	mpStream mp;
+	mpStreamPtr mpp = &mp;
+	memset(&mp, 0, sizeof(mp));
+	if (!cgiContentLength) {
+		return cgiParseSuccess;
+	}
+	/* Read first boundary, including trailing newline */
+	result = afterNextBoundary(mpp, 0, 0, 0, 1);
+	if (result == cgiParseIO) {	
+		/* An empty submission is not necessarily an error */
+		return cgiParseSuccess;
+	} else if (result != cgiParseSuccess) {
+		return result;
+	}
+	while (1) {
+		char d[1024];
+		char fvalue[1024];
+		char fname[1024];
+		int bodyLength = 0;
+		char ffileName[1024];
+		char fcontentType[1024];
+		char attr[1024];
+		char value[1024];
+		fvalue[0] = 0;
+		fname[0] = 0;
+		ffileName[0] = 0;
+		fcontentType[0] = 0;
+		out = 0;
+		outf = 0;
+		/* Check for EOF */
+		got = mpRead(mpp, d, 2);
+		if (got < 2) {
+			/* Crude EOF */
+			break;
+		}
+		if ((d[0] == '-') && (d[1] == '-')) {
+			/* Graceful EOF */
+			break;
+		}
+		mpPutBack(mpp, d, 2);
+		/* Read header lines until end of header */
+		while (readHeaderLine(
+				mpp, attr, sizeof(attr), value, sizeof(value))) 
+		{
+			char *argNames[3];
+			char *argValues[2];
+			/* Content-Disposition: form-data; 
+				name="test"; filename="googley.gif" */
+			if (cgiStrEqNc(attr, "Content-Disposition")) {
+				argNames[0] = "name";
+				argNames[1] = "filename";
+				argNames[2] = 0;
+				argValues[0] = fname;
+				argValues[1] = ffileName;
+				decomposeValue(value, 
+					fvalue, sizeof(fvalue),
+					argNames,
+					argValues,
+					1024);	
+			} else if (cgiStrEqNc(attr, "Content-Type")) {
+				argNames[0] = 0;
+				decomposeValue(value, 
+					fcontentType, sizeof(fcontentType),
+					argNames,
+					0,
+					0);
+			}
+		}
+		if (!cgiStrEqNc(fvalue, "form-data")) {
+			/* Not form data */	
+			continue;
+		}
+		/* Body is everything from here until the next 
+			boundary. So, set it aside and move past boundary. 
+			If a filename was submitted as part of the
+			disposition header, store to a temporary file.
+			Otherwise, store to a memory buffer (it is
+			presumably a regular form field). */
+		if (strlen(ffileName)) {
+			if (getTempFileName(tfileName) != cgiParseSuccess) {
+				return cgiParseIO;
+			}	
+			outf = fopen(tfileName, "w+b");
+		} else {
+			outf = 0;
+			tfileName[0] = '\0';
+		}	
+		result = afterNextBoundary(mpp, outf, &out, &bodyLength, 0);
+		if (result != cgiParseSuccess) {
+			/* Lack of a boundary here is an error. */
+			if (outf) {
+				fclose(outf);
+				unlink(tfileName);
+			}
+			if (out) {
+				free(out);
+			}
+			return result;
+		}
+		/* OK, we have a new pair, add it to the list. */
+		n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));	
+		if (!n) {
+			goto outOfMemory;
+		}
+		memset(n, 0, sizeof(cgiFormEntry));
+		/* 2.01: one of numerous new casts required
+			to please C++ compilers */
+		n->attr = (char *) malloc(strlen(fname) + 1);
+		if (!n->attr) {
+			goto outOfMemory;
+		}
+		strcpy(n->attr, fname);
+		if (out) {
+			n->value = out;
+			out = 0;
+		} else if (outf) {
+			n->value = (char *) malloc(1);
+			if (!n->value) {
+				goto outOfMemory;
+			}
+			n->value[0] = '\0';
+			fclose(outf);
+		}
+		n->valueLength = bodyLength;
+		n->next = 0;
+		if (!l) {
+			cgiFormEntryFirst = n;
+		} else {
+			l->next = n;
+		}
+		n->fileName = (char *) malloc(strlen(ffileName) + 1);
+		if (!n->fileName) {
+			goto outOfMemory;
+		}
+		strcpy(n->fileName, ffileName);
+		n->contentType = (char *) malloc(strlen(fcontentType) + 1);
+		if (!n->contentType) {
+			goto outOfMemory;
+		}
+		strcpy(n->contentType, fcontentType);
+		n->tfileName = (char *) malloc(strlen(tfileName) + 1);
+		if (!n->tfileName) {
+			goto outOfMemory;
+		}
+		strcpy(n->tfileName, tfileName);
+
+		l = n;			
+	}	
+	return cgiParseSuccess;
+outOfMemory:
+	if (n) {
+		if (n->attr) {
+			free(n->attr);
+		}
+		if (n->value) {
+			free(n->value);
+		}
+		if (n->fileName) {
+			free(n->fileName);
+		}
+		if (n->tfileName) {
+			free(n->tfileName);
+		}
+		if (n->contentType) {
+			free(n->contentType);
+		}
+		free(n);
+	}
+	if (out) {
+		free(out);
+	}
+	if (outf) {
+		fclose(outf);
+		unlink(tfileName);
+	}
+	return cgiParseMemory;
+}
+
+static cgiParseResultType getTempFileName(char *tfileName)
+{
+#ifndef WIN32
+	/* Unix. Use the robust 'mkstemp' function to create
+		a temporary file that is truly unique, with
+		permissions that are truly safe. The 
+		fopen-for-write destroys any bogus information
+		written by potential hackers during the brief
+		window between the file's creation and the
+		chmod call (glibc 2.0.6 and lower might
+		otherwise have allowed this). */
+	int outfd; 
+	strcpy(tfileName, cgicTempDir "/cgicXXXXXX");
+	outfd = mkstemp(tfileName);
+	if (outfd == -1) {
+		return cgiParseIO;
+	}
+	close(outfd);
+	/* Fix the permissions */
+	if (chmod(tfileName, 0600) != 0) {
+		unlink(tfileName);
+		return cgiParseIO;
+	}
+#else
+	/* Non-Unix. Do what we can. */
+	if (!tmpnam(tfileName)) {
+		return cgiParseIO;
+	}
+#endif
+	return cgiParseSuccess;
+}
+
+
+#define APPEND(string, char) \
+	{ \
+		if ((string##Len + 1) < string##Space) { \
+			string[string##Len++] = (char); \
+		} \
+	}
+
+#define RAPPEND(string, ch) \
+	{ \
+		if ((string##Len + 1) == string##Space)  { \
+			char *sold = string; \
+			string##Space *= 2; \
+			string = (char *) realloc(string, string##Space); \
+			if (!string) { \
+				string = sold; \
+				goto outOfMemory; \
+			} \
+		} \
+		string[string##Len++] = (ch); \
+	}
+		
+#define BAPPEND(ch) \
+	{ \
+		if (outf) { \
+			putc(ch, outf); \
+			outLen++; \
+		} else if (out) { \
+			RAPPEND(out, ch); \
+		} \
+	}
+
+cgiParseResultType afterNextBoundary(mpStreamPtr mpp, FILE *outf, char **outP,
+	int *bodyLengthP, int first)
+{
+	int outLen = 0;
+	int outSpace = 256;
+	char *out = 0;
+	cgiParseResultType result;
+	int boffset;
+	int got;
+	char d[2];	
+	/* This is large enough, because the buffer into which the
+		original boundary string is fetched is shorter by more
+		than four characters due to the space required for
+		the attribute name */
+	char workingBoundaryData[1024];
+	char *workingBoundary = workingBoundaryData;
+	int workingBoundaryLength;
+	if ((!outf) && (outP)) {
+		out = (char *) malloc(outSpace);
+		if (!out) {
+			goto outOfMemory;
+		}
+	}
+	boffset = 0;
+	sprintf(workingBoundaryData, "\r\n--%s", cgiMultipartBoundary);
+	if (first) {
+		workingBoundary = workingBoundaryData + 2;
+	}
+	workingBoundaryLength = strlen(workingBoundary);
+	while (1) {
+		got = mpRead(mpp, d, 1);
+		if (got != 1) {
+			/* 2.01: cgiParseIO, not cgiFormIO */
+			result = cgiParseIO;
+			goto error;
+		}
+		if (d[0] == workingBoundary[boffset]) {
+			/* We matched the next byte of the boundary.
+				Keep track of our progress into the
+				boundary and don't emit anything. */
+			boffset++;
+			if (boffset == workingBoundaryLength) {
+				break;
+			} 
+		} else if (boffset > 0) {
+			/* We matched part, but not all, of the
+				boundary. Now we have to be careful:
+				put back all except the first
+				character and try again. The 
+				real boundary could begin in the
+				middle of a false match. We can
+				emit the first character only so far. */
+			BAPPEND(workingBoundary[0]);
+			mpPutBack(mpp, 
+				workingBoundary + 1, boffset - 1);
+			mpPutBack(mpp, d, 1);
+			boffset = 0;
+		} else {		
+			/* Not presently in the middle of a boundary
+				match; just emit the character. */
+			BAPPEND(d[0]);
+		}	
+	}
+	/* Read trailing newline or -- EOF marker. A literal EOF here
+		would be an error in the input stream. */
+	got = mpRead(mpp, d, 2);
+	if (got != 2) {
+		result = cgiParseIO;
+		goto error;
+	}	
+	if ((d[0] == '\r') && (d[1] == '\n')) {
+		/* OK, EOL */
+	} else if (d[0] == '-') {
+		/* Probably EOF, but we check for
+			that later */
+		mpPutBack(mpp, d, 2);
+	}	
+	if (out && outSpace) {
+		char *oout = out;
+		out[outLen] = '\0';
+		out = (char *) realloc(out, outLen + 1);
+		if (!out) {
+			/* Surprising if it happens; and not fatal! We were
+				just trying to give some space back. We can
+				keep it if we have to. */
+			out = oout;
+		}
+		*outP = out;
+	}
+	if (bodyLengthP) {
+		*bodyLengthP = outLen;
+	}
+	return cgiParseSuccess;
+outOfMemory:
+	result = cgiParseMemory;
+	if (outP) {
+		if (out) {
+			free(out);
+		}
+		*outP = '\0';	
+	}
+error:
+	if (bodyLengthP) {
+		*bodyLengthP = 0;
+	}
+	if (out) {
+		free(out);
+	}
+	if (outP) {
+		*outP = 0;	
+	}
+	return result;
+}
+
+static void decomposeValue(char *value,
+	char *mvalue, int mvalueSpace,
+	char **argNames,
+	char **argValues,
+	int argValueSpace)
+{
+	char argName[1024];
+	int argNameSpace = sizeof(argName);
+	int argNameLen = 0;
+	int mvalueLen = 0;
+	char *argValue;
+	int argNum = 0;
+	while (argNames[argNum]) {
+		if (argValueSpace) {
+			argValues[argNum][0] = '\0';
+		}
+		argNum++;
+	}
+	while (isspace(*value)) {
+		value++;
+	}
+	/* Quoted mvalue */
+	if (*value == '\"') {
+		value++;
+		while ((*value) && (*value != '\"')) {
+			APPEND(mvalue, *value);
+			value++;
+		}
+		while ((*value) && (*value != ';')) {
+			value++;
+		}
+	} else {
+		/* Unquoted mvalue */
+		while ((*value) && (*value != ';')) {
+			APPEND(mvalue, *value);
+			value++;
+		}	
+	}	
+	if (mvalueSpace) {
+		mvalue[mvalueLen] = '\0';
+	}
+	while (*value == ';') {
+		int argNum;
+		int argValueLen = 0;
+		/* Skip the ; between parameters */
+		value++;
+		/* Now skip leading whitespace */
+		while ((*value) && (isspace(*value))) { 
+			value++;
+		}
+		/* Now read the parameter name */
+		argNameLen = 0;
+		while ((*value) && (isalnum(*value))) {
+			APPEND(argName, *value);
+			value++;
+		}
+		if (argNameSpace) {
+			argName[argNameLen] = '\0';
+		}
+		while ((*value) && isspace(*value)) {
+			value++;
+		}
+		if (*value != '=') {
+			/* Malformed line */
+			return;	
+		}
+		value++;
+		while ((*value) && isspace(*value)) {
+			value++;
+		}
+		/* Find the parameter in the argument list, if present */
+		argNum = 0;
+		argValue = 0;
+		while (argNames[argNum]) {
+			if (cgiStrEqNc(argName, argNames[argNum])) {
+				argValue = argValues[argNum];
+				break;
+			}
+			argNum++;
+		}		
+		/* Finally, read the parameter value */
+		if (*value == '\"') {
+			value++;
+			while ((*value) && (*value != '\"')) {
+				if (argValue) {
+					APPEND(argValue, *value);
+				}
+				value++;
+			}
+			while ((*value) && (*value != ';')) {
+				value++;
+			}
+		} else {
+			/* Unquoted value */
+			while ((*value) && (*value != ';')) {
+				if (argNames[argNum]) {
+					APPEND(argValue, *value);
+				}
+				value++;
+			}	
+		}	
+		if (argValueSpace) {
+			argValue[argValueLen] = '\0';
+		}
+	}	 	
+}
+
+static int readHeaderLine(
+	mpStreamPtr mpp,
+	char *attr,
+	int attrSpace,
+	char *value,
+	int valueSpace)
+{	
+	int attrLen = 0;
+	int valueLen = 0;
+	int valueFound = 0;
+	while (1) {
+		char d[1];
+		int got = mpRead(mpp, d, 1);
+		if (got != 1) {	
+			return 0;
+		}
+		if (d[0] == '\r') {
+			got = mpRead(mpp, d, 1);
+			if (got == 1) {	
+				if (d[0] == '\n') {
+					/* OK */
+				} else {
+					mpPutBack(mpp, d, 1);
+				}
+			}
+			break;
+		} else if (d[0] == '\n') {
+			break;
+		} else if ((d[0] == ':') && attrLen) {
+			valueFound = 1;
+			while (mpRead(mpp, d, 1) == 1) {
+				if (!isspace(d[0])) {
+					mpPutBack(mpp, d, 1);
+					break;
+				} 
+			}
+		} else if (!valueFound) {
+			if (!isspace(*d)) {
+				if (attrLen < (attrSpace - 1)) {
+					attr[attrLen++] = *d;
+				}
+			}		
+		} else if (valueFound) {	
+			if (valueLen < (valueSpace - 1)) {
+				value[valueLen++] = *d;
+			}
+		}
+	}
+	if (attrSpace) {
+		attr[attrLen] = '\0';
+	}
+	if (valueSpace) {
+		value[valueLen] = '\0';
+	}
+	if (attrLen && valueLen) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+static cgiParseResultType cgiParseGetFormInput() {
+	return cgiParseFormInput(cgiQueryString, cgiContentLength);
+}
+
+typedef enum {
+	cgiEscapeRest,
+	cgiEscapeFirst,
+	cgiEscapeSecond
+} cgiEscapeState;
+
+typedef enum {
+	cgiUnescapeSuccess,
+	cgiUnescapeMemory
+} cgiUnescapeResultType;
+
+static cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len);
+
+static cgiParseResultType cgiParseFormInput(char *data, int length) {
+	/* Scan for pairs, unescaping and storing them as they are found. */
+	int pos = 0;
+	cgiFormEntry *n;
+	cgiFormEntry *l = 0;
+	while (pos != length) {
+		int foundEq = 0;
+		int foundAmp = 0;
+		int start = pos;
+		int len = 0;
+		char *attr;
+		char *value;
+		while (pos != length) {
+			if (data[pos] == '=') {
+				foundEq = 1;
+				pos++;
+				break;
+			}
+			pos++;
+			len++;
+		}
+		if (!foundEq) {
+			break;
+		}
+		if (cgiUnescapeChars(&attr, data+start, len)
+			!= cgiUnescapeSuccess) {
+			return cgiParseMemory;
+		}	
+		start = pos;
+		len = 0;
+		while (pos != length) {
+			if (data[pos] == '&') {
+				foundAmp = 1;
+				pos++;
+				break;
+			}
+			pos++;
+			len++;
+		}
+		/* The last pair probably won't be followed by a &, but
+			that's fine, so check for that after accepting it */
+		if (cgiUnescapeChars(&value, data+start, len)
+			!= cgiUnescapeSuccess) {
+			free(attr);
+			return cgiParseMemory;
+		}	
+		/* OK, we have a new pair, add it to the list. */
+		n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));	
+		if (!n) {
+			free(attr);
+			free(value);
+			return cgiParseMemory;
+		}
+		n->attr = attr;
+		n->value = value;
+		n->valueLength = strlen(n->value);
+		n->fileName = (char *) malloc(1);
+		if (!n->fileName) {
+			free(attr);
+			free(value);
+			free(n);
+			return cgiParseMemory;
+		}	
+		n->fileName[0] = '\0';
+		n->contentType = (char *) malloc(1);
+		if (!n->contentType) {
+			free(attr);
+			free(value);
+			free(n->fileName);
+			free(n);
+			return cgiParseMemory;
+		}	
+		n->contentType[0] = '\0';
+		n->tfileName = (char *) malloc(1);
+		if (!n->tfileName) {
+			free(attr);
+			free(value);
+			free(n->fileName);
+			free(n->contentType);
+			free(n);
+			return cgiParseMemory;
+		}	
+		n->tfileName[0] = '\0';
+		n->next = 0;
+		if (!l) {
+			cgiFormEntryFirst = n;
+		} else {
+			l->next = n;
+		}
+		l = n;
+		if (!foundAmp) {
+			break;
+		}			
+	}
+	return cgiParseSuccess;
+}
+
+static int cgiHexValue[256];
+
+cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len) {
+	char *s;
+	cgiEscapeState escapeState = cgiEscapeRest;
+	int escapedValue = 0;
+	int srcPos = 0;
+	int dstPos = 0;
+	s = (char *) malloc(len + 1);
+	if (!s) {
+		return cgiUnescapeMemory;
+	}
+	while (srcPos < len) {
+		int ch = cp[srcPos];
+		if(cgiTreatUrlEncoding==1)
+		switch (escapeState) {
+			case cgiEscapeRest:
+			if (ch == '%') {
+				escapeState = cgiEscapeFirst;
+			} else if (ch == '+') {
+				s[dstPos++] = ' ';
+			} else {
+				s[dstPos++] = ch;
+			}
+			break;
+			case cgiEscapeFirst:
+			escapedValue = cgiHexValue[ch] << 4;	
+			escapeState = cgiEscapeSecond;
+			break;
+			case cgiEscapeSecond:
+			escapedValue += cgiHexValue[ch];
+			s[dstPos++] = escapedValue;
+			escapeState = cgiEscapeRest;
+			break;
+		}
+		else
+		  s[dstPos++] = ch;
+		srcPos++;
+	}
+	s[dstPos] = '\0';
+	*sp = s;
+	return cgiUnescapeSuccess;
+}		
+	
+static void cgiSetupConstants() {
+	int i;
+	for (i=0; (i < 256); i++) {
+		cgiHexValue[i] = 0;
+	}
+	cgiHexValue['0'] = 0;	
+	cgiHexValue['1'] = 1;	
+	cgiHexValue['2'] = 2;	
+	cgiHexValue['3'] = 3;	
+	cgiHexValue['4'] = 4;	
+	cgiHexValue['5'] = 5;	
+	cgiHexValue['6'] = 6;	
+	cgiHexValue['7'] = 7;	
+	cgiHexValue['8'] = 8;	
+	cgiHexValue['9'] = 9;
+	cgiHexValue['A'] = 10;
+	cgiHexValue['B'] = 11;
+	cgiHexValue['C'] = 12;
+	cgiHexValue['D'] = 13;
+	cgiHexValue['E'] = 14;
+	cgiHexValue['F'] = 15;
+	cgiHexValue['a'] = 10;
+	cgiHexValue['b'] = 11;
+	cgiHexValue['c'] = 12;
+	cgiHexValue['d'] = 13;
+	cgiHexValue['e'] = 14;
+	cgiHexValue['f'] = 15;
+}
+
+static void cgiFreeResources() {
+	cgiFormEntry *c = cgiFormEntryFirst;
+	cgiFormEntry *n;
+	while (c) {
+		n = c->next;
+		free(c->attr);
+		free(c->value);
+		free(c->fileName);
+		free(c->contentType);
+		if (strlen(c->tfileName)) {
+			unlink(c->tfileName);
+		}
+		free(c->tfileName);
+		free(c);
+		c = n;
+	}
+	/* If the cgi environment was restored from a saved environment,
+		then these are in allocated space and must also be freed */
+	if (cgiRestored) {
+		free(cgiServerSoftware);
+		free(cgiServerName);
+		free(cgiGatewayInterface);
+		free(cgiServerProtocol);
+		free(cgiServerPort);
+		free(cgiRequestMethod);
+		free(cgiPathInfo);
+		free(cgiPathTranslated);
+		free(cgiScriptName);
+		free(cgiQueryString);
+		free(cgiRemoteHost);
+		free(cgiRemoteAddr);
+		free(cgiAuthType);
+		free(cgiRemoteUser);
+		free(cgiRemoteIdent);
+		free(cgiContentType);
+		free(cgiAccept);
+		free(cgiUserAgent);
+		free(cgiReferrer);
+	}
+	/* 2.0: to clean up the environment for cgiReadEnvironment,
+		we must set these correctly */
+	cgiFormEntryFirst = 0;
+	cgiRestored = 0;
+}
+
+static cgiFormResultType cgiFormEntryString(
+	cgiFormEntry *e, char *result, int max, int newlines);
+
+static cgiFormEntry *cgiFormEntryFindFirst(char *name);
+static cgiFormEntry *cgiFormEntryFindNext();
+
+cgiFormResultType cgiFormString(
+        char *name, char *result, int max) {
+	cgiFormEntry *e;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		strcpy(result, "");
+		return cgiFormNotFound;
+	}
+	return cgiFormEntryString(e, result, max, 1);
+}
+
+cgiFormResultType cgiFormFileName(
+	char *name, char *result, int resultSpace)
+{
+	cgiFormEntry *e;
+	int resultLen = 0;
+	char *s;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		strcpy(result, "");
+		return cgiFormNotFound;
+	}
+	s = e->fileName;
+	while (*s) {
+		APPEND(result, *s);
+		s++;
+	}	
+	if (resultSpace) {
+		result[resultLen] = '\0';
+	}
+	if (!strlen(e->fileName)) {
+		return cgiFormNoFileName;
+	} else if (((int) strlen(e->fileName)) > (resultSpace - 1)) {
+		return cgiFormTruncated;
+	} else {
+		return cgiFormSuccess;
+	}
+}
+
+cgiFormResultType cgiFormFileContentType(
+	char *name, char *result, int resultSpace)
+{
+	cgiFormEntry *e;
+	int resultLen = 0;
+	char *s;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		if (resultSpace) {
+			result[0] = '\0';
+		}	
+		return cgiFormNotFound;
+	}
+	s = e->contentType;
+	while (*s) {
+		APPEND(result, *s);
+		s++;
+	}	
+	if (resultSpace) {
+		result[resultLen] = '\0';
+	}
+	if (!strlen(e->contentType)) {
+		return cgiFormNoContentType;
+	} else if (((int) strlen(e->contentType)) > (resultSpace - 1)) {
+		return cgiFormTruncated;
+	} else {
+		return cgiFormSuccess;
+	}
+}
+
+cgiFormResultType cgiFormFileSize(
+	char *name, int *sizeP)
+{
+	cgiFormEntry *e;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		if (sizeP) {
+			*sizeP = 0;
+		}
+		return cgiFormNotFound;
+	} else if (!strlen(e->tfileName)) {
+		if (sizeP) {
+			*sizeP = 0;
+		}
+		return cgiFormNotAFile;
+	} else {
+		if (sizeP) {
+			*sizeP = e->valueLength;
+		}
+		return cgiFormSuccess;
+	}
+}
+
+typedef struct cgiFileStruct {
+	FILE *in;
+} cgiFile;
+
+cgiFormResultType cgiFormFileOpen(
+	char *name, cgiFilePtr *cfpp)
+{
+	cgiFormEntry *e;
+	cgiFilePtr cfp;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		*cfpp = 0;
+		return cgiFormNotFound;
+	}
+	if (!strlen(e->tfileName)) {
+		*cfpp = 0;
+		return cgiFormNotAFile;
+	}
+	cfp = (cgiFilePtr) malloc(sizeof(cgiFile));
+	if (!cfp) {
+		*cfpp = 0;
+		return cgiFormMemory;
+	}
+	cfp->in = fopen(e->tfileName, "rb");
+	if (!cfp->in) {
+		free(cfp);
+		return cgiFormIO;
+	}
+	*cfpp = cfp;
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiFormFileRead(
+	cgiFilePtr cfp, char *buffer, 
+	int bufferSize, int *gotP)
+{
+	int got = 0;
+	if (!cfp) {
+		return cgiFormOpenFailed;
+	}
+	got = fread(buffer, 1, bufferSize, cfp->in);
+	if (got <= 0) {
+		return cgiFormEOF;
+	}
+	*gotP = got;
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiFormFileClose(cgiFilePtr cfp)
+{
+	if (!cfp) {
+		return cgiFormOpenFailed;
+	}
+	fclose(cfp->in);
+	free(cfp);
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiFormStringNoNewlines(
+        char *name, char *result, int max) {
+	cgiFormEntry *e;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		strcpy(result, "");
+		return cgiFormNotFound;
+	}
+	return cgiFormEntryString(e, result, max, 0);
+}
+
+cgiFormResultType cgiFormStringMultiple(
+        char *name, char ***result) {
+	char **stringArray;
+	cgiFormEntry *e;
+	int i;
+	int total = 0;
+	/* Make two passes. One would be more efficient, but this
+		function is not commonly used. The select menu and
+		radio box functions are faster. */
+	e = cgiFormEntryFindFirst(name);
+	if (e != 0) {
+		do {
+			total++;
+		} while ((e = cgiFormEntryFindNext()) != 0); 
+	}
+	stringArray = (char **) malloc(sizeof(char *) * (total + 1));
+	if (!stringArray) {
+		*result = 0;
+		return cgiFormMemory;
+	}
+	/* initialize all entries to null; the last will stay that way */
+	for (i=0; (i <= total); i++) {
+		stringArray[i] = 0;
+	}
+	/* Now go get the entries */
+	e = cgiFormEntryFindFirst(name);
+#ifdef CGICDEBUG
+	CGICDEBUGSTART
+	fprintf(dout, "StringMultiple Beginning\n");
+	CGICDEBUGEND
+#endif /* CGICDEBUG */
+	if (e) {
+		i = 0;
+		do {
+			int max = (int) (strlen(e->value) + 1);
+			stringArray[i] = (char *) malloc(max);
+			if (stringArray[i] == 0) {
+				/* Memory problems */
+				cgiStringArrayFree(stringArray);
+				*result = 0;
+				return cgiFormMemory;
+			}	
+			strcpy(stringArray[i], e->value);
+			cgiFormEntryString(e, stringArray[i], max, 1);
+			i++;
+		} while ((e = cgiFormEntryFindNext()) != 0); 
+		*result = stringArray;
+#ifdef CGICDEBUG
+		CGICDEBUGSTART
+		fprintf(dout, "StringMultiple Succeeding\n");
+		CGICDEBUGEND
+#endif /* CGICDEBUG */
+		return cgiFormSuccess;
+	} else {
+		*result = stringArray;
+#ifdef CGICDEBUG
+		CGICDEBUGSTART
+		fprintf(dout, "StringMultiple found nothing\n");
+		CGICDEBUGEND
+#endif /* CGICDEBUG */
+		return cgiFormNotFound;
+	}	
+}
+
+cgiFormResultType cgiFormStringSpaceNeeded(
+        char *name, int *result) {
+	cgiFormEntry *e;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		*result = 1;
+		return cgiFormNotFound; 
+	}
+	*result = ((int) strlen(e->value)) + 1;
+	return cgiFormSuccess;
+}
+
+static cgiFormResultType cgiFormEntryString(
+	cgiFormEntry *e, char *result, int max, int newlines) {
+	char *dp, *sp;
+	int truncated = 0;
+	int len = 0;
+	int avail = max-1;
+	int crCount = 0;
+	int lfCount = 0;	
+	dp = result;
+	sp = e->value;	
+	while (1) {
+		int ch;
+		/* 1.07: don't check for available space now.
+			We check for it immediately before adding
+			an actual character. 1.06 handled the
+			trailing null of the source string improperly,
+			resulting in a cgiFormTruncated error. */
+		ch = *sp;
+		/* Fix the CR/LF, LF, CR nightmare: watch for
+			consecutive bursts of CRs and LFs in whatever
+			pattern, then actually output the larger number 
+			of LFs. Consistently sane, yet it still allows
+			consecutive blank lines when the user
+			actually intends them. */
+		if ((ch == 13) || (ch == 10)) {
+			if (ch == 13) {
+				crCount++;
+			} else {
+				lfCount++;
+			}	
+		} else {
+			if (crCount || lfCount) {
+				int lfsAdd = crCount;
+				if (lfCount > crCount) {
+					lfsAdd = lfCount;
+				}
+				/* Stomp all newlines if desired */
+				if (!newlines) {
+					lfsAdd = 0;
+				}
+				while (lfsAdd) {
+					if (len >= avail) {
+						truncated = 1;
+						break;
+					}
+					*dp = 10;
+					dp++;
+					lfsAdd--;
+					len++;		
+				}
+				crCount = 0;
+				lfCount = 0;
+			}
+			if (ch == '\0') {
+				/* The end of the source string */
+				break;				
+			}	
+			/* 1.06: check available space before adding
+				the character, because a previously added
+				LF may have brought us to the limit */
+			if (len >= avail) {
+				truncated = 1;
+				break;
+			}
+			*dp = ch;
+			dp++;
+			len++;
+		}
+		sp++;	
+	}	
+	*dp = '\0';
+	if (truncated) {
+		return cgiFormTruncated;
+	} else if (!len) {
+		return cgiFormEmpty;
+	} else {
+		return cgiFormSuccess;
+	}
+}
+
+static int cgiFirstNonspaceChar(char *s);
+
+cgiFormResultType cgiFormInteger(
+        char *name, int *result, int defaultV) {
+	cgiFormEntry *e;
+	int ch;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		*result = defaultV;
+		return cgiFormNotFound; 
+	}	
+	if (!strlen(e->value)) {
+		*result = defaultV;
+		return cgiFormEmpty;
+	}
+	ch = cgiFirstNonspaceChar(e->value);
+	if (!(isdigit(ch)) && (ch != '-') && (ch != '+')) {
+		*result = defaultV;
+		return cgiFormBadType;
+	} else {
+		*result = atoi(e->value);
+		return cgiFormSuccess;
+	}
+}
+
+cgiFormResultType cgiFormIntegerBounded(
+        char *name, int *result, int min, int max, int defaultV) {
+	cgiFormResultType error = cgiFormInteger(name, result, defaultV);
+	if (error != cgiFormSuccess) {
+		return error;
+	}
+	if (*result < min) {
+		*result = min;
+		return cgiFormConstrained;
+	} 
+	if (*result > max) {
+		*result = max;
+		return cgiFormConstrained;
+	} 
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiFormDouble(
+        char *name, double *result, double defaultV) {
+	cgiFormEntry *e;
+	int ch;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		*result = defaultV;
+		return cgiFormNotFound; 
+	}	
+	if (!strlen(e->value)) {
+		*result = defaultV;
+		return cgiFormEmpty;
+	} 
+	ch = cgiFirstNonspaceChar(e->value);
+	if (!(isdigit(ch)) && (ch != '.') && (ch != '-') && (ch != '+')) {
+		*result = defaultV;
+		return cgiFormBadType;
+	} else {
+		*result = atof(e->value);
+		return cgiFormSuccess;
+	}
+}
+
+cgiFormResultType cgiFormDoubleBounded(
+        char *name, double *result, double min, double max, double defaultV) {
+	cgiFormResultType error = cgiFormDouble(name, result, defaultV);
+	if (error != cgiFormSuccess) {
+		return error;
+	}
+	if (*result < min) {
+		*result = min;
+		return cgiFormConstrained;
+	} 
+	if (*result > max) {
+		*result = max;
+		return cgiFormConstrained;
+	} 
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiFormSelectSingle(
+	char *name, char **choicesText, int choicesTotal, 
+	int *result, int defaultV) 
+{
+	cgiFormEntry *e;
+	int i;
+	e = cgiFormEntryFindFirst(name);
+#ifdef CGICDEBUG
+	CGICDEBUGSTART
+	fprintf(dout, "%d\n", (int) e);
+	CGICDEBUGEND
+#endif /* CGICDEBUG */
+	if (!e) {
+		*result = defaultV;
+		return cgiFormNotFound;
+	}
+	for (i=0; (i < choicesTotal); i++) {
+#ifdef CGICDEBUG
+		CGICDEBUGSTART
+		fprintf(dout, "%s %s\n", choicesText[i], e->value);
+		CGICDEBUGEND
+#endif /* CGICDEBUG */
+		if (cgiStrEq(choicesText[i], e->value)) {
+#ifdef CGICDEBUG
+			CGICDEBUGSTART
+			fprintf(dout, "MATCH\n");
+			CGICDEBUGEND
+#endif /* CGICDEBUG */
+			*result = i;
+			return cgiFormSuccess;
+		}
+	}
+	*result = defaultV;
+	return cgiFormNoSuchChoice;
+}
+
+cgiFormResultType cgiFormSelectMultiple(
+	char *name, char **choicesText, int choicesTotal, 
+	int *result, int *invalid) 
+{
+	cgiFormEntry *e;
+	int i;
+	int hits = 0;
+	int invalidE = 0;
+	for (i=0; (i < choicesTotal); i++) {
+		result[i] = 0;
+	}
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		*invalid = invalidE;
+		return cgiFormNotFound;
+	}
+	do {
+		int hit = 0;
+		for (i=0; (i < choicesTotal); i++) {
+			if (cgiStrEq(choicesText[i], e->value)) {
+				result[i] = 1;
+				hits++;
+				hit = 1;
+				break;
+			}
+		}
+		if (!(hit)) {
+			invalidE++;
+		}
+	} while ((e = cgiFormEntryFindNext()) != 0);
+
+	*invalid = invalidE;
+
+	if (hits) {
+		return cgiFormSuccess;
+	} else {
+		return cgiFormNotFound;
+	}
+}
+
+cgiFormResultType cgiFormCheckboxSingle(
+	char *name)
+{
+	cgiFormEntry *e;
+	e = cgiFormEntryFindFirst(name);
+	if (!e) {
+		return cgiFormNotFound;
+	}
+	return cgiFormSuccess;
+}
+
+extern cgiFormResultType cgiFormCheckboxMultiple(
+	char *name, char **valuesText, int valuesTotal, 
+	int *result, int *invalid)
+{
+	/* Implementation is identical to cgiFormSelectMultiple. */
+	return cgiFormSelectMultiple(name, valuesText, 
+		valuesTotal, result, invalid);
+}
+
+cgiFormResultType cgiFormRadio(
+	char *name, 
+	char **valuesText, int valuesTotal, int *result, int defaultV)
+{
+	/* Implementation is identical to cgiFormSelectSingle. */
+	return cgiFormSelectSingle(name, valuesText, valuesTotal, 
+		result, defaultV);
+}
+
+cgiFormResultType cgiCookieString(
+	char *name,
+	char *value,
+	int space)
+{
+	char *p = cgiCookie;
+	while (*p) {
+		char *n = name;
+		/* 2.02: if cgiCookie is exactly equal to name, this
+			can cause an overrun. The server probably wouldn't
+			allow it, since a name without values makes no sense 
+			-- but then again it might not check, so this is a
+			genuine security concern. Thanks to Nicolas 
+			Tomadakis. */
+		while (*p == *n) {
+			if ((p == '\0') && (n == '\0')) {
+				/* Malformed cookie header from client */
+				return cgiFormNotFound;
+			}
+			p++;
+			n++;
+		}
+		if ((!*n) && (*p == '=')) {
+			p++;
+			while ((*p != ';') && (*p != '\0') &&
+				(space > 1)) 
+			{
+				*value = *p;
+				value++;
+				p++;
+				space--;
+			}
+			if (space > 0) {
+				*value = '\0';
+			}
+			/* Correct parens: 2.02. Thanks to
+				Mathieu Villeneuve-Belair. */
+			if (!(((*p) == ';') || ((*p) == '\0')))
+			{
+				return cgiFormTruncated;
+			} else {	
+				return cgiFormSuccess;
+			}
+		} else {
+			/* Skip to next cookie */	
+			while (*p) {
+				if (*p == ';') {
+					break;
+				}
+				p++;
+			}
+			if (!*p) {
+				/* 2.01: default to empty */
+				if (space) {
+					*value = '\0';
+				}
+				return cgiFormNotFound;
+			}
+			p++;	
+			/* Allow whitespace after semicolon */
+			while ((*p) && isspace(*p)) {
+				p++;
+			} 
+		}
+	}
+	/* 2.01: actually the above loop never terminates except
+		with a return, but do this to placate gcc */
+	if (space) {
+		*value = '\0';
+	}
+	return cgiFormNotFound;
+}
+
+cgiFormResultType cgiCookieInteger(
+	char *name,
+	int *result,
+	int defaultV)
+{
+	char buffer[256];
+	cgiFormResultType r = 
+		cgiCookieString(name, buffer, sizeof(buffer));
+	if (r != cgiFormSuccess) {
+		*result = defaultV;
+	} else {
+		*result = atoi(buffer);
+	}
+	return r;
+}
+
+void cgiHeaderCookieSetInteger(char *name, int value, int secondsToLive,
+	char *path, char *domain)
+{
+	char svalue[256];
+	sprintf(svalue, "%d", value);
+	cgiHeaderCookieSetString(name, svalue, secondsToLive, path, domain);
+}
+
+char *days[] = {
+	"Sun",
+	"Mon",
+	"Tue",
+	"Wed",
+	"Thu",
+	"Fri",
+	"Sat"
+};
+
+char *months[] = {
+	"Jan",
+	"Feb",
+	"Mar",
+	"Apr",
+	"May",
+	"Jun",
+	"Jul",
+	"Aug",
+	"Sep",
+	"Oct",
+	"Nov",
+	"Dec"
+};
+
+void cgiHeaderCookieSetString(char *name, char *value, int secondsToLive,
+	char *path, char *domain)
+{
+	/* cgic 2.02: simpler and more widely compatible implementation.
+		Thanks to Chunfu Lai. 
+	   cgic 2.03: yes, but it didn't work. Reimplemented by
+		Thomas Boutell. ; after last element was a bug. 
+	   Examples of real world cookies that really work:
+   	   Set-Cookie: MSNADS=UM=; domain=.slate.com; 
+             expires=Tue, 26-Apr-2022 19:00:00 GMT; path=/
+	   Set-Cookie: MC1=V=3&ID=b5bc08af2b8a43ff85fcb5efd8b238f0; 
+             domain=.slate.com; expires=Mon, 04-Oct-2021 19:00:00 GMT; path=/
+	*/
+	time_t now;
+	time_t then;
+	struct tm *gt;
+	time(&now);
+	then = now + secondsToLive;
+	gt = gmtime(&then);
+	fprintf(cgiOut, 
+		"Set-Cookie: %s=%s; domain=%s; expires=%s, %02d-%s-%04d %02d:%02d:%02d GMT; path=%s\r\n",
+		name, value, domain, 
+		days[gt->tm_wday],
+		gt->tm_mday,
+		months[gt->tm_mon],
+		gt->tm_year + 1900, 	
+		gt->tm_hour,
+		gt->tm_min,
+		gt->tm_sec,
+		path);
+}
+
+void cgiHeaderLocation(char *redirectUrl) {
+	fprintf(cgiOut, "Location: %s\r\n\r\n", redirectUrl);
+}
+
+void cgiHeaderStatus(int status, char *statusMessage) {
+	fprintf(cgiOut, "Status: %d %s\r\n\r\n", status, statusMessage);
+}
+
+void cgiHeaderContentType(char *mimeType) {
+	fprintf(cgiOut, "Content-type: %s\r\n\r\n", mimeType);
+}
+
+static int cgiWriteString(FILE *out, char *s);
+
+static int cgiWriteInt(FILE *out, int i);
+
+#define CGIC_VERSION "2.0"
+
+cgiEnvironmentResultType cgiWriteEnvironment(char *filename) {
+	FILE *out;
+	cgiFormEntry *e;
+	/* Be sure to open in binary mode */
+	out = fopen(filename, "wb");
+	if (!out) {
+		/* Can't create file */
+		return cgiEnvironmentIO;
+	}
+	if (!cgiWriteString(out, "CGIC2.0")) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiServerSoftware)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiServerName)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiGatewayInterface)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiServerProtocol)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiServerPort)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiRequestMethod)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiPathInfo)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiPathTranslated)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiScriptName)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiQueryString)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiRemoteHost)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiRemoteAddr)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiAuthType)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiRemoteUser)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiRemoteIdent)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiContentType)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiAccept)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiUserAgent)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiReferrer)) {
+		goto error;
+	}
+	if (!cgiWriteString(out, cgiCookie)) {
+		goto error;
+	}
+	if (!cgiWriteInt(out, cgiContentLength)) {
+		goto error;
+	}
+	e = cgiFormEntryFirst;
+	while (e) {
+		cgiFilePtr fp;
+		if (!cgiWriteString(out, e->attr)) {
+			goto error;
+		}
+		if (!cgiWriteString(out, e->value)) {
+			goto error;
+		}
+		/* New 2.0 fields and file uploads */
+		if (!cgiWriteString(out, e->fileName)) {
+			goto error;
+		}
+		if (!cgiWriteString(out, e->contentType)) {
+			goto error;
+		}
+		if (!cgiWriteInt(out, e->valueLength)) {
+			goto error;
+		}
+		if (cgiFormFileOpen(e->attr, &fp) == cgiFormSuccess) {
+			char buffer[1024];
+			int got;
+			if (!cgiWriteInt(out, 1)) {
+				cgiFormFileClose(fp);
+				goto error;
+			}
+			while (cgiFormFileRead(fp, buffer, 
+				sizeof(buffer), &got) == cgiFormSuccess)
+			{
+				if (((int) fwrite(buffer, 1, got, out)) != got) {
+					cgiFormFileClose(fp);
+					goto error;
+				}
+			}
+			if (cgiFormFileClose(fp) != cgiFormSuccess) {
+				goto error;
+			}
+		} else {
+			if (!cgiWriteInt(out, 0)) {
+				goto error;
+			}
+		}
+		e = e->next;
+	}
+	fclose(out);
+	return cgiEnvironmentSuccess;
+error:
+	fclose(out);
+	/* If this function is not defined in your system,
+		you must substitute the appropriate 
+		file-deletion function. */
+	unlink(filename);
+	return cgiEnvironmentIO;
+}
+
+static int cgiWriteString(FILE *out, char *s) {
+	int len = (int) strlen(s);
+	cgiWriteInt(out, len);
+	if (((int) fwrite(s, 1, len, out)) != len) {
+		return 0;
+	}
+	return 1;
+}
+
+static int cgiWriteInt(FILE *out, int i) {
+	if (!fwrite(&i, sizeof(int), 1, out)) {
+		return 0;
+	}
+	return 1;
+}
+
+static int cgiReadString(FILE *out, char **s);
+
+static int cgiReadInt(FILE *out, int *i);
+
+cgiEnvironmentResultType cgiReadEnvironment(char *filename) {
+	FILE *in;
+	cgiFormEntry *e = 0, *p;
+	char *version;
+	/* Prevent compiler warnings */
+	cgiEnvironmentResultType result = cgiEnvironmentIO;
+	/* Free any existing data first */
+	cgiFreeResources();
+	/* Be sure to open in binary mode */
+	in = fopen(filename, "rb");
+	if (!in) {
+		/* Can't access file */
+		return cgiEnvironmentIO;
+	}
+	if (!cgiReadString(in, &version)) {
+		goto error;
+	}
+	if (strcmp(version, "CGIC" CGIC_VERSION)) {
+		/* 2.02: Merezko Oleg */
+		free(version);
+		return cgiEnvironmentWrongVersion;
+	}	
+	/* 2.02: Merezko Oleg */
+	free(version);
+	if (!cgiReadString(in, &cgiServerSoftware)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiServerName)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiGatewayInterface)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiServerProtocol)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiServerPort)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiRequestMethod)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiPathInfo)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiPathTranslated)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiScriptName)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiQueryString)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiRemoteHost)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiRemoteAddr)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiAuthType)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiRemoteUser)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiRemoteIdent)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiContentType)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiAccept)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiUserAgent)) {
+		goto error;
+	}
+	if (!cgiReadString(in, &cgiReferrer)) {
+		goto error;
+	}
+	/* 2.0 */
+	if (!cgiReadString(in, &cgiCookie)) {
+		goto error;
+	}
+	if (!cgiReadInt(in, &cgiContentLength)) {
+		goto error;
+	}
+	p = 0;
+	while (1) {
+		int fileFlag;
+		e = (cgiFormEntry *) calloc(1, sizeof(cgiFormEntry));
+		if (!e) {
+			cgiFreeResources();
+			fclose(in);
+			return cgiEnvironmentMemory;
+		}
+		memset(e, 0, sizeof(cgiFormEntry));
+		if (!cgiReadString(in, &e->attr)) {
+			/* This means we've reached the end of the list. */
+			/* 2.02: thanks to Merezko Oleg */
+			free(e);
+			break;
+		}
+		if (!cgiReadString(in, &e->value)) {
+			goto outOfMemory;
+		}
+		if (!cgiReadString(in, &e->fileName)) {
+			goto outOfMemory;
+		}
+		if (!cgiReadString(in, &e->contentType)) {
+			goto outOfMemory;
+		}
+		if (!cgiReadInt(in, &e->valueLength)) {
+			goto outOfMemory;
+		}
+		if (!cgiReadInt(in, &fileFlag)) {
+			goto outOfMemory;
+		}
+		if (fileFlag) {
+			char buffer[1024];
+			FILE *out;
+			char tfileName[1024];
+			int got;
+			int len = e->valueLength;
+			if (getTempFileName(tfileName)
+				!= cgiParseSuccess)
+			{
+				result = cgiEnvironmentIO;
+				goto error;
+			}
+			out = fopen(tfileName, "w+b");
+			if (!out) {
+				result = cgiEnvironmentIO;
+				goto error;
+			}
+			while (len > 0) {		
+				/* 2.01: try is a bad variable name in
+					C++, and it wasn't being used
+					properly either */
+				int tryr = len;
+				if (tryr > ((int) sizeof(buffer))) {
+					tryr = sizeof(buffer);
+				}
+				got = fread(buffer, 1, tryr, in);
+				if (got <= 0) {
+					result = cgiEnvironmentIO;
+					fclose(out);
+					unlink(tfileName);
+					goto error;
+				}
+				if (((int) fwrite(buffer, 1, got, out)) != got) {
+					result = cgiEnvironmentIO;
+					fclose(out);
+					unlink(tfileName);
+					goto error;
+				}
+				len -= got;
+			}
+			/* cgic 2.05: should be fclose not rewind */
+			fclose(out);
+			e->tfileName = (char *) malloc((int) strlen(tfileName) + 1);
+			if (!e->tfileName) {
+				result = cgiEnvironmentMemory;
+				unlink(tfileName);
+				goto error;
+			}
+			strcpy(e->tfileName, tfileName);
+		} else {
+			e->tfileName = (char *) malloc(1);
+			if (!e->tfileName) {
+				result = cgiEnvironmentMemory;
+				goto error;
+			}
+		}	
+		e->next = 0;
+		if (p) {
+			p->next = e;
+		} else {
+			cgiFormEntryFirst = e;
+		}	
+		p = e;
+	}
+	fclose(in);
+	cgiRestored = 1;
+	return cgiEnvironmentSuccess;
+outOfMemory:
+	result = cgiEnvironmentMemory;
+error:
+	cgiFreeResources();
+	fclose(in);
+	if (e) {
+		if (e->attr) {
+			free(e->attr);
+		}
+		if (e->value) {
+			free(e->value);
+		}
+		if (e->fileName) {
+			free(e->fileName);
+		}
+		if (e->contentType) {
+			free(e->contentType);
+		}
+		if (e->tfileName) {
+			free(e->tfileName);
+		}
+		free(e);
+	}
+	return result;
+}
+
+static int cgiReadString(FILE *in, char **s) {
+	int len;
+	/* 2.0 fix: test cgiReadInt for failure! */ 
+	if (!cgiReadInt(in, &len)) {
+		return 0;
+	}
+	*s = (char *) malloc(len + 1);
+	if (!(*s)) {
+		return 0;
+	}	
+	if (((int) fread(*s, 1, len, in)) != len) {
+		return 0;
+	}
+	(*s)[len] = '\0';
+	return 1;
+}
+
+static int cgiReadInt(FILE *out, int *i) {
+	if (!fread(i, sizeof(int), 1, out)) {
+		return 0;
+	}
+	return 1;
+}
+
+static int cgiStrEqNc(char *s1, char *s2) {
+	while(1) {
+		if (!(*s1)) {
+			if (!(*s2)) {
+				return 1;
+			} else {
+				return 0;
+			}
+		} else if (!(*s2)) {
+			return 0;
+		}
+		if (isalpha(*s1)) {
+			if (tolower(*s1) != tolower(*s2)) {
+				return 0;
+			}
+		} else if ((*s1) != (*s2)) {
+			return 0;
+		}
+		s1++;
+		s2++;
+	}
+}
+
+static int cgiStrBeginsNc(char *s1, char *s2) {
+	while(1) {
+		if (!(*s2)) {
+			return 1;
+		} else if (!(*s1)) {
+			return 0;
+		}
+		if (isalpha(*s1)) {
+			if (tolower(*s1) != tolower(*s2)) {
+				return 0;
+			}
+		} else if ((*s1) != (*s2)) {
+			return 0;
+		}
+		s1++;
+		s2++;
+	}
+}
+
+static char *cgiFindTarget = 0;
+static cgiFormEntry *cgiFindPos = 0;
+
+static cgiFormEntry *cgiFormEntryFindFirst(char *name) {
+	cgiFindTarget = name;
+	cgiFindPos = cgiFormEntryFirst;
+	return cgiFormEntryFindNext();
+}
+
+static cgiFormEntry *cgiFormEntryFindNext() {
+	while (cgiFindPos) {
+		cgiFormEntry *c = cgiFindPos;
+		cgiFindPos = c->next;
+		if (!strcmp(c -> attr, cgiFindTarget)) {
+			return c;
+		}
+	}
+	return 0;
+}
+
+static int cgiFirstNonspaceChar(char *s) {
+	int len = strspn(s, " \n\r\t");
+	return s[len];
+}
+
+void cgiStringArrayFree(char **stringArray) {
+	char *p;
+	char **arrayItself = stringArray;
+	p = *stringArray;
+	while (p) {
+		free(p);
+		stringArray++;
+		p = *stringArray;
+	}
+	/* 2.0: free the array itself! */
+	free(arrayItself);
+}	
+
+cgiFormResultType cgiCookies(char ***result) {
+	char **stringArray;
+	int i;
+	int total = 0;
+	char *p;
+	char *n;
+	p = cgiCookie;
+	while (*p) {
+		if (*p == '=') {
+			total++;
+		}
+		p++;
+	}
+	stringArray = (char **) malloc(sizeof(char *) * (total + 1));
+	if (!stringArray) {
+		*result = 0;
+		return cgiFormMemory;
+	}
+	/* initialize all entries to null; the last will stay that way */
+	for (i=0; (i <= total); i++) {
+		stringArray[i] = 0;
+	}
+	i = 0;
+	p = cgiCookie;
+	while (*p) {
+		while (*p && isspace(*p)) {
+			p++;
+		}
+		n = p;
+		while (*p && (*p != '=')) {
+			p++;
+		}
+		if (p != n) {
+			stringArray[i] = (char *) malloc((p - n) + 1);
+			if (!stringArray[i]) {
+				cgiStringArrayFree(stringArray);
+				*result = 0;
+				return cgiFormMemory;
+			}	
+			memcpy(stringArray[i], n, p - n);
+			stringArray[i][p - n] = '\0';
+			i++;
+		}
+		while (*p && (*p != ';')) {
+			p++;	
+		}
+		if (!*p) {
+			break;
+		}
+		if (*p == ';') {
+			p++;
+		}
+	}
+	*result = stringArray;
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiFormEntries(char ***result) {
+	char **stringArray;
+	cgiFormEntry *e, *pe;
+	int i;
+	int total = 0;
+	e = cgiFormEntryFirst;
+	while (e) {
+		/* Don't count a field name more than once if
+			multiple values happen to be present for it */
+		pe = cgiFormEntryFirst;
+		while (pe != e) {
+			if (!strcmp(e->attr, pe->attr)) {
+				goto skipSecondValue;
+			}
+			pe = pe->next;					
+		}
+		total++;
+skipSecondValue:
+		e = e->next;
+	}
+	stringArray = (char **) malloc(sizeof(char *) * (total + 1));
+	if (!stringArray) {
+		*result = 0;
+		return cgiFormMemory;
+	}
+	/* initialize all entries to null; the last will stay that way */
+	for (i=0; (i <= total); i++) {
+		stringArray[i] = 0;
+	}
+	/* Now go get the entries */
+	e = cgiFormEntryFirst;
+	i = 0;
+	while (e) {
+		int space;
+		/* Don't return a field name more than once if
+			multiple values happen to be present for it */
+		pe = cgiFormEntryFirst;
+		while (pe != e) {
+			if (!strcmp(e->attr, pe->attr)) {
+				goto skipSecondValue2;
+			}
+			pe = pe->next;					
+		}		
+		space = (int) strlen(e->attr) + 1;
+		stringArray[i] = (char *) malloc(space);
+		if (stringArray[i] == 0) {
+			/* Memory problems */
+			cgiStringArrayFree(stringArray);
+			*result = 0;
+			return cgiFormMemory;
+		}	
+		strcpy(stringArray[i], e->attr);
+		i++;
+skipSecondValue2:
+		e = e->next;
+	}
+	*result = stringArray;
+	return cgiFormSuccess;
+}
+
+#define TRYPUTC(ch) \
+	{ \
+		if (putc((ch), cgiOut) == EOF) { \
+			return cgiFormIO; \
+		} \
+	} 
+
+cgiFormResultType cgiHtmlEscapeData(char *data, int len)
+{
+	while (len--) {
+		if (*data == '<') {
+			TRYPUTC('&');
+			TRYPUTC('l');
+			TRYPUTC('t');
+			TRYPUTC(';');
+		} else if (*data == '&') {
+			TRYPUTC('&');
+			TRYPUTC('a');
+			TRYPUTC('m');
+			TRYPUTC('p');
+			TRYPUTC(';');
+		} else if (*data == '>') {
+			TRYPUTC('&');
+			TRYPUTC('g');
+			TRYPUTC('t');
+			TRYPUTC(';');
+		} else {
+			TRYPUTC(*data);
+		}
+		data++;
+	}
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiHtmlEscape(char *s)
+{
+	return cgiHtmlEscapeData(s, (int) strlen(s));
+}
+
+/* Output data with the " character HTML-escaped, and no
+	other characters escaped. This is useful when outputting
+	the contents of a tag attribute such as 'href' or 'src'.
+	'data' is not null-terminated; 'len' is the number of
+	bytes in 'data'. Returns cgiFormIO in the event
+	of error, cgiFormSuccess otherwise. */
+cgiFormResultType cgiValueEscapeData(char *data, int len)
+{
+	while (len--) {
+		if (*data == '\"') {
+			TRYPUTC('&');
+			TRYPUTC('#');
+			TRYPUTC('3');
+			TRYPUTC('4');
+			TRYPUTC(';');
+		} else {
+			TRYPUTC(*data);
+		}
+		data++;
+	}
+	return cgiFormSuccess;
+}
+
+cgiFormResultType cgiValueEscape(char *s)
+{
+	return cgiValueEscapeData(s, (int) strlen(s));
+}
+
+
Index: /tags/rel-1.7.0/thirds/cgic206/cgic.h
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/cgic.h	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/cgic.h	(revision 942)
@@ -0,0 +1,457 @@
+/* The CGI_C library, by Thomas Boutell, version 2.01. CGI_C is intended
+	to be a high-quality API to simplify CGI programming tasks. */
+
+/* Make sure this is only included once. */
+
+#ifndef CGI_C
+#define CGI_C 1
+
+/* Bring in standard I/O since some of the functions refer to
+	types defined by it, such as FILE *. */
+
+#include "fcgi_stdio.h"
+//#include <stdio.h>
+
+/* The various CGI environment variables. Instead of using getenv(),
+	the programmer should refer to these, which are always
+	valid null-terminated strings (they may be empty, but they 
+	will never be null). If these variables are used instead
+	of calling getenv(), then it will be possible to save
+	and restore CGI environments, which is highly convenient
+	for debugging. */
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiServerSoftware;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiServerName;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiGatewayInterface;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiServerProtocol;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiServerPort;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiRequestMethod;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiPathInfo;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiPathTranslated;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiScriptName;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiQueryString;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiRemoteHost;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiRemoteAddr;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiAuthType;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiRemoteUser;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiRemoteIdent;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiContentType;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiAccept;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiUserAgent;
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiReferrer;
+
+/* Cookies as sent to the server. You can also get them
+	individually, or as a string array; see the documentation. */
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiCookie;
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+char *cgiSid;
+
+/* A macro providing the same incorrect spelling that is
+	found in the HTTP/CGI specifications */
+#define cgiReferer cgiReferrer
+
+/* The number of bytes of data received.
+	Note that if the submission is a form submission
+	the library will read and parse all the information
+	directly from cgiIn; the programmer need not do so. */
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+int cgiContentLength;
+
+/* Pointer to CGI output. The cgiHeader functions should be used
+	first to output the mime headers; the output HTML
+	page, GIF image or other web document should then be written
+	to cgiOut by the programmer. In the standard CGIC library,
+	cgiOut is always equivalent to stdout. */
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+FILE *cgiOut;
+
+/* Pointer to CGI input. The programmer does not read from this.
+	We have continued to export it for backwards compatibility
+	so that cgic 1.x applications link properly. */
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+FILE *cgiIn;
+
+/* Possible return codes from the cgiForm family of functions (see below). */
+
+typedef enum {
+	cgiFormSuccess,
+	cgiFormTruncated,
+	cgiFormBadType,
+	cgiFormEmpty,
+	cgiFormNotFound,
+	cgiFormConstrained,
+	cgiFormNoSuchChoice,
+	cgiFormMemory,
+	cgiFormNoFileName,
+	cgiFormNoContentType,
+	cgiFormNotAFile,
+	cgiFormOpenFailed,
+	cgiFormIO,
+	cgiFormEOF
+} cgiFormResultType;
+
+/* These functions are used to retrieve form data. See
+	cgic.html for documentation. */
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormString(
+	char *name, char *result, int max);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormStringNoNewlines(
+	char *name, char *result, int max);
+
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormStringSpaceNeeded(
+	char *name, int *length);
+
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormStringMultiple(
+	char *name, char ***ptrToStringArray);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+void cgiStringArrayFree(char **stringArray);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormInteger(
+	char *name, int *result, int defaultV);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormIntegerBounded(
+	char *name, int *result, int min, int max, int defaultV);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormDouble(
+	char *name, double *result, double defaultV);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormDoubleBounded(
+	char *name, double *result, double min, double max, double defaultV);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormSelectSingle(
+	char *name, char **choicesText, int choicesTotal, 
+	int *result, int defaultV);	
+
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormSelectMultiple(
+	char *name, char **choicesText, int choicesTotal, 
+	int *result, int *invalid);
+
+/* Just an alias; users have asked for this */
+#define cgiFormSubmitClicked cgiFormCheckboxSingle
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormCheckboxSingle(
+	char *name);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormCheckboxMultiple(
+	char *name, char **valuesText, int valuesTotal, 
+	int *result, int *invalid);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormRadio(
+	char *name, char **valuesText, int valuesTotal, 
+	int *result, int defaultV);	
+
+/* The paths returned by this function are the original names of files
+	as reported by the uploading web browser and shoult NOT be
+	blindly assumed to be "safe" names for server-side use! */
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormFileName(
+	char *name, char *result, int max);
+
+/* The content type of the uploaded file, as reported by the browser.
+	It should NOT be assumed that browsers will never falsify
+	such information. */
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormFileContentType(
+	char *name, char *result, int max);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormFileSize(
+	char *name, int *sizeP);
+
+typedef struct cgiFileStruct *cgiFilePtr;
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormFileOpen(
+	char *name, cgiFilePtr *cfpp);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormFileRead(
+	cgiFilePtr cfp, char *buffer, int bufferSize, int *gotP);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormFileClose(
+	cgiFilePtr cfp);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiCookieString(
+	char *name, char *result, int max);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiCookieInteger(
+	char *name, int *result, int defaultV);
+
+cgiFormResultType cgiCookies(
+	char ***ptrToStringArray);
+
+/* path can be null or empty in which case a path of / (entire site) is set. 
+	domain can be a single web site; if it is an entire domain, such as
+	'boutell.com', it should begin with a dot: '.boutell.com' */
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+void cgiHeaderCookieSetString(char *name, char *value, 
+	int secondsToLive, char *path, char *domain);
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+void cgiHeaderCookieSetInteger(char *name, int value,
+	int secondsToLive, char *path, char *domain);
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+void cgiHeaderLocation(char *redirectUrl);
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+void cgiHeaderStatus(int status, char *statusMessage);
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+void cgiHeaderContentType(char *mimeType);
+
+typedef enum {
+	cgiEnvironmentIO,
+	cgiEnvironmentMemory,
+	cgiEnvironmentSuccess,
+	cgiEnvironmentWrongVersion
+} cgiEnvironmentResultType;
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiEnvironmentResultType cgiWriteEnvironment(char *filename);
+extern cgiEnvironmentResultType cgiReadEnvironment(char *filename);
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+int cgiMain();
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+int cgiMain_init();
+
+
+extern 
+#ifdef __cplusplus
+"C" 
+#endif
+cgiFormResultType cgiFormEntries(
+	char ***ptrToStringArray);
+
+/* Output string with the <, &, and > characters HTML-escaped. 
+	's' is null-terminated. Returns cgiFormIO in the event
+	of error, cgiFormSuccess otherwise. */
+cgiFormResultType cgiHtmlEscape(char *s);
+
+/* Output data with the <, &, and > characters HTML-escaped. 
+	'data' is not null-terminated; 'len' is the number of
+	bytes in 'data'. Returns cgiFormIO in the event
+	of error, cgiFormSuccess otherwise. */
+cgiFormResultType cgiHtmlEscapeData(char *data, int len);
+
+/* Output string with the " character HTML-escaped, and no
+	other characters escaped. This is useful when outputting
+	the contents of a tag attribute such as 'href' or 'src'.
+	's' is null-terminated. Returns cgiFormIO in the event
+	of error, cgiFormSuccess otherwise. */
+cgiFormResultType cgiValueEscape(char *s);
+
+/* Output data with the " character HTML-escaped, and no
+	other characters escaped. This is useful when outputting
+	the contents of a tag attribute such as 'href' or 'src'.
+	'data' is not null-terminated; 'len' is the number of
+	bytes in 'data'. Returns cgiFormIO in the event
+	of error, cgiFormSuccess otherwise. */
+cgiFormResultType cgiValueEscapeData(char *data, int len);
+
+#endif /* CGI_C */
+
Index: /tags/rel-1.7.0/thirds/cgic206/cgic.html
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/cgic.html	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/cgic.html	(revision 942)
@@ -0,0 +1,2116 @@
+<html>
+<head>
+<title>cgic: an ANSI C library for CGI Programming</title>
+</head>
+<body>
+<h1>cgic 2.05: an ANSI C library for CGI Programming</h1>
+<h2>By <a href="http://www.boutell.com/boutell/">Thomas Boutell</a></h2>
+<em><a href="http://www.boutell.com/cgic/">
+The LATEST documentation is available here. Check often
+for new releases.</a></em>
+<blockquote>
+<strong>IMPORTANT NOTICES:</strong>
+<p>
+If you have CGIC 1.05 or earlier, you should upgrade to CGIC 1.07,
+or to CGIC 2.02 or better, in order to obtain important security fixes.
+<p>
+If you have CGIC 2.0 or CGIC 2.01 and you use the cgiCookie routines, 
+you should upgrade to CGIC 2.02 or better, in order to obtain
+important security fixes.
+</blockquote>
+<h3>Table of Contents</h3>
+<ul>
+<li><a href="#credits">Credits and license terms</a>
+<li><a href="#support">How to get support</a>
+<li><a href="#whatsnew205">What's new in version XYZ of CGIC?</a>
+<li><a href="#whatis">What is cgic?</a>
+<li><a href="#obtain">Obtaining cgic</a>
+<li><a href="#build">Building and testing cgic: a sample application</a>
+<li><a href="#nocompile">What to do if it won't compile</a>
+<li><a href="#howto">How to write a cgic application</a>
+<li><a href="#images">How can I generate images from my cgic application?</a>
+<li><a href="#debug">CGI debugging features: using capture</a>
+<li><a href="#functions">cgic function reference</a>
+<li><a href="#variables">cgic variable reference</a>
+<li><a href="#resultcodes">cgic result code reference</a>
+<li><a href="#index">cgic quick index</a>
+</ul>
+
+<h3><a name="credits">Credits and License Terms</a></h3>
+
+cgic can be used free of charge, <strong>provided that a
+credit notice is provided online.</strong> Alternatively,
+a nonexclusive Commercial License can be purchased, which
+grants the right to use cgic without a public credit notice.
+<p>
+Please see the file
+<code><a href="license.txt">license.txt</a></code>
+for the details of the Basic License and Commercial License,
+including ordering information for the Commercial License.
+<p>
+Thanks are due to Robert Gustavsson, Ken Holervich, Bob Nestor, 
+Jon Ribbens, Thomas Strangert, Wu Yongwei, and other CGIC users 
+who have corresponded over the years. Although the implementation
+of multipart/form-data file upload support in CGIC 2.x is my own, 
+I particularly wish to thank those who submitted their own 
+implementations of this feature.
+<h3><a name="support">How to Get Support</a></h3>
+<blockquote>
+<h4>STOP! READ THIS FIRST! REALLY!</h4>
+    Are you getting a "server error," indicating that your web server
+    "cannot allow POST to this URL," or a similar message? <strong>YOU MUST
+    CONFIGURE YOUR WEB SERVER TO ALLOW CGI PROGRAMS, AND YOU MUST
+    INSTALL CGI PROGRAMS IN THE LOCATION (OR WITH THE EXTENSION) THAT
+    YOUR WEB SERVER EXPECTS TO SEE.</strong> Please don't send me email about
+    this, unless you wish me to configure your web server for you; I can
+    certainly do that for $50/hr, but you can probably straighten this out
+    yourself or have your web server administrator do it.
+</blockquote>
+<h4>Free Support</h4>
+Please submit support inquiries about CGIC via our                              <a href="http://www.boutell.com/contact/">contact page</a>.
+Please note that we receive a large volume of inquiries and cannot always
+respond personally. Sometimes
+the response must take the form of an eventual
+new release or an addition to a FAQ or other document, as opposed to an
+detailed individual response.
+<h4>Hourly Support</h4>
+Those requiring support in detail may arrange for direct support
+from the author, Thomas Boutell, at the rate of $50/hr, billed
+directly by credit card. To make arrangements, contact us via our
+our <a href="https://www.boutell.com/freeform/">secure
+message page</a>. To avoid delay, be sure to specifically mention
+that you wish to purchase CGIC support at the hourly rate above.
+<h3><a name="whatsnew205">What's new in version 2.05?</a></h3>
+Uploaded files properly closed; corrects a resource leak and enables
+file uploads to work properly on platforms with particular file
+locking semantics.
+<h3><a name="whatsnew204">What's new in version 2.04?</a></h3>
+Documentation fixes: the cgiHtmlEscape, cgiHtmlEscapeData,
+cgiValueEscape, and cgiValueEscapeData routines were named
+incorrectly in the manual. No code changes in version 2.04.
+<h3><a name="whatsnew203">What's new in version 2.03?</a></h3>
+<ul>
+<li>Support for setting cookies has been reimplemented. The new
+code closely follows the actual practice of web sites that successfully
+use cookies, rather than attempting to implement the specification.
+The new code can successfully set more than one cookie at a time in
+typical web browsers.
+</ul>
+<h3><a name="whatsnew202">What's new in version 2.02?</a></h3>
+<ul>
+<li>In CGIC 2.0 and 2.01, if the HTTP_COOKIE environment variable
+was exactly equal to the name of a cookie requested with cgiCookieString,
+with no value or equal sign or other characters present, a buffer
+overrun could take place. This was not normal behavior and it is
+unknown whether any actual web server would allow it to occur, however
+we have of course released a patch to correct it. 
+Thanks to Nicolas Tomadakis.
+<li>cgiCookieString returned cgiFormTruncated when cgiFormSuccess would
+be appropriate. Fixed; thanks to Mathieu Villeneuve-Belair.
+<li>Cookies are now set using a simpler Set-Cookie: header, and with
+one header line per cookie, based on data collected by Chunfu Lai. 
+<li>Memory leaks in cgiReadEnvironment fixed by Merezko Oleg. These
+memory leaks were <em>not</em> experienced in a normal CGI situation, only
+when reading a saved CGI environment.
+</ul>
+<h3><a name="whatsnew201">What's new in version 2.01?</a></h3>
+<ul>
+<li>Makefile supports "make install"
+<li>Compiles without warnings under both C and C++ with strict
+warnings and strict ANSI compliance enabled
+<li>Builds out of the box on Windows (#include &lt;fcntl.h&gt; was needed)
+<li>Rare problem in cgiReadEnvironment corrected; no impact on
+normal CGI operations
+<li>cgiCookieString now sets the result to an empty string
+when returning cgiFormNotFound
+<li>Minor code cleanups
+</ul>
+<h3><a name="whatsnew200">What's new in version 2.0?</a></h3>
+1. CGIC 2.0 provides support for file upload fields. User-uploaded
+files are kept in temporary files, to avoid the use of
+excessive swap space (Solaris users may wish to change the
+<code>cgicTempDir</code> macro in cgic.c before compiling).
+The <code><a href="#cgiFormFileName">cgiFormFileName</a></code>, 
+<code><a href="#cgiFormFileContentType">cgiFormFileContentType</a></code>, 
+<code><a href="#cgiFormFileSize">cgiFormFileSize</a></code>, 
+<code><a href="#cgiFormFileOpen">cgiFormFileOpen</a></code>, 
+<code><a href="#cgiFormFileRead">cgiFormFileRead</a></code>, and
+<code><a href="#cgiFormFileClose">cgiFormFileClose</a></code> functions
+provide a complete interface to this new functionality. Remember,
+the <code>enctype</code> attribute of the <code>form</code> tag
+must be set to <code>multipart/form-data</code> when
+<code>&lt;input type="file"&gt;</code> tags are used.
+<p>
+2. CGIC 2.0 provides support for setting and examining cookies
+(persistent data storage on the browser side).
+The <code><a href="#cgiCookieString">cgiCookieString</a></code>,
+and <code><a href="#cgiCookieInteger">cgiCookieInteger</a></code>
+and <code><a href="#cgiCookies">cgiCookies</a></code>
+functions retrieve cookies. The 
+<code><a href="#cgiHeaderCookieSetString">cgiHeaderCookieSetString</a></code>
+and <code><a href="#cgiHeaderCookieSetInteger">cgiHeaderCookieSetInteger</a></code> functions set cookies.
+<p>
+3. CGIC 2.0 offers a convenient way to retrieve a list of all form fields.
+The new <code><a href="#cgiFormEntries">cgiFormEntries</a></code>
+function performs this operation.
+<p>
+4. CGIC 2.0 provides convenience functions to correctly escape
+text before outputting it as part of HTML, or as part of the 
+value of a tag attribute, such as the <code>HREF</code> or
+<code>VALUE</code> attribute. See 
+<code><a href="#cgiHtmlEscape">cgiHtmlEscape</a></code>,
+<code><a href="#cgiHtmlEscapeData">cgiHtmlEscapeData</a></code>,
+<code><a href="#cgiValueEscape">cgiValueEscape</a></code> and
+<code><a href="#cgiValueEscapeData">cgiValueEscapeData</a></code>.
+<p>
+5. Users have often asked the correct way to determine which submit
+button was clicked. This could always be accomplished in previous versions,
+but CGIC 2.0 also provides 
+<a href="#cgiFormSubmitClicked">cgiFormSubmitClicked</a>,
+a convenient alternate label for the 
+<a href="#cgiFormCheckboxSingle">cgiFormCheckboxSingle</a> function.
+<h3><a name="whatsnew107">What's new in version 1.07?</a></h3>
+A problem with the cgiFormString and related functions has been
+corrected. These functions were previously incorrectly returning cgiFormTruncated
+in cases where the returned string fit the buffer exactly.
+<h3><a name="whatsnew106">What's new in version 1.06?</a></h3>
+1. A potentially significant buffer overflow problem has been
+corrected. Jon Ribbens correctly pointed out to me (and to the
+Internet's bugtraq mailing list) that the cgiFormEntryString
+function, which is used directly or indirectly by almost all
+CGIC programs, can potentially write past the buffer passed
+to it by the programmer. This bug has been corrected.
+Upgrading to version 1.06 is <strong>strongly recommended.</strong>
+<P>
+2. The function <code>cgiSaferSystem()</code> has been
+removed entirely. This function escaped only a few metacharacters,
+while most shells have many, and there was no way to account for
+the many different operating system shells that might be in use
+on different operating systems. Since this led to a false sense
+of security, the function has been removed. It is our recommendation
+that user input should never be passed directly on the command line
+unless it has been carefully shown to contain only characters
+regarded as safe and appropriate by the programmer. Even then, it is
+better to design your utilities to accept their input from standard
+input rather than the command line.
+<h3><a name="whatsnew105">What's new in version 1.05?</a></h3>
+Non-exclusive commercial license fee reduced to $200.
+<h3><a name="whatsnew104">What's new in version 1.04?</a></h3>
+For consistency with other packages, the standard Makefile
+now produces a true library for cgic (libcgic.a). 
+<h3><a name="whatsnew103">What's new in version 1.03?</a></h3>
+Version 1.03 sends line feeds only (ascii 10) to end 
+Content-type:, Status:, and other HTTP protocol output lines,
+instead of CR/LF sequences. The standard specifies CR/LF.
+Unfortunately, too many servers reject CR/LF to make
+implementation of that standard practical. No server
+tested ever rejects LF alone in this context. 
+<h3><a name="whatsnew102">What's new in version 1.02?</a></h3>
+Version 1.02 corrects bugs in previous versions:
+<ul>
+<li>
+<a href="#cgiFormDoubleBounded">cgiFormDoubleBounded</a> specified
+its arguments in the wrong order, with surprising results.
+This bug has been corrected.
+<li>
+Many small changes have been made to increase compatibility.
+cgic now compiles with no warnings under the compilers
+available at boutell.com.
+</ul>
+<h3><a name="whatsnew101">What's new in version 1.01?</a></h3>
+Version 1.01 adds no major functionality but corrects 
+significant bugs and incompatibilities:
+<ul>
+<li>
+<a href="#cgiFormInteger">cgiFormInteger</a>,
+<a href="#cgiFormIntegerBounded">cgiFormIntegerBounded</a>,
+<a href="#cgiFormDouble">cgiFormDouble</a> and
+<a href="#cgiFormDoubleBounded">cgiFormDoubleBounded</a> now
+accept negative numbers properly. They also accept positive
+numbers with an explicit + sign.
+<li>Hex values containing the digit <code>9</code> are
+now properly decoded.
+<li><a href="#cgiFormString">cgiFormString</a> now
+represents each newline as a single line feed (ascii 10 decimal)
+as described in the documentation, not a carriage return
+(ascii 13 decimal) as in version 1.0. The latter approach
+pleased no one.
+<li><a href="#cgiFormString">cgiFormString</a> and
+<a href="#cgiFormStringNoNewlines">cgiFormStringNoNewlines</a>
+no longer erroneously return cgiFormEmpty in place of
+cgiFormSuccess.
+<li>The main() function of cgic now flushes standard output
+and sleeps for one second before exiting in order to inhibit
+problems with the completion of I/O on some platforms. This was
+not a cgic bug per se, but has been reported as a common problem
+with CGI when used with the CERN server. This change should
+improve compatibility.
+<li>The single selection example in the testform.html
+example now works properly. This was an error in the
+form itself, not cgic.
+<li><a href="#cgiRemoteUser">cgiRemoteUser</a> and
+<a href="#cgiRemoteIdent">cgiRemoteIdent</a> are now
+documented accurately. They were reversed earlier.
+</ul>
+<h3><a name="whatis">What is cgic?</a></h3>
+cgic is an ANSI C-language library for the creation of CGI-based
+World Wide Web applications. For basic information about
+the CGI standard, see the <a href="http://hoohoo.ncsa.uiuc.edu/cgi/">
+CGI documentation</a> at NCSA.
+<p>
+cgic performs the following tasks:
+<ul>
+<li>Parses form data, correcting for defective and/or inconsistent browsers
+<li>Transparently accepts both GET and POST form data
+<li>Accepts uploaded files as well as regular form fields
+<li>Provides functions to set and retrieve "cookies"
+(browser-side persistent information)
+<li>Handles line breaks in form fields in a consistent manner
+<li>Provides string, integer, floating-point, and single- and
+multiple-choice functions to retrieve form data
+<li>Provides bounds checking for numeric fields
+<li>Loads CGI environment variables into C strings which are always non-null
+<li>Provides a way to capture CGI situations for replay in a debugging
+environment, including file uploads and cookies
+</ul>
+<p>
+cgic is compatible with any CGI-compliant server environment, and
+compiles without modification in Posix/Unix/Linux and Windows
+environments.
+<h3><a name="obtain">Obtaining cgic</a></h3>
+cgic is distributed via the web in two forms: as a Windows-compatible
+.ZIP file, and as a gzipped tar file. Most users of Windows and
+related operating systems have access to 'unzip' or 'pkunzip'. All modern Unix 
+systems come with 'gunzip' and 'tar' as standard equipment, and gzip/gunzip
+is not difficult to find if yours does not. Versions
+of these programs for other operating systems are widely
+available if you do not already have them.
+<p>
+<strong>Important:</strong> to use cgic, you will need an ANSI-standard
+C compiler. Under Unix, just obtain and use gcc. Most Unix systems have
+standardiszed on gcc. Users of Windows operating systems should not have
+ANSI C-related problems as all of the popular compilers follow the ANSI 
+standard.
+<p>
+<strong>Note for Windows Programmers:</strong> you must use a modern
+32-bit compiler. Visual C++ 2.0 or higher, Borland C++ and the
+mingw32 gcc compiler are all appropriate, as is cygwin. Do 
+<strong>NOT</strong> use an ancient 16-bit DOS executable compiler, please.
+<blockquote>
+<h4>What Operating System Does Your WEB SERVER Run?</h4>
+Remember, the computer on your desk is usually NOT your web server.
+Compiling a Windows console executable will not give you a CGI program that
+can be installed on a Linux-based server. 
+</blockquote>
+Your web browser should inquire whether to save the file to disk
+when you select one of the links below. Under Unix and compatible
+operating systems, save it, then issue the following
+commands to unpack it:
+<pre>
+gunzip cgic205.tar.gz
+tar -xf cgic205.tar
+</pre>
+This should produce the subdirectory 'cgic205', which will contain
+the complete cgic distribution for version 2.05, including a copy of this 
+documentation in the file cgic.html.
+<p>
+Under Windows and compatible operating systems, save it,
+open a console ("DOS") window, and issue the following commands to unpack it:
+<pre>
+unzip /d cgic205.zip
+</pre>
+Or use the unzip utility of your choice.
+<p>
+This command also produces the subdirectory 'cgic205', which will contain
+the complete cgic distribution for version 2.0, including a copy of this 
+documentation in the file cgic.html.
+<p>
+cgic is available via the web from www.boutell.com:
+<ul>
+<li><a href="http://www.boutell.com/cgic/cgic205.tar.gz">Obtain cgic: gzipped tar file</a>
+<li><a href="http://www.boutell.com/cgic/cgic205.zip">Obtain cgic: .ZIP file</a>
+</ul>
+<h3><a name="build">Building cgic: a sample application</a></h3>
+The sample application 'cgictest.c' is provided as part of the
+cgic distribution. This CGI program displays an input form, 
+accepts a submission, and then displays what was submitted.
+In the process essentially all of cgic's features are tested.
+<p>
+On a Unix system, you can build cgictest simply by typing
+'make cgictest.cgi'. cgic.c and cgictest.c will be compiled and linked
+together to produce the cgictest application. Under non-Unix
+operating systems, you will need to create and compile an appropriate
+project containing the files cgic.c and cgictest.c. 
+<p>
+<strong>IMPORTANT:</strong> after compiling cgictest.cgi, you will
+need to place it in a location on your server system which is
+designated by your server administrator as an appropriate location
+for CGI scripts. Some servers are configured to recognize any
+file ending in .cgi as a CGI program when it is found in any
+subdirectory of the server's web space, but this is not always
+the case! The right locations for CGI
+programs vary greatly from one server to another. Resolving
+this issue is between you, your web server administrator,
+and your web server documentation. Before submitting a bug
+report for cgic, make certain that the CGI example programs
+which came with your server <em>do</em> work for you. Otherwise
+it is very likely that you have a server configuration problem.
+<p>
+Once you have moved cgictest.cgi (or cgictest.exe, under Windows)
+to an appropriate cgi directory,
+use the web browser of your choice to access the URL at which
+you have installed it 
+(for instance, <code>www.mysite.com/cgi-bin/cgictest.cgi</code>).
+Fill out the various fields in any manner you wish, then
+select the SUBMIT button.
+<p>
+If all goes well, cgictest.cgi will respond with a page which
+indicates the various settings you submitted. If not,
+please reread the section above regarding the correct location in
+which to install your CGI program on your web server.
+<h3><a name="nocompile">What to do if it won't compile</a></h3>
+<ul>
+<li><strong>Are you using Visual C++ or Borland C++? Did you forget to add
+cgic.c to your project?</strong>
+<li><strong>Make sure you are using an ANSI C or C++ compiler.</strong>
+(All of the Windows compilers are ANSI C compliant.)
+</ul>
+If none of the above proves effective, please see the
+section regarding <a href="#support">support</a>.
+<h3><a name="howto">How to write a cgic application</a></h3>
+<em>Note: </em> All cgic applications must be linked to the cgic.c module
+itself. How to do this depends on your operating system; under Unix,
+just use the provided Makefile as an example.
+<p>
+Since all CGI applications must perform certain initial
+tasks, such as parsing form data and examining
+environment variables, the cgic library provides its
+own main() function. When you write applications that
+use cgic, you will begin your own programs by writing
+a cgiMain() function, which cgic will invoke when
+the initial cgi work has been successfully completed. Your
+program must also be sure to #include the file cgic.h.
+<p>
+<strong>Important:</strong> if you write your own main()
+function, your program will not link properly. Your own
+code should begin with cgiMain(). The library
+provides main() for you. (Those who prefer different behavior
+can easily modify cgic.c.)
+<p>
+Consider the cgiMain function of cgictest.c:
+<p>
+<PRE>
+int cgiMain() {
+#ifdef DEBUG
+  LoadEnvironment();
+#endif /* DEBUG */
+  /* Load a previously saved CGI scenario if that button
+    has been pressed. */
+  if (cgiFormSubmitClicked("loadenvironment") == cgiFormSuccess) {
+    LoadEnvironment();
+  }
+  /* Set any new cookie requested. Must be done *before*
+    outputting the content type. */
+  CookieSet();
+  /* Send the content type, letting the browser know this is HTML */
+  cgiHeaderContentType("text/html");
+  /* Top of the page */
+  fprintf(cgiOut, "&lt;HTML&gt;&lt;HEAD&gt;\n");
+  fprintf(cgiOut, "&lt;TITLE&gt;cgic test&lt;/TITLE&gt;&lt;/HEAD&gt;\n");
+  fprintf(cgiOut, "&lt;BODY&gt;&lt;H1&gt;cgic test&lt;/H1&gt;\n");
+  /* If a submit button has already been clicked, act on the 
+    submission of the form. */
+  if ((cgiFormSubmitClicked("testcgic") == cgiFormSuccess) ||
+    cgiFormSubmitClicked("saveenvironment") == cgiFormSuccess)
+  {
+    HandleSubmit();
+    fprintf(cgiOut, "&lt;hr&gt;\n");
+  }
+  /* Now show the form */
+  ShowForm();
+  /* Finish up the page */
+  fprintf(cgiOut, "&lt;/BODY&gt;&lt;/HTML&gt;\n");
+  return 0;
+}
+</PRE>
+Note the DEBUG #ifdef. If DEBUG is defined at compile time, either by
+inserting the line "#define DEBUG 1" into the program or by setting
+it in the Makefile or other development environment, then the
+LoadEnvironment function is invoked. This function calls 
+<a href="#cgiReadEnvironment">cgiReadEnvironment()</a> 
+to restore a captured CGI environment for debugging purposes. See
+also the discussion of the <a href="#debug">capture</a> program, which is
+provided for use in CGI debugging. Because this is a test program,
+the <a href="#cgiFormSubmitClicked">cgiFormSubmitClicked</a> function is
+also called to check for the use of a button that requests the reloading
+of a saved CGI environment. A completed CGI program typically would
+never allow the end user to make that decision.
+<h4>Setting Cookies</h4>
+Next, one of the cgiHeader functions should be called.
+This particular program demonstrates many features, including
+the setting of cookies. If the programmer wishes to set a cookie,
+the cookie-setting function must be called
+first, before other headers are output. This is done by the
+CookieSet() function of cgictest.c:
+<pre>
+void CookieSet()
+{
+  char cname[1024];
+  char cvalue[1024];
+  /* Must set cookies BEFORE calling 
+    cgiHeaderContentType */
+  cgiFormString("cname", cname, sizeof(cname));  
+  cgiFormString("cvalue", cvalue, sizeof(cvalue));  
+  if (strlen(cname)) {
+    /* Cookie lives for one day (or until 
+      browser chooses to get rid of it, which 
+      may be immediately), and applies only to 
+      this script on this site. */  
+    cgiHeaderCookieSetString(cname, cvalue,
+      86400, cgiScriptName, cgiServerName);
+  }
+}
+</pre>
+Since this is a test program, the <a href="#cgiFormString">cgiFormString</a> 
+function is used to fetch the name and value from the form previously filled
+in by the user. Normally, cookie names and values are chosen to meet the
+needs of the programmer and provide a means of identifying the same
+user again later.
+<p>
+The <a href="#cgiHeaderCookieSetString">cgiHeaderCookieSetString</a>
+function sets the cookie by requesting that the web browser store it.
+<strong>There is never any guarantee that this will happen!</strong>
+Many browsers reject cookies completely; others do not necessarily keep
+them as long as requested or return them with their values intact.
+Always code defensively when using cookies.
+<p>
+The cname and cvalue parameters are of course the namd and value for
+the cookie. The third argument is the time, in seconds, that the
+cookie should "live" on the browser side before it expires; in this
+case it has been set to 86,400 seconds, which is exactly one day. 
+<strong>The browser may or may not respect this setting, as with everything
+else about cookies.</strong>
+<p>
+The fourth argument identifies the "path" within the web site for which
+the cookie is considered valid. A cookie that should be sent back
+for every access to the site should be set with a path of <code>/</code>.
+In this case the cookie is relevant only to the CGI program itself, so
+<code><a href="#cgiScriptName">cgiScriptName</a></code> (the URL of the CGI program, not including the
+domain name) is sent. Similarly, a cookie can be considered relevant
+to a single web site or to an entire domain, such as 
+<code>www.boutell.com</code> or the entire <code>.boutell.com</code>
+domain. In this case, the current site on which the program is running
+is the only relevant site, so <code><a href="#cgiServerName">cgiServerName</a></code> is used
+as the domain.
+<h4>Outputting the Content Type Header</h4>
+Next, <a href="#cgiHeaderContentType">cgiHeaderContentType()</a> is 
+called to indicate the MIME type of the document being output, in this case 
+"text/html" (a normal HTML document). A few other common MIME types are
+"image/gif", "image/jpeg" and "audio/wav". 
+<p>
+Note that <a href="#cgiHeaderStatus">cgiHeaderStatus()</a> or 
+<a href="#cgiHeaderLocation">cgiHeaderLocation()</a> could have
+been invoked instead to output an error code or redirect the
+request to a different URL. Only one of the cgiHeader functions
+should be called in a single execution of the program.
+<p>
+<strong>Important:</strong> one of the cgiHeader functions,
+usually <a href="#cgiHeaderContentType">cgiHeaderContentType()</a>, 
+<em>must</em> be invoked before outputting any other
+response to the user. Otherwise, the result will not be a valid
+document and the browser's behavior will be unpredictable.
+You may, of course, output your own ContentType and other
+header information to <a href="#cgiOut">cgiOut</a> if you prefer. The cgiHeader functions
+are provided as a convenience.
+<h4>Handling Form Submissions</h4>
+Like many CGI programs, cgictest makes decisions about the way it
+should behave based on whether various submit buttons have been clicked.
+When either the testcgic or saveenvironment button is present, cgictest
+invokes the HandleSubmit function, which invokes additional functions to
+handle various parts of the form:
+<pre>
+void HandleSubmit()
+{
+  Name();
+  Address();
+  Hungry();
+  Temperature();
+  Frogs();
+  Color();
+  Flavors();
+  NonExButtons();
+  RadioButtons();
+  File();
+  Entries();
+  Cookies();
+  /* The saveenvironment button, in addition to submitting 
+    the form, also saves the resulting CGI scenario to 
+    disk for later replay with the 'load saved environment' 
+    button. */
+  if (cgiFormSubmitClicked("saveenvironment") == cgiFormSuccess) {
+    SaveEnvironment();
+  }
+}
+</pre>
+<h4>Handling Text Input</h4>
+The Name() function of cgictest is shown below, in its simplest
+possible form:
+<PRE>
+void Name() {
+        char name[81];
+        <a href="#cgiFormStringNoNewlines">cgiFormStringNoNewlines</a>("name", name, 81);
+        fprintf(cgiOut, "Name: ");
+        cgicHtmlEscape(name);
+        fprintf(cgiOut, "<BR>\n");
+}
+</PRE>
+The purpose of this function is to retrieve and display the name that was
+input by the user. Since the programmer has decided that names should
+be permitted to have up to 80 characters, a buffer of 81 characters
+has been declared (allowing for the final null character). 
+The <a href="#cgiFormStringNoNewlines">cgiFormStringNoNewlines()</a>
+function is then invoked to retrieve the name and ensure that
+carriage returns are not present in the name (despite the
+incorrect behavior of some web browsers). The first argument
+is the name of the input field in the form, the second argument
+is the buffer to which the data should be copied, and the third
+argument is the size of the buffer. cgic will never write beyond
+the size of the buffer, and will always provide a null-terminated
+string in response; if the buffer is too small, the string will
+be shortened. If this is not acceptable, the
+<a href="#cgiFormStringSpaceNeeded">cgiFormStringSpaceNeeded()</a>
+function can be used to check the amount of space needed; the
+return value of cgiFormStringNoNewlines() can also be checked
+to determine whether truncation occurred. See
+the full description of <a href="#cgiFormStringNoNewlines">
+cgiFormStringNoNewlines()</a>.
+<h4>Handling Output</h4>
+Note that Name() writes its HTML output to <a href="#cgiOut">cgiOut</a>, not
+to stdout.
+<p>
+The actual name submitted by the user may or may not contain
+characters that have special meaning in HTML, specifically the
+the <code>&lt;</code>, <code>&gt;</code>, and <code>&amp;</code> characters.
+The <a href="#cgiHtmlEscape">cgiHtmlEscape</a> function is used to output
+the user-entered name with any occurrences of these characters
+correctly escaped as <code>&amp;lt;</code>, <code>&amp;gt;</code>, 
+and <code>&amp;amp;</code>.
+<p>
+<strong>Important:</strong> <a href="#cgiOut">cgiOut</a> is normally equivalent
+to stdout, and there is no performance penalty for using it.
+It is recommended that you write output to <a href="#cgiOut">cgiOut</a> to ensure compatibility
+with modified versions of the cgic library for special
+environments that do not provide stdin and stdout for
+each cgi connection.
+<p>
+Note that, for text input areas in which carriage returns <em>are</em>
+desired, the function <a href="#cgiFormString">cgiFormString</a>
+should be used instead. cgiFormString ensures that line breaks
+are always represented by a single carriage return (ascii decimal 13),
+making life easier for the programmer. See the source code to
+the Address() function of cgictest.c for an example.
+<h4>Handling Single Checkboxes</h4>
+Consider the Hungry() function, which determines whether
+the user has selected the "hungry" checkbox:
+<PRE>
+void Hungry() {
+        if (<a href="#cgiFormCheckboxSingle">cgiFormCheckboxSingle</a>("hungry") == <a href="#cgiFormSuccess">cgiFormSuccess</a>) {
+                fprintf(cgiOut, "I'm Hungry!&lt;BR&gt;\n");
+        } else {
+                fprintf(cgiOut, "I'm Not Hungry!&lt;BR&gt;\n");
+        }
+}
+</PRE>
+This function takes advantage of the
+<a href="#cgiFormCheckboxSingle">cgiFormCheckboxSingle()</a> function, which
+determines whether a single checkbox has been selected. 
+cgiFormCheckboxSingle() accepts the name attribute of the checkbox
+as its sole argument and returns <a href="#cgiFormSuccess">
+cgiFormSuccess</a> if the checkbox is selected, or 
+<a href="#cgiFormNotFound">cgiFormNotFound</a> if it is not.
+If multiple checkboxes with the same name are in use,
+consider the <a href="#cgiFormCheckboxMultiple">
+cgiFormCheckboxMultiple()</a> and 
+<a href="#cgiFormStringMultiple">cgiFormStringMultiple()</a>
+functions.
+<h4>Handling Numeric Input</h4>
+Now consider the Temperature() function, which retrieves
+a temperature in degrees (a floating-point value) and ensures
+that it lies within particular bounds:
+<PRE>
+void Temperature() {
+        double temperature;
+        <a href="#cgiFormDoubleBounded">cgiFormDoubleBounded</a>("temperature", &amp;temperature, 80.0, 120.0, 98.6);
+        fprintf(<a href="#cgiOut">cgiOut</a>, "My temperature is %f.&lt;BR&gt;\n", temperature);
+}
+</PRE>
+The temperature is retrieved by the function 
+<a href="#cgiFormDoubleBounded">cgiFormDoubleBounded()</a>. The first
+argument is the name of the temperature input field in the form;
+the second argument points to the address of the variable that will 
+contain the result. The next two arguments are the lower and upper
+bounds, respectively. The final argument is the default value to
+be returned if the user did not submit a value.
+<p>
+This function always retrieves a reasonable value within the
+specified bounds; values above or below bounds are constrained
+to fit the bounds. However, the return value of
+cgiFormDoubleBounded can be checked to make sure the
+actual user entry was in bounds, not blank, and so forth;
+see the description of <a href="#cgiFormDoubleBounded">
+cgiFormDoubleBounded()</a> for more details. If bounds checking
+is not desired, consider using <a href="#cgiFormDouble">
+cgiFormDouble()</a> instead.
+<p>
+Note that, for integer input, the functions
+<a href="#cgiFormInteger">cgiFormInteger</a> and
+<a href="#cgiFormIntegerBounded">cgiFormIntegerBounded</a>
+are available. The behavior of these functions is similar to
+that of their floating-point counterparts above.
+<h4>Handling Single-Choice Input</h4>
+The &lt;SELECT&gt; tag of HTML is used to provide the user with
+several choices. Radio buttons and checkboxes can also be used
+when the number of choices is relatively small. Consider
+the Color() function of cgictest.c:
+<PRE>
+char *colors[] = {
+        "Red",
+        "Green",
+        "Blue"
+};
+
+void Color() {
+        int colorChoice;
+        <a href="#cgiFormSelectSingle">cgiFormSelectSingle</a>("colors", colors, 3, &amp;colorChoice, 0);
+        fprintf(<a href="#cgiOut">cgiOut</a>, "I am: %s&lt;BR&gt;\n", colors[colorChoice]);
+}
+</PRE>
+This function determines which of several colors the user chose
+from a &lt;SELECT&gt; list in the form. An array of colors is
+declared; the <a href="#cgiFormSelectSingle">cgiFormSelectSingle()</a>
+function is then invoked to determine which, if any, of those choices
+was selected. The first argument indicates the name of the input
+field in the form. The second argument points to the list of
+acceptable colors. The third argument indicates the number of
+entries in the color array. The fourth argument points to the
+variable which will accept the chosen color, and the last argument
+indicates the index of the default value to be set if no
+selection was submitted by the browser. 
+<p>
+<a href="#cgiFormSelectSingle">cgiFormSelectSingle()</a> will
+always indicate a reasonable selection value. However, if
+the programmer wishes to know for certain that a value was
+actually submitted, that the value submitted was a legal
+response, and so on, the return value of cgiFormSelectSingle()
+can be consulted. See the full description of
+<a href="#cgiFormSelectSingle">cgiFormSelectSingle()</a> for
+more information.
+<p>
+Note that radio button groups and &lt;SELECT&gt; lists can both
+be handled by this function. If you are processing radio
+button groups, you may prefer to invoke 
+<a href="#cgiFormRadio">cgiFormRadio()</a>, which functions
+identically. 
+<p>
+<em>"What if I won't know the acceptable choices at runtime?"</em>
+<p>
+If the acceptable choices aren't known <em>until</em> runtime,
+one can simply load the choices from disk. But if the acceptable
+choices aren't fixed at all (consider a list of country names;
+new names may be added to the form at any time and it is
+inconvenient to also update program code or a separate list
+of countries), simply invoke 
+<a href="#cgiFormStringNoNewlines">cgiFormStringNoNewlines()</a>
+instead to retrieve the string directly. Keep in mind that, if
+you do so, validating the response to make sure it is
+safe and legitimate becomes a problem for your own
+program to solve. The advantage of cgiFormSelectSingle() is that invalid 
+responses are never returned.
+<p>
+To handle multiple-selection &lt;SELECT&gt; lists and
+groups of checkboxes with the same name, see the
+discussion of the NonExButtons() function of cgictest.c, immediately below.
+<h4>Handling Multiple-Choice Input</h4>
+Consider the first half of the NonExButtons() function of cgictest.c:
+<PRE>
+char *votes[] = {
+  "A",
+  "B",
+  "C",
+  "D"
+};
+
+void NonExButtons() {
+  int voteChoices[4];
+  int i;
+  int result;  
+  int invalid;
+
+  char **responses;
+
+  /* Method #1: check for valid votes. This is a good idea,
+    since votes for nonexistent candidates should probably
+    be discounted... */
+  fprintf(<a href="#cgiOut">cgiOut</a>, "Votes (method 1):&lt;BR&gt;\n");
+  result = <a href="#cgiFormCheckboxMultiple">cgiFormCheckboxMultiple</a>("vote", votes, 4, 
+    voteChoices, &amp;invalid);
+  if (result == <a href="#cgiFormNotFound">cgiFormNotFound</a>) {
+    fprintf(<a href="#cgiOut">cgiOut</a>, "I hate them all!&lt;p&gt;\n");
+  } else {  
+    fprintf(<a href="#cgiOut">cgiOut</a>, "My preferred candidates are:\n");
+    fprintf(<a href="#cgiOut">cgiOut</a>, "&lt;ul&gt;\n");
+    for (i=0; (i &lt; 4); i++) {
+      if (voteChoices[i]) {
+        fprintf(<a href="#cgiOut">cgiOut</a>, "&lt;li&gt;%s\n", votes[i]);
+      }
+    }
+    fprintf(<a href="#cgiOut">cgiOut</a>, "&lt;/ul&gt;\n");
+  }
+</PRE>
+This function takes advantage of
+<a href="#cgiFormCheckboxMultiple">cgiFormCheckboxMultiple()</a>,
+which is used to identify one or more selected checkboxes with 
+the same name. This function performs identically to
+<a href="#cgiFormSelectMultiple">cgiFormSelectMultiple()</a>.
+That is, &lt;SELECT&gt; tags with the MULTIPLE attribute are handled
+just like a group of several checkboxes with the same name.
+<p>
+The first argument to <a href="#cgiFormCheckboxMultiple">
+cgiFormCheckboxMultiple()</a> is the name given to all
+checkbox input fields in the group. The second argument
+points to an array of legitimate values; these should
+correspond to the VALUE attributes of the checkboxes
+(or OPTION tags in a &lt;SELECT&gt; list). The third argument
+indicates the number of entries in the array of
+legitimate values. The fourth argument points to
+an array of integers with the same number of entries
+as the array of legitimate values; each entry
+will be set true if that checkbox or option was selected,
+false otherwise.
+<p>
+The last argument points to an integer which will be set to the 
+number of invalid responses (responses not in the array of
+valid responses) that were submitted. If this value is not
+of interest, the last argument may be a null pointer (0).
+<p>
+Note that the return value of cgiFormCheckboxMultiple is
+inspected to determine whether any choices at all were
+set. See the full description of
+<a href="#cgiFormCheckboxMultiple">cgiFormCheckboxMultiple</a>
+for other possible return values. 
+<p>
+<em>"What if I won't know the acceptable choices at runtime?"</em>
+<p>
+If the acceptable choices aren't known <em>until</em> runtime,
+one can simply load the choices from disk. But if the acceptable
+choices aren't fixed at all (consider a list of ice cream flavors;
+new names may be added to the form at any time and it is
+inconvenient to also update program code or a separate list
+of countries), a more dynamic approach is needed. Consider
+the second half of the NonExButtons() function of cgictest.c:
+<PRE>
+  /* Method #2: get all the names voted for and trust them.
+    This is good if the form will change more often
+    than the code and invented responses are not a danger
+    or can be checked in some other way. */
+  fprintf(<a href="#cgiOut">cgiOut</a>, "Votes (method 2):&lt;BR&gt;\n");
+  result = <a href="#cgiFormStringMultiple">cgiFormStringMultiple</a>("vote", &amp;responses);
+  if (result == <a href="#cgiFormNotFound">cgiFormNotFound</a>) {  
+    fprintf(<a href="#cgiOut">cgiOut</a>, "I hate them all!&lt;p&gt;\n");
+  } else {
+    int i = 0;
+    fprintf(<a href="#cgiOut">cgiOut</a>, "My preferred candidates are:\n");
+    fprintf(<a href="#cgiOut">cgiOut</a>, "&lt;ul&gt;\n");
+    while (responses[i]) {
+      fprintf(<a href="#cgiOut">cgiOut</a>, "&lt;li&gt;%s\n", responses[i]);
+      i++;
+    }
+    fprintf(<a href="#cgiOut">cgiOut</a>, "&lt;/ul&gt;\n");
+  }
+  /* We must be sure to free the string array or a memory
+    leak will occur. Simply calling free() would free
+    the array but not the individual strings. The
+    function cgiStringArrayFree() does the job completely. */  
+  <A HREF="#cgiStringArrayFree">cgiStringArrayFree</a>(responses);
+}
+</PRE>
+This code excerpt demonstrates an alternate means of retrieving
+a list of choices. The function
+<a href="#cgiFormStringMultiple">cgiFormStringMultiple()</a> is used
+to retrieve an array consisting of all the strings submitted
+for with a particular input field name. This works both for
+&lt;SELECT&gt; tags with the MULTIPLE attribute and for 
+groups of checkboxes with the same name. 
+<P>
+The first argument to <a href="#cgiFormStringMultiple">
+cgiFormStringMultiple()</a> is the name of the input field or
+group of input fields in question. The second argument should
+be the address of a pointer to a pointer to a string, which
+isn't as bad as it sounds. Consider the following simple call
+of the function:
+<PRE>
+/* An array of strings; each C string is an array of characters */
+char **responses; 
+
+<a href="#cgiFormStringMultiple">cgiFormStringMultiple</a>("vote", &amp;responses);
+</PRE>
+<em>"How do I know how many responses there are?"</em>
+<p>
+After the call, the last entry in the string array will be
+a null pointer. Thus the simple loop:
+<PRE>
+int i = 0;
+while (responses[i]) {
+  /* Do something with the string responses[i] */
+  i++;
+}
+</PRE>
+can be used to walk through the array until the last
+entry is encountered.
+<p>
+<strong>Important:</strong> the 
+<a href="#cgiFormStringMultiple">cgiFormStringMultiple</a> function
+returns a pointer to <strong>allocated memory</strong>. Your code
+should not modify the strings in the responses array or the responses
+array itself; if modification is needed, the strings should be
+copied. When your code is done examining the responses array,
+you <strong>MUST</strong> call <a href="#cgiStringArrayFree">
+cgiStringArrayFree()</a> with the array as an argument to free the memory 
+associated with the array. Otherwise, the memory will not be available 
+again until the program exists. <strong>Don't</strong> just call the 
+free() function; if you do, the individual strings will not be freed.
+<h4>Accessing Uploaded Files</h4>
+CGIC provides functions to access files that have been uploaded
+as part of a form submission. <strong>IMPORTANT: you MUST</strong> set
+the <code>enctype</code> attribute of your <code>form</code> tag
+to <code>multipart/form-data</code> for this feature to work! For an
+example, see the <a href="#ShowForm">ShowForm</a> function of 
+cgictest.c, examined below.
+<p>
+The <code>File</code> function of cgictest.c takes care of 
+receiving uploaded files:
+<pre>
+void File()
+{
+  cgiFilePtr file;
+  char name[1024];
+  char contentType[1024];
+  char buffer[1024];
+  int size;
+  int got;
+  if (cgiFormFileName("file", name, sizeof(name)) != 
+    cgiFormSuccess) 
+  {
+    printf("&lt;p&gt;No file was uploaded.&lt;p&gt;\n");
+    return;
+  } 
+        fprintf(cgiOut, "The filename submitted was: ");
+        cgiHtmlEscape(name);
+        fprintf(cgiOut, "&lt;p&gt;\n");
+        cgiFormFileSize("file", &size);
+        fprintf(cgiOut, "The file size was: %d bytes&lt;p&gt;\n", size);
+        cgiFormFileContentType("file", contentType, sizeof(contentType));
+        fprintf(cgiOut, "The alleged content type of the file was: ");
+        cgiHtmlEscape(contentType);
+        fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "Of course, this is only the claim the browser "
+    "made when uploading the file. Much like the filename, "
+    "it cannot be trusted.&lt;p&gt;\n");
+  fprintf(cgiOut, "The file's contents are shown here:&lt;p&gt;\n");
+  if (cgiFormFileOpen("file", &file) != cgiFormSuccess) {
+    fprintf(cgiOut, "Could not open the file.&lt;p&gt;\n");
+    return;
+  }
+  fprintf(cgiOut, "&lt;pre&gt;\n");
+  while (cgiFormFileRead(file, buffer, sizeof(buffer), &got) ==
+    cgiFormSuccess)
+  {
+    cgiHtmlEscapeData(buffer, got);
+  }
+  fprintf(cgiOut, "&lt;/pre&gt;\n");
+  cgiFormFileClose(file);
+}
+</pre>
+First, the File function checks to determine the filename that was
+submitted by the user. <strong>VERY IMPORTANT: this filename may or
+may not bear any relation to the real name of the file on the user's
+computer, may be deliberately manipulated with malicious intent,</strong>
+and should not be used for <strong>any</strong> purpose unless you have
+determined that its content is safe for your intended use and will not,
+at the very least, overwrite another file of importance to you, especially if
+you intend to use it as a file name on the server side. The cgic library
+itself does not use this file name for temporary storage.
+<p>
+If the <a href="#cgiFormFileName">cgiFormFileName</a> function does
+not succeed, no file was uploaded.
+<p>
+Next, the <a href="#cgiFormFileSize">cgiFormFileSize</a> function is called
+to determine the size of the uploaded file, in bytes.
+<p>
+The File function then proceeds to query the content type of the uploaded
+file.  Files uploaded by the user have their own content type information, 
+which may be useful in determining whether the file is an image, HTML document,
+word processing document, or other type of file. However,
+<strong>as with the filename and any other claim made by the browser,
+this information should not be blindly trusted.</strong> The browser
+may upload a file with the name <code>picture.jpg</code> and the
+content type <code>image/jpeg</code>, but this does not guarantee that the
+actual file will contain a valid JPEG image suitable for display.
+<p>
+The content type submitted by the browser can be queried using the
+<a href="#cgiFormFileContentType">cgiFormFileContentType</a> function.
+<p>
+Of course, CGIC also provides access to the actual uploded file. 
+First, the programmer calls <a href="#cgiFormFileOpen">cgiFormFileOpen</a>,
+passing the address of a <code>cgiFilePtr</code> object. If this function
+succeeds, the <code>cgiFilePtr</code> object becomes valid, and can be
+used in subsequent calls to <a href="#cgiFormFileRead">cgiFormFileRead</a>.
+Notice that the number of bytes read may be less than the number requested,
+in particular on the last successful call before cgiFormFileRead begins
+to return <code>cgiFormEOF</code>. When cgiFormFileRead no longer returns 
+cgiFormSuccess, 
+the programmer calls <a href="#cgiFormClose">cgiFormFileClose</a> to
+release the <code>cgiFilePtr</code> object.
+<p>
+The uploaded file data may contain anything, including binary data,
+null characters, and so on. The example program uses the 
+<a href="#cgiHtmlEscapeData">cgiHtmlEscapeData</a> function to output the
+data with any special characters that have meaning in HTML escaped.
+Most programs will save the uploaded information to a server-side file or
+database.
+<h4>Fetching All Form Entries</h4>
+From time to time, the programmer may not know the names of all
+form fields in advance. In such situations it is convenient to
+use the <a href="#cgiFormEntries">cgiFormEntries</a> function.
+The Entries function of cgictest.c demonstrates the use of
+cgiFormEntries:
+<pre>
+void Entries()
+{
+        char **array, **arrayStep;
+        fprintf(cgiOut, "List of All Submitted Form Field Names:&lt;p&gt;\n");
+        if (cgiFormEntries(&array) != cgiFormSuccess) {
+                return;
+        }
+        arrayStep = array;
+        fprintf(cgiOut, "&lt;ul&gt;\n");
+        while (*arrayStep) {
+                fprintf(cgiOut, "&lt;li&gt;");
+                cgiHtmlEscape(*arrayStep);
+                fprintf(cgiOut, "\n");
+                arrayStep++;
+        }
+        fprintf(cgiOut, "&lt;/ul&gt;\n");
+        cgiStringArrayFree(array);
+}
+</pre>
+The cgiFormEntries function retrieves an array of form field names.
+This array consists of pointers to strings, with a final null pointer
+to mark the end of the list. The above code illustrates one way of
+looping through the returned strings. Note the final call to
+<a href="#cgiStringArrayFree">cgiStringArrayFree</a>, which is
+essential in order to return the memory used to store the strings
+and the string array.
+<h4>Retrieving Cookies</h4>
+The Cookies function of cgictest.c displays a list of all cookies
+submitted by the browser with the current form submission, along
+with their values:
+<pre>
+void Cookies()
+{
+  char **array, **arrayStep;
+  char cname[1024], cvalue[1024];
+  fprintf(cgiOut, "Cookies Submitted On This Call, With Values "
+    "(Many Browsers NEVER Submit Cookies):&lt;p&gt;\n");
+  if (cgiCookies(&array) != cgiFormSuccess) {
+    return;
+  }
+  arrayStep = array;
+  fprintf(cgiOut, "&lt;table border=1&gt;\n");
+  fprintf(cgiOut, "&lt;tr&gt;&lt;th&gt;Cookie&lt;th&gt;Value&lt;/tr&gt;\n");
+  while (*arrayStep) {
+    char value[1024];
+    fprintf(cgiOut, "&lt;tr&gt;");
+    fprintf(cgiOut, "&lt;td&gt;");
+    cgiHtmlEscape(*arrayStep);
+    fprintf(cgiOut, "&lt;td&gt;");
+    cgiCookieString(*arrayStep, value, sizeof(value));
+    cgiHtmlEscape(value);
+    fprintf(cgiOut, "\n");
+    arrayStep++;
+  }
+  fprintf(cgiOut, "&lt;/table&gt;\n");
+  cgiFormString("cname", cname, sizeof(cname));  
+  cgiFormString("cvalue", cvalue, sizeof(cvalue));  
+  if (strlen(cname)) {
+    fprintf(cgiOut, "New Cookie Set On This Call:&lt;p&gt;\n");
+    fprintf(cgiOut, "Name: ");  
+    cgiHtmlEscape(cname);
+    fprintf(cgiOut, "Value: ");  
+    cgiHtmlEscape(cvalue);
+    fprintf(cgiOut, "&lt;p&gt;\n");
+    fprintf(cgiOut, "If your browser accepts cookies "
+      "(many do not), this new cookie should appear "
+      "in the above list the next time the form is "
+      "submitted.&lt;p&gt;\n"); 
+  }
+  cgiStringArrayFree(array);
+}
+</pre>
+<strong>VERY IMPORTANT: YOUR BROWSER MIGHT NOT SUBMIT COOKIES,
+EVER, REGARDLESS OF WHAT VALUES YOU ENTER INTO THE TEST FORM.</strong>
+Many, many browsers are configured not to accept or send cookies;
+others are configured to send them as little as possible to meet the
+bare minimum requirements for entry into popular sites. Users will often
+refuse your cookies; make sure your code still works in that situation!
+<p>
+The above code uses the <a href="#cgiCookies">cgiCookies</a> function
+to retrieve a list of all currently set cookies as a null-terminated
+array of strings. The <a href="#cgiCookieString">cgiCookieString</a>
+function is then used to fetch the value associated with each cookie;
+this function works much like <a href="#cgiFormString">cgiFormString</a>,
+discussed earlier. Note that a cookie set as a part of the current
+form submission process does not appear on this list immediately, as
+it has not yet been sent back by the browser. It should appear on
+future submissions, provided that the browser chooses to accept
+and resend the cookie at all.
+<h4>Displaying a Form That Submits to the Current Program</h4>
+CGI programmers often need to display HTML pages as part of the output
+of CGI programs; these HTML pages often contain forms which should submit
+fields back to the same program they came from. Provided that your
+web server is well-configured, this can be done conveniently using
+the cgiScriptName environment variable, as shown below. Here is the
+source code of the ShowForm function of cgictest.c:
+<pre>
+void ShowForm()
+{
+  fprintf(cgiOut, "&lt;!-- 2.0: multipart/form-data is required 
+    "for file uploads. --&gt;");
+  fprintf(cgiOut, "&lt;form method=\"POST\" "
+    "enctype=\"multipart/form-data\" ");
+  fprintf(cgiOut, "  action=\"");
+  cgiValueEscape(cgiScriptName);
+  fprintf(cgiOut, "\"&gt;\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "Text Field containing Plaintext\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;input type=\"text\" name=\"name\"&gt;Your Name\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "Multiple-Line Text Field\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;textarea NAME=\"address\" ROWS=4 COLS=40&gt;\n");
+  fprintf(cgiOut, "Default contents go here. \n");
+  fprintf(cgiOut, "&lt;/textarea&gt;\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "Checkbox\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;input type=\"checkbox\" name=\"hungry\" checked&gt;Hungry\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "Text Field containing a Numeric Value\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;input type=\"text\" name=\"temperature\" value=\"98.6\"&gt;\n");
+  fprintf(cgiOut, "Blood Temperature (80.0-120.0)\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "Text Field containing an Integer Value\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;input type=\"text\" name=\"frogs\" value=\"1\"&gt;\n");
+  fprintf(cgiOut, "Frogs Eaten\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "Single-SELECT\n");
+  fprintf(cgiOut, "&lt;br&gt;\n");
+  fprintf(cgiOut, "&lt;select name=\"colors\"&gt;\n");
+  fprintf(cgiOut, "&lt;option value=\"Red\"&gt;Red\n");
+  fprintf(cgiOut, "&lt;option value=\"Green\"&gt;Green\n");
+  fprintf(cgiOut, "&lt;option value=\"Blue\"&gt;Blue\n");
+  fprintf(cgiOut, "&lt;/select&gt;\n");
+  fprintf(cgiOut, "&lt;br&gt;\n");
+  fprintf(cgiOut, "Multiple-SELECT\n");
+  fprintf(cgiOut, "&lt;br&gt;\n");
+  fprintf(cgiOut, "&lt;select name=\"flavors\" multiple&gt;\n");
+  fprintf(cgiOut, "&lt;option value=\"pistachio\"&gt;Pistachio\n");
+  fprintf(cgiOut, "&lt;option value=\"walnut\"&gt;Walnut\n");
+  fprintf(cgiOut, "&lt;option value=\"creme\"&gt;Creme\n");
+  fprintf(cgiOut, "&lt;/select&gt;\n");
+  fprintf(cgiOut, "&lt;p&gt;Exclusive Radio Button Group: Age of "
+    "Truck in Years\n");
+  fprintf(cgiOut, "&lt;input type=\"radio\" name=\"age\" "
+    "value=\"1\"&gt;1\n");
+  fprintf(cgiOut, "&lt;input type=\"radio\" name=\"age\" "
+    "value=\"2\"&gt;2\n");
+  fprintf(cgiOut, "&lt;input type=\"radio\" name=\"age\" "
+    "value=\"3\" checked&gt;3\n");
+  fprintf(cgiOut, "&lt;input type=\"radio\" name=\"age\" "
+    "value=\"4\"&gt;4\n");
+  fprintf(cgiOut, "&lt;p&gt;Nonexclusive Checkbox Group: "
+    "Voting for Zero through Four Candidates\n");
+  fprintf(cgiOut, "&lt;input type=\"checkbox\" name=\"vote\" "
+    "value=\"A\"&gt;A\n");
+  fprintf(cgiOut, "&lt;input type=\"checkbox\" name=\"vote\" "
+    "value=\"B\"&gt;B\n");
+  fprintf(cgiOut, "&lt;input type=\"checkbox\" name=\"vote\" "
+    "value=\"C\"&gt;C\n");
+  fprintf(cgiOut, "&lt;input type=\"checkbox\" name=\"vote\" "
+    "value=\"D\"&gt;D\n");
+  fprintf(cgiOut, "&lt;p&gt;File Upload:\n");
+  fprintf(cgiOut, "&lt;input type=\"file\" name=\"file\" "
+    "value=\"\"&gt; (Select A Local File)\n");
+  fprintf(cgiOut, "&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;p&gt;Set a Cookie&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;input name=\"cname\" "
+    "value=\"\"&gt; Cookie Name\n");
+  fprintf(cgiOut, "&lt;input name=\"cvalue\" "
+    "value=\"\"&gt; Cookie Value&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;input type=\"submit\" "
+    "name=\"testcgic\" value=\"Submit Request\"&gt;\n");
+  fprintf(cgiOut, "&lt;input type=\"reset\" "
+    "value=\"Reset Request\"&gt;\n");
+  fprintf(cgiOut, "&lt;p&gt;Save the CGI Environment&lt;p&gt;\n");
+  fprintf(cgiOut, "Pressing this button will submit the form, then "
+    "save the CGI environment so that it can be replayed later "
+    "by calling cgiReadEnvironment (in a debugger, for "
+    "instance).&lt;p&gt;\n");
+  fprintf(cgiOut, "&lt;input type=\"submit\" name=\"saveenvironment\" "
+    "value=\"Save Environment\"&gt;\n");
+  fprintf(cgiOut, "&lt;/form&gt;\n");
+}
+</pre>
+Note the use of <code>enctype="multipart/form-data"</code> in the
+<code>FORM</code> tag. This is absolutely required if the form
+will contain file upload fields, as in the above example. Most
+browsers will not even attempt file uploads without the
+presence of this attribute.
+<h4>Examining CGI environment variables</h4>
+The CGI standard specifies a number of environment variables
+which are set by the server. However, servers are somewhat
+unpredictable as to whether these variables will be null or
+point to empty strings when an environment variable is not set.
+Also, in order to allow the programmer to restore saved
+CGI environments, the cgic library needs have a way of insulating
+the programmer from the actual environment variables.
+<p>
+Instead of calling getenv() to determine the value of a
+variable such as HTTP_USER_AGENT (the browser software being used),
+always use the
+<a href="#variables">cgic copies of the environment variables</a>,
+which are always valid C strings (they are never null, although
+they may point to an empty string). For instance, the cgic
+variable containing the name of the browser software is
+<a href="#cgiUserAgent">cgiUserAgent</a>. The referring URL appears
+in the variable <a href="#cgiReferrer">cgiReferrer</a>.
+<h3><a name="images">How can I generate images from my cgic application?</a></h3>
+cgic can be used in conjunction with the
+<a href="http://www.boutell.com/gd/">gd graphics library</a>, which
+can produce GIF images on the fly.
+<p>
+The following short sample program hints at the possibilities:
+<pre>
+#include "cgic.h"
+#include "gd.h"
+
+char *colors[] = {
+  "red", "green", "blue"
+};
+
+#define colorsTotal 3
+
+int cgiMain() {
+  int colorChosen;
+  gdImagePtr im;
+  int r, g, b;
+  /* Use gd to create an image */
+  im = gdImageCreate(64, 64);
+  r = gdImageColorAllocate(im, 255, 0, 0);  
+  g = gdImageColorAllocate(im, 0, 255, 0);  
+  b = gdImageColorAllocate(im, 0, 0, 255);  
+  /* Now use cgic to find out what color the user requested */
+  <a href="#cgiFormSelectSingle">cgiFormSelectSingle</a>("color", 3, &amp;colorChosen, 0);  
+  /* Now fill with the desired color */
+  switch(colorChosen) {
+    case 0:
+    gdImageFill(im, 32, 32, r);
+    break;
+    case 1:
+    gdImageFill(im, 32, 32, g);
+    break;
+    case 2:
+    gdImageFill(im, 32, 32, b);
+    break;
+  }  
+  /* Now output the image. Note the content type! */
+  cgiHeaderContentType("image/gif");
+  /* Send the image to cgiOut */
+  gdImageGif(im, cgiOut);
+  /* Free the gd image */
+  gdImageDestroy(im);
+  return 0;
+}
+</pre>
+Note that this program would need to be linked with both cgic.o
+and libgd.a. Often programs of this type respond to one
+cgiPathInfo value or set of form fields by returning an HTML page 
+with an inline image reference that, in turn, generates a GIF image.
+<h3><a name="debug">Debugging CGI applications: using capture</a></h3>
+Debugging CGI applications can be a painful task. Since CGI applications
+run in a special environment created by the web server, it is difficult
+to execute them in a debugger. However, the cgic library provides a way 
+of capturing "live" CGI environments to a file, and also provides a way
+to reload saved environments. 
+<p>
+The provided program 'capture.c' can be used to capture CGI
+environments. Just change the first line of the cgiMain() function
+of capture.c to save the CGI environment to a filename appropriate
+on your system and type 'make capture'. Then place capture in your
+cgi directory and set the form action or other link you want to test
+to point to it. When the form submission or other link takes place,
+capture will write the CGI environment active at that time to
+the filename you specified in the source. The
+<a href="#cgiReadEnvironment">cgiReadEnvironment()</a> function can then 
+be invoked on the same filename at the beginning of the cgiMain() function 
+of the application you want to test in order to restore the captured 
+environment.  You can then execute your program in the debugger of your choice,
+and it should perform exactly as it would have performed had
+it been launched by the actual web server, including file uploads,
+cookies and all other phenomena within the purview of cgic.
+<p>
+<strong>Important:</strong> Make sure you specify the full path, as the
+current working directory of a CGI script may not be what you
+think it is!
+<p>
+<strong>Even More Important:</strong> If you call getenv() yourself
+in your code, instead of using the provided <a href="#variables">
+cgic copies of the CGI environment variables</a>, you will
+<em>not</em> get the values you expect when running with
+a saved CGI environment. Always use the cgic variables instead
+of calling getenv().
+<h3><a name="functions">cgic function reference</a></h3>
+<dl>
+<br><dt><strong><a name="cgiFormString">cgiFormResultType cgiFormString(
+  char *name, char *result, int max)</a>
+</strong><br><dd>cgiFormString attempts to retrieve the string sent for the
+  specified input field. The text will be copied into
+  the buffer specified by result, up to but not
+  exceeding max-1 bytes; a terminating null is then
+  added to complete the string. Regardless of the newline
+  format submitted by the browser, cgiFormString always
+  encodes each newline as a single line feed (ascii decimal 10); as
+  a result the final string may be slightly shorter than indicated
+  by a call to <a href="#cgiFormStringSpaceNeeded">
+  cgiFormStringSpaceNeeded</a> but will never be longer.
+  cgiFormString returns <a href="#cgiFormSuccess">cgiFormSuccess</a> if the string was 
+  successfully retrieved, 
+  <a href="#cgiFormTruncated">cgiFormTruncated</a> if the string was
+  retrieved but was truncated to fit the buffer,
+  cgiFormEmpty if the string was 
+  retrieved but was empty, and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no 
+  such input field was submitted. In the last case, 
+  an empty string is copied to result. 
+<br><br><dt><strong><a name="cgiFormStringNoNewlines">
+cgiFormResultType cgiFormStringNoNewlines(
+  char *name, char *result, int max)</a>
+</strong><br><dd>
+cgiFormStringNoNewlines() is exactly equivalent to <a href="#cgiFormString">
+  cgiFormString()</a>, except
+  that any carriage returns or line feeds that occur in the input
+  will be stripped out. The use of this function is recommended
+  for single-line text input fields, as some browsers will submit
+  carriage returns and line feeds when they should not. 
+<br><br><dt><strong><a name="cgiFormStringSpaceNeeded">
+cgiFormResultType cgiFormStringSpaceNeeded(
+  char *name, int *length)</a>
+</strong><br><dd>
+cgiFormStringSpaceNeeded() is used to determine the length of the input text 
+  buffer needed to receive the contents of the specified input field. 
+  This is useful if the programmer wishes to allocate sufficient memory 
+  for input of arbitrary length. The actual length of the string 
+  retrieved by a subsequent call to cgiFormString() may be slightly shorter
+  but will never be longer than *result. On success, cgiFormStringSpaceNeeded() 
+  sets the value pointed to by length to the number of bytes of data, 
+  including the terminating null, and returns <a href="#cgiFormSuccess">cgiFormSuccess</a>. If no 
+  value was submitted for the specified field, cgiFormStringSpaceNeeded sets 
+  the value pointed to by length to 1 and returns <a href="#cgiFormNotFound">cgiFormNotFound</a>. 1 is
+  set to ensure space for an empty string (a single null
+  character) if cgiFormString is called despite the return value.
+
+<br><br><dt><strong><a name="cgiFormStringMultiple">cgiFormResultType cgiFormStringMultiple(
+  char *name, char ***ptrToStringArray)</a>
+</strong><br><dd>cgiFormStringMultiple is useful in the unusual case in which several
+  input elements in the form have the same name and, for whatever
+  reason, the programmer does not wish to use the checkbox, radio 
+  button and selection menu functions provided below. This is
+  occasionally needed if the programmer cannot know 
+  in advance what values might appear in a multiple-selection list
+  or group of checkboxes on a form. The value pointed to
+  by result will be set to a pointer to an array of strings; the last
+  entry in the array will be a null pointer.  This array is allocated 
+  by the CGI library. Important: when done working with the array,
+  you must call cgiStringArrayFree() with the array pointer as the 
+  argument.  cgiFormStringMultiple() returns <a href="#cgiFormSuccess">cgiFormSuccess</a> if at least
+  one occurrence of the name is found, <a href="#cgiFormNotFound">cgiFormNotFound</a>
+  if no occurrences are found, or cgiFormMemory if not enough
+  memory is available to allocate the array to be returned.
+  In all cases except the last, ptrToStringArray is set to point to a 
+  valid array of strings, with the last element in the array being a 
+  null pointer; in the out-of-memory case ptrToStringArray is set to 
+  a null pointer.
+
+<br><br><dt><strong><a name="cgiFormEntries">cgiFormResultType cgiFormEntries(
+  char ***ptrToStringArray)</a>
+</strong><br><dd>cgiFormEntries is useful when the programmer cannot know the names
+  of all relevant form fields in advance. The value pointed to
+  by result will be set to a pointer to an array of strings; the last
+  entry in the array will be a null pointer.  This array is allocated 
+  by the CGI library. Important: when done working with the array,
+  you must call cgiStringArrayFree() with the array pointer as the 
+  argument. cgiFormEntries() returns <a href="#cgiFormSuccess">cgiFormSuccess</a> except in the event of an out of memory error.
+  On success, ptrToStringArray is set to point to a 
+  valid array of strings, with the last element in the array being a 
+  null pointer; in the out-of-memory case ptrToStringArray is set to 
+  a null pointer, and 
+  <a href="#cgiFormOutOfMemory">cgiFormOutOfMemory</a> is returned.
+
+<br><br><dt><strong><a name="cgiStringArrayFree">void cgiStringArrayFree(char **stringArray)
+</a>
+</strong><br><dd>
+cgiStringArrayFree() is used to free the memory associated with
+  a string array created by 
+  <a href="#cgiFormStringMultiple">cgiFormStringMultiple()</a>,
+  <a href="#cgiFormEntries">cgiFormEntries()</a>, or
+  <a href="#cgiFormCookies">cgiFormCookies()</a>.
+<br><br><dt><strong><a name="cgiFormInteger">cgiFormResultType cgiFormInteger(
+  char *name, int *result, int defaultV)</a>
+</strong><br><dd>cgiFormInteger() attempts to retrieve the integer sent for the
+  specified input field. The value pointed to by result
+  will be set to the value submitted. cgiFormInteger() returns 
+  cgiFormSuccess if the value was successfully retrieved,
+  cgiFormEmpty if the value submitted is an empty string,
+  cgiFormBadType if the value submitted is not an integer,
+  and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no such input field was submitted. 
+  In the last three cases, the value pointed to by result
+  is set to the specified default.
+<br><br><dt><strong><a name="cgiFormIntegerBounded">
+cgiFormResultType cgiFormIntegerBounded(
+  char *name, int *result, int min, int max, int defaultV)</a>
+</strong><br><dd>cgiFormIntegerBounded() attempts to retrieve the integer sent for the
+  specified input field, and constrains the result to be within
+  the specified bounds. The value pointed to by result
+  will be set to the value submitted. cgiFormIntegerBounded() returns 
+  cgiFormSuccess if the value was successfully retrieved,
+  <a href="#cgiFormConstrained">cgiFormConstrained</a> if the value was out of bounds and result
+  was adjusted accordingly, <a href="#cgiFormEmpty">cgiFormEmpty</a> if the value submitted is 
+  an empty string, <a href="#cgiFormBadType">cgiFormBadType</a> if the value submitted is not an 
+  integer, and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no such input field was submitted. 
+  In the last three cases, the value pointed to by result
+  is set to the specified default.
+
+<br><br><dt><strong><a name="cgiFormDouble">cgiFormResultType cgiFormDouble(
+  char *name, double *result, double defaultV)</a>
+</strong><br><dd>cgiFormDouble attempts to retrieve the floating-point value sent for 
+  the specified input field. The value pointed to by result
+  will be set to the value submitted. cgiFormDouble returns 
+  cgiFormSuccess if the value was successfully retrieved,
+  cgiFormEmpty if the value submitted is an empty string,
+  cgiFormBadType if the value submitted is not a number,
+  and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no such input field was submitted. 
+  In the last three cases, the value pointed to by result
+  is set to the specified default. 
+<br><br><dt><strong><a name="cgiFormDoubleBounded">
+cgiFormResultType cgiFormDoubleBounded(
+  char *name, double *result, double min, double max, 
+  double defaultV)</a>
+</strong><br><dd>
+cgiFormDoubleBounded() attempts to retrieve the floating-point
+  value  sent for the specified input field, and constrains the 
+  result to be within the specified bounds. The value pointed to by 
+  result will be set to the value submitted. cgiFormDoubleBounded() returns 
+  cgiFormSuccess if the value was successfully retrieved,
+  <a href="#cgiFormConstrained">cgiFormConstrained</a> if the value was out of bounds and result
+  was adjusted accordingly, <a href="#cgiFormEmpty">cgiFormEmpty</a> if the value submitted is 
+  an empty string, <a href="#cgiFormBadType">cgiFormBadType</a> if the value submitted is not a 
+  number, and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no such input field was submitted. 
+  In the last three cases, the value pointed to by result
+  is set to the specified default. 
+
+<br><br><dt><strong><a name="cgiFormSelectSingle">
+cgiFormResultType cgiFormSelectSingle(
+  char *name, char **choicesText, int choicesTotal, 
+  int *result, int defaultV)</a>
+</strong><br><dd>
+cgiFormSelectSingle() retrieves the selection number associated with a
+  &lt;SELECT&gt; element that does not allow multiple selections. name
+  should identify the NAME attribute of the &lt;SELECT&gt; element. choicesText 
+  should point to an array of strings identifying each choice; 
+  choicesTotal should indicate the total number of choices. The value 
+  pointed to by result will be set to the position of the actual choice
+  selected within the choicesText array, if any, or to the value of 
+  default, if no selection was submitted or an invalid selection was 
+  made.  cgiFormSelectSingle() returns <a href="#cgiFormSuccess">cgiFormSuccess</a> if the value was
+  successfully retrieved, <a href="#cgiFormNotFound">cgiFormNotFound</a> if no selection
+  was submitted, and <a href="#cgiFormNoSuchChoice">cgiFormNoSuchChoice</a> if the selection
+  does not match any of the possibilities in the choicesText array. 
+<br><dt><strong>
+<a name="cgiFormSelectMultiple">
+cgiFormResultType cgiFormSelectMultiple(
+  char *name, char **choicesText, int choicesTotal, 
+  int *result, int *invalid)</a>
+</strong><br><dd>cgiFormSelectMultiple() retrieves the selection numbers associated with a
+  &lt;SELECT&gt; element that does allow multiple selections. name should
+  identify the NAME attribute of the &lt;SELECT&gt; element. choicesText 
+  should point to an array of strings identifying each choice; 
+  choicesTotal should indicate the total number of choices. result
+  should point to an array of integers with as many elements as there
+  are strings in the choicesText array. For each choice in the
+  choicesText array that is selected, the corresponding integer in
+  the result array will be set to one; other entries in the result
+  array will be set to zero. cgiFormSelectMultiple() returns <a href="#cgiFormSuccess">cgiFormSuccess</a> 
+  if at least one valid selection was successfully retrieved or
+  cgiFormNotFound if no valid selections were submitted.
+  The integer pointed to by invalid is set to the number of
+  invalid selections that were submitted, which should be zero
+  unless the form and the choicesText array do not agree.
+
+<br><br><dt><strong>
+<a name="cgiFormSubmitClicked">
+cgiFormResultType cgiFormSubmitClicked(
+  char *name)</a>
+</strong><br><dd>
+It is often desirable to know whether a particular submit button was clicked,
+  when multiple submit buttons with different name attributes exist.
+  cgiFormSubmitClicked is an alternative name for the 
+  <a href="#cgiFormCheckboxSingle">cgiFormCheckboxSingle</a> function,
+  which is suitable for testing whether a particular submit button
+  was used.
+<br><br><dt><strong>
+<a name="cgiFormCheckboxSingle">
+cgiFormResultType cgiFormCheckboxSingle(
+  char *name)</a>
+</strong><br><dd>
+cgiFormCheckboxSingle determines whether the checkbox with the specified name
+  is checked. cgiFormCheckboxSingle returns <a href="#cgiFormSuccess">cgiFormSuccess</a> if the
+  button is checked, <a href="#cgiFormNotFound">cgiFormNotFound</a> if the checkbox is
+  not checked. cgiFormCheckboxSingle is intended for single
+  checkboxes with a unique name; see below for functions to
+  deal with multiple checkboxes with the same name, and
+  with radio buttons.
+
+<br><br><dt><strong><a name="cgiFormCheckboxMultiple">
+cgiFormResultType cgiFormCheckboxMultiple(
+  char *name, char **valuesText, int valuesTotal, 
+  int *result, int *invalid)</a>
+</strong><br><dd>cgiFormCheckboxMultiple() determines which checkboxes among a group
+  of checkboxes with the same name are checked. This is distinct
+  from radio buttons (see <a href="#cgiFormRadio">cgiFormRadio</a>). 
+  valuesText 
+  should point to an array of strings identifying the VALUE
+  attribute of each checkbox; valuesTotal should indicate the total 
+  number of checkboxes. result should point to an array of integers with 
+  as many elements as there are strings in the valuesText array. For 
+  each choice in the valuesText array that is selected, the corresponding
+  integer in the result array will be set to one; other entries in the 
+  result array will be set to zero. cgiFormCheckboxMultiple returns 
+  cgiFormSuccess if at least one valid checkbox was checked or
+  cgiFormNotFound if no valid checkboxes were checked.
+  The integer pointed to by invalid is set to the number of
+  invalid selections that were submitted, which should be zero
+  unless the form and the valuesText array do not agree.
+<br><br><dt><strong><a name="cgiFormRadio">
+cgiFormResultType cgiFormRadio(
+  char *name, char **valuesText, int valuesTotal, 
+  int *result, int defaultV)</a>
+</strong><br><dd>cgiFormRadio() determines which, if any, of a group of radio boxes with
+  the same name was selected. valuesText should point to an array of 
+  strings identifying the VALUE attribute of each radio box; 
+  valuesTotal should indicate the total number of radio boxes. The value 
+  pointed to by result will be set to the position of the actual choice 
+  selected within the valuesText array, if any, or to the value of 
+  default, if no radio box was checked or an invalid selection was 
+  made. cgiFormRadio() returns <a href="#cgiFormSuccess">cgiFormSuccess</a> if a checked radio box was 
+  found in the group, <a href="#cgiFormNotFound">cgiFormNotFound</a> if no box was checked, and 
+  <a href="#cgiFormNoSuchChoice">cgiFormNoSuchChoice</a> if the radio box submitted does not match any of 
+  the possibilities in the valuesText array.
+
+<br><dt><strong><a name="cgiFormFileName">cgiFormResultType cgiFormFileName(
+  char *name, char *fileName, int max)</a>
+</strong><br><dd>cgiFormFileName attempts to retrieve the file name uploaded by the
+  user for the specified form input field of type <code>file</code>. 
+  <strong>NEVER, EVER TRUST THIS FILENAME TO BE REASONABLE AND
+  SAFE FOR DIRECT USE ON THE SERVER SIDE.</strong>
+  The text will be copied into
+  the buffer specified by fileName, up to but not
+  exceeding max-1 bytes; a terminating null is then
+  added to complete the string. cgiFormFileName returns 
+  <a href="#cgiFormSuccess">cgiFormSuccess</a> if the string was 
+  successfully retrieved and was not empty,
+  <a href="#cgiFormNoFileName">cgiFormNoFileName</a> if the string was 
+  successfully retrieved but empty indicating that no file was uploaded,
+  <a href="#cgiFormTruncated">cgiFormTruncated</a> if the string was
+  retrieved but was truncated to fit the buffer,
+  and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no 
+  such input field was submitted. In the last case, 
+  an empty string is copied to result. 
+<br><dt><strong><a name="cgiFormFileSize">cgiFormResultType cgiFormFileSize(
+  char *name, int *sizeP)</a>
+</strong><br><dd>cgiFormFileSize attempts to retrieve the size, in bytes, of a
+  file uploaded by the browser in response to the
+  input field of type <code>file</code> specified by the
+  <code>name</code> parameter. On success, the size is stored
+  to *sizeP, and this function returns 
+  <a href="#cgiFormSuccess">cgiFormSuccess</a>. If the form
+  field does not exist, this function returns 
+  <a href="#cgiFormNotFound">cgiFormNotFound</a>.
+  If the form field exists but no file was uploaded, this function
+  returns <a href="#cgiFormNotAFile">cgiFormNotAFile</a>.
+<br><dt><strong><a name="cgiFormFileContentType">cgiFormResultType cgiFormFileContentType(
+  char *name, char *contentType, int max)</a>
+</strong><br><dd>cgiFormString attempts to retrieve the content name claimed by the
+  user for the specified form input field of type <code>file</code>. 
+  <strong>THERE IS NO GUARANTEE THAT THE CONTENT TYPE WILL BE
+  ACCURATE.</strong>
+  The content type string will be copied into
+  the buffer specified by contentType, up to but not
+  exceeding max-1 bytes; a terminating null is then
+  added to complete the string. cgiFormFileContentType returns 
+  <a href="#cgiFormSuccess">cgiFormSuccess</a> if the string was 
+  successfully retrieved and was not empty,
+  <a href="#cgiFormNoContentType">cgiFormNoContentType</a> if the string was 
+  successfully retrieved but empty indicating that no file was uploaded
+  or the browser did not know the content type,
+  <a href="#cgiFormTruncated">cgiFormTruncated</a> if the string was
+  retrieved but was truncated to fit the buffer,
+  and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no 
+  such input field was submitted. In the last case, 
+  an empty string is copied to result. 
+
+<br><dt><strong><a name="cgiFormFileOpen">cgiFormResultType cgiFormFileOpen(
+  char *name, cgiFilePtr *cfpp)</a>
+</strong><br><dd>cgiFormFileOpen attempts to open the actual uploaded file data for
+  the specified form field of type <code>file</code>. Upon success,
+  this function returns retrieve the content name claimed by the
+  user for the specified form input field of type <code>file</code>. 
+  On success, this function sets *cfpp to a valid cgiFilePtr
+  object for use with <a href="#cgiFormFileRead</a>cgiFormFileRead</a>
+  and returns <a href="#cgiFormSuccess">cgiFormSuccess</a>.
+  On failure, this function sets *cfpp to a null pointer, and
+  returns <a href="#cgiFormNotFound">cgiFormNotFound</a>,
+  <a href="#cgiFormNotAFile">cgiFormNotAFile</a>,
+  <a href="#cgiFormMemory">cgiFormMemory</a> or
+  <a href="#cgiFormIO">cgiFormIO</a> as appropriate.
+<p>
+  See also <a href="#cgiFormFileRead">cgiFormFileRead</a> 
+and <a href="#cgiFormFileClose">cgiFormFileClose</a>.
+<br><dt><strong><a name="cgiFormFileRead">cgiFormResultType cgiFormFileRead(
+  cgiFilePtr cfp, char *buffer, int bufferSize, int *gotP)</a>
+</strong><br><dd>cgiFormFileRead attempts to read up to <code>bufferSize</code>
+  bytes from a cgiFilePtr object previously opened with
+  <a href="#cgiFormFileOpen">cgiFormFileOpen</a>. If any data
+  is successfully read, it is copied to <code>buffer</code>, 
+  and the number of bytes successfully read is stored 
+  to <code>*gotP</code>. This function returns 
+  <a href="#cgiFormSuccess">cgiFormSuccess</a> if any data
+  is successfully read. At end of file, this function
+  returns <a href="#cgiFormEOF">cgiFormEOF</a>. In the event
+  of an I/O error, this function returns 
+  <a href="#cgiFormIO">cgiFormIO</a>. If cfp is a null pointer,
+  this function returns <a href="#cgiFormOpenFailed">cgiFormOpenFailed</a>.
+  <p>
+  See also <a href="#cgiFormFileOpen">cgiFormFileOpen</a> 
+and <a href="#cgiFormFileClose">cgiFormFileClose</a>.
+<br><dt><strong><a name="cgiFormFileClose">cgiFormResultType cgiFormFileClose(
+  cgiFilePtr cfp)</a>
+</strong><br><dd>cgiFormFileClose closes a cgiFilePtr object previously opened
+  with <a href="#cgiFormFileOpen">cgiFormFileOpen</a>, freeing
+  memory and other system resources. This
+  function returns <a href="#cgiFormSuccess">cgiFormSuccess</a>
+  unless cfp is null, in which case 
+  <a href="#cgiFormOpenFailed">cgiFormOpenFailed</a> is returned.
+<p>
+  See also <a href="#cgiFormFileOpen">cgiFormFileOpen</a> 
+and <a href="#cgiFormFileRead">cgiFormFileRead</a>.
+<br><br><dt><strong><a name="cgiHeaderLocation">
+void cgiHeaderLocation(char *redirectUrl)</a>
+</strong><br><dd>
+cgiHeaderLocation() should be called if the programmer wishes to
+redirect the user to a different URL. No further output
+is needed in this case.
+<p>
+If you wish to set cookies,
+<strong>you must make your calls to 
+<a href="#cgiHeaderCookieSetString">cgiHeaderCookieSetString</a>
+and 
+<a href="#cgiHeaderCookieSetInteger">cgiHeaderCookieSetInteger</a>
+</strong> BEFORE invoking cgiHeaderLocation. 
+<br><br><dt><strong><a name="cgiHeaderStatus">
+void cgiHeaderStatus(int status, char *statusMessage)</a>
+</strong><br><dd>
+cgiHeaderStatus() should be called if the programmer wishes to
+output an HTTP error status code instead of a document. The status
+code is the first argument; the second argument is the status
+message to be displayed to the user.
+<p>
+If you wish to set cookies,
+<strong>you must make your calls to 
+<a href="#cgiHeaderCookieSetString">cgiHeaderCookieSetString</a>
+and 
+<a href="#cgiHeaderCookieSetInteger">cgiHeaderCookieSetInteger</a>
+</strong> BEFORE invoking cgiHeaderStatus.
+<br><br><dt><strong><a name="cgiHeaderContentType">
+void cgiHeaderContentType(char *mimeType)</a>
+</strong><br><dd>
+cgiHeaderContentType() should be called if the programmer wishes to
+output a new document in response to the user's request. This is
+the normal case. The single argument is the MIME document type
+of the response; typical values are "text/html" for HTML documents, 
+"text/plain" for plain ASCII without HTML tags, "image/gif" for
+a GIF image and "audio/basic" for .au-format audio.
+<p>
+If you wish to set cookies,
+<strong>you must make your calls to 
+<a href="#cgiHeaderCookieSetString">cgiHeaderCookieSetString</a>
+and 
+<a href="#cgiHeaderCookieSetInteger">cgiHeaderCookieSetInteger</a>
+</strong> BEFORE invoking cgiHeaderContentType.
+<br><br><dt><strong><a name="cgiHeaderCookieSetString">
+void cgiHeaderCookieSetString(char *name, char *value,
+  int secondsToLive, char *path, char *domain)</a>
+</strong><br><dd>
+cgiHeaderCookieSetString() should be called when the programmer wishes
+to store a piece of information in the user's browser, so that the
+stored information is again presented to the server on subsequent
+accesses to the relevant site. The first argument is the name of the
+cookie to be stored; for best results in all browsers, use a short
+name without spaces or unusual punctuation. The second argument is
+the value of the cookie to be stored. Again, for best results, use
+a short string; it is recommended that cookies be used to store a
+unique identifier which is then used to look up more detailed
+information in a database on the server side. Attempts to store
+elaborate information on the browser side are much more likely to fail.
+The third argument is the number of seconds that the cookie should
+be kept by the browser; 86400 is a single full day, 365*86400 is
+roughly one year. The fourth argument is the partial URL of the
+web site within which the cookie is relevant. If the cookie should
+be sent to the server for every access to the entire site, 
+set this argument to <code>/</code>. The final argument is the
+web site name or entire domain for which this cookie should be
+submitted; if you choose to have the cookie sent back for an
+entire domain, this argument must begin with a dot, such as
+<code>.boutell.com</code>. The cgic variables <a name="#cgiScriptName</a>
+and <a name="#cgiServerName">cgiServerName</a> are convenient
+values for the fourth and fifth arguments.
+See also <a href="#cgiHeaderCookieSetInteger">cgiHeaderCookieSetInteger</a>,
+<a href="#cgiCookieString">cgiCookieString</a>, 
+<a href="#cgiCookieString">cgiCookieInteger</a> and
+<a href="#cgiCookies">cgiCookies</a>.
+<br><br><dt><strong><a name="cgiHeaderCookieSetInteger">
+void cgiHeaderCookieSetInteger(char *name, int value,
+  int secondsToLive, char *path, char *domain)</a>
+</strong><br><dd>
+cgiHeaderCookieSetInteger() is identical to
+<a href="#cgiHeaderCookieSetString">cgiHeaderCookieSetString</a>,
+except that the value to be set is an integer rather than a string.
+See <a href="#cgiHeaderCookieSetString">cgiHeaderCookieSetString</a>
+for complete information.
+<br>
+<br><dt><strong><a name="cgiCookieString">cgiFormResultType cgiCookieString(
+  char *name, char *result, int max)</a>
+</strong><br><dd>cgiFormString attempts to retrieve the string sent for the
+  specified cookie (browser-side persistent storage). The 
+  text will be copied into
+  the buffer specified by result, up to but not
+  exceeding max-1 bytes; a terminating null is then
+  added to complete the string.
+  cgiCookieString returns <a href="#cgiFormSuccess">cgiFormSuccess</a> if the string was 
+  successfully retrieved, 
+  <a href="#cgiFormTruncated">cgiFormTruncated</a> if the string was
+  retrieved but was truncated to fit the buffer,
+  cgiFormEmpty if the string was 
+  retrieved but was empty, and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no 
+  such cookie was submitted. In the last case, 
+  an empty string is copied to result. 
+<br><br><dt><strong><a name="cgiCookieInteger">cgiFormResultType cgiCookieInteger(
+  char *name, int *result, int defaultV)</a>
+  See also <a href="#cgiCookieString">cgiCookieInteger</a>,
+  <a href="#cgiCookies">cgiCookies</a>,
+  <a href="#cgiHeaderCookieSetString>cgiHeaderCookieSetString</a>, and
+  <a href="#cgiHeaderCookieSetInteger>cgiHeaderCookieSetInteger</a>.
+</strong><br><dd>cgiCookieInteger() attempts to retrieve the integer sent for the
+  specified cookie (browser-side persistent storage). The value 
+  pointed to by result will be set to the value submitted. 
+  cgiCookieInteger() returns 
+  cgiFormSuccess if the value was successfully retrieved,
+  cgiFormEmpty if the value submitted is an empty string,
+  cgiFormBadType if the value submitted is not an integer,
+  and <a href="#cgiFormNotFound">cgiFormNotFound</a> if no such 
+  input field was submitted. In the last three cases, the value 
+  pointed to by result is set to the specified default.
+  See also <a href="#cgiCookieString">cgiCookieString</a>,
+  <a href="#cgiCookies">cgiCookies</a>,
+  <a href="#cgiHeaderCookieSetString>cgiHeaderCookieSetString</a>, and
+  <a href="#cgiHeaderCookieSetInteger>cgiHeaderCookieSetInteger</a>.
+<br><br><dt><strong><a name="cgiCookies">cgiFormResultType cgiCookies(
+  char *name, char ***ptrToStringArray)</a>
+</strong><br><dd>cgiCookies is useful when the programmer cannot know the names
+  of all relevant cookies (browser-side persistent strings) in advance.
+  The value pointed to by result will be set to a pointer to an array 
+  of strings; the last
+  entry in the array will be a null pointer.  This array is allocated 
+  by the CGI library. Important: when done working with the array,
+  you must call cgiStringArrayFree() with the array pointer as the 
+  argument. cgiCookies() returns <a href="#cgiFormSuccess">cgiFormSuccess</a> except in the event of an out of memory error.
+  On success, ptrToStringArray is set to point to a 
+  valid array of strings, with the last element in the array being a 
+  null pointer; in the out-of-memory case ptrToStringArray is set to 
+  a null pointer, and 
+  <a href="#cgiFormOutOfMemory">cgiFormOutOfMemory</a> is returned.
+<br><br><dt><strong><a name="cgiHtmlEscape">
+cgiFormResultType cgiHtmlEscape(char *s)</a>
+</strong><br><dd>
+cgiHtmlEscape() outputs the specified null-terminated string to 
+<a href="#cgiOut">cgiOut</a>,
+escaping any &lt;, &amp;, and &gt; characters encountered correctly so that
+they do not interfere with HTML markup. Returns 
+<a href="#cgiFormSuccess">cgiFormSuccess</a>, or
+<a href="#cgiFormIO">cgiFormIO</a> in the event of an I/O error.
+<p> 
+<br><br><dt><strong><a name="cgiHtmlEscapeData">
+cgiFormResultType cgiHtmlEscapeData(char *data, int len)</a>
+</strong><br><dd>
+cgiHtmlEscapeData() is identical to <a href="#cgiHtmlEscape">cgiHtmlEscape</a>,
+except that the data is not null-terminated. This version of the function
+outputs <code>len</code> bytes. See <a href="#cgiHtmlEscape">cgiHtmlEscape</a>
+for more information.
+<br><br><dt><strong><a name="cgiValueEscape">
+cgiFormResultType cgiValueEscape(char *s)</a>
+</strong><br><dd>
+cgiValueEscape() outputs the specified null-terminated string to 
+<a href="#cgiOut">cgiOut</a>,
+escaping any " characters encountered correctly so that
+they do not interfere with the quotation marks of HTML attribute
+values. This is useful when outputting a string as part of the
+value attribute of an input tag, or the href attribute of a link
+or form tag. This function returns
+<a href="#cgiFormSuccess">cgiFormSuccess</a>, or
+<a href="#cgiFormIO">cgiFormIO</a> in the event of an I/O error.
+<p> 
+<br><br><dt><strong><a name="cgiValueEscapeData">
+cgiFormResultType cgiValueEscapeData(char *data, int len)</a>
+</strong><br><dd>
+cgiValueEscapeData() is identical to <a href="#cgiValueEscape">cgiValueEscape</a>,
+except that the data is not null-terminated. This version of the function
+outputs <code>len</code> bytes. See <a href="#cgiValueEscape">cgiValueEscape</a>
+for more information.
+<br><br><dt><strong><a name="cgiWriteEnvironment">
+cgiEnvironmentResultType cgiWriteEnvironment(char *filename)</a>
+</strong><br><dd>
+cgiWriteEnvironment() can
+  be used to write the entire CGI environment, including
+  form data, to the specified output file; <a href="#cgiReadEnvironment">
+  cgiReadEnvironment()</a> 
+  can then be used to restore that environment from the specified
+  input file for debugging. Of course, these will only work as expected
+  if you use the <a href="#variables">cgic copies of the CGI environment 
+  variables</a> and <a href="#cgiIn">cgiIn</a> and 
+  <a href="#cgiOut">cgiOut</a> rather than stdin and
+  stdout (also see above). These functions are useful in order 
+  to capture real CGI situations while the web server is running, then
+  recreate them in a debugging environment. Both functions
+  return <a href="#cgiEnvironmentSuccess">cgiEnvironmentSuccess</a> on 
+  success, <a href="#cgiEnvironmentIO">cgiEnvironmentIO</a> on an I/O 
+  error, and <a href="#cgiEnvironmentMemory">cgiEnvironmentMemory</a>
+  on an out-of-memory error.
+<br><br><dt><strong><a name="cgiReadEnvironment">
+cgiEnvironmentResultType cgiReadEnvironment(char *filename)</a>
+</strong><br><dd>
+cgiReadEnvironment() restores a CGI environment saved to the specified file by
+  <a href="#cgiWriteEnvironment">cgiWriteEnvironment().</a> 
+  Of course, these will only work as expected
+  if you use the <a href="#variables">cgic copies of the CGI environment 
+  variables</a> and <a href="#cgiIn">cgiIn</a> and 
+  <a href="#cgiOut">cgiOut</a> rather than stdin and
+  stdout (also see above). These functions are useful in order 
+  to capture real CGI situations while the web server is running, then
+  recreate them in a debugging environment. Both functions
+  return <a href="#cgiEnvironmentSuccess">cgiEnvironmentSuccess</a> on success, 
+  <a href="#cgiEnvironmentIO">cgiEnvironmentIO</a> on an I/O error, and 
+  <a href="#cgiEnvironmentMemory">cgiEnvironmentMemory</a>
+  on an out-of-memory error.
+<br><br><dt><strong><a name="cgiMain">int cgiMain()</a>
+</strong><br><dd><strong>The programmer must write this function</strong>, which performs 
+  the unique task of the program and is invoked by the true main() 
+  function, found in the cgic library itself. The return value from 
+  cgiMain will be the return value of the program. It is expected that 
+  the user will make numerous calls to the cgiForm functions
+  from within this function. See <a href="#howto">how to write
+  a cgic application</a> for details.
+</dl>
+<h3><a name="variables">cgic variable reference</a></h3>
+This section provides a reference guide to the various global
+variables provided by cgic for the programmer to utilize.
+These variables should always be used in preference to
+stdin, stdout, and calls to getenv() in order to ensure
+compatibility with the <a href="#debug">cgic CGI debugging features</a>.
+<p>
+Most of these variables are equivalent to various CGI environment
+variables. The most important difference is that the cgic
+environment string variables are never null pointers. They will always 
+point to valid C strings of zero or more characters.
+<dl>
+<br><dt><strong><a name="cgiServerSoftware">char *cgiServerSoftware</a>
+</strong><br><dd>Points to the name of the server software,
+or to an empty string if unknown.
+<br><dt><strong><a name="cgiServerName">char *cgiServerName</a>
+</strong><br><dd>Points to the name of the server,
+or to an empty string if unknown.
+<br><dt><strong><a name="cgiGatewayInterface">char *cgiGatewayInterface</a>
+</strong><br><dd>Points to the name of the gateway interface (usually CGI/1.1),
+or to an empty string if unknown.
+<br><dt><strong><a name="cgiServerProtocol">char *cgiServerProtocol</a>
+</strong><br><dd>Points to the protocol in use (usually HTTP/1.0),
+or to an empty string if unknown.
+<br><dt><strong><a name="cgiServerPort">char *cgiServerPort</a>
+</strong><br><dd>Points to the port number on which the server is listening
+for HTTP connections (usually 80), or an empty string if unknown.
+<br><dt><strong><a name="cgiRequestMethod">char *cgiRequestMethod</a>
+</strong><br><dd>Points to the method used in the request (usually GET or POST),
+or an empty string if unknown (this should not happen).
+<br><dt><strong><a name="cgiPathInfo">char *cgiPathInfo</a>
+</strong><br><dd>Most web servers recognize any additional path information in 
+the URL of the request beyond the name of the CGI program itself and
+pass that information on to the program. cgiPathInfo points to this
+additional path information.
+<br><dt><strong><a name="cgiPathTranslated">char *cgiPathTranslated</a>
+</strong><br><dd>Most web servers recognize any additional path information in 
+the URL of the request beyond the name of the CGI program itself and
+pass that information on to the program. cgiPathTranslated points
+to this additional path information, translated by the server into a 
+filesystem path on the local server.
+<br><dt><strong><a name="cgiScriptName">char *cgiScriptName</a>
+</strong><br><dd>Points to the name under which the program was invoked.
+<br><dt><strong><a name="cgiQueryString">char *cgiQueryString</a>
+</strong><br><dd>Contains any query information submitted by the user as a result
+of a GET-method form or an &lt;ISINDEX&gt; tag. Note that this
+information need not be parsed directly unless an &lt;ISINDEX&gt; tag
+was used; normally it is parsed automatically by the cgic library. Use 
+the cgiForm family of functions to retrieve the values associated
+with form input fields. See <a href="#howto">how to write
+a cgic application</a> for more information.
+<br><dt><strong><a name="cgiRemoteHost">char *cgiRemoteHost</a>
+</strong><br><dd>Points to the fully resolved hostname of the browser, if known,
+or an empty string if unknown.
+<br><dt><strong><a name="cgiRemoteAddr">char *cgiRemoteAddr</a>
+</strong><br><dd>Points to the dotted-decimal IP address of the browser, if known,
+or an empty string if unknown.
+<br><dt><strong><a name="cgiAuthType">char *cgiAuthType</a>
+</strong><br><dd>Points to the type of authorization used for the request,
+if any, or an empty string if none or unknown.
+<br><dt><strong><a name="cgiRemoteUser">char *cgiRemoteUser</a>
+</strong><br><dd>Points to the user name under which the user has 
+authenticated; an empty string if no authentication has
+taken place. The certainty of this information depends on
+the type of authorization in use; see
+<a href="#cgiAuthType">cgiAuthType</a>.
+<br><dt><strong><a name="cgiRemoteIdent">char *cgiRemoteIdent</a>
+</strong><br><dd>Points to the user name volunteered by the user via
+the user identification protocol; an empty
+string if unknown. This information is not secure.
+Identification demons can be installed by users on
+insecure systems such as Windows machines.
+<br><dt><strong><a name="cgiContentType">char *cgiContentType</a>
+</strong><br><dd>Points to the MIME content type of the information
+submitted by the user, if any; an empty string if no
+information was submitted. If this string is equal to
+<code>application/x-www-form-urlencoded</code> or
+<code>multipart/form-data</code>, the cgic
+library will automatically examine the form data submitted.
+If this string has any other non-empty value, a different
+type of data has been submitted. This is currently very rare,
+as most browsers can only submit forms and file uploads which
+cgic parses directly.
+<br><dt><strong><a name="cgiContentType">char *cgiCookie</a>
+</strong><br><dd>Points to the raw cookie (browser-side persistent storage)
+data submitted by the web browser. 
+Programmers should use the functions <a href="#cgiCookies">cgiCookies</a>,
+<a href="#cgiCookieString">cgiCookieString</a> and
+<a href="#cgiCookieInteger">cgiCookieInteger</a> instead of
+examining this string directly.
+<br><dt><strong><a name="cgiAccept">char *cgiAccept</a>
+</strong><br><dd>Points to a space-separated list of MIME content types
+acceptable to the browser (see <a href="#cgiHeaderContentType">
+cgiHeaderContentType()</a> ), or an empty string. Unfortunately, this variable
+is not supplied in a useful form by most current browsers. Programmers wishing
+to make decisions based on the capabilities of the browser
+are advised to check the <a href="#cgiUserAgent">cgiUserAgent</a>
+variable against a list of browsers and capabilities instead.
+<br><dt><strong><a name="cgiUserAgent">char *cgiUserAgent</a>
+</strong><br><dd>
+Points to the name of the browser in use, or an empty
+string if this information is not available. 
+<br><dt><strong><a name="cgiReferrer">char *cgiReferrer</a>
+</strong><br><dd>
+Points to the URL of the previous page visited by the user. This is
+often the URL of the form that brought the user to your program.
+Note that reporting this information is entirely up to the browser,
+which may choose not do so, and may choose not to do so truthfully.
+However, this variable is typically accurate. <strong>The frequently
+used misspelling cgiReferer is also supplied as a macro.</strong>
+<br><dt><strong><a name="cgiContentLength">int cgiContentLength</a>
+</strong><br><dd>The number of bytes of form or query data received.
+  Note that if the submission is a form or query submission
+  the library will read and parse all the information
+  directly from cgiIn and/or cgiQueryString. The programmer should
+  not do so, and indeed the cgiIn pointer will be at end-of-file
+  in such cases.
+<br><dt><strong><a name="cgiOut">FILE *cgiOut</a>
+</strong><br><dd>Pointer to CGI output. The cgiHeader functions, such as
+  <a href="#cgiHeaderContentType">cgiHeaderContentType</a>, should 
+  be used first to output the mime headers; the output HTML
+  page, GIF image or other web document should then be written
+  to cgiOut by the programmer using standard C I/O functions
+  such as fprintf() and fwrite(). cgiOut is normally equivalent
+  to stdout; however, it is recommended that cgiOut be used to
+  ensure compatibility with future versions of cgic for
+  specialized environments.
+<br><dt><strong><a name="cgiIn">FILE *cgiIn</a>
+</strong><br><dd>Pointer to CGI input. In 99.99% of cases, you will not 
+  need this. CGIC 2.0 supports both regular POST form submissions
+  and multipart/form-data file upload form submissions directly.
+</dl>
+<H3><a name="resultcodes">cgic result code reference</a></h3>
+<p>
+In most cases, cgic functions are designed to produce reasonable results
+even when browsers and users do unreasonable things. However, it is sometimes
+important to know precisely which unreasonable things took place, especially
+when assigning a default value or bounding a value is an inadequate
+solution. The following result codes are useful in making this determination.
+<dl>
+<br><dt><strong><a name="cgiFormSuccess">cgiFormSuccess</a>
+</strong><br><dd>Indicates that the function successfully performed at least one
+action (or retrieved at least one value, where applicable).
+<br><dt><strong><a name="cgiFormTruncated">cgiFormTruncated</a>
+</strong><br><dd>Indicates that a string value retrieved from the user was
+cut short to avoid overwriting the end of a buffer.
+<br><dt><strong><a name="cgiFormBadType">cgiFormBadType</a>
+</strong><br><dd>Indicates that a "numeric" value submitted by the user was
+in fact not a legal number.
+<br><dt><strong><a name="cgiFormEmpty">cgiFormEmpty</a>
+</strong><br><dd>Indicates that a field was retrieved but contained no data.
+<br><dt><strong><a name="cgiFormNotFound">cgiFormNotFound</a>
+</strong><br><dd>Indicates that no value was submitted for a particular field.
+<br><dt><strong><a name="cgiFormConstrained">cgiFormConstrained</a>
+</strong><br><dd>Indicates that a numeric value was beyond the specified bounds
+and was forced to the lower or upper bound as appropriate.
+<br><dt><strong><a name="cgiFormNoSuchChoice">cgiFormNoSuchChoice</a>
+</strong><br><dd>Indicates that the value submitted for a single-choice field
+(such as a radio-button group) was not one of the acceptable values.
+This usually indicates a discrepancy between the form and the program.
+<br><dt><strong><a name="cgiFormEOF">cgiFormEOF</a>
+</strong><br><dd>Returned by <a href="#cgiFormFileRead">cgiFormFileRead</a>
+when, at the start of the call, the cgiFilePtr object is already
+positioned at the end of the uploaded file data. 
+<br><dt><strong><a name="cgiFormEOF">cgiFormIO</a>
+</strong><br><dd>Returned by <a href="#cgiFormFileRead">cgiFormFileRead</a>
+when an I/O error occurs while reading uploaded file data.
+<br><dt><strong><a name="cgiFormNotAFile">cgiFormNotAFile</a>
+</strong><br><dd>Returned in response to an attempt to manipulate a form field
+that is not a file upload field using a file-related function.
+<br><dt><strong><a name="cgiFormNoContentType">cgiFormNoContentType</a>
+</strong><br><dd>Returned in response to an attempt to fetch the content type of
+a file-upload field when the content type is not specified by the browser.
+<br><dt><strong><a name="cgiFormNoFileName">cgiFormNoFileName</a>
+</strong><br><dd>Returned in response to an attempt to fetch the file name of
+a file-upload field when a file name is not specified by the browser.
+<br><dt><strong><a name="cgiFormOpenFailed">cgiFormOpenFailed</a>
+</strong><br><dd>Returned in response to an attempt to read from a null
+cgiFilePtr object, typically when the programmer has failed to
+check the result of a call to <a href="#cgiFormFileOpen">cgiFormFileOpen</a>.
+<br><dt><strong><a name="cgiEnvironmentMemory">cgiEnvironmentMemory</a>
+</strong><br><dd>Indicates that an attempt to read or write the CGI environment
+to or from a capture file failed due to an out-of-memory error.
+<br><dt><strong><a name="cgiEnvironmentSuccess">cgiEnvironmentSuccess</a>
+</strong><br><dd>Indicates that an attempt to read or write the CGI environment
+to or from a capture file was successful.
+<br><dt><strong><a name="cgiEnvironmentIO">cgiEnvironmentIO</a>
+</strong><br><dd>Indicates that an attempt to read or write the CGI environment
+to or from a capture file failed due to an I/O error. 
+<br><dt><strong><a name="cgiEnvironmentWrongVersion">cgiEnvironmentWrongVersion</a>
+</strong><br><dd>Indicates that an attempt to read from a saved debugging CGI environment
+produced by a pre-2.0 version of CGIC was made. 
+</dl>
+<h3><a name="index">cgic quick index</a></h3>
+<a href="#cgiAccept">cgiAccept</a> |
+<a href="#cgiAuthType">cgiAuthType</a> |
+<a href="#cgiContentLength">cgiContentLength</a> |
+<a href="#cgiContentType">cgiContentType</a> |
+<a href="#cgiEnvironmentIO">cgiEnvironmentIO</a> |
+<a href="#cgiEnvironmentMemory">cgiEnvironmentMemory</a> |
+<a href="#cgiEnvironmentSuccess">cgiEnvironmentSuccess</a> |
+<a href="#cgiCookieInteger">cgiCookieInteger</a> |
+<a href="#cgiCookies">cgiCookies</a> |
+<a href="#cgiCookieSetInteger">cgiCookieSetInteger</a> |
+<a href="#cgiCookieSetString">cgiCookieSetString</a> |
+<a href="#cgiCookieString">cgiCookieString</a> |
+<a href="#cgiHtmlEscape">cgiHtmlEscape</a> |
+<a href="#cgiHtmlEscapeData">cgiHtmlEscapeData</a> |
+<a href="#cgiValueEscape">cgiValueEscape</a> |
+<a href="#cgiValueEscapeData">cgiValueEscapeData</a> |
+<a href="#cgiFormBadType">cgiFormBadType</a> |
+<a href="#cgiFormCheckboxMultiple">cgiFormCheckboxMultiple()</a> |
+<a href="#cgiFormCheckboxSingle">cgiFormCheckboxSingle()</a> |
+<a href="#cgiFormConstrained">cgiFormConstrained</a> |
+<a href="#cgiFormDouble">cgiFormDouble()</a> |
+<a href="#cgiFormDoubleBounded">cgiFormDoubleBounded()</a> |
+<a href="#cgiFormEOF">cgiFormEOF</a> |
+<a href="#cgiFormEmpty">cgiFormEmpty</a> |
+<a href="#cgiFormEntries">cgiFormEntries</a> |
+<a href="#cgiFormFileClose">cgiFormFileClose</a> |
+<a href="#cgiFormFileContentType">cgiFormFileContentType</a> |
+<a href="#cgiFormFileName">cgiFormFileName</a> |
+<a href="#cgiFormFileOpen">cgiFormFileOpen</a> |
+<a href="#cgiFormFileRead">cgiFormFileRead</a> |
+<a href="#cgiFormFileSize">cgiFormFileSize</a> |
+<a href="#cgiFormInteger">cgiFormInteger()</a> |
+<a href="#cgiFormIntegerBounded">cgiFormIntegerBounded()</a> |
+<a href="#cgiFormNoContentType>cgiFormNoContentType</a> |
+<a href="#cgiFormNoFileName>cgiFormNoFileName</a> |
+<a href="#cgiFormNoSuchChoice">cgiFormNoSuchChoice</a> |
+<a href="#cgiFormNotAFile>cgiFormNotAFile</a> |
+<a href="#cgiFormNotFound">cgiFormNotFound</a> |
+<a href="#cgiFormRadio">cgiFormRadio()</a> |
+<a href="#cgiFormSelectMultiple">cgiFormSelectMultiple()</a> |
+<a href="#cgiFormSelectSingle">cgiFormSelectSingle()</a> |
+<a href="#cgiFormString">cgiFormString()</a> |
+<a href="#cgiFormStringMultiple">cgiFormStringMultiple()</a> |
+<a href="#cgiFormStringNoNewlines">cgiFormStringNoNewlines()</a> |
+<a href="#cgiFormStringSpaceNeeded">cgiFormStringSpaceNeeded()</a> |
+<a href="#cgiFormSuccess">cgiFormSuccess</a> |
+<a href="#cgiFormTruncated">cgiFormTruncated</a> |
+<a href="#cgiGatewayInterface">cgiGatewayInterface</a> |
+<a href="#cgiHeaderContentType">cgiHeaderContentType()</a> |
+<a href="#cgiHeaderLocation">cgiHeaderLocation()</a> |
+<a href="#cgiHeaderStatus">cgiHeaderStatus()</a> |
+<a href="#cgiIn">cgiIn</a> |
+<a href="#cgiMain">cgiMain()</a>
+<a href="#cgiOut">cgiOut</a> |
+<a href="#cgiPathInfo">cgiPathInfo</a> |
+<a href="#cgiPathTranslated">cgiPathTranslated</a> |
+<a href="#cgiQueryString">cgiQueryString</a> |
+<a href="#cgiReadEnvironment">cgiReadEnvironment()</a> |
+<a href="#cgiReferrer">cgiReferrer()</a> |
+<a href="#cgiRemoteAddr">cgiRemoteAddr</a> |
+<a href="#cgiRemoteHost">cgiRemoteHost</a> |
+<a href="#cgiRemoteIdent">cgiRemoteIdent</a> |
+<a href="#cgiRemoteUser">cgiRemoteUser</a> |
+<a href="#cgiRequestMethod">cgiRequestMethod</a> |
+<a href="#cgiScriptName">cgiScriptName</a> |
+<a href="#cgiServerName">cgiServerName</a> |
+<a href="#cgiServerPort">cgiServerPort</a> |
+<a href="#cgiServerProtocol">cgiServerProtocol</a> |
+<a href="#cgiServerSoftware">cgiServerSoftware</a> |
+<a href="#cgiStringArrayFree">cgiStringArrayFree()</a> |
+<a href="#cgiUserAgent">cgiUserAgent</a> |
+<a href="#cgiWriteEnvironment">cgiWriteEnvironment()</a>
+<p>
+<hr>
+<em><a href="http://www.boutell.com/">Boutell.Com, Inc.</a></em>
+</body>
+</html>
+
+
Index: /tags/rel-1.7.0/thirds/cgic206/cgictest.c
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/cgictest.c	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/cgictest.c	(revision 942)
@@ -0,0 +1,222 @@
+
+/*
+  $Id: cgictest.c,v 1.2 2004/04/07 17:09:27 fox Exp $
+ */
+
+#include <stdio.h>
+#include "cgic.h"
+
+void Name();
+void Address();
+void Hungry();
+void Temperature();
+void Frogs();
+void Color();
+void Flavors();
+void NonExButtons();
+void RadioButtons();
+
+
+int cgiMain() {
+#if DEBUG
+	/* Load a saved CGI scenario if we're debugging */
+	cgiReadEnvironment("/home/boutell/public_html/capcgi.dat");
+#endif
+	dup2(cgiOut,stdout);
+	printf("Content-Type: text/html; charset=utf-8\r\nStatus: 200 OK\r\n\r\n");
+	//cgiHeaderContentType("text/html");
+	printf( "<HTML><HEAD>\n");
+	printf( "<TITLE>cgic test</TITLE></HEAD>\n");
+	printf( "<BODY><H1>cgic test</H1>\n");
+	Name();
+	Address();
+	Hungry();
+	Temperature();
+	Frogs();
+	Color();
+	Flavors();
+	NonExButtons();
+	RadioButtons();
+	printf( "</BODY></HTML>\n");
+	return 0;
+}
+
+void Name() {
+	char name[81];
+	int result = cgiFormStringNoNewlines("name", name, 81);
+	switch (result) {
+		case cgiFormSuccess:
+		printf( "Name fetched, result code: cgiFormSuccess<br>\n");
+		break;
+		case cgiFormTruncated:
+		printf( "Name fetched, result code: cgiFormTruncated<br>\n");
+		break;
+		case cgiFormEmpty:
+		printf( "Name fetched, result code: cgiFormEmpty<br>\n");
+		break;
+		case cgiFormNotFound:
+		printf( "Name fetched, result code: cgiFormNotFound<br>\n");
+		break;
+		case cgiFormMemory:
+		printf( "Name fetched, result code: cgiFormMemory<br>\n");
+		break;
+		default:
+		printf( "Name fetched, unexpected result code: %d\n", result);
+		break;
+	}	
+	printf( "Name: %s<BR>\n", name);
+}
+	
+void Address() {
+	char address[241];
+	cgiFormString("address", address, 241);
+	printf( "Address: <PRE>\n%s</PRE>\n", address);
+}
+
+void Hungry() {
+	if (cgiFormCheckboxSingle("hungry") == cgiFormSuccess) {
+		printf( "I'm Hungry!<BR>\n");
+	} else {
+		printf( "I'm Not Hungry!<BR>\n");
+	}
+}
+	
+void Temperature() {
+	double temperature;
+	cgiFormDoubleBounded("temperature", &temperature, 80.0, 120.0, 98.6);
+	printf( "My temperature is %f.<BR>\n", temperature);
+}
+	
+void Frogs() {
+	int frogsEaten;
+	cgiFormInteger("frogs", &frogsEaten, 0);
+	printf( "I have eaten %d frogs.<BR>\n", frogsEaten);
+}
+
+char *colors[] = {
+	"Red",
+	"Green",
+	"Blue"
+};
+
+void Color() {
+	int colorChoice;
+	cgiFormSelectSingle("colors", colors, 3, &colorChoice, 0);
+	printf( "I am: %s<BR>\n", colors[colorChoice]);
+}	 
+
+char *flavors[] = {
+	"pistachio",
+	"walnut",
+	"creme"
+};
+
+void Flavors() {
+	int flavorChoices[3];
+	int i;
+	int result;	
+	int invalid;
+	result = cgiFormSelectMultiple("flavors", flavors, 3, 
+		flavorChoices, &invalid);
+	if (result == cgiFormNotFound) {
+		printf( "I hate ice cream.<p>\n");
+	} else {	
+		printf( "My favorite ice cream flavors are:\n");
+		printf( "<ul>\n");
+		for (i=0; (i < 3); i++) {
+			if (flavorChoices[i]) {
+				printf( "<li>%s\n", flavors[i]);
+			}
+		}
+		printf( "</ul>\n");
+	}
+}
+
+char *ages[] = {
+	"1",
+	"2",
+	"3",
+	"4"
+};
+
+void RadioButtons() {
+	int ageChoice;
+	char ageText[10];
+	/* Approach #1: check for one of several valid responses. 
+		Good if there are a short list of possible button values and
+		you wish to enumerate them. */
+	cgiFormRadio("age", ages, 4, &ageChoice, 0);
+
+	printf( "Age of Truck: %s (method #1)<BR>\n", 
+		ages[ageChoice]);
+
+	/* Approach #2: just get the string. Good
+		if the information is not critical or if you wish
+		to verify it in some other way. Note that if
+		the information is numeric, cgiFormInteger,
+		cgiFormDouble, and related functions may be
+		used instead of cgiFormString. */	
+	cgiFormString("age", ageText, 10);
+
+	printf( "Age of Truck: %s (method #2)<BR>\n", ageText);
+}
+
+char *votes[] = {
+	"A",
+	"B",
+	"C",
+	"D"
+};
+
+void NonExButtons() {
+	int voteChoices[4];
+	int i;
+	int result;	
+	int invalid;
+
+	char **responses;
+
+	/* Method #1: check for valid votes. This is a good idea,
+		since votes for nonexistent candidates should probably
+		be discounted... */
+	printf( "Votes (method 1):<BR>\n");
+	result = cgiFormCheckboxMultiple("vote", votes, 4, 
+		voteChoices, &invalid);
+	if (result == cgiFormNotFound) {
+		printf( "I hate them all!<p>\n");
+	} else {	
+		printf( "My preferred candidates are:\n");
+		printf( "<ul>\n");
+		for (i=0; (i < 4); i++) {
+			if (voteChoices[i]) {
+				printf( "<li>%s\n", votes[i]);
+			}
+		}
+		printf( "</ul>\n");
+	}
+
+	/* Method #2: get all the names voted for and trust them.
+		This is good if the form will change more often
+		than the code and invented responses are not a danger
+		or can be checked in some other way. */
+	printf( "Votes (method 2):<BR>\n");
+	result = cgiFormStringMultiple("vote", &responses);
+	if (result == cgiFormNotFound) {	
+		printf( "I hate them all!<p>\n");
+	} else {
+		int i = 0;
+		printf( "My preferred candidates are:\n");
+		printf( "<ul>\n");
+		while (responses[i]) {
+			printf( "<li>%s\n", responses[i]);
+			i++;
+		}
+		printf( "</ul>\n");
+	}
+	/* We must be sure to free the string array or a memory
+		leak will occur. Simply calling free() would free
+		the array but not the individual strings. The
+		function cgiStringArrayFree() does the job completely. */	
+	cgiStringArrayFree(responses);
+}
+
Index: /tags/rel-1.7.0/thirds/cgic206/debian/changelog
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/changelog	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/changelog	(revision 942)
@@ -0,0 +1,32 @@
+libcgic (2.06-1~trusty3) trusty; urgency=low
+
+  * New version to be used for ZOO-Kernel.
+
+ -- Angelos Tzotsos <gcpp.kalxas@gmail.com>  Tue, 10 Jun 2014 19:29:04 +0200
+
+libcgic (2.05-3) unstable; urgency=low
+
+  * debian/control: Suggests: httpd.  Closes: #600138.
+  * debian/control: Fixed debhelper-but-no-misc-depends.
+
+ -- Bart Martens <bartm@debian.org>  Sun, 13 May 2012 08:33:04 +0000
+
+libcgic (2.05-2) unstable; urgency=low
+
+  * debian/control: Standards-Version, Homepage.
+
+ -- Bart Martens <bartm@debian.org>  Sun, 13 Jul 2008 09:31:48 +0200
+
+libcgic (2.05-1) unstable; urgency=low
+
+  * New maitnainer.  Closes: #438643.
+  * New upstream release.
+  * debian/*: Repackaged with cdbs.
+  * debian/changelog-upstream.html: Removed.
+  * debian/Makefile.examples: Removed.
+  * debian/README.Debian: Removed.
+  * debian/copyright: Updated.
+  * debian/watch: Updated.
+
+ -- Bart Martens <bartm@knars.be>  Sun, 19 Aug 2007 09:18:53 +0200
+
Index: /tags/rel-1.7.0/thirds/cgic206/debian/compat
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/compat	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/compat	(revision 942)
@@ -0,0 +1,1 @@
+5
Index: /tags/rel-1.7.0/thirds/cgic206/debian/control
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/control	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/control	(revision 942)
@@ -0,0 +1,35 @@
+Source: libcgic
+Section: libs
+Priority: optional
+Maintainer: Bart Martens <bartm@debian.org>
+Build-Depends: cdbs, libfcgi-dev, debhelper (>= 5)
+Standards-Version: 3.9.3
+Homepage: http://www.boutell.com/cgic/
+
+Package: libcgic-dev
+Section: libdevel
+Architecture: any
+Depends: libc6-dev, ${misc:Depends}
+Suggests: httpd
+Conflicts: libcgicg1-dev
+Replaces: libcgicg1-dev
+Description: C library for developing CGI applications
+ Cgic is an ANSI-C library for the creation of CGI-based World Wide Web
+ applications.  Cgic provides the following:
+ .
+   * Parses form data, correcting for defective and/or inconsistent
+     browsers
+   * Transparently accepts both GET and POST form data
+   * Handles line breaks in form fields in a consistent manner
+   * Provides string, integer, floating-point, and single- and
+     multiple-choice functions to retrieve form data
+   * Provides bounds checking for numeric fields
+   * Loads CGI environment variables into C strings which are always
+     non-null
+   * Provides a way to capture CGI situations for replay in a debugging
+     environment
+ .
+ This package provides a static library version of cgic, examples of using
+ cgic (including a CGI application that captures a CGI environment for use
+ in debugging), and header files.
+
Index: /tags/rel-1.7.0/thirds/cgic206/debian/copyright
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/copyright	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/copyright	(revision 942)
@@ -0,0 +1,28 @@
+This package was debianized by Brian Bassett brian@butterfly.ml.org on
+Tue, 11 Nov 1997 17:28:04 -0800.
+
+It was downloaded from:
+
+    http://www.boutell.com/cgic/
+
+Upstream author:
+
+    Thomas Boutell <boutell@boutell.com>
+
+Copyright:
+
+    Copyright (C) 1996-2004 by Thomas Boutell and Boutell.Com, Inc.
+
+License:
+
+    CGIC, copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+    2004 by Thomas Boutell and Boutell.Com, Inc.. Permission is granted to
+    use CGIC in any application, commercial or noncommercial, at no cost.
+    HOWEVER, this copyright paragraph must appear on a "credits" page
+    accessible in the public online and offline documentation of the program.
+    Modified versions of the CGIC library should not be distributed without
+    the attachment of a clear statement regarding the author of the
+    modifications, and this notice may in no case be removed.
+    Modifications may also be submitted to the author for inclusion
+    in the main CGIC distribution.
+
Index: /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.docs
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.docs	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.docs	(revision 942)
@@ -0,0 +1,1 @@
+cgic.html
Index: /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.examples
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.examples	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.examples	(revision 942)
@@ -0,0 +1,2 @@
+capture.c
+cgictest.c
Index: /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.install
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.install	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.install	(revision 942)
@@ -0,0 +1,2 @@
+cgic.h usr/include/
+libcgic.a usr/lib/
Index: /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.links
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.links	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/libcgic-dev.links	(revision 942)
@@ -0,0 +1,1 @@
+/usr/lib/libcgic.so.2.06 /usr/lib/libcgic.so
Index: /tags/rel-1.7.0/thirds/cgic206/debian/rules
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/rules	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/rules	(revision 942)
@@ -0,0 +1,7 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/makefile.mk
+
+clean::
+	rm -f libcgic.so.2.06
Index: /tags/rel-1.7.0/thirds/cgic206/debian/watch
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/debian/watch	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/debian/watch	(revision 942)
@@ -0,0 +1,4 @@
+version=3
+opts="uversionmangle=s/^(\d)(\d\d)$/$1.$2/" \
+http://www.boutell.com/cgic/ \
+cgic(.*)\.t.*
Index: /tags/rel-1.7.0/thirds/cgic206/license.txt
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/license.txt	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/license.txt	(revision 942)
@@ -0,0 +1,109 @@
+CGIC License Terms
+------------------
+
+Basic License
+-------------
+
+CGIC, copyright 2009 GeoLabs SARL.
+CGIC, copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+2004 by Thomas Boutell and Boutell.Com, Inc.. Permission is granted to 
+use CGIC in any application, commercial or noncommercial, at no cost. 
+HOWEVER, this copyright paragraph must appear on a "credits" page 
+accessible in the public online and offline documentation of the program. 
+Modified versions of the CGIC library should not be distributed without 
+the attachment of a clear statement regarding the author of the 
+modifications, and this notice may in no case be removed. 
+Modifications may also be submitted to the author for inclusion 
+in the main CGIC distribution.                                 
+
+IF YOU WOULD PREFER NOT TO ATTACH THE ABOVE NOTICE to
+the public documentation of your application, consult the
+information which follows regarding the availability
+of a nonexclusive commercial license for CGIC.
+
+Commercial License
+------------------
+
+The price of a nonexclusive commercial license is $200 U.S. 
+To purchase the license:
+
+1. Print and sign two copies of the document below.
+
+2. Send both copies, along with Visa, Mastercard, Discover, or
+Amex card number, cardholder's name, and expiration date 
+OR a check for $200 in U.S. funds drawn on a U.S. bank, to:
+
+Boutell.Com, Inc.
+PO Box 63767
+Philadelphia, PA 19147 USA
+
+Credit card orders may alternatively be faxed to:
+
+Boutell.Com, Inc.
+(208) 445-0327
+
+BE SURE TO INCLUDE AN EMAIL ADDRESS, as well as
+a postal address and phone number.
+
+3. We will return one signed copy to you promptly.
+
+You will also receive swift notification of new
+versions of CGIC, in addition to ongoing
+email support.
+
+* * *
+
+CGIC Nonexclusive Commercial License
+
+The licensee named below is granted the right
+to utilize CGIC, major version 1 or 2, any minor
+version thereof, in CGI applications without the
+need for a credit notice of any kind. CGI applications
+developed by the holder of this license may be
+distributed freely in source code or binary form
+without additional fees or royalties. This license does 
+not grant the right to use CGIC to create a development tool 
+which passes on substantially all of the capabilities of the 
+CGIC library to the user of the tool, unless that tool is 
+to be used internally by the license holder only in order
+to develop CGI applications. This license may not
+be resold, but applications developed in accordance
+with the terms of the license may be distributed
+freely subject to the limitations described above.
+
+Future minor (2.x) versions of CGIC will be covered by this
+license free of charge. If significant defects of workmanship
+are discovered in version 2.x, minor releases to correct them
+will be made available before or at the same time that 
+those defects are addressed in any future major version. 
+Future "major" (3.x) versions will be available to
+licensees at an upgrade price of $50.
+
+If, for any reason, any portion of this license is found 
+to be invalid, that portion of the license only
+is invalidated and the remainder of the agreement
+remains in effect.
+
+If this license has not been signed by Thomas Boutell
+or M. L. Grant on behalf of Boutell. Com, Inc., 
+it is invalid.
+
+Licensee's Name:              _____________________
+
+Signed for Licensee:          _____________________
+
+Complete Mailing Address:     _____________________
+
+                              _____________________
+
+                              _____________________
+
+Phone Number:                 _____________________
+
+Email Address:                _____________________
+
+Signed for Boutell.Com, Inc.: _____________________
+
+Date:                         _____________________
+
+
Index: /tags/rel-1.7.0/thirds/cgic206/makefile.vc
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/makefile.vc	(revision 942)
@@ -0,0 +1,35 @@
+GEODIR=\MMBK\SRCS\fcgi-2.4.1-SNAP-0311112127\ 
+DESTDIR=..
+CFLAGS=-g -Wall
+CC=cl /TP
+LIBS=$(GEODIR)/libfcgi/Release/libfcgi.lib /nologo
+LIBS1=./libcgic.lib
+
+CFLAGS=/EHa /nologo /DCRT_SECURE_NO_WARNING /MD /W2 /O2 /D "WIN32" \
+	-I $(GEODIR)\include 
+
+all: libcgic.lib #cgictest.exe capture.exe 
+
+install: libcgic.lib
+	copy libcgic.lib  $(DESTDIR)\lib
+	copy cgic.h  $(DESTDIR)\include
+	@echo libcgic.lib is now installed in  $(DESTDIR)\lib and cgic.h is in  $(DESTDIR)\include.
+
+libcgic.lib: cgic.obj cgic.h
+	if exist cgic.lib del cgic.lib
+	lib /out:libcgic.lib cgic.obj $(LIBS)
+
+cgictest.obj: cgictest.c libcgic.lib
+	$(CC) $(CFLAGS) -c cgictest.c
+
+cgictest.exe: cgictest.obj 
+	link cgictest.obj $(LIBS) /out:cgictest.exe
+
+cgic.obj: 
+	$(CC) $(CFLAGS) -c cgic.c 
+
+capture.exe: capture.obj libcgic.lib
+	$(CC) $(CFLAGS) capture.c $(LIBS)
+
+clean:
+	erase *.obj *.lib *.exe *.manifest
Index: /tags/rel-1.7.0/thirds/cgic206/readme.txt
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/readme.txt	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/readme.txt	(revision 942)
@@ -0,0 +1,14 @@
+This is the CGIC CGI development library for C programmers.
+Copyright 2009 GeoLabs SARL
+Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+2004, Thomas Boutell and Boutell.Com, Inc.
+
+See the file cgic.html for complete documentation in a single
+HTML hypertext file to be accessed with your web browser. If you
+preferer, there is a plaintext version in the file cgic.txt. 
+Or see http://www.boutell.com/cgic/ for the latest copy of 
+the documentation.
+
+See the files license.txt and support.txt for terms of use and
+technical support information.
+
Index: /tags/rel-1.7.0/thirds/cgic206/support.txt
===================================================================
--- /tags/rel-1.7.0/thirds/cgic206/support.txt	(revision 942)
+++ /tags/rel-1.7.0/thirds/cgic206/support.txt	(revision 942)
@@ -0,0 +1,46 @@
+Support for CGIC
+----------------
+
+   ____
+  /    \
+ | STOP |
+  \____/
+  
+    Are you getting a "server error," indicating that your web server
+    "cannot allow POST to this URL," or a similar message? YOU MUST
+    CONFIGURE YOUR WEB SERVER TO ALLOW CGI PROGRAMS, AND YOU MUST
+    INSTALL CGI PROGRAMS IN THE LOCATION (OR WITH THE EXTENSION) THAT
+    YOUR WEB SERVER EXPECTS TO SEE. Please don't send me email about
+    this, unless you are purchasing commercial support. It is strictly 
+    between you and your web server's documentation, or between you and 
+    your ISP. If you wish to purchase commercial support, we will gladly 
+    attempt to help you resolve such problems, but the cooperation of 
+    your web server administrator will be necessary in most cases. Thanks!
+
+Free Support
+------------
+ 
+Anyone can mail questions about the gd and cgic libraries to 
+boutell@boutell.com. However, I receive a very large volume of email on 
+many subjects, and while I do my best to respond to all queries this can 
+take some time. Sometimes the response must take the form of an eventual 
+new release or an addition to a FAQ or other document, as opposed to an 
+detailed individual response.
+
+Hourly Support
+--------------
+
+Those requiring support in detail may arrange for direct support
+from the author, Thomas Boutell, at the rate of $50/hr, billed
+directly by credit card. Purchase orders are also accepted from
+Fortune 500 corporations and institutions in good standing.
+To make arrangements, contact boutell@boutell.com. Alternatively,
+use our free-form secure message page at:
+
+https://www.boutell.com/freeform/
+
+To avoid delay and/or confusion, be sure to specifically mention that 
+you wish to purchase CGIC support at the hourly rate above.
+
+-Thomas Boutell, boutell@boutell.com
+
Index: /tags/rel-1.7.0/thirds/dirent-win32/dirent.h
===================================================================
--- /tags/rel-1.7.0/thirds/dirent-win32/dirent.h	(revision 942)
+++ /tags/rel-1.7.0/thirds/dirent-win32/dirent.h	(revision 942)
@@ -0,0 +1,373 @@
+/*****************************************************************************
+ * dirent.h - dirent API for Microsoft Visual Studio
+ *
+ * Copyright (C) 2006 Toni Ronkko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * ``Software''), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Mar 15, 2011, Toni Ronkko
+ * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
+ *
+ * Aug 11, 2010, Toni Ronkko
+ * Added d_type and d_namlen fields to dirent structure.  The former is
+ * especially useful for determining whether directory entry represents a
+ * file or a directory.  For more information, see
+ * http://www.delorie.com/gnu/docs/glibc/libc_270.html
+ *
+ * Aug 11, 2010, Toni Ronkko
+ * Improved conformance to the standards.  For example, errno is now set
+ * properly on failure and assert() is never used.  Thanks to Peter Brockam
+ * for suggestions.
+ *
+ * Aug 11, 2010, Toni Ronkko
+ * Fixed a bug in rewinddir(): when using relative directory names, change
+ * of working directory no longer causes rewinddir() to fail.
+ *
+ * Dec 15, 2009, John Cunningham
+ * Added rewinddir member function
+ *
+ * Jan 18, 2008, Toni Ronkko
+ * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
+ * between multi-byte and unicode representations.  This makes the
+ * code simpler and also allows the code to be compiled under MingW.  Thanks
+ * to Azriel Fasten for the suggestion.
+ *
+ * Mar 4, 2007, Toni Ronkko
+ * Bug fix: due to the strncpy_s() function this file only compiled in
+ * Visual Studio 2005.  Using the new string functions only when the
+ * compiler version allows.
+ *
+ * Nov  2, 2006, Toni Ronkko
+ * Major update: removed support for Watcom C, MS-DOS and Turbo C to
+ * simplify the file, updated the code to compile cleanly on Visual
+ * Studio 2005 with both unicode and multi-byte character strings,
+ * removed rewinddir() as it had a bug.
+ *
+ * Aug 20, 2006, Toni Ronkko
+ * Removed all remarks about MSVC 1.0, which is antiqued now.  Simplified
+ * comments by removing SGML tags.
+ *
+ * May 14 2002, Toni Ronkko
+ * Embedded the function definitions directly to the header so that no
+ * source modules need to be included in the Visual Studio project.  Removed
+ * all the dependencies to other projects so that this very header can be
+ * used independently.
+ *
+ * May 28 1998, Toni Ronkko
+ * First version.
+ *****************************************************************************/
+#ifndef DIRENT_H
+#define DIRENT_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+# define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat() */
+#if defined(_MSC_VER)  &&  !defined(S_IREAD)
+# define S_IFMT   _S_IFMT                      /* file type mask */
+# define S_IFDIR  _S_IFDIR                     /* directory */
+# define S_IFCHR  _S_IFCHR                     /* character device */
+# define S_IFFIFO _S_IFFIFO                    /* pipe */
+# define S_IFREG  _S_IFREG                     /* regular file */
+# define S_IREAD  _S_IREAD                     /* read permission */
+# define S_IWRITE _S_IWRITE                    /* write permission */
+# define S_IEXEC  _S_IEXEC                     /* execute permission */
+#endif
+#define S_IFBLK   0                            /* block device */
+#define S_IFLNK   0                            /* link */
+#define S_IFSOCK  0                            /* socket */
+
+#if defined(_MSC_VER)
+# define S_IRUSR  S_IREAD                      /* read, user */
+# define S_IWUSR  S_IWRITE                     /* write, user */
+# define S_IXUSR  0                            /* execute, user */
+# define S_IRGRP  0                            /* read, group */
+# define S_IWGRP  0                            /* write, group */
+# define S_IXGRP  0                            /* execute, group */
+# define S_IROTH  0                            /* read, others */
+# define S_IWOTH  0                            /* write, others */
+# define S_IXOTH  0                            /* execute, others */
+#endif
+
+/* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* File type flags for d_type */
+#define DT_LNK -100
+#define DT_UNKNOWN  0
+#define DT_REG      S_IFREG
+#define DT_DIR      S_IFDIR
+#define DT_FIFO     S_IFFIFO
+#define DT_SOCK     S_IFSOCK
+#define DT_CHR      S_IFCHR
+#define DT_BLK      S_IFBLK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+ * File type macros.  Note that block devices, sockets and links cannot be
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+ * only defined for compatibility.  These macros should always return false
+ * on Windows.
+ */
+#define	S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
+#define	S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
+#define	S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)
+#define	S_ISLNK(mode)  (((mode) & S_IFMT) == S_IFLNK)
+#define	S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#define	S_ISCHR(mode)  (((mode) & S_IFMT) == S_IFCHR)
+#define	S_ISBLK(mode)  (((mode) & S_IFMT) == S_IFBLK)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct dirent
+{
+   char d_name[MAX_PATH + 1];                  /* File name */
+   size_t d_namlen;                            /* Length of name without \0 */
+   int d_type;                                 /* File type */
+} dirent;
+
+
+typedef struct DIR
+{
+   dirent           curentry;                  /* Current directory entry */
+   WIN32_FIND_DATAA find_data;                 /* Private file data */
+   int              cached;                    /* True if data is valid */
+   HANDLE           search_handle;             /* Win32 search handle */
+   char             patt[MAX_PATH + 3];        /* Initial directory name */
+} DIR;
+
+
+/* Forward declarations */
+static DIR *opendir(const char *dirname);
+static struct dirent *readdir(DIR *dirp);
+static int closedir(DIR *dirp);
+static void rewinddir(DIR* dirp);
+
+
+/* Use the new safe string functions introduced in Visual Studio 2005 */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
+#else
+# define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size))
+#endif
+
+/* Set errno variable */
+#if defined(_MSC_VER)
+#define DIRENT_SET_ERRNO(x) _set_errno (x)
+#else
+#define DIRENT_SET_ERRNO(x) (errno = (x))
+#endif
+
+
+
+/*****************************************************************************
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+static DIR *opendir(const char *dirname)
+{
+   DIR *dirp;
+
+   /* ensure that the resulting search pattern will be a valid file name */
+   if (dirname == NULL) {
+      DIRENT_SET_ERRNO (ENOENT);
+      return NULL;
+   }
+   if (strlen (dirname) + 3 >= MAX_PATH) {
+      DIRENT_SET_ERRNO (ENAMETOOLONG);
+      return NULL;
+   }
+
+   /* construct new DIR structure */
+   dirp = (DIR*) malloc (sizeof (struct DIR));
+   if (dirp != NULL) {
+      int error;
+
+      /*
+       * Convert relative directory name to an absolute one.  This
+       * allows rewinddir() to function correctly when the current working
+       * directory is changed between opendir() and rewinddir().
+       */
+      if (GetFullPathNameA (dirname, MAX_PATH, dirp->patt, NULL)) {
+         char *p;
+
+         /* append the search pattern "\\*\0" to the directory name */
+         p = strchr (dirp->patt, '\0');
+         if (dirp->patt < p  &&  *(p-1) != '\\'  &&  *(p-1) != ':') {
+           *p++ = '\\';
+         }
+         *p++ = '*';
+         *p = '\0';
+
+         /* open directory stream and retrieve the first entry */
+         dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
+         if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+            /* a directory entry is now waiting in memory */
+            dirp->cached = 1;
+            error = 0;
+         } else {
+            /* search pattern is not a directory name? */
+            DIRENT_SET_ERRNO (ENOENT);
+            error = 1;
+         }
+      } else {
+         /* buffer too small */
+         DIRENT_SET_ERRNO (ENOMEM);
+         error = 1;
+      }
+
+      if (error) {
+         free (dirp);
+         dirp = NULL;
+      }
+   }
+
+   return dirp;
+}
+
+
+/*****************************************************************************
+ * Read a directory entry, and return a pointer to a dirent structure
+ * containing the name of the entry in d_name field.  Individual directory
+ * entries returned by this very function include regular files,
+ * sub-directories, pseudo-directories "." and "..", but also volume labels,
+ * hidden files and system files may be returned.
+ */
+static struct dirent *readdir(DIR *dirp)
+{
+   DWORD attr;
+   if (dirp == NULL) {
+      /* directory stream did not open */
+      DIRENT_SET_ERRNO (EBADF);
+      return NULL;
+   }
+
+   /* get next directory entry */
+   if (dirp->cached != 0) {
+      /* a valid directory entry already in memory */
+      dirp->cached = 0;
+   } else {
+      /* get the next directory entry from stream */
+      if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+         return NULL;
+      }
+      if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) {
+         /* the very last entry has been processed or an error occurred */
+         FindClose (dirp->search_handle);
+         dirp->search_handle = INVALID_HANDLE_VALUE;
+         return NULL;
+      }
+   }
+
+   /* copy as a multibyte character string */
+   DIRENT_STRNCPY ( dirp->curentry.d_name,
+             dirp->find_data.cFileName,
+             sizeof(dirp->curentry.d_name) );
+   dirp->curentry.d_name[MAX_PATH] = '\0';
+
+   /* compute the length of name */
+   dirp->curentry.d_namlen = strlen (dirp->curentry.d_name);
+
+   /* determine file type */
+   attr = dirp->find_data.dwFileAttributes;
+   if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+      dirp->curentry.d_type = DT_CHR;
+   } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+      dirp->curentry.d_type = DT_DIR;
+   } else {
+      dirp->curentry.d_type = DT_REG;
+   }
+   return &dirp->curentry;
+}
+
+
+/*****************************************************************************
+ * Close directory stream opened by opendir() function.  Close of the
+ * directory stream invalidates the DIR structure as well as any previously
+ * read directory entry.
+ */
+static int closedir(DIR *dirp)
+{
+   if (dirp == NULL) {
+      /* invalid directory stream */
+      DIRENT_SET_ERRNO (EBADF);
+      return -1;
+   }
+
+   /* release search handle */
+   if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+      FindClose (dirp->search_handle);
+      dirp->search_handle = INVALID_HANDLE_VALUE;
+   }
+
+   /* release directory structure */
+   free (dirp);
+   return 0;
+}
+
+
+/*****************************************************************************
+ * Resets the position of the directory stream to which dirp refers to the
+ * beginning of the directory.  It also causes the directory stream to refer
+ * to the current state of the corresponding directory, as a call to opendir()
+ * would have done.  If dirp does not refer to a directory stream, the effect
+ * is undefined.
+ */
+static void rewinddir(DIR* dirp)
+{
+   if (dirp != NULL) {
+      /* release search handle */
+      if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+         FindClose (dirp->search_handle);
+      }
+
+      /* open new search handle and retrieve the first entry */
+      dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
+      if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+         /* a directory entry is now waiting in memory */
+         dirp->cached = 1;
+      } else {
+         /* failed to re-open directory: no directory entry in memory */
+         dirp->cached = 0;
+      }
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/
Index: /tags/rel-1.7.0/thirds/grass/grass2zcfg.sh
===================================================================
--- /tags/rel-1.7.0/thirds/grass/grass2zcfg.sh	(revision 942)
+++ /tags/rel-1.7.0/thirds/grass/grass2zcfg.sh	(revision 942)
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Author : Gérald FENOY
+# 
+# Copyright 2015 GeoLabs SARL. All rights reserved.
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+
+
+# Set below the location of the xsl file 
+XSL=/Users/djay/MapMint/zoo-project-1.5.0/trunk/thirds/grass/xml2zcfg.xsl
+
+# Set below the location of your GRASS 7.0.X installation
+GRASSROOT=/Applications/GRASS-7.0.app/Contents/MacOS
+
+for i in $(ls $GRASSROOT/bin/{v,r}.* | grep -v "v\.in" | grep -v "v\.out" | grep -v "r\.in" | grep -v "r\.out" ); 
+do 
+    j=$(echo $i | sed "s:$GRASSROOT/bin/::g")
+    zcfg=$(echo $j | sed "s:\.:_:g")
+    $i --wps-process-description  > $zcfg.xml
+    xsltproc $XSL $zcfg.xml > $zcfg.zcfg
+    rm $zcfg.xml
+    echo "#####################################################
+# This service was generated using wps-grass-bridge #
+#####################################################
+import ZOOGrassModuleStarter as zoo
+def $zcfg(m, inputs, outputs):
+    service = zoo.ZOOGrassModuleStarter()
+    service.fromMaps(\"$j\", inputs, outputs)
+    return 3
+" > $zcfg.py
+done
Index: /tags/rel-1.7.0/thirds/grass/xml2zcfg.xsl
===================================================================
--- /tags/rel-1.7.0/thirds/grass/xml2zcfg.xsl	(revision 942)
+++ /tags/rel-1.7.0/thirds/grass/xml2zcfg.xsl	(revision 942)
@@ -0,0 +1,247 @@
+<xsl:stylesheet version="1.0" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:ows="http://www.opengis.net/ows/1.1"
+                xmlns:wps="http://www.opengis.net/wps/1.0.0"
+                xmlns:xlink="http://www.w3.org/1999/xlink">
+  <!--
+      Author : Gérald FENOY
+      
+      Copyright 2015 GeoLabs SARL. All rights reserved.
+      
+      Permission is hereby granted, free of charge, to any person obtaining a copy
+      of this software and associated documentation files (the "Software"), to deal
+      in the Software without restriction, including without limitation the rights
+      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+      copies of the Software, and to permit persons to whom the Software is
+      furnished to do so, subject to the following conditions:
+      
+      The above copyright notice and this permission notice shall be included in
+      all copies or substantial portions of the Software.
+      
+      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+      THE SOFTWARE.
+      
+  -->
+  <xsl:output method="text"/>
+
+  <xsl:template match="/*">
+    <xsl:for-each select="./ProcessDescription">
+      <xsl:call-template name="extractBasicMetaData">
+	<xsl:with-param name="context" select="." /> 
+	<xsl:with-param name="total" select="1" /> 
+      </xsl:call-template>
+      <xsl:text>storeSupported=true</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>statusSupported=true</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>serviceType=Python</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>serviceProvider=</xsl:text>
+      <xsl:value-of select="translate(./ows:Identifier,'.','_')" />      
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>&lt;DataInputs&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:for-each select="./DataInputs/Input">
+	<xsl:call-template name="extractBasicMetaData">
+	  <xsl:with-param name="context" select="." /> 
+	  <xsl:with-param name="total" select="3" /> 
+	</xsl:call-template>
+	<xsl:call-template name="printSpace">
+	  <xsl:with-param name="index" select="1" />
+	  <xsl:with-param name="total" select="3" />
+	</xsl:call-template>
+	<xsl:text>minOccurs = </xsl:text>
+	<xsl:value-of select="./@minOccurs" />
+	<xsl:text>&#xa;</xsl:text>
+	<xsl:call-template name="printSpace">
+	  <xsl:with-param name="index" select="1" />
+	  <xsl:with-param name="total" select="3" />
+	</xsl:call-template>
+	<xsl:text>maxOccurs = </xsl:text>
+	<xsl:value-of select="./@maxOccurs" />
+	<xsl:text>&#xa;</xsl:text>
+	<xsl:call-template name="extractLiteralData">
+	  <xsl:with-param name="context" select=". /LiteralData" /> 
+	</xsl:call-template>
+	<xsl:call-template name="extractComplexData">
+	  <xsl:with-param name="context" select=". /ComplexData" /> 
+	</xsl:call-template>
+      </xsl:for-each>
+      <xsl:text>&lt;/DataInputs&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>&lt;DataOutputs&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:for-each select="./ProcessOutputs/Output">
+	<xsl:call-template name="extractBasicMetaData">
+	  <xsl:with-param name="context" select="." /> 
+	  <xsl:with-param name="total" select="3" /> 
+	</xsl:call-template>
+	<xsl:call-template name="extractComplexData">
+	  <xsl:with-param name="context" select=". /ComplexOutput" /> 
+	  <xsl:with-param name="total" select="3" /> 
+	</xsl:call-template>
+      </xsl:for-each>
+      <xsl:text>&lt;/DataOutputs&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+    </xsl:for-each>
+
+  </xsl:template>
+
+  <xsl:template name="extractBasicMetaData">
+    <xsl:param name="context" />
+    <xsl:param name="index" select="1" />
+    <xsl:param name="total" select="1" />
+    <xsl:call-template name="printSpace">
+      <xsl:with-param name="index" select="1" />
+      <xsl:with-param name="total" select="$total" />
+    </xsl:call-template>
+    <xsl:text>[</xsl:text>
+    <xsl:copy-of select="translate($context/ows:Identifier,'.','_')" />
+    <xsl:text>]</xsl:text>
+    <xsl:text>&#xa;</xsl:text>
+    <xsl:call-template name="printSpace">
+      <xsl:with-param name="index" select="1" />
+      <xsl:with-param name="total" select="$total" />
+    </xsl:call-template>
+    <xsl:text>Title = </xsl:text>
+    <xsl:copy-of select="$context/ows:Title" />
+    <xsl:text>&#xa;</xsl:text>
+    <xsl:call-template name="printSpace">
+      <xsl:with-param name="index" select="1" />
+      <xsl:with-param name="total" select="$total" />
+    </xsl:call-template>
+    <xsl:text>Abstract = </xsl:text>
+    <xsl:copy-of select="$context/ows:Abstract" />
+    <xsl:text>&#xa;</xsl:text>
+  </xsl:template>
+
+  <xsl:template name="printSpace">
+    <xsl:param name="index" select="1"/>
+    <xsl:param name="total" />
+    <xsl:if test="not($index = $total)">
+      <xsl:text> </xsl:text>
+      <xsl:call-template name="printSpace">
+	<xsl:with-param name="index" select="$index + 1" />
+	<xsl:with-param name="total" select="$total" />
+      </xsl:call-template>	
+    </xsl:if>
+  </xsl:template>
+  
+  <xsl:template name="extractLiteralData">
+    <xsl:param name="context" />
+    <xsl:for-each select="$context">
+      <xsl:call-template name="printSpace">
+	<xsl:with-param name="index" select="1" />
+	<xsl:with-param name="total" select="3" />
+      </xsl:call-template>
+      <xsl:text>&lt;LiteralData&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:call-template name="printSpace">
+	<xsl:with-param name="index" select="1" />
+	<xsl:with-param name="total" select="4" />
+      </xsl:call-template>
+      <xsl:text>dataType=</xsl:text>
+      <xsl:copy-of select="./ows:DataType" />
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:if test="./ows:AllowedValues">
+	<xsl:call-template name="printSpace">
+	  <xsl:with-param name="index" select="1" />
+	  <xsl:with-param name="total" select="4" />
+	</xsl:call-template>
+	<xsl:text>AllowedValues=</xsl:text>
+	<xsl:for-each select="./ows:AllowedValues/ows:Value">
+	  <xsl:copy-of select="." /><xsl:if test="position() != last()" ><xsl:text>,</xsl:text></xsl:if>
+	</xsl:for-each>
+	<xsl:text>&#xa;</xsl:text>
+      </xsl:if>
+      <xsl:choose>
+	<xsl:when test="./DefaultValue">
+	  <xsl:call-template name="printSpace">
+	    <xsl:with-param name="index" select="1" />
+	    <xsl:with-param name="total" select="4" />
+	  </xsl:call-template>
+	  <xsl:text>&lt;Default&gt;</xsl:text>
+	  <xsl:text>&#xa;</xsl:text>
+	  <xsl:call-template name="printSpace">
+	    <xsl:with-param name="index" select="1" />
+	    <xsl:with-param name="total" select="5" />
+	  </xsl:call-template>
+	  <xsl:text>value=</xsl:text>
+	  <xsl:copy-of select="./DefaultValue" />
+	  <xsl:text>&#xa;</xsl:text>
+	  <xsl:call-template name="printSpace">
+	    <xsl:with-param name="index" select="1" />
+	    <xsl:with-param name="total" select="4" />
+	  </xsl:call-template>
+	  <xsl:text>&lt;/Default&gt;</xsl:text>
+	  <xsl:text>&#xa;</xsl:text>  
+	</xsl:when>
+	<xsl:otherwise>
+	  <xsl:call-template name="printSpace">
+	    <xsl:with-param name="index" select="1" />
+	    <xsl:with-param name="total" select="4" />
+	  </xsl:call-template>
+	  <xsl:text>&lt;Default /&gt;</xsl:text>
+	  <xsl:text>&#xa;</xsl:text>
+	</xsl:otherwise>
+      </xsl:choose>
+      <xsl:call-template name="printSpace">
+	<xsl:with-param name="index" select="1" />
+	<xsl:with-param name="total" select="3" />
+      </xsl:call-template>
+      <xsl:text>&lt;/LiteralData&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+    </xsl:for-each>
+  </xsl:template>
+
+  <xsl:template name="extractComplexFormat">
+    <xsl:param name="context" />
+    <xsl:for-each select="$context">
+	<xsl:text>    mimeType=</xsl:text>
+	<xsl:copy-of select="./MimeType" />
+	<xsl:text>&#xa;</xsl:text>
+	<xsl:if test="./Encoding">
+	  <xsl:text>    encoding=</xsl:text>
+	  <xsl:copy-of select="./Encoding" />
+	  <xsl:text>&#xa;</xsl:text>
+	</xsl:if>
+	<xsl:if test="./Schema">
+	  <xsl:text>    schema=</xsl:text>
+	  <xsl:copy-of select="./Schema" />
+	  <xsl:text>&#xa;</xsl:text>
+	</xsl:if>
+      </xsl:for-each>
+  </xsl:template>
+  
+  <xsl:template name="extractComplexData">
+    <xsl:param name="context" />
+    <xsl:for-each select="$context">
+      <xsl:text>  &lt;ComplexData&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>   &lt;Default&gt;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:call-template name="extractComplexFormat">
+	<xsl:with-param name="context" select=". /Default/Format" /> 
+      </xsl:call-template>
+      <xsl:text>   &lt;/Default&gt;</xsl:text>
+      <xsl:for-each select="./Supported/Format">
+	<xsl:text>&#xa;</xsl:text>
+	<xsl:text>   &lt;Supported&gt;</xsl:text>
+	<xsl:text>&#xa;</xsl:text>
+	<xsl:call-template name="extractComplexFormat">
+	  <xsl:with-param name="context" select=". " /> 
+	</xsl:call-template>
+	<xsl:text>   &lt;/Supported&gt;</xsl:text>	
+      </xsl:for-each>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>  &lt;/ComplexData&gt;</xsl:text>	
+      <xsl:text>&#xa;</xsl:text>
+    </xsl:for-each>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /tags/rel-1.7.0/thirds/include/unistd.h
===================================================================
--- /tags/rel-1.7.0/thirds/include/unistd.h	(revision 942)
+++ /tags/rel-1.7.0/thirds/include/unistd.h	(revision 942)
@@ -0,0 +1,41 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2013 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef __STRICT_AINSI__
+
+#include <io.h>
+#include <process.h>
+#define mode_t int
+#define strtok_r strtok_s
+#define S_IRWXU _S_IREAD|_S_IWRITE
+#define S_IRGRP _S_IREAD|_S_IWRITE
+#define S_IROTH _S_IREAD|_S_IWRITE
+#define S_IXGRP _S_IREAD|_S_IWRITE
+#define S_IXOTH _S_IREAD|_S_IWRITE
+#define S_IWOTH _S_IREAD|_S_IWRITE
+#define S_IRUSR _S_IREAD
+#define S_IXGRP _S_IREAD|_S_IWRITE
+#define S_IWGRP _S_IREAD|_S_IWRITE
+#define S_IWUSR _S_IREAD|_S_IWRITE
+
+#endif
Index: /tags/rel-1.7.0/thirds/otb2zcfg/CMakeLists.txt
===================================================================
--- /tags/rel-1.7.0/thirds/otb2zcfg/CMakeLists.txt	(revision 942)
+++ /tags/rel-1.7.0/thirds/otb2zcfg/CMakeLists.txt	(revision 942)
@@ -0,0 +1,14 @@
+PROJECT(otb2zcfg)  
+ 
+cmake_minimum_required(VERSION 2.6)  
+ 
+FIND_PACKAGE(OTB)  
+IF(OTB_FOUND)  
+  INCLUDE(${OTB_USE_FILE})  
+ELSE(OTB_FOUND)  
+  MESSAGE(FATAL_ERROR  
+      "Cannot build OTB project without OTB.  Please set OTB_DIR.")  
+ENDIF(OTB_FOUND)  
+ 
+ADD_EXECUTABLE(otb2zcfg otb2zcfg.cxx )  
+TARGET_LINK_LIBRARIES(otb2zcfg OTBCommon OTBApplicationEngine OTBImageIO ${ITK_LIBRARIES}) 
Index: /tags/rel-1.7.0/thirds/otb2zcfg/README.txt
===================================================================
--- /tags/rel-1.7.0/thirds/otb2zcfg/README.txt	(revision 942)
+++ /tags/rel-1.7.0/thirds/otb2zcfg/README.txt	(revision 942)
@@ -0,0 +1,17 @@
+To build the otb2zcfg utility you should run the following command:
+
+ mkdir build
+ cd build
+ ccmake ..
+ make
+
+ 
+To generate the zcfgs for the OTB Applications available, you should run the following:
+
+ mkdir zcfgs
+ cd zcfgs
+ export ITK_AUTOLOAD_PATH=/your/path/to/otb/applications
+ ../build/otb2zcfg
+ cp *zcfg /location/to/your/cgi-bin
+
+This ITK_AUTOLOAD_PATH environment variable will be required in the [env] section of your main.cfg.
Index: /tags/rel-1.7.0/thirds/otb2zcfg/otb2zcfg.cxx
===================================================================
--- /tags/rel-1.7.0/thirds/otb2zcfg/otb2zcfg.cxx	(revision 942)
+++ /tags/rel-1.7.0/thirds/otb2zcfg/otb2zcfg.cxx	(revision 942)
@@ -0,0 +1,433 @@
+#include "otbWrapperApplicationRegistry.h"
+#include "otbWrapperApplication.h"
+#include "otbImage.h" 
+#include <iostream> 
+
+using namespace otb::Wrapper;
+
+std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
+    size_t start_pos = 0;
+    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
+        str.replace(start_pos, from.length(), to);
+        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
+    }
+    return str;
+}
+
+void printDefaultOutput(){
+  std::cout << "  [Result]" << std::endl;
+  std::cout << "   Title = the result message" << std::endl;
+  std::cout << "   Abstract = the result message" << std::endl;
+  std::cout << "   <LiteralData>" << std::endl;
+  std::cout << "    dataType = string" << std::endl;
+  std::cout << "    <Default />" << std::endl;
+  std::cout << "   </LiteralData>" << std::endl;
+}
+
+void printAscii(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = text/plain" << std::endl;
+  std::cout << "     encoding = ascii" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+}
+
+void printXml(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = text/xml" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+}
+
+void printGeoid(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = application/octet-stream" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+}
+
+void printCSV(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = text/csv" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+}
+
+void printUnknown(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = text/xml" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+  std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = text/plain" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+}
+
+void printImages(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = image/tiff" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+#if defined(OTB_USE_JPEG2000)
+  std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = image/jp2" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+#endif
+  std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = image/jpeg" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+  std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = image/png" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+}
+
+void printKmz(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = application/vnd.google-earth.kmz" << std::endl;
+  std::cout << "     extension = kmz" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+}
+
+void printVector(){
+  std::cout << "    <Default>" << std::endl;
+  std::cout << "     mimeType = text/xml" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+  std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = application/vnd.google-earth.kml+xml" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+  std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = application/json" << std::endl;
+  std::cout << "     encoding = utf-8" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+  std::cout << "    <Supported>" << std::endl;
+  std::cout << "     mimeType = application/zip" << std::endl;
+  std::cout << "    </Supported>" << std::endl;
+}
+
+void printOutputImage(ImagePixelType pt){
+  std::cout << "   <LiteralData>" << std::endl;
+  std::cout << "    dataType = string" << std::endl;
+  std::cout << "    <Default>" << std::endl;
+  // Check for the default pixel type
+  switch(pt){
+  case ImagePixelType_uint8:
+    std::cout << "     value = uint8" << std::endl;
+    break;
+  case ImagePixelType_int16:
+    std::cout << "     value = int16" << std::endl;
+    break;
+  case ImagePixelType_uint16:
+    std::cout << "     value = uint16" << std::endl;
+    break;
+  case ImagePixelType_int32:
+    std::cout << "     value = int32" << std::endl;
+    break;
+  case ImagePixelType_uint32:
+    std::cout << "     value = uint8" << std::endl;
+    break;
+  case ImagePixelType_double:
+    std::cout << "     value = uint8" << std::endl;
+    break;
+  default:
+    std::cout << "     value = float" << std::endl;
+    break;
+  }
+  std::cout << "     AllowedValues = uint8,uint16,int16,int32,int32,float,double" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+  std::cout << "   </LiteralData>" << std::endl;
+}
+
+void printOutputComplexImage(ComplexImagePixelType pt){
+  std::cout << "   <LiteralData>" << std::endl;
+  std::cout << "    dataType = string" << std::endl;
+  std::cout << "    <Default>" << std::endl;
+  // Check for the default pixel type
+  switch(pt){
+  case ComplexImagePixelType_double:
+    std::cout << "     value = cdouble" << std::endl;
+    break;
+  default:
+    std::cout << "     value = cfloat" << std::endl;
+    break;
+  }
+  std::cout << "     AllowedValues = cfloat,cdouble" << std::endl;
+  std::cout << "    </Default>" << std::endl;
+  std::cout << "   </LiteralData>" << std::endl;
+}
+
+int main(int itkNotUsed(argc), char * itkNotUsed(argv)[]) 
+{ 
+  typedef otb::Image<unsigned short, 2> ImageType; 
+ 
+  ImageType::Pointer image = ImageType::New(); 
+ 
+  const char * ITK_AUTOLOAD_PATH = itksys::SystemTools::GetEnv("ITK_AUTOLOAD_PATH");
+  std::cerr << "INFO: Module search path: " << (ITK_AUTOLOAD_PATH ? ITK_AUTOLOAD_PATH : "none (check ITK_AUTOLOAD_PATH)") << std::endl;
+
+  std::vector<std::string> list = ApplicationRegistry::GetAvailableApplications();
+  if (list.size() == 0)
+    std::cerr << "ERROR: no module found." << std::endl;
+  else{
+    std::cerr << "INFO: Available modules :" << std::endl;
+    for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it){
+      std::string filename= *it + ".zcfg";
+      std::ofstream out(filename.c_str(),std::ofstream::out);
+      std::streambuf *coutbuf = std::cout.rdbuf();
+      std::cout.rdbuf(out.rdbuf());
+
+      std::cerr << *it << std::endl;
+      std::cout << "[" << *it << "]" << std::endl;
+      Application::Pointer m_Application=ApplicationRegistry::CreateApplication(*it);
+      std::string s0 = m_Application->GetDescription();
+      s0=ReplaceAll(ReplaceAll(s0,std::string("\n"),std::string("")),std::string("\t"),std::string(""));
+      std::cout << " Title = " << s0 << std::endl;
+      s0 = m_Application->GetDocLongDescription();
+      s0=ReplaceAll(ReplaceAll(s0,std::string("\n"),std::string("")),std::string("\t"),std::string(""));
+      std::cout << " Abstract = " << s0 << std::endl;
+      const std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
+      std::cout << " storeSupported = true"<< std::endl;
+      std::cout << " statusSupported = true" << std::endl;
+      std::cout << " serviceProvider = " << *it << std::endl;
+      std::cout << " serviceType = OTB" << std::endl;
+      std::cout << " <DataInputs>" << std::endl;
+      for (unsigned int i = 0; i < appKeyList.size(); i++){
+	const std::string paramKey(appKeyList[i]);
+	Parameter::Pointer param = m_Application->GetParameterByKey(paramKey);
+	ParameterType type = m_Application->GetParameterType(paramKey);
+	Role role = m_Application->GetParameterRole(paramKey);
+      
+	if(paramKey!="inxml" && paramKey!="outxml" && role==0 && type!=17 
+	   && type!=ParameterType_OutputFilename && type!=ParameterType_OutputVectorData){
+	  std::vector<std::string> values;
+	  std::string s = m_Application->GetParameterDescription(paramKey);
+	  s=ReplaceAll(ReplaceAll(ReplaceAll(s,std::string("\n"),std::string("")),std::string("\t"),std::string("")),std::string("<"),std::string("&lt;"));
+	  std::cout << "  [" << paramKey << "]" << std::endl;
+	  if(s.length()>0){
+	    std::cout << "   Title = " << s << std::endl;
+	    std::cout << "   Abstract = " << s << std::endl;
+	  }else{
+	    std::cout << "   Title = " << paramKey << std::endl;
+	    std::cout << "   Abstract = " << paramKey << std::endl;
+	  }
+	  std::cout << "   minOccurs = " << m_Application->IsMandatory(paramKey) << std::endl;
+	  /* Bounded and unbounded parameters */
+	  if(type == ParameterType_StringList || type == ParameterType_InputImageList
+	     || type == ParameterType_InputVectorDataList || type == ParameterType_InputFilenameList
+	     || type == ParameterType_ListView)
+	    std::cout << "   maxOccurs = 1024" << std::endl;
+	  else
+	    std::cout << "   maxOccurs = 1" << std::endl;
+	  std::replace( s.begin(), s.end(), '\n', ' ');
+	  
+	  if(type == ParameterType_StringList || type == ParameterType_String || type == ParameterType_Float
+	     || type == ParameterType_Int || type == ParameterType_Choice || type == ParameterType_ListView
+	     || type == ParameterType_RAM || type == ParameterType_Empty || type == ParameterType_Directory){
+	    std::cout << "   <LiteralData>" << std::endl;
+	    std::string lt;
+	    if(type == ParameterType_Int || type == ParameterType_RAM)
+	      lt="integer";
+	    if(type == ParameterType_Float)
+	      lt="float";
+	    if(type == ParameterType_String || type == ParameterType_StringList
+	       || type == ParameterType_Choice || type == ParameterType_Directory
+	       || type == ParameterType_ListView)
+	      lt="string";
+	    if(type == ParameterType_Empty)
+	      lt="boolean";
+	    std::cout << "    dataType = " << lt << std::endl;
+	    if(type == ParameterType_Choice || type == ParameterType_ListView){
+	      const std::vector<std::string> nList = m_Application->GetChoiceNames(paramKey);
+	      const std::vector<std::string> keysList = m_Application->GetChoiceKeys(paramKey);
+	      if(keysList.size()==0){
+		std::cout << "    <Default />" << std::endl;
+	      }
+	      for (unsigned int j = 0; j < keysList.size(); j++){
+		const std::string key(keysList[j]);
+		if(j==0){
+		  std::cout << "    <Default>" << std::endl;
+		  if(m_Application->HasValue(paramKey))
+		    std::cout << "    value = " << m_Application->GetParameterAsString(paramKey) << std::endl;
+		  else
+		    std::cout << "    value = " << key << std::endl;
+		}
+		else{
+		  if(j==1){
+		    std::cout << "    AllowedValues = "+keysList[0]+",";
+		  }
+		  std::cout << keysList[j];
+		  if(j+1>=keysList.size()){
+		    std::cout << std::endl;
+		    std::cout << "    </Default>" << std::endl;
+		  }
+		  else
+		    std::cout << ",";
+		}
+	      }
+	    }
+	    else{
+	      if(type!=17 && m_Application->HasValue(paramKey)){
+		std::cout << "    <Default>" << std::endl;
+		std::cout << "     value = " << m_Application->GetParameterAsString(paramKey) << std::endl;
+		std::cout << "    </Default>" << std::endl;
+	      }
+	      else
+		std::cout << "    <Default />" << std::endl;
+	    }
+	    std::cout << "   </LiteralData>" << std::endl;
+	  }
+	  else{
+	    if(type == ParameterType_OutputImage){
+	      printOutputImage(m_Application->GetParameterOutputImagePixelType(paramKey));
+	    }
+	    else{
+	      if(type == ParameterType_ComplexOutputImage){
+		printOutputComplexImage(m_Application->GetParameterComplexOutputImagePixelType(paramKey));
+	      }else{
+		std::cout << "   <ComplexData>" << std::endl;
+		if(type == ParameterType_InputImage || type == ParameterType_InputImageList || type == ParameterType_ComplexInputImage){
+		  printImages();
+		}
+		else
+		  if(type == ParameterType_InputVectorData || type == ParameterType_InputVectorDataList){
+		    printVector();
+		  }
+		  else
+		    if(type == ParameterType_InputFilename || type == ParameterType_OutputFilename){
+		      
+		      std::string geoid("geoid");
+		      if(paramKey.find(geoid)!= std::string::npos)
+			printGeoid();
+		      else{
+			std::string dtype("vector");
+			std::string descr(m_Application->GetParameterDescription(paramKey));
+			if(descr.find(dtype)!= std::string::npos)
+			  printVector();
+			else{
+			  std::string dtype1("ASCII");
+			  if(descr.find(dtype1)!= std::string::npos)
+			    printAscii();
+			  else{
+			    std::string dtype2("XML");
+			    std::string dtype3("xml");
+			    if(descr.find(dtype2)!= std::string::npos || descr.find(dtype3)!= std::string::npos)
+			      printXml();
+			    else
+			      printImages();
+			  }
+			}
+		      }
+		    }
+		std::cout << "   </ComplexData>" << std::endl;
+	      }
+	    }
+	  }
+
+
+	}
+      }
+      std::cout << " </DataInputs>" << std::endl;
+      std::cout << " <DataOutputs>" << std::endl;
+      int hasOutput=-1;
+      for (unsigned int i = 0; i < appKeyList.size(); i++){
+	const std::string paramKey(appKeyList[i]);
+	std::vector<std::string> values;
+	Parameter::Pointer param = m_Application->GetParameterByKey(paramKey);
+	ParameterType type = m_Application->GetParameterType(paramKey);
+	Role role = m_Application->GetParameterRole(paramKey);
+	
+	if(paramKey!="inxml" && paramKey!="outxml" &&
+	   ((type == ParameterType_OutputVectorData || type == ParameterType_OutputImage
+	     || type == ParameterType_OutputImage || type == ParameterType_ComplexOutputImage
+	     || type == ParameterType_OutputFilename) || role==1) && type != ParameterType_Group){
+	  hasOutput=1;
+	  std::vector<std::string> values;
+	  Parameter::Pointer param = m_Application->GetParameterByKey(paramKey);
+	  ParameterType type = m_Application->GetParameterType(paramKey);
+	  Role role = m_Application->GetParameterRole(paramKey);
+	  std::cout << "  [" << paramKey << "]" << std::endl;
+	  std::string s=m_Application->GetParameterDescription(paramKey);
+	  if(s.length()>0){
+	    s=ReplaceAll(ReplaceAll(s,std::string("\n"),std::string("")),std::string("\t"),std::string(""));
+	    std::cout << "   Title = " << s << std::endl;
+	    std::cout << "   Abstract = " << s << std::endl;
+	  }else{
+	    std::cout << "   Title = " << paramKey << std::endl;
+	    std::cout << "   Abstract = " << paramKey << std::endl;
+	  }
+
+	  if(type == ParameterType_OutputImage || type == ParameterType_ComplexOutputImage){
+	    std::cout << "   <ComplexData>" << std::endl;
+	    printImages();
+	    std::cout << "   </ComplexData>" << std::endl;
+	  }
+	  else
+	    if(type == ParameterType_OutputVectorData || type == ParameterType_OutputImage){
+	      std::cout << "   <ComplexData>" << std::endl;
+	      if(type == ParameterType_OutputImage)
+		printImages();
+	      else
+		printVector();
+	      std::cout << "   </ComplexData>" << std::endl;
+	    }
+	    else
+	      if(type == ParameterType_String || type == ParameterType_StringList
+		 || type == ParameterType_Float || type == ParameterType_Int){
+		std::cout << "   <LiteralData>" << std::endl;
+		std::string lt;
+		if(type == ParameterType_Int)
+		  lt="integer";
+		if(type == ParameterType_Float)
+		  lt="float";
+		if(type == ParameterType_String || type == ParameterType_StringList)
+		  lt="string";
+		std::cout << "    dataType = " << lt << std::endl;
+		std::cout << "    <Default />" << std::endl;
+		std::cout << "   </LiteralData>" << std::endl;
+	      }
+	      else
+		if(type == ParameterType_OutputFilename){
+		  std::cout << "   <ComplexData>" << std::endl;
+		  std::string descr(m_Application->GetParameterDescription(paramKey));
+		  std::string dtype("csv");
+		  std::string dtype1("CSV");
+		  if(descr.find(dtype)!= std::string::npos || descr.find(dtype1)!= std::string::npos)
+		    printCSV();
+		  else{
+		    std::string dtype2("text file");
+		    if(descr.find(dtype2)!= std::string::npos)
+		      printAscii();
+		    else{
+		      std::string dtype2("XML");
+		      std::string dtype3("xml");
+		      if(descr.find(dtype2)!= std::string::npos || descr.find(dtype3)!= std::string::npos)
+			printXml();
+		      else{
+			std::string dtype4("vector");
+			std::string dtype5("Vector");
+			if(descr.find(dtype4)!= std::string::npos || descr.find(dtype5)!= std::string::npos)
+			  printVector();
+		       	else{
+			  std::string dtype6("kmz");
+			  std::string dtype7("Kmz");
+			  if(descr.find(dtype6)!= std::string::npos || descr.find(dtype6)!= std::string::npos)
+			    printKmz();
+			  else
+			    printUnknown();
+			}
+		      }
+		    }
+		  }
+		  std::cout << "   </ComplexData>" << std::endl;
+		}
+	}
+      }
+      if(hasOutput<0)
+	printDefaultOutput();
+      std::cout << " </DataOutputs>" << std::endl;
+      std::cout.rdbuf(coutbuf);
+    }
+  }
+ 
+  return EXIT_SUCCESS; 
+}
+
Index: /tags/rel-1.7.0/thirds/saga2zcfg/Makefile
===================================================================
--- /tags/rel-1.7.0/thirds/saga2zcfg/Makefile	(revision 942)
+++ /tags/rel-1.7.0/thirds/saga2zcfg/Makefile	(revision 942)
@@ -0,0 +1,14 @@
+ZRPATH=../../zoo-project
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+WXCXX=`wx-config --cxx`
+WXCFLAGS=`wx-config --cxxflags`
+WXLIBS=`wx-config --libs`
+
+saga2zcfg: saga2zcfg.c
+	${WXCXX} ${SAGA_CFLAGS} ${WXCFLAGS} ${CFLAGS} -fpic -o saga2zcfg ./saga2zcfg.c ${GDAL_LIBS} ${MACOS_LD_FLAGS}  ${WXLIBS} ${SAGA_LDFLAGS}
+
+clean:
+	rm -f saga2zcfg
Index: /tags/rel-1.7.0/thirds/saga2zcfg/saga2zcfg.c
===================================================================
--- /tags/rel-1.7.0/thirds/saga2zcfg/saga2zcfg.c	(revision 942)
+++ /tags/rel-1.7.0/thirds/saga2zcfg/saga2zcfg.c	(revision 942)
@@ -0,0 +1,462 @@
+#include <locale.h>
+
+#include <wx/app.h>
+#include <wx/utils.h>
+
+#include <api_core.h>
+#include <saga_api.h>
+
+int Callback(TSG_UI_Callback_ID ID, CSG_UI_Parameter &Param_1, CSG_UI_Parameter &Param_2){
+  return( 1 );
+}
+
+TSG_PFNC_UI_Callback Get_Callback(void){
+  return( &Callback );
+}
+
+void cleanAbstract(CSG_String abstract,char**res){
+  char* tmp=strdup(abstract.b_str());
+  CSG_String val=CSG_String("")+tmp;
+  if(val.Contains("\r")){
+    val.Replace("\r","<br/>");
+  }
+  if(val.Contains("\n")){
+    val.Replace("\n","<br/>");
+  }
+  if(val.Contains("<")){
+    val.Replace("<","&lt;");
+  }
+  if(val.Contains(">")){
+    val.Replace(">","&gt;");
+  }
+  free(tmp);
+  if(val.is_Empty())
+    *res=NULL;
+  else
+    *res=strdup(val.b_str());
+}
+
+void printBasicMetadata(FILE* stdout,CSG_Parameter* param,bool out=false,bool range=false,bool min=true,bool tin=false,char* tname=NULL,char* ttitle=NULL){
+  fprintf(stdout," [%s]\n",(CSG_String(param->Get_Identifier())+(range?(min?"_MIN":"_MAX"):(tin?CSG_String("_")+tname:""))).b_str());
+  fprintf(stdout,"  Title = %s\n",(CSG_String(param->Get_Name())+(range?(min?" (min value)":" (max value)"):(tin&&ttitle!=NULL?ttitle:""))).b_str());
+  if(CSG_String(param->Get_Description()).is_Empty())
+    fprintf(stdout,"  Abstract = %s\n",CSG_String(param->Get_Name()).b_str());
+  else{
+    char* tmp=strdup(CSG_String(param->Get_Description()).b_str());
+    CSG_String val=CSG_String("")+tmp;
+    if(val.Contains("\r")){
+      val.Replace("\r","<br/>");
+    }
+    if(val.Contains("\n")){
+      val.Replace("\n","<br/>");
+    }
+    if(val.Contains("<")){
+      val.Replace("<","&lt;");
+    }
+    if(val.Contains(">")){
+      val.Replace(">","&gt;");
+    }
+    free(tmp);
+    fprintf(stdout,"  Abstract = %s\n",val.b_str());
+  }
+  if(!out){
+    if(param->is_Option() || param->is_Optional()){
+      fprintf(stdout,"  minOccurs = 0\n");
+      if(param->is_Option())
+	fprintf(stdout,"  maxOccurs = 1\n");
+      else{
+	if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("_list")))
+	  fprintf(stdout,"  maxOccurs = 1024\n");
+	else
+	  fprintf(stdout,"  maxOccurs = 1\n");
+      }
+    }else{
+      if(param->is_Input())
+	fprintf(stdout,"  minOccurs = 1\n");
+      if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("_list")))
+	fprintf(stdout,"  maxOccurs = 1024\n");
+      else
+	fprintf(stdout,"  maxOccurs = 1\n");
+    }
+  }
+  if(range){
+    
+  }
+}
+
+void printGrids(FILE* stdout){
+  fprintf(stdout,"  <ComplexData>\n");
+  fprintf(stdout,"   <Default>\n");
+  fprintf(stdout,"    mimeType = image/tiff\n");
+  fprintf(stdout,"   </Default>\n");
+  fprintf(stdout,"   <Supported>\n");
+  fprintf(stdout,"    mimeType = application/x-ogc-envi\n");
+  fprintf(stdout,"   </Supported>\n");
+  fprintf(stdout,"   <Supported>\n");
+  fprintf(stdout,"    mimeType = application/x-ogc-aaigrid\n");
+  fprintf(stdout,"   </Supported>\n");
+  fprintf(stdout,"  </ComplexData>\n");
+}
+
+void printShapes(FILE* stdout){
+  fprintf(stdout,"  <ComplexData>\n");
+  fprintf(stdout,"   <Default>\n");
+  fprintf(stdout,"    mimeType = text/xml\n");
+  fprintf(stdout,"    encoding = utf-8\n");
+  fprintf(stdout,"   </Default>\n");
+  fprintf(stdout,"   <Supported>\n");
+  fprintf(stdout,"    mimeType = application/vnd.google-earth.kml+xml\n");
+  fprintf(stdout,"   </Supported>\n");
+  fprintf(stdout,"   <Supported>\n");
+  fprintf(stdout,"    mimeType = application/json\n");
+  fprintf(stdout,"   </Supported>\n");
+  fprintf(stdout,"  </ComplexData>\n");
+}
+
+void printTables(FILE* stdout){
+  fprintf(stdout,"  <ComplexData>\n");
+  fprintf(stdout,"   <Default>\n");
+  fprintf(stdout,"    mimeType = text/csv\n");
+  fprintf(stdout,"    encoding = utf-8\n");
+  fprintf(stdout,"   </Default>\n");
+  fprintf(stdout,"   <Supported>\n");
+  fprintf(stdout,"    mimeType = text/csv\n");
+  fprintf(stdout,"    encoding = base64\n");
+  fprintf(stdout,"   </Supported>\n");
+  fprintf(stdout,"  </ComplexData>\n");
+}
+
+void printPoints(FILE* stdout){
+  fprintf(stdout,"  <ComplexData>\n");
+  fprintf(stdout,"   <Default>\n");
+  fprintf(stdout,"    mimeType = application/x-ogc-lasf\n");
+  fprintf(stdout,"    extension = las\n");
+  fprintf(stdout,"   </Default>\n");
+  fprintf(stdout,"  </ComplexData>\n");
+}
+
+int main(int argc, char *argv[]) {
+  if( !wxInitialize() ){
+    fprintf(stderr,"initialisation failed");
+    return -1;
+  }
+  setlocale(LC_NUMERIC, "C");
+  static bool g_bShow_Messages = false;
+  SG_Set_UI_Callback(Get_Callback());
+#if SAGA_MAJOR_VERSION == 2
+  int n = SG_Get_Module_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
+  if( SG_Get_Module_Library_Manager().Get_Count() <= 0 )
+#else
+  int n = SG_Get_Tool_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
+  if( SG_Get_Tool_Library_Manager().Get_Count() <= 0 )
+#endif
+  {
+    fprintf(stderr,"could not load any tool library");
+    return -2;
+  }
+
+#if SAGA_MAJOR_VERSION == 2
+  for(int i=0;i<SG_Get_Module_Library_Manager().Get_Count();i++)
+#else
+  for(int i=0;i<SG_Get_Tool_Library_Manager().Get_Count();i++)
+#endif
+    {
+    
+#if SAGA_MAJOR_VERSION == 2
+    CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(i);
+#else
+    CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(i);
+#endif
+    int lc=library->Get_Count();
+    if(!library->Get_Library_Name().Contains("io_")) {
+
+      for(int j=0;j<lc;j++){
+#if SAGA_MAJOR_VERSION == 2
+	CSG_Module * module=library->Get_Module(j);
+#else
+	CSG_Tool * module=library->Get_Tool(j);
+#endif
+	if(module!=NULL && !module->needs_GUI() /*&& !module->is_Interactive()*/ ){
+
+	  mkdir(library->Get_Library_Name().b_str(),0755);
+	  
+	  FILE *stdout1=fopen((library->Get_Library_Name()+"/"+module->Get_ID()+".zcfg").b_str(),"w+");
+	  fprintf(stdout1,"[%d]\n",j);
+	  fprintf(stdout1," Title = %s\n",module->Get_Name().b_str());
+	  if(CSG_String(module->Get_Description()).is_Empty() ||
+	     module->Get_Description().Length()<module->Get_Name().Length() )
+	    fprintf(stdout1," Abstract = %s\n",module->Get_Name().b_str());
+	  else{
+	    char *val0;
+	    cleanAbstract(module->Get_Description(),&val0);
+	    if(val0==NULL)
+	      fprintf(stdout1," Abstract = %s\n",module->Get_Name().b_str());
+	    else{
+	      fprintf(stdout1," Abstract = %s\n",val0);
+	      free(val0);
+	    }
+	  }
+	  fprintf(stdout1," storeSupported = true\n");
+	  fprintf(stdout1," statusSupported = true\n");
+	  fprintf(stdout1," serviceType = SAGA\n");
+	  fprintf(stdout1," serviceProvider = %s\n",library->Get_Library_Name().b_str());
+	  CSG_Parameters * params=module->Get_Parameters();
+	  int pc=params->Get_Count();
+
+	  fprintf(stdout1," <DataInputs>\n");
+	  for(int k=0;k<pc;k++){
+	    CSG_Parameter * param=params->Get_Parameter(k);
+	    
+	    if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("parameters"),true)){
+	      int pc0=param->asParameters()->Get_Count();
+	      int l;
+	      fprintf(stderr,"%s\n",CSG_String(param->Get_Name()).b_str());
+	      for(l=0;l<pc0;l++){
+		CSG_Parameter * param0=param->asParameters()->Get_Parameter(l);
+		fprintf(stderr,"%s\n",CSG_String(param0->Get_Type_Identifier()).b_str());
+	      }
+	    }
+	    
+	    // Node should be used for defining Complex ComplexData
+	    if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("color"))){
+	      
+	    }
+	    else if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("date"),true)){
+	      printBasicMetadata(stdout1,param,false,true,true);
+	      fprintf(stdout1,"  <LiteralData>\n");
+	      fprintf(stdout1,"   dataType = date\n");
+	      fprintf(stdout1,"   <Default/>\n");
+	      fprintf(stdout1,"  </LiteralData>\n");
+	      
+	    }
+	    else if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("range"),true)){
+
+	      param->Restore_Default();
+
+	      printBasicMetadata(stdout1,param,false,true,true);
+	      fprintf(stdout1,"  <LiteralData>\n");
+	      fprintf(stdout1,"   dataType = float\n");
+	      CSG_Parameter_Range *range=param->asRange();
+	      fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
+	      fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->Get_Data())->Get_LoVal());
+#else
+	      //fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->asDataObject())->Get_Min());	      
+#endif
+	      fprintf(stdout1,"   </Default>\n");
+	      fprintf(stdout1,"  </LiteralData>\n");
+
+	      printBasicMetadata(stdout1,param,false,true,false);
+	      fprintf(stdout1,"  <LiteralData>\n");
+	      fprintf(stdout1,"   dataType = float\n");
+	      fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
+	      fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->Get_Data())->Get_HiVal());
+#else
+	      //fprintf(stdout1,"    value = %f\n",((CSG_Parameter_Range*)param->asDataObject())->Get_Max());	      
+#endif
+	      fprintf(stdout1,"   </Default>\n");
+	      fprintf(stdout1,"  </LiteralData>\n");
+
+	    }
+	    else if(param!=NULL && !param->is_Output() 
+		    && 
+		    !CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("parameters"),true)
+		    && 
+		    !CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("grid_system"),true)
+		    && 
+		    !CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("node"),true)){
+	    
+	      printBasicMetadata(stdout1,param);
+
+	      if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("file"),true)){
+		if(CSG_String(param->Get_Description()).Contains(CSG_String("HTML"))){
+		  fprintf(stdout1,"  <ComplexData>\n");	       
+		  fprintf(stdout1,"   <Default>\n");
+		  fprintf(stdout1,"    mimeType = text/html\n");
+		  fprintf(stdout1,"    encoding = utf-8\n");
+		  fprintf(stdout1,"   </Default>\n");
+		  fprintf(stdout1,"  <ComplexData>\n");
+		}
+		else{
+		  fprintf(stdout1,"  <ComplexData>\n");	       
+		  fprintf(stdout1,"   <Default>\n");
+		  if(CSG_String(param->Get_Description()).Contains(CSG_String("HTML"))){
+		    fprintf(stdout1,"    mimeType = text/html\n");
+		  }else
+		    if(CSG_String(param->Get_Description()).Contains(CSG_String("SVG"))){
+		      fprintf(stdout1,"    mimeType = image/svg+xml\n");
+		    }else
+		      fprintf(stdout1,"    mimeType = text/plain\n");
+		  if(CSG_String(param->Get_Description()).Contains(CSG_String("ASCII"))){
+		    fprintf(stdout1,"    encoding = ascii\n");
+		  }else
+		    fprintf(stdout1,"    encoding = utf-8\n");
+		  fprintf(stdout1,"   </Default>\n");
+		  fprintf(stdout1,"  </ComplexData>\n");
+		}
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes")) ||
+		 CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin")) ){
+		printShapes(stdout1);
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).Contains("points")){
+		printPoints(stdout1);
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).Contains("grid") ||
+		 CSG_String(param->Get_Type_Identifier()).Contains("data_")){
+		printGrids(stdout1);
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
+		printTables(stdout1);
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("text"))){
+		fprintf(stdout1,"  <LiteralData>\n");
+		fprintf(stdout1,"   dataType = string\n");
+		fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
+		if( !param->Get_Data()->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",param->Get_Data()->Get_Default().b_str());
+		}
+#else
+		if( !param->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",param->Get_Default().b_str());
+		}
+#endif
+		fprintf(stdout1,"   </Default>\n");
+		fprintf(stdout1,"  </LiteralData>\n");
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("double"),true)
+		 || 
+		 CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("degree"),true)
+		 || 
+		 CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("integer"),true)){
+		fprintf(stdout1,"  <LiteralData>\n");
+		if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("double"),true) || 
+		 CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("degree"),true))
+		  fprintf(stdout1,"   dataType = float\n");
+		else
+		  fprintf(stdout1,"   dataType = integer\n");
+
+		fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
+		if( !param->Get_Data()->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",param->Get_Data()->Get_Default().b_str());
+		}
+#else
+		if( !param->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",param->Get_Default().b_str());
+		}
+#endif
+		if(param->asValue()->has_Minimum() && param->asValue()->has_Maximum()){
+		  fprintf(stdout1,"    rangeMin = %f\n",param->asValue()->Get_Minimum());
+		  fprintf(stdout1,"    rangeMax = %f\n",param->asValue()->Get_Maximum());
+		  fprintf(stdout1,"    rangeClosure = c\n");
+		}
+		fprintf(stdout1,"   </Default>\n");
+		fprintf(stdout1,"  </LiteralData>\n");
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("boolean"),true)){
+		fprintf(stdout1,"  <LiteralData>\n");
+		fprintf(stdout1,"   dataType = bool\n");
+		fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
+		if( !param->Get_Data()->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",(param->Get_Data()->Get_Default().Contains("0")?"false":"true"));
+		}
+#else
+		if( !param->Get_Default().is_Empty() ){
+		  fprintf(stdout1,"    value = %s\n",(param->Get_Default().Contains("0")?"false":"true"));
+		}
+#endif
+		fprintf(stdout1,"   </Default>\n");
+		fprintf(stdout1,"  </LiteralData>\n");	
+	      }
+	      if(CSG_String(param->Get_Type_Identifier()).is_Same_As(CSG_String("choice"),true)){
+		CSG_Parameter_Choice* choice=param->asChoice();
+		if(choice!=NULL){
+		  fprintf(stdout1,"  <LiteralData>\n");
+		  fprintf(stdout1,"   dataType = string\n");
+		  fprintf(stdout1,"   AllowedValues = ");
+		  int clen=choice->Get_Count();
+		  if(clen>0){
+		    for(int l=0;l<clen;l++){
+		      //fprintf(stdout1,"%d",l);
+		      fprintf(stdout1,"%s",(CSG_String(choice->Get_Item(l))).b_str());
+		      if(l+1<clen)
+			fprintf(stdout1,",");
+		    }
+		    fprintf(stdout1,"\n");
+		  }
+		  fprintf(stdout1,"   <Default>\n");
+#if SAGA_MAJOR_VERSION == 2
+		  if( !param->Get_Data()->Get_Default().is_Empty() ){
+		    fprintf(stdout1,"    value = %s\n",CSG_String(choice->Get_Item(atoi(param->Get_Data()->Get_Default()))).b_str());
+		  }
+#else
+		  if( !param->Get_Default().is_Empty() ){
+		    fprintf(stdout1,"    value = %s\n",CSG_String(choice->Get_Item(atoi(param->Get_Default()))).b_str());
+		  }		  
+#endif
+		  fprintf(stdout1,"   </Default>\n");
+		  fprintf(stdout1,"  </LiteralData>\n");
+		}
+	      }
+	    }
+	  }
+	  fprintf(stdout1," </DataInputs>\n");
+	  fprintf(stdout1," <DataOutputs>\n");
+
+	  bool hasOutput=false;
+
+	  for(int k=0;k<pc;k++){
+	    CSG_Parameter * param=params->Get_Parameter(k);
+	    if(param!=NULL && param->is_Output()){
+	      hasOutput=true;
+	      if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
+		char* tinOut[5]={
+		  (char*)"POINTS",
+		  (char*)"CENTER",
+		  (char*)"EDGES",
+		  (char*)"TRIANGLES",
+		  (char*)"POLYGONS"
+		};
+		for(int l=0;l<5;l++){
+		  char *ttitle=(char*)malloc((strlen(tinOut[l])+8)*sizeof(char));
+		  sprintf(ttitle,"%s Shapes",tinOut[l]);
+		  printBasicMetadata(stdout1,param,true,false,true,true,tinOut[l],ttitle);
+		  printShapes(stdout1);
+		}
+	      }
+	      else {
+		printBasicMetadata(stdout1,param,true);
+
+		if(CSG_String(param->Get_Type_Identifier()).Contains("points")){
+		  printPoints(stdout1);
+		}
+		if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes"))){
+		  printShapes(stdout1);
+		}
+		if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("grid")) ||
+		   CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("data_object"))){
+		  printGrids(stdout1);
+		}
+		if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
+		  printTables(stdout1);
+		}
+
+	      }
+	    }
+	  }
+	  fprintf(stdout1,"</DataOutputs>\n");
+	  fclose(stdout1);
+	  if(!hasOutput)
+	    unlink((library->Get_Library_Name()+"/"+module->Get_ID()+".zcfg").b_str());
+	}
+      }
+    }
+  }
+  wxUninitialize();
+
+  return 0;
+}
Index: /tags/rel-1.7.0/thirds/zcfg2sql/Makefile
===================================================================
--- /tags/rel-1.7.0/thirds/zcfg2sql/Makefile	(revision 942)
+++ /tags/rel-1.7.0/thirds/zcfg2sql/Makefile	(revision 942)
@@ -0,0 +1,16 @@
+ZRPATH=../../zoo-project
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+LCFLAGS=${CFLAGS} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+ifeq (${CALLBACK_FILE},service_callback.o)
+CALLBACK_FILES=${ZRPATH}/zoo-kernel/${CALLBACK_FILE} ${ZRPATH}/zoo-kernel/ulinet.o ${ZRPATH}/zoo-kernel/caching.o
+else
+CALLBACK_FILES=
+endif
+zcfg2sql: zcfg2sql.c
+	g++ -g -O2 ${JSCFLAGS} ${RUBYCFLAGS} ${XML2CFLAGS} ${LCFLAGS} -c zcfg2sql.c  -fno-common -DPIC -o zcfg2sql.o
+	g++  ${XML2CFLAGS} ${LCFLAGS} zcfg2sql.o ${CALLBACK_FILES} ${ZRPATH}/zoo-kernel/server_internal.o ${ZRPATH}/zoo-kernel/service_internal.o ${ZRPATH}/zoo-kernel/${MS_FILE} ${ZRPATH}/zoo-kernel/response_print.o ${ZRPATH}/zoo-kernel/lex.cr.o ${ZRPATH}/zoo-kernel/lex.sr.o ${ZRPATH}/zoo-kernel/service_conf.tab.o ${ZRPATH}/zoo-kernel/main_conf_read.tab.o  ${ZRPATH}/zoo-kernel/${YAML_FILE} -o zcfg2sql -L${ZRPATH}/zoo-kernel/ ${LDFLAGS}
+
+clean:
+	rm -f zcfg2sql
Index: /tags/rel-1.7.0/thirds/zcfg2sql/zcfg2sql.c
===================================================================
--- /tags/rel-1.7.0/thirds/zcfg2sql/zcfg2sql.c	(revision 942)
+++ /tags/rel-1.7.0/thirds/zcfg2sql/zcfg2sql.c	(revision 942)
@@ -0,0 +1,494 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright (c) 2017-2019 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service.h"
+
+extern int getServiceFromFile (maps *, const char *, service **);
+
+/**
+ * Dump an elements on stderr using the SQL syntaxe
+ *
+ * @param e the elements to dump
+ */
+void dumpElementsAsSQL(const char* type,elements* e,int index,int level,FILE* f){
+  elements* tmp=e;
+  int i;
+  while(tmp!=NULL){
+    fprintf(f,"--\n-- %s %s \n--\n",type,tmp->name);
+    map* mcurs=tmp->content;
+    iotype* tmpio=tmp->defaults;
+    int ioc=0;
+    if(tmp->format!=NULL){
+      //fprintf(stderr,"%s:\n",tmp->format);
+      if(strncmp(tmp->format,"Complex",7)==0){
+	while(tmpio!=NULL){
+	  map* values[3]={
+	    getMap(tmpio->content,"mimeType"),
+	    getMap(tmpio->content,"encoding"),
+	    getMap(tmpio->content,"schema")
+	  };
+	  char cond[3][256]={
+	    "mime_type is NULL",
+	    "encoding is NULL",
+	    "schema is NULL"
+	  };
+	  char *condNames[3]={
+	    "mime_type",
+	    "encoding",
+	    "schema"
+	  };
+	  for(i=0;i<3;i++)
+	    if(values[i]!=NULL){
+	      sprintf(cond[i],"%s='%s'",condNames[i],values[i]->value);
+	    }
+	  fprintf(f,"INSERT INTO CollectionDB.ows_Format"
+		  " (def,primitive_format_id) VALUES \n(true,");
+	  fprintf(f,"(SELECT id from CollectionDB.PrimitiveFormats"
+		  " WHERE %s AND %s AND %s));\n",cond[0],cond[1],cond[2]);
+	  fprintf(f,"INSERT INTO CollectionDB.ows_DataDescription (format_id)"
+		  " VALUES ((SELECT last_value FROM CollectionDB.ows_Format_id_seq));\n");
+	  tmpio=tmpio->next;
+	  ioc++;
+	}
+      }else{
+	if(strncmp(tmp->format,"Literal",7)==0){
+	  while(tmpio!=NULL){
+	    map* values[4]={
+	      getMap(tmpio->content,"dataType"),
+	      getMap(tmpio->content,"value"),
+	      getMap(tmpio->content,"uom"),
+	      getMap(tmpio->content,"AllowedValues")
+	    };
+	    char *fields[20]={
+	      "default_value",
+	      "def"
+	    };
+	    fprintf(f,"INSERT INTO CollectionDB.LiteralDataDomain"
+		    " (def,data_type_id) VALUES \n(true,");
+	    fprintf(f,"(SELECT id from CollectionDB.PrimitiveDatatypes"
+		    " where name = '%s'));\n",values[0]->value);
+	    if(values[1]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set %s = $q$%s$q$ \n WHERE id = \n"
+		      "  ((SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq));\n ",
+		      fields[0],values[1]->value);
+	    if(values[2]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set uom = (SELECT id from CollectionDB.PrimitiveUOM WHERE uom=$q$%s$q$) \n WHERE id = \n"
+		      "  (SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq);\n ",
+		      values[2]->value);
+	    if(values[3]!=NULL){
+	      char *tmp=strtok(values[3]->value,",");
+	      while(tmp!=NULL){
+		fprintf(f,"INSERT INTO CollectionDB.AllowedValues (allowed_value) VALUES ('%s');\n",tmp);
+		fprintf(f,"INSERT INTO CollectionDB.AllowedValuesAssignment"
+			" (allowed_value_id,literal_data_domain_id) VALUES "
+			"((SELECT last_value FROM CollectionDB.AllowedValues_id_seq),"
+			"(SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq));\n",tmp);
+		tmp=strtok(NULL,",");
+	      }
+	    }
+	    tmpio=tmpio->next;
+	    ioc++;
+	  }	  
+	}
+      }
+
+    }
+    
+    map* values[4]={
+      getMap(tmp->content,"Title"),
+      getMap(tmp->content,"Abstract"),
+      getMap(tmp->content,"minOccurs"),
+      getMap(tmp->content,"maxOccurs")
+    };
+    char *toto=",min_occurs,max_occurs";
+    if(strcmp(type,"Input")==0){
+      fprintf(f,"INSERT INTO CollectionDB.ows_Input "
+	      "(identifier,title,abstract,min_occurs,max_occurs)"
+	      " VALUES "
+	      "($q$%s$q$,\n$q$%s$q$,\n$q$%s$q$,\n%s,\n%s);\n",
+	      tmp->name,
+	      values[0]->value,
+	      values[1]->value,
+	      values[2]->value,
+	      values[3]->value
+	      );
+      if(tmp->format!=NULL)
+	fprintf(f,"INSERT INTO CollectionDB.InputDataDescriptionAssignment"
+		" (input_id,data_description_id) VALUES "
+		"((select last_value as id "
+	        "from CollectionDB.Descriptions_id_seq),"
+		"(select last_value "
+		"from CollectionDB.ows_DataDescription_id_seq));\n");
+      if(level==0)
+	fprintf(f,"INSERT INTO CollectionDB.ProcessInputAssignment"
+		"(process_id,input_id)"
+		" VALUES"
+		"((select id from pid),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n");
+      else
+	fprintf(f,"INSERT INTO CollectionDB.InputInputAssignment"
+		"(parent_input,child_input)"
+		" VALUES"
+		"((select id from cid_%d),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n",level-1);
+    }
+    else{
+      fprintf(f,"INSERT INTO CollectionDB.ows_Output\n"
+	      "\t(identifier,title,abstract)\n"
+	      "\t VALUES \n"
+	      "($q$%s$q$,$q$%s$q$,$q$%s$q$);\n",
+	      tmp->name,
+	      values[0]->value,
+	      values[1]->value
+	      );
+      if(tmp->format!=NULL)
+	fprintf(f,"INSERT INTO CollectionDB.OutputDataDescriptionAssignment"
+		" (output_id,data_description_id) VALUES "
+		"((select last_value as id "
+	        "from CollectionDB.Descriptions_id_seq),"
+		"(select last_value "
+		"from CollectionDB.ows_DataDescription_id_seq));\n");
+      if(level==0)
+	fprintf(f,"INSERT INTO CollectionDB.ProcessOutputAssignment"
+		"(process_id,output_id)"
+		" VALUES"
+		"((select id from pid),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n");
+      else
+	fprintf(f,"INSERT INTO CollectionDB.OutputOutputAssignment"
+		"(parent_output,child_output)"
+		" VALUES"
+		"((select id from cid_%d),"
+		"(select last_value as id from CollectionDB.Descriptions_id_seq));\n",level-1);
+    }
+
+    map* mcurs1=tmp->metadata;
+    if(mcurs1!=NULL){
+      while(mcurs1!=NULL){
+	if(strncasecmp(mcurs1->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_Metadata (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain0:
+	  if(mcurs1->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs1->next->value);
+	      mcurs1=mcurs1->next;
+	      goto tryagain0;
+	    }
+	    else{
+	      if(strncasecmp(mcurs1->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs1->next->value);
+		mcurs1=mcurs1->next;
+		goto tryagain0;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsMetadataAssignment (descriptions_id,metadata_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq));\n");	  
+	}
+	mcurs1=mcurs1->next;
+      }
+    }
+    mcurs=tmp->additional_parameters;
+    if(mcurs!=NULL){
+      while(mcurs!=NULL){
+	if(strncasecmp(mcurs->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameters (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain:
+	  if(mcurs->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+	      mcurs=mcurs->next;
+	      goto tryagain;
+	    }
+	    else{
+	      if(strncasecmp(mcurs->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+		mcurs=mcurs->next;
+		goto tryagain;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsAdditionalParametersAssignment (descriptions_id,additional_parameters_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n");	  
+	}else{
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameter (key,value,additional_parameters_id) "
+		  "VALUES ($q$%s$q$,$q$%s$q$,"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n",mcurs->name,mcurs->value);	  
+	}
+	mcurs=mcurs->next;
+      }
+    }
+
+    if(tmp->format!=NULL){
+      tmpio=tmp->supported;
+      if(strncmp(tmp->format,"Complex",7)==0){
+	while(tmpio!=NULL){
+	  map* values[3]={
+	    getMap(tmpio->content,"mimeType"),
+	    getMap(tmpio->content,"encoding"),
+	    getMap(tmpio->content,"schema")
+	  };
+	  char cond[3][256]={
+	    "mime_type is NULL",	    
+	    "encoding is NULL",
+	    "schema is NULL",
+	  };
+	  char *condNames[3]={
+	    "mime_type",
+	    "encoding",
+	    "schema"
+	  };
+	  for(i=0;i<3;i++)
+	    if(values[i]!=NULL){
+	      sprintf(cond[i],"%s='%s'",condNames[i],values[i]->value);
+	    }
+	  fprintf(f,"INSERT INTO CollectionDB.ows_Format"
+		  " (def,primitive_format_id) VALUES \n(false,");
+	  fprintf(f,"(SELECT id from CollectionDB.PrimitiveFormats"
+		  " WHERE %s AND %s AND %s));\n",cond[0],cond[1],cond[2]);
+	  fprintf(f,"INSERT INTO CollectionDB.ows_DataDescription (format_id)"
+		  " VALUES ((SELECT last_value FROM CollectionDB.ows_Format_id_seq));\n");
+	  fprintf(f,"INSERT INTO CollectionDB.%sDataDescriptionAssignment"
+		  " (%s_id,data_description_id) VALUES "
+		  "((select last_value as id "
+		  "from CollectionDB.Descriptions_id_seq),"
+		  "(select last_value "
+		  "from CollectionDB.ows_DataDescription_id_seq));\n",
+		  type,type);	  
+	  tmpio=tmpio->next;
+	  ioc++;
+	}
+      }else{
+	if(strncmp(tmp->format,"Literal",7)==0){
+	  while(tmpio!=NULL){
+	    map* values[4]={
+	      getMap(tmpio->content,"dataType"),
+	      getMap(tmpio->content,"value"),
+	      getMap(tmpio->content,"uom"),
+	      getMap(tmpio->content,"AllowedValues")
+	    };
+	    map* values0[4]={
+	      getMap(tmp->defaults->content,"dataType"),
+	      getMap(tmp->defaults->content,"value"),
+	      getMap(tmp->defaults->content,"uom"),
+	      getMap(tmp->defaults->content,"AllowedValues")
+	    };
+	    char *fields[20]={
+	      "default_value",
+	      "def"
+	    };
+	    fprintf(f,"INSERT INTO CollectionDB.LiteralDataDomain"
+		    " (def,data_type_id) VALUES \n(false,");
+	    if(values[0]!=NULL)
+	      fprintf(f,"(SELECT id from CollectionDB.PrimitiveDatatypes"
+		      " where name = '%s'));\n",values[0]->value);
+	    else
+	      fprintf(f,"(SELECT id from CollectionDB.PrimitiveDatatypes"
+		      " where name = '%s'));\n",values0[0]->value);
+	    if(values[1]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set %s = $q$%s$q$ \n WHERE id = \n"
+		      "  ((SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq));\n ",
+		      fields[0],values[1]->value);
+	    if(values[2]!=NULL)
+	      fprintf(f,"UPDATE CollectionDB.LiteralDataDomain \n"
+		      "set uom = (SELECT id from CollectionDB.PrimitiveUOM WHERE uom=$q$%s$q$) \n WHERE id = \n"
+		      "  (SELECT last_value FROM CollectionDB.ows_DataDescription_id_seq);\n ",
+		      values[2]->value);
+	    if(type!=NULL)
+	    fprintf(f,"INSERT INTO CollectionDB.%sDataDescriptionAssignment"
+		    " (%s_id,data_description_id) VALUES "
+		    "((select last_value "
+		    "from CollectionDB.Descriptions_id_seq),"
+		    "(select last_value "
+		    "from CollectionDB.ows_DataDescription_id_seq));\n",
+		    type,type);	  
+	    tmpio=tmpio->next;
+	    ioc++;
+	  }	  
+	}
+      }
+    }
+
+    if(tmp->format==NULL){
+      fprintf(f,"--\n-- Child %d \n--\n",level);
+      fprintf(f,"CREATE TEMPORARY TABLE cid_%d AS (select last_value as id from CollectionDB.Descriptions_id_seq) ;\n",level);
+      if(tmp->child!=NULL)
+	dumpElementsAsSQL(type,tmp->child,0,level+1,f);
+      fprintf(f,"DROP TABLE cid_%d;\n",level);
+      fprintf(f,"--\n-- End Child %d \n--\n",level);
+    }
+    tmp=tmp->next;
+  }
+}
+
+
+int main(int argc, char *argv[]) {
+  service* s=NULL;
+  maps *m=NULL;
+  char conf_file[1024];
+  snprintf(conf_file,1024,"%s",argv[1]);
+  s=(service*)malloc(SERVICE_SIZE);
+  if(s == NULL){
+    fprintf(stderr,"Unable to allocate memory");
+    return -1;
+  }
+  int t=getServiceFromFile(m,conf_file,&s);
+
+  fprintf(stdout,"--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+  int i;
+  fprintf(stdout,"--\n-- Service %s\n--\n",s->name);
+  if(s->content!=NULL){
+    map* values[4]={
+      getMap(s->content,"Title"),
+      getMap(s->content,"Abstract"),
+      getMap(s->content,"serviceProvider"),
+      getMap(s->content,"serviceType")
+    };
+    fprintf(stdout,"INSERT INTO CollectionDB.zoo_DeploymentMetadata\n"
+	    "(executable_name,service_type_id)\n"
+	    "\nVALUES\n"
+	    "($q$%s$q$,\n(SELECT id from CollectionDB.zoo_ServiceTypes WHERE service_type=$q$%s$q$));\n\n",
+	    values[2]->value,
+	    values[3]->value);
+    fprintf(stdout,"INSERT INTO CollectionDB.zoo_PrivateMetadata"
+	    "(id) VALUES (default);\n"); 
+    fprintf(stdout,"INSERT INTO CollectionDB.PrivateMetadataDeploymentMetadataAssignment"
+	    "(private_metadata_id,deployment_metadata_id) VALUES \n"
+	    "((SELECT last_value FROM CollectionDB.zoo_PrivateMetadata_id_seq),\n"
+	    "(SELECT last_value FROM CollectionDB.zoo_DeploymentMetadata_id_seq));\n");
+    fprintf(stdout,"INSERT INTO CollectionDB.ows_Process\n"
+	    "(identifier,title,abstract,private_metadata_id,"
+	    "availability)\n"
+	    "\nVALUES\n"
+	    "($q$%s$q$,\n$q$%s$q$,\n$q$%s$q$,(SELECT last_value FROM CollectionDB.PrivateMetadataDeploymentMetadataAssignment_id_seq),\ntrue);\n\n",
+	    s->name,
+	    values[0]->value,
+	    values[1]->value);
+    fprintf(stdout,"CREATE TEMPORARY TABLE pid AS "
+	    "(select last_value as id from CollectionDB.Descriptions_id_seq);\n");
+    map* mcurs=s->content;
+    //dumpMap(mcurs);
+    mcurs=s->metadata;
+    if(mcurs!=NULL){
+      while(mcurs!=NULL){
+	if(strncasecmp(mcurs->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_Metadata (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain0:
+	  if(mcurs->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs->next->value);
+	      mcurs=mcurs->next;
+	      goto tryagain0;
+	    }
+	    else{
+	      if(strncasecmp(mcurs->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_Metadata set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq);\n",mcurs->next->value);
+		mcurs=mcurs->next;
+		goto tryagain0;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsMetadataAssignment (descriptions_id,metadata_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_Metadata_id_seq));\n");	  
+	}
+	mcurs=mcurs->next;
+      }
+    }
+    mcurs=s->additional_parameters;
+    if(mcurs!=NULL){
+      while(mcurs!=NULL){
+	if(strncasecmp(mcurs->name,"title",5)==0){
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameters (title) "
+		  "VALUES ($q$%s$q$);\n",mcurs->value);
+	tryagain:
+	  if(mcurs->next!=NULL){
+	    if(strncasecmp(mcurs->next->name,"role",4)==0){
+	      fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set role = \n"
+		      "$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+	      mcurs=mcurs->next;
+	      goto tryagain;
+	    }
+	    else{
+	      if(strncasecmp(mcurs->next->name,"href",4)==0){
+		fprintf(stdout,"UPDATE CollectionDB.ows_AdditionalParameters set href = \n"
+			"$q$%s$q$ where id=(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq);\n",mcurs->next->value);
+		mcurs=mcurs->next;
+		goto tryagain;
+	      }
+	    }
+	  }
+	  fprintf(stdout,"INSERT INTO CollectionDB.DescriptionsAdditionalParametersAssignment (descriptions_id,additional_parameters_id) "
+		  "VALUES ((select last_value as id from CollectionDB.Descriptions_id_seq),"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n");	  
+	}else{
+	  fprintf(stdout,"INSERT INTO CollectionDB.ows_AdditionalParameter (key,value,additional_parameters_id) "
+		  "VALUES ($q$%s$q$,$q$%s$q$,"
+		  "(SELECT last_value FROM CollectionDB.ows_AdditionalParameters_id_seq));\n",mcurs->name,mcurs->value);	  
+	}
+	mcurs=mcurs->next;
+      }
+    }
+    
+  }
+  if(s->inputs!=NULL){
+    //fprintf(stderr,"\ninputs:\n");
+    dumpElementsAsSQL("Input",s->inputs,0,0,stdout);
+  }
+  if(s->outputs!=NULL){
+    //fprintf(stderr,"\noutputs:\n");
+    dumpElementsAsSQL("Output",s->outputs,0,0,stdout);
+  }
+  fprintf(stdout,"--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+
+  
+  
+  /*fprintf(stderr,"--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+  fflush(stderr);
+  printf("--\n-- Load from %s %d \n--",__FILE__,__LINE__);
+  if(t>=0){
+    fprintf(stderr,"--\n-- Service %s\n--",s->name);
+    fflush(stderr);
+    dumpServiceAsSQL(s); 
+    fprintf(stderr,"--\n-- Service %s\n--",s->name);
+    fflush(stderr);
+  }
+  */
+  fflush(stderr);
+  return 0;
+}
Index: /tags/rel-1.7.0/zoo-project/COMMITTERS
===================================================================
--- /tags/rel-1.7.0/zoo-project/COMMITTERS	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/COMMITTERS	(revision 942)
@@ -0,0 +1,33 @@
+===========================================================
+List of ZOO-Project committers
+===========================================================
+
+Folks who have agreed to ZOO-Project Commiter Guildlines terms:
+
+SVN Login(s)  Name/Contact
+============  ============
+david         David SAGGIORATO
+	      dsaggiorato at free.fr
+djay          Gérald FENOY *SVN Admin*
+	      gerald.fenoy at geolabs.fr
+jmckenna      Jeff MCKENNA
+	      jmckenna at gatewaygeomatics.com
+kalxas        Angelos TZOTSOS
+	      gcpp.kalxas at gmail.com
+lucadelu      Luca DELUCCHI
+	      lucadeluge at gmail.com
+nbozon	      Nicolas BOZON
+	      nicolas.bozon@gmail.com
+neteler       Markus NETELER
+	      neteler at osgeo.org
+nmarco        Marco NEGRETTI
+	      marco.negretti at polimi.it
+knut	      Knut LANDMARK
+	      Knut.Landmark@ffi.no
+reluc         René-Luc D'HONT
+	      rldhont at gmail.com
+tclarke       Trevor CLARKE
+	      tclarke at ball.com
+cresson       Remi CRESSON
+              remi.cresson at irstea.fr
+
Index: /tags/rel-1.7.0/zoo-project/HISTORY.txt
===================================================================
--- /tags/rel-1.7.0/zoo-project/HISTORY.txt	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/HISTORY.txt	(revision 942)
@@ -0,0 +1,201 @@
+Version 1.7.0-dev
+  * Fix issue with UOM definitions in zcfg2sql
+  * Make callback and HPC support independent from each other
+  * Update SAGA-GIS support to version 7.2.0
+  * Add support for custom MapServer style definition for raster output
+  * Fix returned bbox definition #170 
+  * Store semaphore status in lenv section for future deletion 
+  * Update Windows support to newer compiler
+  * Fix issue with UpdateStatus function from the Mono ZOO-API
+  * Add logging functionality and other utility functions to the C-API
+  * Return an exception for every output for which nb_pixel or
+  nb_features is 0 
+  * Add a shared key to the security section to differentiate the
+  referenced data 
+  * Add MapServer output style definition depending on the geometry
+  type 
+  * Add ogr.tindex service
+  * Add support for literaldata input arrays and to call services
+  asyncrhonously from the JavaScript ZOO-API   
+  * Expose a sleep function to the JavaScript ZOO-API
+  * Provide FinalizeHPC and FinalizeHPC1 services using scontrol and
+  sacct respectively  
+  * Store md5sum of the cached file (so, local to the WPS server) to
+  compare before uploading (if different md5sum) on the HPC server 
+  * Add support for R language
+  * Add support for using "file://"  for referenced data input
+  * Add an optional ecookie key for returning third-party cookies
+  * Fix issue when parsing BoundingBox input #163 
+  * Add memory key to the main section to force the ZOO-Kernel to load
+  data into memory or use local file 
+  * Add the dialect input to the ogr2ogr service
+  * Store the list of generated mapfiles in a file (cf DeleteData service)
+  * Define the correct MS_IMAGEMODE in the generated mapfile 
+  * Option to use MapServer support to publish heatmap
+  * Add status_code key to the lenv for setting Status HTTP response header 
+  * Add the Creation Option inputs to the Gdal_Dem service
+  * Add prohibited key in the callback section to define a list of
+  services not requiring any invocation
+  * Produce zcfg for OTB applications using the correct default pixel type
+  * Add asynchronous callback invocation to send information about
+  the ongoing services to a third-party software
+  * Add mapsToJson, mapsToJson, and elementsToJson to the API 
+  * Provide a zcfg2sql tool to convert a zcfg metadata file to SQL script
+  * Add support to store service metadata information into a database
+  * Add HPC Support for remote execution of SBATCH scripts through Slurm
+  * Add cookie reference to _HINTERNET
+  * Support headers for GET requests from the js ZOO-API 
+  * Pass all headers listed in the attributes parameter from the
+  [security] section to the hosts listed in the hosts parameter of the
+  same section (ticket #139)
+
+Version 1.6.0
+  * Add the C# as a supported programming language for Services 
+  * Add nested inputs and outputs support (WPS 2.0.0)
+  * Add servicePath special key to specify the service location
+  * Add the PHP version 7 support
+  * Add --with-etc-dir option to specify the location of the main.cfg file
+  * Support GDAL version 2.1.0.
+  * Add the MapServer 7.0.1 internal support.
+  * Support for exotic location of openssl.
+  * Add ZOO-Client API documentation reference in the official documentation.
+  * Add CORS support.
+  * Fix issue when dealing with Array in JavaScript support.
+  * Update the Centos installation procedure.
+  * Small fixes in java support.
+  * Fix issue when XML request contains empty nodes for inputs
+  * Add status update for contour lines computation
+  * Fix FASTCGI location using the --with-fastcgi option.
+  * Redefined the API function addToMapWithSize to fix problem with Python/PHP support.
+
+Version 1.5.0
+  * Complete rewrite of the documentation to use modern style
+  * Fix asynchronous POST request on WIN32 platforms
+  * Add utils/registry service
+  * Initial support for WPS 2.0.0 including the Dismiss extension
+  * Fix concurrency access to status information
+  * Use simple file rather than shared memory for storing status information
+  * Add support for db backend to store status information
+  * Add the lib_zoo_service shared library to be linked against C services
+  * Add ZOO-API for the PHP language (with documentation)
+  * Add doxygen comments in source code
+  * Add support for multiple Exception nodes
+  * Add a length key when creating MapArray
+  * Add OTB support for applications as a service
+  * Add the otb2zcfg utility to produce zcfg for otb applications
+  * Add OTB Application Observer to have progress status updates
+  * Fix maxOccurs handling
+  * Fix gesture of downloaded inputs when multiple values are given
+  * Add detection of generated_file key in outputs to read the file
+  generated by a service
+  * Add a minimal parsing API 
+  * Run validateRequest (download, default settings and decoding)
+  after fork if any
+  * Add SAGA-GIS support for modules as a service
+  * Add saga2zcfg utility to generate zcfg for SAGA-GIS modules
+  * Add SAGA-GIS Observer to have ongoing status updates
+
+Version 1.4.0
+  * Small fix for mimeType of results for CGAL services
+
+Version 1.4.0-rc1
+  * Binary support for PHP language
+  * ZOO-API for the Java language
+  * ZOO-Client Javascript API
+  * FastCGI fixes
+  * JavaScript ZOO-API enhancements (COOKIE use and Output in
+  generated XML)
+  * Add debian files
+  * Inputs passed by reference downloaded in parallel
+  * Conform behavior for DescribeProcess when the Identifier was not
+  found
+  * Add support of maximumMegabytes keywords for ComplexData Inputs
+  * Add the optional YAML ZCFG support #4 and the zcfg2yaml converter
+  * Return error messages that enable the service provider to quickly
+  identify the root cause of errors due to configuration file syntax
+  (ticket #90)
+  * Fix logic in addMapToMap (ticket #91)
+  * Enable AllowedValue and multiple Range definitions using default
+  and supported blocks
+  * Add the lastest revision number in version.h (available in Python
+  ZOO-API)
+  * Add the optional Ruby Language Support to the ZOO-Kernel with an
+  API similar to the Python ZOO-API
+  * Small rewrite of Python support
+  * Inputs can be requested over https protocol (ticket #86)
+  * Add capability to define both percentage of execution and a
+  message (ticket #87). 
+  * Add usid in lenv section used to generate an unique identifier
+  based on time and the process identifier.
+  * Add gdal_contour service
+  * Add dynamic definition of serverAddress from the main section
+
+Version 1.3.0-rc2
+  * Fix POST Request issue (ticket #34)
+  * Fix COOKIE gesture (ticket #79)
+  * Remove verbose messages when using MapServer W*S (ticket #80)
+  * Add COMMITTERS  and LICENSE files
+
+Version 1.3.0-rc1
+
+  * Updating ZOO.Class object with the OpenLayers.Class Updating
+    ZOO.Class with the (ticket #64)
+  * Correct the content of proj4js (ticket #63)
+  * Enhance the COOKIE gesture (ticket #68)
+  * Support for dataInputs URLEncoded and xlink:href (ticket #62)
+  * Use the same object structure for JavaScript arguments than for
+    Python
+  * Add the Normalized Difference Vegetation Index service
+  * Add importScripts function to JavaScript support (ticket #66)
+  * Add multiple inputs values for the same identifier (ticket #72)
+  * Add Python ZOO-API to access ZOO-Kernel internel functions
+  * Add a [headers] section in main.cfg file to add specifics to
+    header returned
+  * Add support for multiple outputs for both GET and POST requests
+  * Add Content-Length to the headers if the result is sized
+  * Add Content-Disposition to the headers if the result contains a
+    filename
+  * Add support for sending headers through JS ZOO-api
+  * Add support for multi-valued inputs in JS ZOO-api
+  * Fixing issue about invalid status document #73
+  * Add Python-3.3.0 support
+  * Update documentation
+  * Add MapServer W*S Support documentation #34
+
+Version 1.2.0-rc3
+
+  * add basic SOAP Envelope support (ticket #49)
+  * support request when Content-Length header is not set by the
+  * client (ticket #57)
+  * fix issue when POST request is empty (ticket #45)
+  * add minimalist cache system (ticket #51)
+  * fix Python support (ticket #29)
+
+Verseion 1.2.0-rc2
+
+  * fix for process to run in background
+  * add support for ALL identifier for !DescribeProcess
+  * add a small test suite in the testing directory to test ogr base-vect-ops
+  * big fix for storage of Session maps on disk
+  * support for {{{<Default />}}} node in ZCFG files
+  * fastcgi version now support both !GetCapabilities and !DescribeProcess requests
+
+Version 1.2.0-rc1
+
+  * add WIN32 support
+  * add GRASS support through wps-grass-bridge
+  * add languages support using libintl 
+  * binary support for inputs and outputs for both JAVA and Python
+  * automatic loading of ZOO-API and proj4js files (if present in the ZOO-Kernel directory) when loading JS Service Provider 
+  * numerous memory leaks removed
+  * add PERL support
+  * enhance speed for JAVA support 
+  * enhance POST request support
+  * add !BoundingBoxData support
+  * Python support is now optional as other languages
+  * add lenv section before running the service to store information runtime specific 
+  * add COOKIE support and {{{senv}}} section to store information session specific
+  * add {{{USE_GDB}}} compilation flag to remove signal handling for debuging purpose
+  * enhance base64 support when included in and XML POST request
+  * return !ExceptionReport when no protocol was specified for xlink:href value
+
Index: /tags/rel-1.7.0/zoo-project/LICENSE
===================================================================
--- /tags/rel-1.7.0/zoo-project/LICENSE	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/LICENSE	(revision 942)
@@ -0,0 +1,166 @@
+ZOO-Project Licensing
+---------------------
+
+This file attempts to include all licenses that apply within the ZOO-Project
+source tree, in particular any that are supposed to be exposed to the end user
+for credit requirements for instance.
+
+ZOO-Kernel License
+------------------
+
+Copyright (c) 2009-2015 GeoLabs SARL
+Copyright 2010-2011 Fondazione Edmund Mach. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights 
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies of this Software or works derived from this Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ZOO-Kernel OTB Support
+----------------------
+
+Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+See OTBCopyright.txt for details.
+
+Some parts of this code are derived from ITK. See ITKCopyright.txt
+for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.  See the above copyright notices for more information.
+
+See Ref: http://hg.orfeo-toolbox.org/OTB/ Copyright
+
+ZOO-API License
+---------------
+
+Copyright 2011-2013 GeoLabs SARL. All rights reserved.
+Copyright 2010 3liz SARL. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+Copyright (c) 2006-2011 by OpenLayers Contributors (see 
+https://github.com/openlayers/openlayers/blob/master/authors.txt for full 
+list of contributors). Published under the Clear BSD license.
+See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+full text of the license.
+
+qrencode ZOO-Services License
+-----------------------------
+
+Copyright (C) 2006-2012 Kentaro Fukuchi <kentaro@fukuchi.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Other ZOO-Services License
+--------------------------
+
+Copyright (c) 2009-2013, GeoLabs SARL
+Copyright (c) 2006, 2009 Matthew Perry 
+Copyright (c) 2009 Even Rouault
+Copyright (c) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
+Copyright (c) 1998, 1999, 2002, Frank Warmerdam
+Copyright (c) 2002, i3 - information integration and imaging Fort Collin, CO
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+CGIC License
+------------
+
+CGIC, copyright 2009 GeoLabs SARL.
+CGIC, copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+2004 by Thomas Boutell and Boutell.Com, Inc.. Permission is granted to 
+use CGIC in any application, commercial or noncommercial, at no cost. 
+HOWEVER, this copyright paragraph must appear on a "credits" page 
+accessible in the public online and offline documentation of the program. 
+Modified versions of the CGIC library should not be distributed without 
+the attachment of a clear statement regarding the author of the 
+modifications, and this notice may in no case be removed. 
+Modifications may also be submitted to the author for inclusion 
+in the main CGIC distribution.                                 
+
+IF YOU WOULD PREFER NOT TO ATTACH THE ABOVE NOTICE to
+the public documentation of your application, consult the
+information which follows regarding the availability
+of a nonexclusive commercial license for CGIC.
+
+dirent-win32 License
+--------------------
+
+Copyright (C) 2006 Toni Ronkko
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+``Software''), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
Index: /tags/rel-1.7.0/zoo-project/zoo-api/java/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/java/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/java/Makefile	(revision 942)
@@ -0,0 +1,39 @@
+include ../../zoo-kernel/ZOOMakefile.opts
+
+OS:=$(shell uname -s)
+ext=so
+ifeq ($(OS),Darwin)
+	ext=dylib
+endif
+
+JAVA_FILES=../../zoo-kernel/${JAVA_FILE}
+
+ifeq ($(JS_ENABLED),-DUSE_JS)
+	JS_FILES=../../zoo-kernel/${JS_FILE},
+endif
+ifeq ($(MS_FILE),service_internal_ms.o)
+	MS_FILES=../../zoo-kernel/${MS_FILE},
+endif
+
+ifeq ($(YAML_FILE),service_yaml.o)
+	YAML_FILES=../../zoo-kernel/${YAML_FILE},
+endif
+
+
+
+all: libZOO.${ext}
+
+org/zoo_project/ZOO.class: org/zoo_project/ZOO.java
+	javac org/zoo_project/ZOO.java
+
+org_zoo_project_ZOO.h: org/zoo_project/ZOO.java org/zoo_project/ZOO.class
+	javah org.zoo_project.ZOO
+
+zoo-api.o: zoo-api.c org_zoo_project_ZOO.h
+	gcc -fPIC -c zoo-api.c ${JAVACFLAGS} ${XML2CFLAGS} -I../../zoo-kernel/ -I../../../thirds/cgic206/
+
+libZOO.${ext}: zoo-api.o
+	gcc zoo-api.o -shared -o libZOO.${ext} -Wl,${YAML_FILES}../../zoo-kernel/lex.cr.o,../../zoo-kernel/main_conf_read.tab.o,../../zoo-kernel/lex.sr.o,../../zoo-kernel/service_conf.tab.o,../../zoo-kernel/service_internal.o,../../zoo-kernel/server_internal.o,../../zoo-kernel/response_print.o,${JAVA_FILES},${MS_FILES}${JS_FILES}../../zoo-kernel/ulinet.o ${GDAL_LIBS} ${XML2LDFLAGS} ${PYTHONLDFLAGS} ${PERLLDFLAGS}  ${PHPLDFLAGS} ${JAVALDFLAGS} ${JSLDFLAGS} -lcrypto ${MS_LDFLAGS} ${MACOS_LD_FLAGS} -lcurl -lfcgi ${MACOS_LD_NET_FLAGS} -lzoo_service ${YAML_LDFLAGS}
+
+clean:
+	rm -f *${ext} *o *.h *class org/zoo_project/*.class
Index: /tags/rel-1.7.0/zoo-project/zoo-api/java/org/zoo_project/ZOO.java
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/java/org/zoo_project/ZOO.java	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/java/org/zoo_project/ZOO.java	(revision 942)
@@ -0,0 +1,12 @@
+package org.zoo_project;
+
+import java.lang.*;
+import java.util.*;
+
+public class ZOO {
+    static { System.loadLibrary("ZOO"); }
+    public static Integer SERVICE_SUCCEEDED=3;
+    public static Integer SERVICE_FAILED=4;
+    public static native String translate(String a);
+    public static native Integer updateStatus(HashMap conf,String pourcent,String message);
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-api/java/zoo-api.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/java/zoo-api.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/java/zoo-api.c	(revision 942)
@@ -0,0 +1,39 @@
+#include "org_zoo_project_ZOO.h"
+#include "service.h"
+#include "service_internal.h"
+#include "service_internal_java.h"
+
+JNIEXPORT jstring JNICALL Java_org_zoo_1project_ZOO_translate
+  (JNIEnv *env, jclass _class, jstring msg){
+  const char *message = 
+#ifdef JAVA7
+    (*env).GetStringUTFChars(msg,0);
+  return (*env).NewStringUTF(_(message));
+#else
+    (*env)->GetStringUTFChars(env,msg, 0);
+  return (*env)->NewStringUTF(env, _(message));
+#endif
+
+}
+
+JNIEXPORT jobject JNICALL Java_org_zoo_1project_ZOO_updateStatus
+  (JNIEnv *env, jclass _class, jobject conf, jstring pourc, jstring msg){
+
+  jclass scHashMapClass,scHashMap_class;
+#ifdef JAVA7
+  scHashMapClass = (*env).FindClass("java/util/HashMap");
+  const char *pourcent = (*env).GetStringUTFChars(pourc,0);
+  const char *message = (*env).GetStringUTFChars(msg,0);
+#else
+  scHashMapClass = (*env)->FindClass(env, "java/util/HashMap");
+  const char *pourcent = (*env)->GetStringUTFChars(env,pourc, 0);
+  const char *message = (*env)->GetStringUTFChars(env,msg, 0);
+#endif
+  maps* m = mapsFromHashMap(env,conf,scHashMapClass);
+  setMapInMaps(m,"lenv","status",pourcent);
+  setMapInMaps(m,"lenv","message",message);
+  _updateStatus(m);
+  freeMaps(&m);
+  free(m);
+  return (jint)0;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-api/js/ZOO-api.js
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/js/ZOO-api.js	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/js/ZOO-api.js	(revision 942)
@@ -0,0 +1,6373 @@
+/**
+ * Author : René-Luc D'Hont
+ *
+ * Copyright 2010 3liz SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see 
+ * https://github.com/openlayers/openlayers/blob/master/authors.txt for full 
+ * list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. 
+ */
+
+/**
+ * Class: ZOO
+ */
+ZOO = {
+  /**
+   * Constant: SERVICE_ACCEPTED
+   * {Integer} used for
+   */
+  SERVICE_ACCEPTED: 0,
+  /**
+   * Constant: SERVICE_STARTED
+   * {Integer} used for
+   */
+  SERVICE_STARTED: 1,
+  /**
+   * Constant: SERVICE_PAUSED
+   * {Integer} used for
+   */
+  SERVICE_PAUSED: 2,
+  /**
+   * Constant: SERVICE_SUCCEEDED
+   * {Integer} used for
+   */
+  SERVICE_SUCCEEDED: 3,
+  /**
+   * Constant: SERVICE_FAILED
+   * {Integer} used for
+   */
+  SERVICE_FAILED: 4,
+  /** 
+   * Function: removeItem
+   * Remove an object from an array. Iterates through the array
+   *     to find the item, then removes it.
+   *
+   * Parameters:
+   * array - {Array}
+   * item - {Object}
+   * 
+   * Return
+   * {Array} A reference to the array
+   */
+  removeItem: function(array, item) {
+    for(var i = array.length - 1; i >= 0; i--) {
+        if(array[i] == item) {
+            array.splice(i,1);
+        }
+    }
+    return array;
+  },
+  /** 
+   * Function: indexOf
+   * 
+   * Parameters:
+   * array - {Array}
+   * obj - {Object}
+   * 
+   * Returns:
+   * {Integer} The index at, which the first object was found in the array.
+   *           If not found, returns -1.
+   */
+  indexOf: function(array, obj) {
+    for(var i=0, len=array.length; i<len; i++) {
+      if (array[i] == obj)
+        return i;
+    }
+    return -1;   
+  },
+  /**
+   * Function: extend
+   * Copy all properties of a source object to a destination object. Modifies
+   *     the passed in destination object.  Any properties on the source object
+   *     that are set to undefined will not be (re)set on the destination object.
+   *
+   * Parameters:
+   * destination - {Object} The object that will be modified
+   * source - {Object} The object with properties to be set on the destination
+   *
+   * Returns:
+   * {Object} The destination object.
+   */
+  extend: function(destination, source) {
+    destination = destination || {};
+    if(source) {
+      for(var property in source) {
+        var value = source[property];
+        if(value !== undefined)
+          destination[property] = value;
+      }
+    }
+    return destination;
+  },
+  /**
+   * Function: rad
+   * 
+   * Parameters:
+   * x - {Float}
+   * 
+   * Returns:
+   * {Float}
+   */
+  rad: function(x) {return x*Math.PI/180;},
+  /**
+   * Function: distVincenty
+   * Given two objects representing points with geographic coordinates, this
+   *     calculates the distance between those points on the surface of an
+   *     ellipsoid.
+   * 
+   * Parameters:
+   * p1 - {<ZOO.Geometry.Point>} (or any object with both .x, .y properties)
+   * p2 - {<ZOO.Geometry.Point>} (or any object with both .x, .y properties)
+   * 
+   * Returns:
+   * {Float} The distance (in km) between the two input points as measured on an
+   *     ellipsoid.  Note that the input point objects must be in geographic
+   *     coordinates (decimal degrees) and the return distance is in kilometers.
+   */
+  distVincenty: function(p1, p2) {
+    var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;
+    var L = ZOO.rad(p2.x - p1.y);
+    var U1 = Math.atan((1-f) * Math.tan(ZOO.rad(p1.y)));
+    var U2 = Math.atan((1-f) * Math.tan(ZOO.rad(p2.y)));
+    var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
+    var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
+    var lambda = L, lambdaP = 2*Math.PI;
+    var iterLimit = 20;
+    while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
+        var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
+        var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
+        (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
+        if (sinSigma==0) {
+            return 0;  // co-incident points
+        }
+        var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
+        var sigma = Math.atan2(sinSigma, cosSigma);
+        var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
+        var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
+        var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
+        var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
+        lambdaP = lambda;
+        lambda = L + (1-C) * f * Math.sin(alpha) *
+        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
+    }
+    if (iterLimit==0) {
+        return NaN;  // formula failed to converge
+    }
+    var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
+    var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
+    var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
+    var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
+        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
+    var s = b*A*(sigma-deltaSigma);
+    var d = s.toFixed(3)/1000; // round to 1mm precision
+    return d;
+  },
+  /**
+   * Function: Class
+   * Method used to create ZOO classes. Includes support for
+   *     multiple inheritance.
+   */
+  Class: function() {
+    var Class = function() {
+      this.initialize.apply(this, arguments);
+    };
+    var extended = {};
+    var parent;
+    for(var i=0; i<arguments.length; ++i) {
+      if(typeof arguments[i] == "function") {
+        // get the prototype of the superclass
+        parent = arguments[i].prototype;
+      } else {
+        // in this case we're extending with the prototype
+        parent = arguments[i];
+      }
+      ZOO.extend(extended, parent);
+    }
+    Class.prototype = extended;
+
+    return Class;
+  },
+  /**
+   * Function: UpdateStatus
+   * Method used to update the status of the process
+   *
+   * Parameters:
+   * env - {Object} The environment object
+   * value - {Float} the status value between 0 to 100
+   */
+  UpdateStatus: function(env,value) {
+    return ZOOUpdateStatus(env,value);
+  }
+};
+
+/**
+ * Class: ZOO.String
+ * Contains convenience methods for string manipulation
+ */
+ZOO.String = {
+  /**
+   * Function: startsWith
+   * Test whether a string starts with another string. 
+   * 
+   * Parameters:
+   * str - {String} The string to test.
+   * sub - {Sring} The substring to look for.
+   *  
+   * Returns:
+   * {Boolean} The first string starts with the second.
+   */
+  startsWith: function(str, sub) {
+    return (str.indexOf(sub) == 0);
+  },
+  /**
+   * Function: contains
+   * Test whether a string contains another string.
+   * 
+   * Parameters:
+   * str - {String} The string to test.
+   * sub - {String} The substring to look for.
+   * 
+   * Returns:
+   * {Boolean} The first string contains the second.
+   */
+  contains: function(str, sub) {
+    return (str.indexOf(sub) != -1);
+  },
+  /**
+   * Function: trim
+   * Removes leading and trailing whitespace characters from a string.
+   * 
+   * Parameters:
+   * str - {String} The (potentially) space padded string.  This string is not
+   *     modified.
+   * 
+   * Returns:
+   * {String} A trimmed version of the string with all leading and 
+   *     trailing spaces removed.
+   */
+  trim: function(str) {
+    return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+  },
+  /**
+   * Function: camelize
+   * Camel-case a hyphenated string. 
+   *     Ex. "chicken-head" becomes "chickenHead", and
+   *     "-chicken-head" becomes "ChickenHead".
+   *
+   * Parameters:
+   * str - {String} The string to be camelized.  The original is not modified.
+   * 
+   * Returns:
+   * {String} The string, camelized
+   *
+   */
+  camelize: function(str) {
+    var oStringList = str.split('-');
+    var camelizedString = oStringList[0];
+    for (var i=1, len=oStringList.length; i<len; i++) {
+      var s = oStringList[i];
+      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+    }
+    return camelizedString;
+  },
+  /**
+   * Property: tokenRegEx
+   * Used to find tokens in a string.
+   * Examples: ${a}, ${a.b.c}, ${a-b}, ${5}
+   */
+  tokenRegEx:  /\$\{([\w.]+?)\}/g,
+  /**
+   * Property: numberRegEx
+   * Used to test strings as numbers.
+   */
+  numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,
+  /**
+   * Function: isNumeric
+   * Determine whether a string contains only a numeric value.
+   *
+   * Examples:
+   * (code)
+   * ZOO.String.isNumeric("6.02e23") // true
+   * ZOO.String.isNumeric("12 dozen") // false
+   * ZOO.String.isNumeric("4") // true
+   * ZOO.String.isNumeric(" 4 ") // false
+   * (end)
+   *
+   * Returns:
+   * {Boolean} String contains only a number.
+   */
+  isNumeric: function(value) {
+    return ZOO.String.numberRegEx.test(value);
+  },
+  /**
+   * Function: numericIf
+   * Converts a string that appears to be a numeric value into a number.
+   * 
+   * Returns
+   * {Number|String} a Number if the passed value is a number, a String
+   *     otherwise. 
+   */
+  numericIf: function(value) {
+    return ZOO.String.isNumeric(value) ? parseFloat(value) : value;
+  }
+};
+
+/**
+ * Class: ZOO.Class
+ * Object for creating CLASS
+ */
+ZOO.Class = function() {
+  var len = arguments.length;
+  var P = arguments[0];
+  var F = arguments[len-1];
+  var C = typeof F.initialize == "function" ?
+    F.initialize :
+    function(){ P.prototype.initialize.apply(this, arguments); };
+
+  if (len > 1) {
+    var newArgs = [C, P].concat(
+          Array.prototype.slice.call(arguments).slice(1, len-1), F);
+    ZOO.inherit.apply(null, newArgs);
+  } else {
+    C.prototype = F;
+  }
+  return C;
+};
+/**
+ * Function: create
+ * Function for creating CLASS
+ */
+ZOO.Class.create = function() {
+  return function() {
+    if (arguments && arguments[0] != ZOO.Class.isPrototype) {
+      this.initialize.apply(this, arguments);
+    }
+  };
+};
+/**
+ * Function: inherit
+ * Function for inheriting CLASS
+ */
+ZOO.Class.inherit = function (P) {
+  var C = function() {
+   P.call(this);
+  };
+  var newArgs = [C].concat(Array.prototype.slice.call(arguments));
+  ZOO.inherit.apply(null, newArgs);
+  return C.prototype;
+};
+/**
+ * Function: inherit
+ * Function for inheriting CLASS
+ */
+ZOO.inherit = function(C, P) {
+  var F = function() {};
+  F.prototype = P.prototype;
+  C.prototype = new F;
+  var i, l, o;
+  for(i=2, l=arguments.length; i<l; i++) {
+    o = arguments[i];
+    if(typeof o === "function") {
+      o = o.prototype;
+    }
+    ZOO.Util.extend(C.prototype, o);
+  }
+};
+/**
+ * Class: ZOO.Util
+ * Object for utilities
+ */
+ZOO.Util = ZOO.Util || {};
+/**
+ * Function: extend
+ * Function for extending object
+ */
+ZOO.Util.extend = function(destination, source) {
+  destination = destination || {};
+  if (source) {
+    for (var property in source) {
+      var value = source[property];
+      if (value !== undefined) {
+        destination[property] = value;
+      }
+    }
+  }
+  return destination;
+};
+
+ZOO._=function(str){
+    return ZOOTranslate(str);
+};
+
+/**
+ * Class: ZOO.Request
+ * Contains convenience methods for working with ZOORequest which
+ *     replace XMLHttpRequest. Because of we are not in a browser
+ *     JavaScript environment, ZOO Project provides a method to 
+ *     query servers which is based on curl : ZOORequest.
+ */
+ZOO.Request = {
+  /**
+   * Function: GET
+   * Send an HTTP GET request.
+   *
+   * Parameters:
+   * url - {String} The URL to request.
+   * params - {Object} Params to add to the url
+   * headers - {Object/Array}  A key-value object of headers
+   * 
+   * Returns:
+   * {String} Request result.
+   */
+    Get: function(url,params,headers) {
+    var paramsArray = [];
+    for (var key in params) {
+      var value = params[key];
+      if ((value != null) && (typeof value != 'function')) {
+        var encodedValue;
+        if (typeof value == 'object' && value.constructor == Array) {
+          /* value is an array; encode items and separate with "," */
+          var encodedItemArray = [];
+          for (var itemIndex=0, len=value.length; itemIndex<len; itemIndex++) {
+            encodedItemArray.push(encodeURIComponent(value[itemIndex]));
+          }
+          encodedValue = encodedItemArray.join(",");
+        }
+        else {
+          /* value is a string; simply encode */
+          encodedValue = encodeURIComponent(value);
+        }
+        paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
+      }
+    }
+    var paramString = paramsArray.join("&");
+    if(paramString.length > 0) {
+      var separator = (url.indexOf('?') > -1) ? '&' : '?';
+      url += separator + paramString;
+    }
+    if(!(headers instanceof Array)) {
+	var headersArray = [];
+	for (var name in headers) {
+            headersArray.push(name+': '+headers[name]); 
+	}
+	headers = headersArray;
+    }
+    return ZOORequest('GET',url,headers);
+  },
+  /**
+   * Function: POST
+   * Send an HTTP POST request.
+   *
+   * Parameters:
+   * url - {String} The URL to request.
+   * body - {String} The request's body to send.
+   * headers - {Object} A key-value object of headers to push to
+   *     the request's head
+   * 
+   * Returns:
+   * {String} Request result.
+   */
+  Post: function(url,body,headers) {
+    if(!(headers instanceof Array)) {
+      var headersArray = [];
+      for (var name in headers) {
+        headersArray.push(name+': '+headers[name]); 
+      }
+      headers = headersArray;
+    }
+    return ZOORequest('POST',url,body,headers);
+  }
+};
+
+/**
+ * Class: ZOO.Bounds
+ * Instances of this class represent bounding boxes.  Data stored as left,
+ *     bottom, right, top floats. All values are initialized to null,
+ *     however, you should make sure you set them before using the bounds
+ *     for anything.
+ */
+ZOO.Bounds = ZOO.Class({
+  /**
+   * Property: left
+   * {Number} Minimum horizontal coordinate.
+   */
+  left: null,
+  /**
+   * Property: bottom
+   * {Number} Minimum vertical coordinate.
+   */
+  bottom: null,
+  /**
+   * Property: right
+   * {Number} Maximum horizontal coordinate.
+   */
+  right: null,
+  /**
+   * Property: top
+   * {Number} Maximum vertical coordinate.
+   */
+  top: null,
+  /**
+   * Constructor: ZOO.Bounds
+   * Construct a new bounds object.
+   *
+   * Parameters:
+   * left - {Number} The left bounds of the box.  Note that for width
+   *        calculations, this is assumed to be less than the right value.
+   * bottom - {Number} The bottom bounds of the box.  Note that for height
+   *          calculations, this is assumed to be more than the top value.
+   * right - {Number} The right bounds.
+   * top - {Number} The top bounds.
+   */
+  initialize: function(left, bottom, right, top) {
+    if (left != null)
+      this.left = parseFloat(left);
+    if (bottom != null)
+      this.bottom = parseFloat(bottom);
+    if (right != null)
+      this.right = parseFloat(right);
+    if (top != null)
+      this.top = parseFloat(top);
+  },
+  /**
+   * Method: clone
+   * Create a cloned instance of this bounds.
+   *
+   * Returns:
+   * {<ZOO.Bounds>} A fresh copy of the bounds
+   */
+  clone:function() {
+    return new ZOO.Bounds(this.left, this.bottom, 
+                          this.right, this.top);
+  },
+  /**
+   * Method: equals
+   * Test a two bounds for equivalence.
+   *
+   * Parameters:
+   * bounds - {<ZOO.Bounds>}
+   *
+   * Returns:
+   * {Boolean} The passed-in bounds object has the same left,
+   *           right, top, bottom components as this.  Note that if bounds 
+   *           passed in is null, returns false.
+   */
+  equals:function(bounds) {
+    var equals = false;
+    if (bounds != null)
+        equals = ((this.left == bounds.left) && 
+                  (this.right == bounds.right) &&
+                  (this.top == bounds.top) && 
+                  (this.bottom == bounds.bottom));
+    return equals;
+  },
+  /** 
+   * Method: toString
+   * 
+   * Returns:
+   * {String} String representation of bounds object. 
+   *          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
+   */
+  toString:function() {
+    return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
+              + " right-top=(" + this.right + "," + this.top + ")" );
+  },
+  /**
+   * APIMethod: toArray
+   *
+   * Returns:
+   * {Array} array of left, bottom, right, top
+   */
+  toArray: function() {
+    return [this.left, this.bottom, this.right, this.top];
+  },
+  /** 
+   * Method: toBBOX
+   * 
+   * Parameters:
+   * decimal - {Integer} How many significant digits in the bbox coords?
+   *                     Default is 6
+   * 
+   * Returns:
+   * {String} Simple String representation of bounds object.
+   *          (ex. <i>"5,42,10,45"</i>)
+   */
+  toBBOX:function(decimal) {
+    if (decimal== null)
+      decimal = 6; 
+    var mult = Math.pow(10, decimal);
+    var bbox = Math.round(this.left * mult) / mult + "," + 
+               Math.round(this.bottom * mult) / mult + "," + 
+               Math.round(this.right * mult) / mult + "," + 
+               Math.round(this.top * mult) / mult;
+    return bbox;
+  },
+  /**
+   * Method: toGeometry
+   * Create a new polygon geometry based on this bounds.
+   *
+   * Returns:
+   * {<ZOO.Geometry.Polygon>} A new polygon with the coordinates
+   *     of this bounds.
+   */
+  toGeometry: function() {
+    return new ZOO.Geometry.Polygon([
+      new ZOO.Geometry.LinearRing([
+        new ZOO.Geometry.Point(this.left, this.bottom),
+        new ZOO.Geometry.Point(this.right, this.bottom),
+        new ZOO.Geometry.Point(this.right, this.top),
+        new ZOO.Geometry.Point(this.left, this.top)
+      ])
+    ]);
+  },
+  /**
+   * Method: getWidth
+   * 
+   * Returns:
+   * {Float} The width of the bounds
+   */
+  getWidth:function() {
+    return (this.right - this.left);
+  },
+  /**
+   * Method: getHeight
+   * 
+   * Returns:
+   * {Float} The height of the bounds (top minus bottom).
+   */
+  getHeight:function() {
+    return (this.top - this.bottom);
+  },
+  /**
+   * Method: add
+   * 
+   * Parameters:
+   * x - {Float}
+   * y - {Float}
+   * 
+   * Returns:
+   * {<ZOO.Bounds>} A new bounds whose coordinates are the same as
+   *     this, but shifted by the passed-in x and y values.
+   */
+  add:function(x, y) {
+    if ( (x == null) || (y == null) )
+      return null;
+    return new ZOO.Bounds(this.left + x, this.bottom + y,
+                                 this.right + x, this.top + y);
+  },
+  /**
+   * Method: extend
+   * Extend the bounds to include the point, lonlat, or bounds specified.
+   *     Note, this function assumes that left < right and bottom < top.
+   * 
+   * Parameters: 
+   * object - {Object} Can be Point, or Bounds
+   */
+  extend:function(object) {
+    var bounds = null;
+    if (object) {
+      // clear cached center location
+      switch(object.CLASS_NAME) {
+        case "ZOO.Geometry.Point":
+          bounds = new ZOO.Bounds(object.x, object.y,
+                                         object.x, object.y);
+          break;
+        case "ZOO.Bounds":    
+          bounds = object;
+          break;
+      }
+      if (bounds) {
+        if ( (this.left == null) || (bounds.left < this.left))
+          this.left = bounds.left;
+        if ( (this.bottom == null) || (bounds.bottom < this.bottom) )
+          this.bottom = bounds.bottom;
+        if ( (this.right == null) || (bounds.right > this.right) )
+          this.right = bounds.right;
+        if ( (this.top == null) || (bounds.top > this.top) )
+          this.top = bounds.top;
+      }
+    }
+  },
+  /**
+   * APIMethod: contains
+   * 
+   * Parameters:
+   * x - {Float}
+   * y - {Float}
+   * inclusive - {Boolean} Whether or not to include the border.
+   *     Default is true.
+   *
+   * Returns:
+   * {Boolean} Whether or not the passed-in coordinates are within this
+   *     bounds.
+   */
+  contains:function(x, y, inclusive) {
+     //set default
+     if (inclusive == null)
+       inclusive = true;
+     if (x == null || y == null)
+       return false;
+     x = parseFloat(x);
+     y = parseFloat(y);
+
+     var contains = false;
+     if (inclusive)
+       contains = ((x >= this.left) && (x <= this.right) && 
+                   (y >= this.bottom) && (y <= this.top));
+     else
+       contains = ((x > this.left) && (x < this.right) && 
+                   (y > this.bottom) && (y < this.top));
+     return contains;
+  },
+  /**
+   * Method: intersectsBounds
+   * Determine whether the target bounds intersects this bounds.  Bounds are
+   *     considered intersecting if any of their edges intersect or if one
+   *     bounds contains the other.
+   * 
+   * Parameters:
+   * bounds - {<ZOO.Bounds>} The target bounds.
+   * inclusive - {Boolean} Treat coincident borders as intersecting.  Default
+   *     is true.  If false, bounds that do not overlap but only touch at the
+   *     border will not be considered as intersecting.
+   *
+   * Returns:
+   * {Boolean} The passed-in bounds object intersects this bounds.
+   */
+  intersectsBounds:function(bounds, inclusive) {
+    if (inclusive == null)
+      inclusive = true;
+    var intersects = false;
+    var mightTouch = (
+        this.left == bounds.right ||
+        this.right == bounds.left ||
+        this.top == bounds.bottom ||
+        this.bottom == bounds.top
+    );
+    if (inclusive || !mightTouch) {
+      var inBottom = (
+          ((bounds.bottom >= this.bottom) && (bounds.bottom <= this.top)) ||
+          ((this.bottom >= bounds.bottom) && (this.bottom <= bounds.top))
+          );
+      var inTop = (
+          ((bounds.top >= this.bottom) && (bounds.top <= this.top)) ||
+          ((this.top > bounds.bottom) && (this.top < bounds.top))
+          );
+      var inLeft = (
+          ((bounds.left >= this.left) && (bounds.left <= this.right)) ||
+          ((this.left >= bounds.left) && (this.left <= bounds.right))
+          );
+      var inRight = (
+          ((bounds.right >= this.left) && (bounds.right <= this.right)) ||
+          ((this.right >= bounds.left) && (this.right <= bounds.right))
+          );
+      intersects = ((inBottom || inTop) && (inLeft || inRight));
+    }
+    return intersects;
+  },
+  /**
+   * Method: containsBounds
+   * Determine whether the target bounds is contained within this bounds.
+   * 
+   * bounds - {<ZOO.Bounds>} The target bounds.
+   * partial - {Boolean} If any of the target corners is within this bounds
+   *     consider the bounds contained.  Default is false.  If true, the
+   *     entire target bounds must be contained within this bounds.
+   * inclusive - {Boolean} Treat shared edges as contained.  Default is
+   *     true.
+   *
+   * Returns:
+   * {Boolean} The passed-in bounds object is contained within this bounds. 
+   */
+  containsBounds:function(bounds, partial, inclusive) {
+    if (partial == null)
+      partial = false;
+    if (inclusive == null)
+      inclusive = true;
+    var bottomLeft  = this.contains(bounds.left, bounds.bottom, inclusive);
+    var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
+    var topLeft  = this.contains(bounds.left, bounds.top, inclusive);
+    var topRight = this.contains(bounds.right, bounds.top, inclusive);
+    return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
+                     : (bottomLeft && bottomRight && topLeft && topRight);
+  },
+  CLASS_NAME: 'ZOO.Bounds'
+});
+
+/**
+ * Class: ZOO.Projection
+ * Class for coordinate transforms between coordinate systems.
+ *     Depends on the zoo-proj4js library. zoo-proj4js library 
+ *     is loaded by the ZOO Kernel with zoo-api.
+ */
+ZOO.Projection = ZOO.Class({
+  /**
+   * Property: proj
+   * {Object} Proj4js.Proj instance.
+   */
+  proj: null,
+  /**
+   * Property: projCode
+   * {String}
+   */
+  projCode: null,
+  /**
+   * Constructor: ZOO.Projection
+   * This class offers several methods for interacting with a wrapped 
+   *     zoo-pro4js projection object. 
+   *
+   * Parameters:
+   * projCode - {String} A string identifying the Well Known Identifier for
+   *    the projection.
+   * options - {Object} An optional object to set additional properties.
+   *
+   * Returns:
+   * {<ZOO.Projection>} A projection object.
+   */
+  initialize: function(projCode, options) {
+    ZOO.extend(this, options);
+    this.projCode = projCode;
+    if (Proj4js) {
+      this.proj = new Proj4js.Proj(projCode);
+    }
+  },
+  /**
+   * Method: getCode
+   * Get the string SRS code.
+   *
+   * Returns:
+   * {String} The SRS code.
+   */
+  getCode: function() {
+    return this.proj ? this.proj.srsCode : this.projCode;
+  },
+  /**
+   * Method: getUnits
+   * Get the units string for the projection -- returns null if 
+   *     zoo-proj4js is not available.
+   *
+   * Returns:
+   * {String} The units abbreviation.
+   */
+  getUnits: function() {
+    return this.proj ? this.proj.units : null;
+  },
+  /**
+   * Method: toString
+   * Convert projection to string (getCode wrapper).
+   *
+   * Returns:
+   * {String} The projection code.
+   */
+  toString: function() {
+    return this.getCode();
+  },
+  /**
+   * Method: equals
+   * Test equality of two projection instances.  Determines equality based
+   *     soley on the projection code.
+   *
+   * Returns:
+   * {Boolean} The two projections are equivalent.
+   */
+  equals: function(projection) {
+    if (projection && projection.getCode)
+      return this.getCode() == projection.getCode();
+    else
+      return false;
+  },
+  /* Method: destroy
+   * Destroy projection object.
+   */
+  destroy: function() {
+    this.proj = null;
+    this.projCode = null;
+  },
+  CLASS_NAME: 'ZOO.Projection'
+});
+/**
+ * Method: transform
+ * Transform a point coordinate from one projection to another.  Note that
+ *     the input point is transformed in place.
+ * 
+ * Parameters:
+ * point - {{ZOO.Geometry.Point> | Object} An object with x and y
+ *     properties representing coordinates in those dimensions.
+ * sourceProj - {ZOO.Projection} Source map coordinate system
+ * destProj - {ZOO.Projection} Destination map coordinate system
+ *
+ * Returns:
+ * point - {object} A transformed coordinate.  The original point is modified.
+ */
+ZOO.Projection.transform = function(point, source, dest) {
+    if (source.proj && dest.proj)
+        point = Proj4js.transform(source.proj, dest.proj, point);
+    return point;
+};
+
+/**
+ * Class: ZOO.Format
+ * Base class for format reading/writing a variety of formats. Subclasses
+ *     of ZOO.Format are expected to have read and write methods.
+ */
+ZOO.Format = ZOO.Class({
+  /**
+   * Property: options
+   * {Object} A reference to options passed to the constructor.
+   */
+  options:null,
+  /**
+   * Property: externalProjection
+   * {<ZOO.Projection>} When passed a externalProjection and
+   *     internalProjection, the format will reproject the geometries it
+   *     reads or writes. The externalProjection is the projection used by
+   *     the content which is passed into read or which comes out of write.
+   *     In order to reproject, a projection transformation function for the
+   *     specified projections must be available. This support is provided 
+   *     via zoo-proj4js.
+   */
+  externalProjection: null,
+  /**
+   * Property: internalProjection
+   * {<ZOO.Projection>} When passed a externalProjection and
+   *     internalProjection, the format will reproject the geometries it
+   *     reads or writes. The internalProjection is the projection used by
+   *     the geometries which are returned by read or which are passed into
+   *     write.  In order to reproject, a projection transformation function
+   *     for the specified projections must be available. This support is 
+   *     provided via zoo-proj4js.
+   */
+  internalProjection: null,
+  /**
+   * Property: data
+   * {Object} When <keepData> is true, this is the parsed string sent to
+   *     <read>.
+   */
+  data: null,
+  /**
+   * Property: keepData
+   * {Object} Maintain a reference (<data>) to the most recently read data.
+   *     Default is false.
+   */
+  keepData: false,
+  /**
+   * Constructor: ZOO.Format
+   * Instances of this class are not useful.  See one of the subclasses.
+   *
+   * Parameters:
+   * options - {Object} An optional object with properties to set on the
+   *           format
+   *
+   * Valid options:
+   * keepData - {Boolean} If true, upon <read>, the data property will be
+   *     set to the parsed object (e.g. the json or xml object).
+   *
+   * Returns:
+   * An instance of ZOO.Format
+   */
+  initialize: function(options) {
+    ZOO.extend(this, options);
+    this.options = options;
+  },
+  /**
+   * Method: destroy
+   * Clean up.
+   */
+  destroy: function() {
+  },
+  /**
+   * Method: read
+   * Read data from a string, and return an object whose type depends on the
+   * subclass. 
+   * 
+   * Parameters:
+   * data - {string} Data to read/parse.
+   *
+   * Returns:
+   * Depends on the subclass
+   */
+  read: function(data) {
+  },
+  /**
+   * Method: write
+   * Accept an object, and return a string. 
+   *
+   * Parameters:
+   * object - {Object} Object to be serialized
+   *
+   * Returns:
+   * {String} A string representation of the object.
+   */
+  write: function(data) {
+  },
+  CLASS_NAME: 'ZOO.Format'
+});
+/**
+ * Class: ZOO.Format.WKT
+ * Class for reading and writing Well-Known Text. Create a new instance
+ * with the <ZOO.Format.WKT> constructor.
+ * 
+ * Inherits from:
+ *  - <ZOO.Format>
+ */
+ZOO.Format.WKT = ZOO.Class(ZOO.Format, {
+  /**
+   * Constructor: ZOO.Format.WKT
+   * Create a new parser for WKT
+   *
+   * Parameters:
+   * options - {Object} An optional object whose properties will be set on
+   *           this instance
+   *
+   * Returns:
+   * {<ZOO.Format.WKT>} A new WKT parser.
+   */
+  initialize: function(options) {
+    this.regExes = {
+      'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
+      'spaces': /\s+/,
+      'parenComma': /\)\s*,\s*\(/,
+      'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/,  // can't use {2} here
+      'trimParens': /^\s*\(?(.*?)\)?\s*$/
+    };
+    ZOO.Format.prototype.initialize.apply(this, [options]);
+  },
+  /**
+   * Method: read
+   * Deserialize a WKT string and return a vector feature or an
+   *     array of vector features.  Supports WKT for POINT, 
+   *     MULTIPOINT, LINESTRING, MULTILINESTRING, POLYGON, 
+   *     MULTIPOLYGON, and GEOMETRYCOLLECTION.
+   *
+   * Parameters:
+   * wkt - {String} A WKT string
+   *
+   * Returns:
+   * {<ZOO.Feature.Vector>|Array} A feature or array of features for
+   *     GEOMETRYCOLLECTION WKT.
+   */
+  read: function(wkt) {
+    var features, type, str;
+    var matches = this.regExes.typeStr.exec(wkt);
+    if(matches) {
+      type = matches[1].toLowerCase();
+      str = matches[2];
+      if(this.parse[type]) {
+        features = this.parse[type].apply(this, [str]);
+      }
+      if (this.internalProjection && this.externalProjection) {
+        if (features && 
+            features.CLASS_NAME == "ZOO.Feature") {
+          features.geometry.transform(this.externalProjection,
+                                      this.internalProjection);
+        } else if (features &&
+            type != "geometrycollection" &&
+            typeof features == "object") {
+          for (var i=0, len=features.length; i<len; i++) {
+            var component = features[i];
+            component.geometry.transform(this.externalProjection,
+                                         this.internalProjection);
+          }
+        }
+      }
+    }    
+    return features;
+  },
+  /**
+   * Method: write
+   * Serialize a feature or array of features into a WKT string.
+   *
+   * Parameters:
+   * features - {<ZOO.Feature.Vector>|Array} A feature or array of
+   *            features
+   *
+   * Returns:
+   * {String} The WKT string representation of the input geometries
+   */
+  write: function(features) {
+    var collection, geometry, type, data, isCollection;
+    if(features.constructor == Array) {
+      collection = features;
+      isCollection = true;
+    } else {
+      collection = [features];
+      isCollection = false;
+    }
+    var pieces = [];
+    if(isCollection)
+      pieces.push('GEOMETRYCOLLECTION(');
+    for(var i=0, len=collection.length; i<len; ++i) {
+      if(isCollection && i>0)
+        pieces.push(',');
+      geometry = collection[i].geometry;
+      type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
+      if(!this.extract[type])
+        return null;
+      if (this.internalProjection && this.externalProjection) {
+        geometry = geometry.clone();
+        geometry.transform(this.internalProjection, 
+                          this.externalProjection);
+      }                       
+      data = this.extract[type].apply(this, [geometry]);
+      pieces.push(type.toUpperCase() + '(' + data + ')');
+    }
+    if(isCollection)
+      pieces.push(')');
+    return pieces.join('');
+  },
+  /**
+   * Property: extract
+   * Object with properties corresponding to the geometry types.
+   * Property values are functions that do the actual data extraction.
+   */
+  extract: {
+    /**
+     * Return a space delimited string of point coordinates.
+     * @param {<ZOO.Geometry.Point>} point
+     * @returns {String} A string of coordinates representing the point
+     */
+    'point': function(point) {
+      return point.x + ' ' + point.y;
+    },
+    /**
+     * Return a comma delimited string of point coordinates from a multipoint.
+     * @param {<ZOO.Geometry.MultiPoint>} multipoint
+     * @returns {String} A string of point coordinate strings representing
+     *                  the multipoint
+     */
+    'multipoint': function(multipoint) {
+      var array = [];
+      for(var i=0, len=multipoint.components.length; i<len; ++i) {
+        array.push(this.extract.point.apply(this, [multipoint.components[i]]));
+      }
+      return array.join(',');
+    },
+    /**
+     * Return a comma delimited string of point coordinates from a line.
+     * @param {<ZOO.Geometry.LineString>} linestring
+     * @returns {String} A string of point coordinate strings representing
+     *                  the linestring
+     */
+    'linestring': function(linestring) {
+      var array = [];
+      for(var i=0, len=linestring.components.length; i<len; ++i) {
+        array.push(this.extract.point.apply(this, [linestring.components[i]]));
+      }
+      return array.join(',');
+    },
+    /**
+     * Return a comma delimited string of linestring strings from a multilinestring.
+     * @param {<ZOO.Geometry.MultiLineString>} multilinestring
+     * @returns {String} A string of of linestring strings representing
+     *                  the multilinestring
+     */
+    'multilinestring': function(multilinestring) {
+      var array = [];
+      for(var i=0, len=multilinestring.components.length; i<len; ++i) {
+        array.push('(' +
+            this.extract.linestring.apply(this, [multilinestring.components[i]]) +
+            ')');
+      }
+      return array.join(',');
+    },
+    /**
+     * Return a comma delimited string of linear ring arrays from a polygon.
+     * @param {<ZOO.Geometry.Polygon>} polygon
+     * @returns {String} An array of linear ring arrays representing the polygon
+     */
+    'polygon': function(polygon) {
+      var array = [];
+      for(var i=0, len=polygon.components.length; i<len; ++i) {
+        array.push('(' +
+            this.extract.linestring.apply(this, [polygon.components[i]]) +
+            ')');
+      }
+      return array.join(',');
+    },
+    /**
+     * Return an array of polygon arrays from a multipolygon.
+     * @param {<ZOO.Geometry.MultiPolygon>} multipolygon
+     * @returns {Array} An array of polygon arrays representing
+     *                  the multipolygon
+     */
+    'multipolygon': function(multipolygon) {
+      var array = [];
+      for(var i=0, len=multipolygon.components.length; i<len; ++i) {
+        array.push('(' +
+            this.extract.polygon.apply(this, [multipolygon.components[i]]) +
+            ')');
+      }
+      return array.join(',');
+    }
+  },
+  /**
+   * Property: parse
+   * Object with properties corresponding to the geometry types.
+   *     Property values are functions that do the actual parsing.
+   */
+  parse: {
+    /**
+     * Method: parse.point
+     * Return point feature given a point WKT fragment.
+     *
+     * Parameters:
+     * str - {String} A WKT fragment representing the point
+     * Returns:
+     * {<ZOO.Feature>} A point feature
+     */
+    'point': function(str) {
+       var coords = ZOO.String.trim(str).split(this.regExes.spaces);
+            return new ZOO.Feature(
+                new ZOO.Geometry.Point(coords[0], coords[1])
+            );
+    },
+    /**
+     * Method: parse.multipoint
+     * Return a multipoint feature given a multipoint WKT fragment.
+     *
+     * Parameters:
+     * str - {String} A WKT fragment representing the multipoint
+     *
+     * Returns:
+     * {<ZOO.Feature>} A multipoint feature
+     */
+    'multipoint': function(str) {
+       var points = ZOO.String.trim(str).split(',');
+       var components = [];
+       for(var i=0, len=points.length; i<len; ++i) {
+         components.push(this.parse.point.apply(this, [points[i]]).geometry);
+       }
+       return new ZOO.Feature(
+           new ZOO.Geometry.MultiPoint(components)
+           );
+    },
+    /**
+     * Method: parse.linestring
+     * Return a linestring feature given a linestring WKT fragment.
+     *
+     * Parameters:
+     * str - {String} A WKT fragment representing the linestring
+     *
+     * Returns:
+     * {<ZOO.Feature>} A linestring feature
+     */
+    'linestring': function(str) {
+      var points = ZOO.String.trim(str).split(',');
+      var components = [];
+      for(var i=0, len=points.length; i<len; ++i) {
+        components.push(this.parse.point.apply(this, [points[i]]).geometry);
+      }
+      return new ZOO.Feature(
+          new ZOO.Geometry.LineString(components)
+          );
+    },
+    /**
+     * Method: parse.multilinestring
+     * Return a multilinestring feature given a multilinestring WKT fragment.
+     *
+     * Parameters:
+     * str - {String} A WKT fragment representing the multilinestring
+     *
+     * Returns:
+     * {<ZOO.Feature>} A multilinestring feature
+     */
+    'multilinestring': function(str) {
+      var line;
+      var lines = ZOO.String.trim(str).split(this.regExes.parenComma);
+      var components = [];
+      for(var i=0, len=lines.length; i<len; ++i) {
+        line = lines[i].replace(this.regExes.trimParens, '$1');
+        components.push(this.parse.linestring.apply(this, [line]).geometry);
+      }
+      return new ZOO.Feature(
+          new ZOO.Geometry.MultiLineString(components)
+          );
+    },
+    /**
+     * Method: parse.polygon
+     * Return a polygon feature given a polygon WKT fragment.
+     *
+     * Parameters:
+     * str - {String} A WKT fragment representing the polygon
+     *
+     * Returns:
+     * {<ZOO.Feature>} A polygon feature
+     */
+    'polygon': function(str) {
+       var ring, linestring, linearring;
+       var rings = ZOO.String.trim(str).split(this.regExes.parenComma);
+       var components = [];
+       for(var i=0, len=rings.length; i<len; ++i) {
+         ring = rings[i].replace(this.regExes.trimParens, '$1');
+         linestring = this.parse.linestring.apply(this, [ring]).geometry;
+         linearring = new ZOO.Geometry.LinearRing(linestring.components);
+         components.push(linearring);
+       }
+       return new ZOO.Feature(
+           new ZOO.Geometry.Polygon(components)
+           );
+    },
+    /**
+     * Method: parse.multipolygon
+     * Return a multipolygon feature given a multipolygon WKT fragment.
+     *
+     * Parameters:
+     * str - {String} A WKT fragment representing the multipolygon
+     *
+     * Returns:
+     * {<ZOO.Feature>} A multipolygon feature
+     */
+    'multipolygon': function(str) {
+      var polygon;
+      var polygons = ZOO.String.trim(str).split(this.regExes.doubleParenComma);
+      var components = [];
+      for(var i=0, len=polygons.length; i<len; ++i) {
+        polygon = polygons[i].replace(this.regExes.trimParens, '$1');
+        components.push(this.parse.polygon.apply(this, [polygon]).geometry);
+      }
+      return new ZOO.Feature(
+          new ZOO.Geometry.MultiPolygon(components)
+          );
+    },
+    /**
+     * Method: parse.geometrycollection
+     * Return an array of features given a geometrycollection WKT fragment.
+     *
+     * Parameters:
+     * str - {String} A WKT fragment representing the geometrycollection
+     *
+     * Returns:
+     * {Array} An array of ZOO.Feature
+     */
+    'geometrycollection': function(str) {
+      // separate components of the collection with |
+      str = str.replace(/,\s*([A-Za-z])/g, '|$1');
+      var wktArray = ZOO.String.trim(str).split('|');
+      var components = [];
+      for(var i=0, len=wktArray.length; i<len; ++i) {
+        components.push(ZOO.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
+      }
+      return components;
+    }
+  },
+  CLASS_NAME: 'ZOO.Format.WKT'
+});
+/**
+ * Class: ZOO.Format.JSON
+ * A parser to read/write JSON safely. Create a new instance with the
+ *     <ZOO.Format.JSON> constructor.
+ *
+ * Inherits from:
+ *  - <ZOO.Format>
+ */
+ZOO.Format.JSON = ZOO.Class(ZOO.Format, {
+  /**
+   * Property: indent
+   * {String} For "pretty" printing, the indent string will be used once for
+   *     each indentation level.
+   */
+  indent: "    ",
+  /**
+   * Property: space
+   * {String} For "pretty" printing, the space string will be used after
+   *     the ":" separating a name/value pair.
+   */
+  space: " ",
+  /**
+   * Property: newline
+   * {String} For "pretty" printing, the newline string will be used at the
+   *     end of each name/value pair or array item.
+   */
+  newline: "\n",
+  /**
+   * Property: level
+   * {Integer} For "pretty" printing, this is incremented/decremented during
+   *     serialization.
+   */
+  level: 0,
+  /**
+   * Property: pretty
+   * {Boolean} Serialize with extra whitespace for structure.  This is set
+   *     by the <write> method.
+   */
+  pretty: false,
+  /**
+   * Constructor: ZOO.Format.JSON
+   * Create a new parser for JSON.
+   *
+   * Parameters:
+   * options - {Object} An optional object whose properties will be set on
+   *     this instance.
+   */
+  initialize: function(options) {
+    ZOO.Format.prototype.initialize.apply(this, [options]);
+  },
+  /**
+   * Method: read
+   * Deserialize a json string.
+   *
+   * Parameters:
+   * json - {String} A JSON string
+   * filter - {Function} A function which will be called for every key and
+   *     value at every level of the final result. Each value will be
+   *     replaced by the result of the filter function. This can be used to
+   *     reform generic objects into instances of classes, or to transform
+   *     date strings into Date objects.
+   *     
+   * Returns:
+   * {Object} An object, array, string, or number .
+   */
+  read: function(json, filter) {
+    /**
+     * Parsing happens in three stages. In the first stage, we run the text
+     *     against a regular expression which looks for non-JSON
+     *     characters. We are especially concerned with '()' and 'new'
+     *     because they can cause invocation, and '=' because it can cause
+     *     mutation. But just to be safe, we will reject all unexpected
+     *     characters.
+     */
+    try {
+      if (/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g, '@').
+                          replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+                          replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+        /**
+         * In the second stage we use the eval function to compile the
+         *     text into a JavaScript structure. The '{' operator is
+         *     subject to a syntactic ambiguity in JavaScript - it can
+         *     begin a block or an object literal. We wrap the text in
+         *     parens to eliminate the ambiguity.
+         */
+        var object = eval('(' + json + ')');
+        /**
+         * In the optional third stage, we recursively walk the new
+         *     structure, passing each name/value pair to a filter
+         *     function for possible transformation.
+         */
+        if(typeof filter === 'function') {
+          function walk(k, v) {
+            if(v && typeof v === 'object') {
+              for(var i in v) {
+                if(v.hasOwnProperty(i)) {
+                  v[i] = walk(i, v[i]);
+                }
+              }
+            }
+            return filter(k, v);
+          }
+          object = walk('', object);
+        }
+        if(this.keepData) {
+          this.data = object;
+        }
+        return object;
+      }
+    } catch(e) {
+      // Fall through if the regexp test fails.
+    }
+    return null;
+  },
+  /**
+   * Method: write
+   * Serialize an object into a JSON string.
+   *
+   * Parameters:
+   * value - {String} The object, array, string, number, boolean or date
+   *     to be serialized.
+   * pretty - {Boolean} Structure the output with newlines and indentation.
+   *     Default is false.
+   *
+   * Returns:
+   * {String} The JSON string representation of the input value.
+   */
+  write: function(value, pretty) {
+    this.pretty = !!pretty;
+    var json = null;
+    var type = typeof value;
+    if(this.serialize[type]) {
+      try {
+        json = this.serialize[type].apply(this, [value]);
+      } catch(err) {
+        //OpenLayers.Console.error("Trouble serializing: " + err);
+      }
+    }
+    return json;
+  },
+  /**
+   * Method: writeIndent
+   * Output an indentation string depending on the indentation level.
+   *
+   * Returns:
+   * {String} An appropriate indentation string.
+   */
+  writeIndent: function() {
+    var pieces = [];
+    if(this.pretty) {
+      for(var i=0; i<this.level; ++i) {
+        pieces.push(this.indent);
+      }
+    }
+    return pieces.join('');
+  },
+  /**
+   * Method: writeNewline
+   * Output a string representing a newline if in pretty printing mode.
+   *
+   * Returns:
+   * {String} A string representing a new line.
+   */
+  writeNewline: function() {
+    return (this.pretty) ? this.newline : '';
+  },
+  /**
+   * Method: writeSpace
+   * Output a string representing a space if in pretty printing mode.
+   *
+   * Returns:
+   * {String} A space.
+   */
+  writeSpace: function() {
+    return (this.pretty) ? this.space : '';
+  },
+  /**
+   * Property: serialize
+   * Object with properties corresponding to the serializable data types.
+   *     Property values are functions that do the actual serializing.
+   */
+  serialize: {
+    /**
+     * Method: serialize.object
+     * Transform an object into a JSON string.
+     *
+     * Parameters:
+     * object - {Object} The object to be serialized.
+     * 
+     * Returns:
+     * {String} A JSON string representing the object.
+     */
+    'object': function(object) {
+       // three special objects that we want to treat differently
+       if(object == null)
+         return "null";
+       if(object.constructor == Date)
+         return this.serialize.date.apply(this, [object]);
+       if(object.constructor == Array)
+         return this.serialize.array.apply(this, [object]);
+       var pieces = ['{'];
+       this.level += 1;
+       var key, keyJSON, valueJSON;
+
+       var addComma = false;
+       for(key in object) {
+         if(object.hasOwnProperty(key)) {
+           // recursive calls need to allow for sub-classing
+           keyJSON = ZOO.Format.JSON.prototype.write.apply(this,
+                                                           [key, this.pretty]);
+           valueJSON = ZOO.Format.JSON.prototype.write.apply(this,
+                                                             [object[key], this.pretty]);
+           if(keyJSON != null && valueJSON != null) {
+             if(addComma)
+               pieces.push(',');
+             pieces.push(this.writeNewline(), this.writeIndent(),
+                         keyJSON, ':', this.writeSpace(), valueJSON);
+             addComma = true;
+           }
+         }
+       }
+       this.level -= 1;
+       pieces.push(this.writeNewline(), this.writeIndent(), '}');
+       return pieces.join('');
+    },
+    /**
+     * Method: serialize.array
+     * Transform an array into a JSON string.
+     *
+     * Parameters:
+     * array - {Array} The array to be serialized
+     * 
+     * Returns:
+     * {String} A JSON string representing the array.
+     */
+    'array': function(array) {
+      var json;
+      var pieces = ['['];
+      this.level += 1;
+      for(var i=0, len=array.length; i<len; ++i) {
+        // recursive calls need to allow for sub-classing
+        json = ZOO.Format.JSON.prototype.write.apply(this,
+                                                     [array[i], this.pretty]);
+        if(json != null) {
+          if(i > 0)
+            pieces.push(',');
+          pieces.push(this.writeNewline(), this.writeIndent(), json);
+        }
+      }
+      this.level -= 1;    
+      pieces.push(this.writeNewline(), this.writeIndent(), ']');
+      return pieces.join('');
+    },
+    /**
+     * Method: serialize.string
+     * Transform a string into a JSON string.
+     *
+     * Parameters:
+     * string - {String} The string to be serialized
+     * 
+     * Returns:
+     * {String} A JSON string representing the string.
+     */
+    'string': function(string) {
+      var m = {
+                '\b': '\\b',
+                '\t': '\\t',
+                '\n': '\\n',
+                '\f': '\\f',
+                '\r': '\\r',
+                '"' : '\\"',
+                '\\': '\\\\'
+      };
+      if(/["\\\x00-\x1f]/.test(string)) {
+        return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) {
+            var c = m[b];
+            if(c)
+              return c;
+            c = b.charCodeAt();
+            return '\\u00' +
+            Math.floor(c / 16).toString(16) +
+            (c % 16).toString(16);
+        }) + '"';
+      }
+      return '"' + string + '"';
+    },
+    /**
+     * Method: serialize.number
+     * Transform a number into a JSON string.
+     *
+     * Parameters:
+     * number - {Number} The number to be serialized.
+     *
+     * Returns:
+     * {String} A JSON string representing the number.
+     */
+    'number': function(number) {
+      return isFinite(number) ? String(number) : "null";
+    },
+    /**
+     * Method: serialize.boolean
+     * Transform a boolean into a JSON string.
+     *
+     * Parameters:
+     * bool - {Boolean} The boolean to be serialized.
+     * 
+     * Returns:
+     * {String} A JSON string representing the boolean.
+     */
+    'boolean': function(bool) {
+      return String(bool);
+    },
+    /**
+     * Method: serialize.date
+     * Transform a date into a JSON string.
+     *
+     * Parameters:
+     * date - {Date} The date to be serialized.
+     * 
+     * Returns:
+     * {String} A JSON string representing the date.
+     */
+    'date': function(date) {    
+      function format(number) {
+        // Format integers to have at least two digits.
+        return (number < 10) ? '0' + number : number;
+      }
+      return '"' + date.getFullYear() + '-' +
+        format(date.getMonth() + 1) + '-' +
+        format(date.getDate()) + 'T' +
+        format(date.getHours()) + ':' +
+        format(date.getMinutes()) + ':' +
+        format(date.getSeconds()) + '"';
+    }
+  },
+  CLASS_NAME: 'ZOO.Format.JSON'
+});
+/**
+ * Class: ZOO.Format.GeoJSON
+ * Read and write GeoJSON. Create a new parser with the
+ *     <ZOO.Format.GeoJSON> constructor.
+ *
+ * Inherits from:
+ *  - <ZOO.Format.JSON>
+ */
+ZOO.Format.GeoJSON = ZOO.Class(ZOO.Format.JSON, {
+  /**
+   * Constructor: ZOO.Format.GeoJSON
+   * Create a new parser for GeoJSON.
+   *
+   * Parameters:
+   * options - {Object} An optional object whose properties will be set on
+   *     this instance.
+   */
+  initialize: function(options) {
+    ZOO.Format.JSON.prototype.initialize.apply(this, [options]);
+  },
+  /**
+   * Method: read
+   * Deserialize a GeoJSON string.
+   *
+   * Parameters:
+   * json - {String} A GeoJSON string
+   * type - {String} Optional string that determines the structure of
+   *     the output.  Supported values are "Geometry", "Feature", and
+   *     "FeatureCollection".  If absent or null, a default of
+   *     "FeatureCollection" is assumed.
+   * filter - {Function} A function which will be called for every key and
+   *     value at every level of the final result. Each value will be
+   *     replaced by the result of the filter function. This can be used to
+   *     reform generic objects into instances of classes, or to transform
+   *     date strings into Date objects.
+   *
+   * Returns: 
+   * {Object} The return depends on the value of the type argument. If type
+   *     is "FeatureCollection" (the default), the return will be an array
+   *     of <ZOO.Feature>. If type is "Geometry", the input json
+   *     must represent a single geometry, and the return will be an
+   *     <ZOO.Geometry>.  If type is "Feature", the input json must
+   *     represent a single feature, and the return will be an
+   *     <ZOO.Feature>.
+   */
+  read: function(json, type, filter) {
+    type = (type) ? type : "FeatureCollection";
+    var results = null;
+    var obj = null;
+    if (typeof json == "string")
+      obj = ZOO.Format.JSON.prototype.read.apply(this,[json, filter]);
+    else
+      obj = json;
+    if(!obj) {
+      //ZOO.Console.error("Bad JSON: " + json);
+    } else if(typeof(obj.type) != "string") {
+      //ZOO.Console.error("Bad GeoJSON - no type: " + json);
+    } else if(this.isValidType(obj, type)) {
+      switch(type) {
+        case "Geometry":
+          try {
+            results = this.parseGeometry(obj);
+          } catch(err) {
+            //ZOO.Console.error(err);
+          }
+          break;
+        case "Feature":
+          try {
+            results = this.parseFeature(obj);
+            results.type = "Feature";
+          } catch(err) {
+            //ZOO.Console.error(err);
+          }
+          break;
+        case "FeatureCollection":
+          // for type FeatureCollection, we allow input to be any type
+          results = [];
+          switch(obj.type) {
+            case "Feature":
+              try {
+                results.push(this.parseFeature(obj));
+              } catch(err) {
+                results = null;
+                //ZOO.Console.error(err);
+              }
+              break;
+            case "FeatureCollection":
+              for(var i=0, len=obj.features.length; i<len; ++i) {
+                try {
+                  results.push(this.parseFeature(obj.features[i]));
+                } catch(err) {
+                  results = null;
+                  //ZOO.Console.error(err);
+                }
+              }
+              break;
+            default:
+              try {
+                var geom = this.parseGeometry(obj);
+                results.push(new ZOO.Feature(geom));
+              } catch(err) {
+                results = null;
+                //ZOO.Console.error(err);
+              }
+          }
+          break;
+      }
+    }
+    return results;
+  },
+  /**
+   * Method: isValidType
+   * Check if a GeoJSON object is a valid representative of the given type.
+   *
+   * Returns:
+   * {Boolean} The object is valid GeoJSON object of the given type.
+   */
+  isValidType: function(obj, type) {
+    var valid = false;
+    switch(type) {
+      case "Geometry":
+        if(ZOO.indexOf(
+              ["Point", "MultiPoint", "LineString", "MultiLineString",
+              "Polygon", "MultiPolygon", "Box", "GeometryCollection"],
+              obj.type) == -1) {
+          // unsupported geometry type
+          //ZOO.Console.error("Unsupported geometry type: " +obj.type);
+        } else {
+          valid = true;
+        }
+        break;
+      case "FeatureCollection":
+        // allow for any type to be converted to a feature collection
+        valid = true;
+        break;
+      default:
+        // for Feature types must match
+        if(obj.type == type) {
+          valid = true;
+        } else {
+          //ZOO.Console.error("Cannot convert types from " +obj.type + " to " + type);
+        }
+    }
+    return valid;
+  },
+  /**
+   * Method: parseFeature
+   * Convert a feature object from GeoJSON into an
+   *     <ZOO.Feature>.
+   *
+   * Parameters:
+   * obj - {Object} An object created from a GeoJSON object
+   *
+   * Returns:
+   * {<ZOO.Feature>} A feature.
+   */
+  parseFeature: function(obj) {
+    var feature, geometry, attributes, bbox;
+    attributes = (obj.properties) ? obj.properties : {};
+    bbox = (obj.geometry && obj.geometry.bbox) || obj.bbox;
+    try {
+      geometry = this.parseGeometry(obj.geometry);
+    } catch(err) {
+      // deal with bad geometries
+      throw err;
+    }
+    feature = new ZOO.Feature(geometry, attributes);
+    if(bbox)
+      feature.bounds = ZOO.Bounds.fromArray(bbox);
+    if(obj.id)
+      feature.fid = obj.id;
+    return feature;
+  },
+  /**
+   * Method: parseGeometry
+   * Convert a geometry object from GeoJSON into an <ZOO.Geometry>.
+   *
+   * Parameters:
+   * obj - {Object} An object created from a GeoJSON object
+   *
+   * Returns: 
+   * {<ZOO.Geometry>} A geometry.
+   */
+  parseGeometry: function(obj) {
+    if (obj == null)
+      return null;
+    var geometry, collection = false;
+    if(obj.type == "GeometryCollection") {
+      if(!(obj.geometries instanceof Array)) {
+        throw "GeometryCollection must have geometries array: " + obj;
+      }
+      var numGeom = obj.geometries.length;
+      var components = new Array(numGeom);
+      for(var i=0; i<numGeom; ++i) {
+        components[i] = this.parseGeometry.apply(
+            this, [obj.geometries[i]]
+            );
+      }
+      geometry = new ZOO.Geometry.Collection(components);
+      collection = true;
+    } else {
+      if(!(obj.coordinates instanceof Array)) {
+        throw "Geometry must have coordinates array: " + obj;
+      }
+      if(!this.parseCoords[obj.type.toLowerCase()]) {
+        throw "Unsupported geometry type: " + obj.type;
+      }
+      try {
+        geometry = this.parseCoords[obj.type.toLowerCase()].apply(
+            this, [obj.coordinates]
+            );
+      } catch(err) {
+        // deal with bad coordinates
+        throw err;
+      }
+    }
+        // We don't reproject collections because the children are reprojected
+        // for us when they are created.
+    if (this.internalProjection && this.externalProjection && !collection) {
+      geometry.transform(this.externalProjection, 
+          this.internalProjection); 
+    }                       
+    return geometry;
+  },
+  /**
+   * Property: parseCoords
+   * Object with properties corresponding to the GeoJSON geometry types.
+   *     Property values are functions that do the actual parsing.
+   */
+  parseCoords: {
+    /**
+     * Method: parseCoords.point
+     * Convert a coordinate array from GeoJSON into an
+     *     <ZOO.Geometry.Point>.
+     *
+     * Parameters:
+     * array - {Object} The coordinates array from the GeoJSON fragment.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Point>} A geometry.
+     */
+    "point": function(array) {
+      if(array.length != 2) {
+        throw "Only 2D points are supported: " + array;
+      }
+      return new ZOO.Geometry.Point(array[0], array[1]);
+    },
+    /**
+     * Method: parseCoords.multipoint
+     * Convert a coordinate array from GeoJSON into an
+     *     <ZOO.Geometry.MultiPoint>.
+     *
+     * Parameters:
+     * array - {Object} The coordinates array from the GeoJSON fragment.
+     *
+     * Returns:
+     * {<ZOO.Geometry.MultiPoint>} A geometry.
+     */
+    "multipoint": function(array) {
+      var points = [];
+      var p = null;
+      for(var i=0, len=array.length; i<len; ++i) {
+        try {
+          p = this.parseCoords["point"].apply(this, [array[i]]);
+        } catch(err) {
+          throw err;
+        }
+        points.push(p);
+      }
+      return new ZOO.Geometry.MultiPoint(points);
+    },
+    /**
+     * Method: parseCoords.linestring
+     * Convert a coordinate array from GeoJSON into an
+     *     <ZOO.Geometry.LineString>.
+     *
+     * Parameters:
+     * array - {Object} The coordinates array from the GeoJSON fragment.
+     *
+     * Returns:
+     * {<ZOO.Geometry.LineString>} A geometry.
+     */
+    "linestring": function(array) {
+      var points = [];
+      var p = null;
+      for(var i=0, len=array.length; i<len; ++i) {
+        try {
+          p = this.parseCoords["point"].apply(this, [array[i]]);
+        } catch(err) {
+          throw err;
+        }
+        points.push(p);
+      }
+      return new ZOO.Geometry.LineString(points);
+    },
+    /**
+     * Method: parseCoords.multilinestring
+     * Convert a coordinate array from GeoJSON into an
+     *     <ZOO.Geometry.MultiLineString>.
+     *
+     * Parameters:
+     * array - {Object} The coordinates array from the GeoJSON fragment.
+     *
+     * Returns:
+     * {<ZOO.Geometry.MultiLineString>} A geometry.
+     */
+    "multilinestring": function(array) {
+      var lines = [];
+      var l = null;
+      for(var i=0, len=array.length; i<len; ++i) {
+        try {
+          l = this.parseCoords["linestring"].apply(this, [array[i]]);
+        } catch(err) {
+          throw err;
+        }
+        lines.push(l);
+      }
+      return new ZOO.Geometry.MultiLineString(lines);
+    },
+    /**
+     * Method: parseCoords.polygon
+     * Convert a coordinate array from GeoJSON into an
+     *     <ZOO.Geometry.Polygon>.
+     *
+     * Parameters:
+     * array - {Object} The coordinates array from the GeoJSON fragment.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Polygon>} A geometry.
+     */
+    "polygon": function(array) {
+      var rings = [];
+      var r, l;
+      for(var i=0, len=array.length; i<len; ++i) {
+        try {
+          l = this.parseCoords["linestring"].apply(this, [array[i]]);
+        } catch(err) {
+          throw err;
+        }
+        r = new ZOO.Geometry.LinearRing(l.components);
+        rings.push(r);
+      }
+      return new ZOO.Geometry.Polygon(rings);
+    },
+    /**
+     * Method: parseCoords.multipolygon
+     * Convert a coordinate array from GeoJSON into an
+     *     <ZOO.Geometry.MultiPolygon>.
+     *
+     * Parameters:
+     * array - {Object} The coordinates array from the GeoJSON fragment.
+     *
+     * Returns:
+     * {<ZOO.Geometry.MultiPolygon>} A geometry.
+     */
+    "multipolygon": function(array) {
+      var polys = [];
+      var p = null;
+      for(var i=0, len=array.length; i<len; ++i) {
+        try {
+          p = this.parseCoords["polygon"].apply(this, [array[i]]);
+        } catch(err) {
+          throw err;
+        }
+        polys.push(p);
+      }
+      return new ZOO.Geometry.MultiPolygon(polys);
+    },
+    /**
+     * Method: parseCoords.box
+     * Convert a coordinate array from GeoJSON into an
+     *     <ZOO.Geometry.Polygon>.
+     *
+     * Parameters:
+     * array - {Object} The coordinates array from the GeoJSON fragment.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Polygon>} A geometry.
+     */
+    "box": function(array) {
+      if(array.length != 2) {
+        throw "GeoJSON box coordinates must have 2 elements";
+      }
+      return new ZOO.Geometry.Polygon([
+          new ZOO.Geometry.LinearRing([
+            new ZOO.Geometry.Point(array[0][0], array[0][1]),
+            new ZOO.Geometry.Point(array[1][0], array[0][1]),
+            new ZOO.Geometry.Point(array[1][0], array[1][1]),
+            new ZOO.Geometry.Point(array[0][0], array[1][1]),
+            new Z0O.Geometry.Point(array[0][0], array[0][1])
+          ])
+      ]);
+    }
+  },
+  /**
+   * Method: write
+   * Serialize a feature, geometry, array of features into a GeoJSON string.
+   *
+   * Parameters:
+   * obj - {Object} An <ZOO.Feature>, <ZOO.Geometry>,
+   *     or an array of features.
+   * pretty - {Boolean} Structure the output with newlines and indentation.
+   *     Default is false.
+   *
+   * Returns:
+   * {String} The GeoJSON string representation of the input geometry,
+   *     features, or array of features.
+   */
+  write: function(obj, pretty) {
+    var geojson = {
+      "type": null
+    };
+    if(obj instanceof Array) {
+      geojson.type = "FeatureCollection";
+      var numFeatures = obj.length;
+      geojson.features = new Array(numFeatures);
+      for(var i=0; i<numFeatures; ++i) {
+        var element = obj[i];
+        if(!element instanceof ZOO.Feature) {
+          var msg = "FeatureCollection only supports collections " +
+            "of features: " + element;
+          throw msg;
+        }
+        geojson.features[i] = this.extract.feature.apply(this, [element]);
+      }
+    } else if (obj.CLASS_NAME.indexOf("ZOO.Geometry") == 0) {
+      geojson = this.extract.geometry.apply(this, [obj]);
+    } else if (obj instanceof ZOO.Feature) {
+      geojson = this.extract.feature.apply(this, [obj]);
+      /*
+      if(obj.layer && obj.layer.projection) {
+        geojson.crs = this.createCRSObject(obj);
+      }
+      */
+    }
+    return ZOO.Format.JSON.prototype.write.apply(this,
+                                                 [geojson, pretty]);
+  },
+  /**
+   * Method: createCRSObject
+   * Create the CRS object for an object.
+   *
+   * Parameters:
+   * object - {<ZOO.Feature>} 
+   *
+   * Returns:
+   * {Object} An object which can be assigned to the crs property
+   * of a GeoJSON object.
+   */
+  createCRSObject: function(object) {
+    //var proj = object.layer.projection.toString();
+    var proj = object.projection.toString();
+    var crs = {};
+    if (proj.match(/epsg:/i)) {
+      var code = parseInt(proj.substring(proj.indexOf(":") + 1));
+      if (code == 4326) {
+        crs = {
+          "type": "OGC",
+          "properties": {
+            "urn": "urn:ogc:def:crs:OGC:1.3:CRS84"
+          }
+        };
+      } else {    
+        crs = {
+          "type": "EPSG",
+          "properties": {
+            "code": code 
+          }
+        };
+      }    
+    }
+    return crs;
+  },
+  /**
+   * Property: extract
+   * Object with properties corresponding to the GeoJSON types.
+   *     Property values are functions that do the actual value extraction.
+   */
+  extract: {
+    /**
+     * Method: extract.feature
+     * Return a partial GeoJSON object representing a single feature.
+     *
+     * Parameters:
+     * feature - {<ZOO.Feature>}
+     *
+     * Returns:
+     * {Object} An object representing the point.
+     */
+    'feature': function(feature) {
+      var geom = this.extract.geometry.apply(this, [feature.geometry]);
+      return {
+        "type": "Feature",
+        "id": feature.fid == null ? feature.id : feature.fid,
+        "properties": feature.attributes,
+        "geometry": geom
+      };
+    },
+    /**
+     * Method: extract.geometry
+     * Return a GeoJSON object representing a single geometry.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry>}
+     *
+     * Returns:
+     * {Object} An object representing the geometry.
+     */
+    'geometry': function(geometry) {
+      if (geometry == null)
+        return null;
+      if (this.internalProjection && this.externalProjection) {
+        geometry = geometry.clone();
+        geometry.transform(this.internalProjection, 
+            this.externalProjection);
+      }                       
+      var geometryType = geometry.CLASS_NAME.split('.')[2];
+      var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]);
+      var json;
+      if(geometryType == "Collection")
+        json = {
+          "type": "GeometryCollection",
+          "geometries": data
+        };
+      else
+        json = {
+          "type": geometryType,
+          "coordinates": data
+        };
+      return json;
+    },
+    /**
+     * Method: extract.point
+     * Return an array of coordinates from a point.
+     *
+     * Parameters:
+     * point - {<ZOO.Geometry.Point>}
+     *
+     * Returns: 
+     * {Array} An array of coordinates representing the point.
+     */
+    'point': function(point) {
+      return [point.x, point.y];
+    },
+    /**
+     * Method: extract.multipoint
+     * Return an array of coordinates from a multipoint.
+     *
+     * Parameters:
+     * multipoint - {<ZOO.Geometry.MultiPoint>}
+     *
+     * Returns: 
+     * {Array} An array of point coordinate arrays representing
+     *     the multipoint.
+     */
+    'multipoint': function(multipoint) {
+      var array = [];
+      for(var i=0, len=multipoint.components.length; i<len; ++i) {
+        array.push(this.extract.point.apply(this, [multipoint.components[i]]));
+      }
+      return array;
+    },
+    /**
+     * Method: extract.linestring
+     * Return an array of coordinate arrays from a linestring.
+     *
+     * Parameters:
+     * linestring - {<ZOO.Geometry.LineString>}
+     *
+     * Returns:
+     * {Array} An array of coordinate arrays representing
+     *     the linestring.
+     */
+    'linestring': function(linestring) {
+      var array = [];
+      for(var i=0, len=linestring.components.length; i<len; ++i) {
+        array.push(this.extract.point.apply(this, [linestring.components[i]]));
+      }
+      return array;
+    },
+    /**
+     * Method: extract.multilinestring
+     * Return an array of linestring arrays from a linestring.
+     * 
+     * Parameters:
+     * multilinestring - {<ZOO.Geometry.MultiLineString>}
+     * 
+     * Returns:
+     * {Array} An array of linestring arrays representing
+     *     the multilinestring.
+     */
+    'multilinestring': function(multilinestring) {
+      var array = [];
+      for(var i=0, len=multilinestring.components.length; i<len; ++i) {
+        array.push(this.extract.linestring.apply(this, [multilinestring.components[i]]));
+      }
+      return array;
+    },
+    /**
+     * Method: extract.polygon
+     * Return an array of linear ring arrays from a polygon.
+     *
+     * Parameters:
+     * polygon - {<ZOO.Geometry.Polygon>}
+     * 
+     * Returns:
+     * {Array} An array of linear ring arrays representing the polygon.
+     */
+    'polygon': function(polygon) {
+      var array = [];
+      for(var i=0, len=polygon.components.length; i<len; ++i) {
+        array.push(this.extract.linestring.apply(this, [polygon.components[i]]));
+      }
+      return array;
+    },
+    /**
+     * Method: extract.multipolygon
+     * Return an array of polygon arrays from a multipolygon.
+     * 
+     * Parameters:
+     * multipolygon - {<ZOO.Geometry.MultiPolygon>}
+     * 
+     * Returns:
+     * {Array} An array of polygon arrays representing
+     *     the multipolygon
+     */
+    'multipolygon': function(multipolygon) {
+      var array = [];
+      for(var i=0, len=multipolygon.components.length; i<len; ++i) {
+        array.push(this.extract.polygon.apply(this, [multipolygon.components[i]]));
+      }
+      return array;
+    },
+    /**
+     * Method: extract.collection
+     * Return an array of geometries from a geometry collection.
+     * 
+     * Parameters:
+     * collection - {<ZOO.Geometry.Collection>}
+     * 
+     * Returns:
+     * {Array} An array of geometry objects representing the geometry
+     *     collection.
+     */
+    'collection': function(collection) {
+      var len = collection.components.length;
+      var array = new Array(len);
+      for(var i=0; i<len; ++i) {
+        array[i] = this.extract.geometry.apply(
+            this, [collection.components[i]]
+            );
+      }
+      return array;
+    }
+  },
+  CLASS_NAME: 'ZOO.Format.GeoJSON'
+});
+/**
+ * Class: ZOO.Format.KML
+ * Read/Write KML. Create a new instance with the <ZOO.Format.KML>
+ *     constructor. 
+ * 
+ * Inherits from:
+ *  - <ZOO.Format>
+ */
+ZOO.Format.KML = ZOO.Class(ZOO.Format, {
+  /**
+   * Property: kmlns
+   * {String} KML Namespace to use. Defaults to 2.2 namespace.
+   */
+  kmlns: "http://www.opengis.net/kml/2.2",
+  /** 
+   * Property: foldersName
+   * {String} Name of the folders.  Default is "ZOO export".
+   *          If set to null, no name element will be created.
+   */
+  foldersName: "ZOO export",
+  /** 
+   * Property: foldersDesc
+   * {String} Description of the folders. Default is "Exported on [date]."
+   *          If set to null, no description element will be created.
+   */
+  foldersDesc: "Created on " + new Date(),
+  /** 
+   * Property: placemarksDesc
+   * {String} Name of the placemarks.  Default is "No description available".
+   */
+  placemarksDesc: "No description available",
+  /**
+   * Property: extractAttributes
+   * {Boolean} Extract attributes from KML.  Default is true.
+   *           Extracting styleUrls requires this to be set to true
+   */
+  extractAttributes: true,
+  /**
+   * Constructor: ZOO.Format.KML
+   * Create a new parser for KML.
+   *
+   * Parameters:
+   * options - {Object} An optional object whose properties will be set on
+   *     this instance.
+   */
+  initialize: function(options) {
+    // compile regular expressions once instead of every time they are used
+    this.regExes = {
+           trimSpace: (/^\s*|\s*$/g),
+           removeSpace: (/\s*/g),
+           splitSpace: (/\s+/),
+           trimComma: (/\s*,\s*/g),
+           kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/),
+           kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/),
+           straightBracket: (/\$\[(.*?)\]/g)
+    };
+    // KML coordinates are always in longlat WGS84
+    this.externalProjection = new ZOO.Projection("EPSG:4326");
+    ZOO.Format.prototype.initialize.apply(this, [options]);
+  },
+  /**
+   * APIMethod: read
+   * Read data from a string, and return a list of features. 
+   * 
+   * Parameters: 
+   * data    - {String} data to read/parse.
+   *
+   * Returns:
+   * {Array(<ZOO.Feature>)} List of features.
+   */
+  read: function(data) {
+    this.features = [];
+    data = data.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, "");
+    data = new XML(data);
+    var placemarks = data..*::Placemark;
+    this.parseFeatures(placemarks);
+    return this.features;
+  },
+  /**
+   * Method: parseFeatures
+   * Loop through all Placemark nodes and parse them.
+   * Will create a list of features
+   * 
+   * Parameters: 
+   * nodes    - {Array} of {E4XElement} data to read/parse.
+   * options  - {Object} Hash of options
+   * 
+   */
+  parseFeatures: function(nodes) {
+    var features = new Array(nodes.length());
+    for(var i=0, len=nodes.length(); i<len; i++) {
+      var featureNode = nodes[i];
+      var feature = this.parseFeature.apply(this,[featureNode]) ;
+      features[i] = feature;
+    }
+    this.features = this.features.concat(features);
+  },
+  /**
+   * Method: parseFeature
+   * This function is the core of the KML parsing code in ZOO.
+   *     It creates the geometries that are then attached to the returned
+   *     feature, and calls parseAttributes() to get attribute data out.
+   *
+   * Parameters:
+   * node - {E4XElement}
+   *
+   * Returns:
+   * {<ZOO.Feature>} A vector feature.
+   */
+  parseFeature: function(node) {
+    // only accept one geometry per feature - look for highest "order"
+    var order = ["MultiGeometry", "Polygon", "LineString", "Point"];
+    var type, nodeList, geometry, parser;
+    for(var i=0, len=order.length; i<len; ++i) {
+      type = order[i];
+      nodeList = node.descendants(QName(null,type));
+      if (nodeList.length()> 0) {
+        var parser = this.parseGeometry[type.toLowerCase()];
+        if(parser) {
+          geometry = parser.apply(this, [nodeList[0]]);
+          if (this.internalProjection && this.externalProjection) {
+            geometry.transform(this.externalProjection, 
+                               this.internalProjection); 
+          }                       
+        }
+        // stop looking for different geometry types
+        break;
+      }
+    }
+    // construct feature (optionally with attributes)
+    var attributes;
+    if(this.extractAttributes) {
+      attributes = this.parseAttributes(node);
+    }
+    var feature = new ZOO.Feature(geometry, attributes);
+    var fid = node.@id || node.@name;
+    if(fid != null)
+      feature.fid = fid;
+    return feature;
+  },
+  /**
+   * Property: parseGeometry
+   * Properties of this object are the functions that parse geometries based
+   *     on their type.
+   */
+  parseGeometry: {
+    /**
+     * Method: parseGeometry.point
+     * Given a KML node representing a point geometry, create a ZOO
+     *     point geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A KML Point node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Point>} A point geometry.
+     */
+    'point': function(node) {
+      var coordString = node.*::coordinates.toString();
+      coordString = coordString.replace(this.regExes.removeSpace, "");
+      coords = coordString.split(",");
+      var point = null;
+      if(coords.length > 1) {
+        // preserve third dimension
+        if(coords.length == 2) {
+          coords[2] = null;
+        }
+        point = new ZOO.Geometry.Point(coords[0], coords[1], coords[2]);
+      }
+      return point;
+    },
+    /**
+     * Method: parseGeometry.linestring
+     * Given a KML node representing a linestring geometry, create a
+     *     ZOO linestring geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A KML LineString node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.LineString>} A linestring geometry.
+     */
+    'linestring': function(node, ring) {
+      var line = null;
+      var coordString = node.*::coordinates.toString();
+      coordString = coordString.replace(this.regExes.trimSpace,
+          "");
+      coordString = coordString.replace(this.regExes.trimComma,
+          ",");
+      var pointList = coordString.split(this.regExes.splitSpace);
+      var numPoints = pointList.length;
+      var points = new Array(numPoints);
+      var coords, numCoords;
+      for(var i=0; i<numPoints; ++i) {
+        coords = pointList[i].split(",");
+        numCoords = coords.length;
+        if(numCoords > 1) {
+          if(coords.length == 2) {
+            coords[2] = null;
+          }
+          points[i] = new ZOO.Geometry.Point(coords[0],
+                                             coords[1],
+                                             coords[2]);
+        }
+      }
+      if(numPoints) {
+        if(ring) {
+          line = new ZOO.Geometry.LinearRing(points);
+        } else {
+          line = new ZOO.Geometry.LineString(points);
+        }
+      } else {
+        throw "Bad LineString coordinates: " + coordString;
+      }
+      return line;
+    },
+    /**
+     * Method: parseGeometry.polygon
+     * Given a KML node representing a polygon geometry, create a
+     *     ZOO polygon geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A KML Polygon node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Polygon>} A polygon geometry.
+     */
+    'polygon': function(node) {
+      var nodeList = node..*::LinearRing;
+      var numRings = nodeList.length();
+      var components = new Array(numRings);
+      if(numRings > 0) {
+        // this assumes exterior ring first, inner rings after
+        var ring;
+        for(var i=0, len=nodeList.length(); i<len; ++i) {
+          ring = this.parseGeometry.linestring.apply(this,
+                                                     [nodeList[i], true]);
+          if(ring) {
+            components[i] = ring;
+          } else {
+            throw "Bad LinearRing geometry: " + i;
+          }
+        }
+      }
+      return new ZOO.Geometry.Polygon(components);
+    },
+    /**
+     * Method: parseGeometry.multigeometry
+     * Given a KML node representing a multigeometry, create a
+     *     ZOO geometry collection.
+     *
+     * Parameters:
+     * node - {E4XElement} A KML MultiGeometry node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Collection>} A geometry collection.
+     */
+    'multigeometry': function(node) {
+      var child, parser;
+      var parts = [];
+      var children = node.*::*;
+      for(var i=0, len=children.length(); i<len; ++i ) {
+        child = children[i];
+        var type = child.localName();
+        var parser = this.parseGeometry[type.toLowerCase()];
+        if(parser) {
+          parts.push(parser.apply(this, [child]));
+        }
+      }
+      return new ZOO.Geometry.Collection(parts);
+    }
+  },
+  /**
+   * Method: parseAttributes
+   *
+   * Parameters:
+   * node - {E4XElement}
+   *
+   * Returns:
+   * {Object} An attributes object.
+   */
+  parseAttributes: function(node) {
+    var attributes = {};
+    var edNodes = node.*::ExtendedData;
+    if (edNodes.length() > 0) {
+      attributes = this.parseExtendedData(edNodes[0])
+    }
+    var child, grandchildren;
+    var children = node.*::*;
+    for(var i=0, len=children.length(); i<len; ++i) {
+      child = children[i];
+      grandchildren = child..*::*;
+      if(grandchildren.length() == 1) {
+        var name = child.localName();
+        var value = child.toString();
+        if (value) {
+          value = value.replace(this.regExes.trimSpace, "");
+          attributes[name] = value;
+        }
+      }
+    }
+    return attributes;
+  },
+  /**
+   * Method: parseExtendedData
+   * Parse ExtendedData from KML. Limited support for schemas/datatypes.
+   *     See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata
+   *     for more information on extendeddata.
+   *
+   * Parameters:
+   * node - {E4XElement}
+   *
+   * Returns:
+   * {Object} An attributes object.
+   */
+  parseExtendedData: function(node) {
+    var attributes = {};
+    var dataNodes = node.*::Data;
+    for (var i = 0, len = dataNodes.length(); i < len; i++) {
+      var data = dataNodes[i];
+      var key = data.@name;
+      var ed = {};
+      var valueNode = data.*::value;
+      if (valueNode.length() > 0)
+        ed['value'] = valueNode[0].toString();
+      var nameNode = data.*::displayName;
+      if (nameNode.length() > 0)
+        ed['displayName'] = valueNode[0].toString();
+      attributes[key] = ed;
+    }
+    return attributes;
+  },
+  /**
+   * Method: write
+   * Accept Feature Collection, and return a string. 
+   * 
+   * Parameters:
+   * features - {Array(<ZOO.Feature>} An array of features.
+   *
+   * Returns:
+   * {String} A KML string.
+   */
+  write: function(features) {
+    if(!(features instanceof Array))
+      features = [features];
+    var kml = new XML('<kml xmlns="'+this.kmlns+'"></kml>');
+    var folder = kml.Document.Folder;
+    folder.name = this.foldersName;
+    folder.description = this.foldersDesc;
+    for(var i=0, len=features.length; i<len; ++i) {
+      folder.Placemark[i] = this.createPlacemark(features[i]);
+    }
+    return kml.toXMLString();
+  },
+  /**
+   * Method: createPlacemark
+   * Creates and returns a KML placemark node representing the given feature. 
+   * 
+   * Parameters:
+   * feature - {<ZOO.Feature>}
+   * 
+   * Returns:
+   * {E4XElement}
+   */
+  createPlacemark: function(feature) {
+    var placemark = new XML('<Placemark xmlns="'+this.kmlns+'"></Placemark>');
+    placemark.name = (feature.attributes.name) ?
+                    feature.attributes.name : feature.id;
+    placemark.description = (feature.attributes.description) ?
+                             feature.attributes.description : this.placemarksDesc;
+    if(feature.fid != null)
+      placemark.@id = feature.fid;
+    placemark.*[2] = this.buildGeometryNode(feature.geometry);
+    return placemark;
+  },
+  /**
+   * Method: buildGeometryNode
+   * Builds and returns a KML geometry node with the given geometry.
+   * 
+   * Parameters:
+   * geometry - {<ZOO.Geometry>}
+   * 
+   * Returns:
+   * {E4XElement}
+   */
+  buildGeometryNode: function(geometry) {
+    if (this.internalProjection && this.externalProjection) {
+      geometry = geometry.clone();
+      geometry.transform(this.internalProjection, 
+                         this.externalProjection);
+    }
+    var className = geometry.CLASS_NAME;
+    var type = className.substring(className.lastIndexOf(".") + 1);
+    var builder = this.buildGeometry[type.toLowerCase()];
+    var node = null;
+    if(builder) {
+      node = builder.apply(this, [geometry]);
+    }
+    return node;
+  },
+  /**
+   * Property: buildGeometry
+   * Object containing methods to do the actual geometry node building
+   *     based on geometry type.
+   */
+  buildGeometry: {
+    /**
+     * Method: buildGeometry.point
+     * Given a ZOO point geometry, create a KML point.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.Point>} A point geometry.
+     *
+     * Returns:
+     * {E4XElement} A KML point node.
+     */
+    'point': function(geometry) {
+      var kml = new XML('<Point xmlns="'+this.kmlns+'"></Point>');
+      kml.coordinates = this.buildCoordinatesNode(geometry);
+      return kml;
+    },
+    /**
+     * Method: buildGeometry.multipoint
+     * Given a ZOO multipoint geometry, create a KML
+     *     GeometryCollection.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.MultiPoint>} A multipoint geometry.
+     *
+     * Returns:
+     * {E4XElement} A KML GeometryCollection node.
+     */
+    'multipoint': function(geometry) {
+      return this.buildGeometry.collection.apply(this, [geometry]);
+    },
+    /**
+     * Method: buildGeometry.linestring
+     * Given a ZOO linestring geometry, create a KML linestring.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.LineString>} A linestring geometry.
+     *
+     * Returns:
+     * {E4XElement} A KML linestring node.
+     */
+    'linestring': function(geometry) {
+      var kml = new XML('<LineString xmlns="'+this.kmlns+'"></LineString>');
+      kml.coordinates = this.buildCoordinatesNode(geometry);
+      return kml;
+    },
+    /**
+     * Method: buildGeometry.multilinestring
+     * Given a ZOO multilinestring geometry, create a KML
+     *     GeometryCollection.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.MultiLineString>} A multilinestring geometry.
+     *
+     * Returns:
+     * {E4XElement} A KML GeometryCollection node.
+     */
+    'multilinestring': function(geometry) {
+      return this.buildGeometry.collection.apply(this, [geometry]);
+    },
+    /**
+     * Method: buildGeometry.linearring
+     * Given a ZOO linearring geometry, create a KML linearring.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.LinearRing>} A linearring geometry.
+     *
+     * Returns:
+     * {E4XElement} A KML linearring node.
+     */
+    'linearring': function(geometry) {
+      var kml = new XML('<LinearRing xmlns="'+this.kmlns+'"></LinearRing>');
+      kml.coordinates = this.buildCoordinatesNode(geometry);
+      return kml;
+    },
+    /**
+     * Method: buildGeometry.polygon
+     * Given a ZOO polygon geometry, create a KML polygon.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.Polygon>} A polygon geometry.
+     *
+     * Returns:
+     * {E4XElement} A KML polygon node.
+     */
+    'polygon': function(geometry) {
+      var kml = new XML('<Polygon xmlns="'+this.kmlns+'"></Polygon>');
+      var rings = geometry.components;
+      var ringMember, ringGeom, type;
+      for(var i=0, len=rings.length; i<len; ++i) {
+        type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
+        ringMember = new XML('<'+type+' xmlns="'+this.kmlns+'"></'+type+'>');
+        ringMember.LinearRing = this.buildGeometry.linearring.apply(this,[rings[i]]);
+        kml.*[i] = ringMember;
+      }
+      return kml;
+    },
+    /**
+     * Method: buildGeometry.multipolygon
+     * Given a ZOO multipolygon geometry, create a KML
+     *     GeometryCollection.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.Point>} A multipolygon geometry.
+     *
+     * Returns:
+     * {E4XElement} A KML GeometryCollection node.
+     */
+    'multipolygon': function(geometry) {
+      return this.buildGeometry.collection.apply(this, [geometry]);
+    },
+    /**
+     * Method: buildGeometry.collection
+     * Given a ZOO geometry collection, create a KML MultiGeometry.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.Collection>} A geometry collection.
+     *
+     * Returns:
+     * {E4XElement} A KML MultiGeometry node.
+     */
+    'collection': function(geometry) {
+      var kml = new XML('<MultiGeometry xmlns="'+this.kmlns+'"></MultiGeometry>');
+      var child;
+      for(var i=0, len=geometry.components.length; i<len; ++i) {
+        kml.*[i] = this.buildGeometryNode.apply(this,[geometry.components[i]]);
+      }
+      return kml;
+    }
+  },
+  /**
+   * Method: buildCoordinatesNode
+   * Builds and returns the KML coordinates node with the given geometry
+   *     <coordinates>...</coordinates>
+   * 
+   * Parameters:
+   * geometry - {<ZOO.Geometry>}
+   * 
+   * Return:
+   * {E4XElement}
+   */
+  buildCoordinatesNode: function(geometry) {
+    var cooridnates = new XML('<coordinates xmlns="'+this.kmlns+'"></coordinates>');
+    var points = geometry.components;
+    if(points) {
+      // LineString or LinearRing
+      var point;
+      var numPoints = points.length;
+      var parts = new Array(numPoints);
+      for(var i=0; i<numPoints; ++i) {
+        point = points[i];
+        parts[i] = point.x + "," + point.y;
+      }
+      coordinates = parts.join(" ");
+    } else {
+      // Point
+      coordinates = geometry.x + "," + geometry.y;
+    }
+    return coordinates;
+  },
+  CLASS_NAME: 'ZOO.Format.KML'
+});
+/**
+ * Class: ZOO.Format.GML
+ * Read/Write GML. Create a new instance with the <ZOO.Format.GML>
+ *     constructor.  Supports the GML simple features profile.
+ * 
+ * Inherits from:
+ *  - <ZOO.Format>
+ */
+ZOO.Format.GML = ZOO.Class(ZOO.Format, {
+  /**
+   * Property: schemaLocation
+   * {String} Schema location for a particular minor version.
+   */
+  schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",
+  /**
+   * Property: namespaces
+   * {Object} Mapping of namespace aliases to namespace URIs.
+   */
+  namespaces: {
+    ogr: "http://ogr.maptools.org/",
+    gml: "http://www.opengis.net/gml",
+    xlink: "http://www.w3.org/1999/xlink",
+    xsi: "http://www.w3.org/2001/XMLSchema-instance",
+    wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection
+  },
+  /**
+   * Property: defaultPrefix
+   */
+  defaultPrefix: 'ogr',
+  /** 
+   * Property: collectionName
+   * {String} Name of featureCollection element.
+   */
+  collectionName: "FeatureCollection",
+  /*
+   * Property: featureName
+   * {String} Element name for features. Default is "sql_statement".
+   */
+  featureName: "sql_statement",
+  /**
+   * Property: geometryName
+   * {String} Name of geometry element.  Defaults to "geometryProperty".
+   */
+  geometryName: "geometryProperty",
+  /**
+   * Property: xy
+   * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
+   * Changing is not recommended, a new Format should be instantiated.
+   */
+  xy: true,
+  /**
+   * Property: extractAttributes
+   * {Boolean} Could we extract attributes
+   */
+  extractAttributes: true,
+  /**
+   * Constructor: ZOO.Format.GML
+   * Create a new parser for GML.
+   *
+   * Parameters:
+   * options - {Object} An optional object whose properties will be set on
+   *     this instance.
+   */
+  initialize: function(options) {
+    // compile regular expressions once instead of every time they are used
+    this.regExes = {
+      trimSpace: (/^\s*|\s*$/g),
+      removeSpace: (/\s*/g),
+      splitSpace: (/\s+/),
+      trimComma: (/\s*,\s*/g)
+    };
+    ZOO.Format.prototype.initialize.apply(this, [options]);
+  },
+  /**
+   * Method: read
+   * Read data from a string, and return a list of features. 
+   * 
+   * Parameters:
+   * data - {String} data to read/parse.
+   *
+   * Returns:
+   * {Array(<ZOO.Feature>)} An array of features.
+   */
+  read: function(data) {
+    this.features = [];
+    data = data.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, "");
+    data = new XML(data);
+
+    var gmlns = Namespace(this.namespaces['gml']);
+    var featureNodes = data..gmlns::featureMember;
+    if (data.localName() == 'featureMember')
+      featureNodes = data;
+    var features = [];
+    for(var i=0,len=featureNodes.length(); i<len; i++) {
+      var feature = this.parseFeature(featureNodes[i]);
+      if(feature) {
+        features.push(feature);
+      }
+    }
+    return features;
+  },
+  /**
+   * Method: parseFeature
+   * This function is the core of the GML parsing code in ZOO.
+   *    It creates the geometries that are then attached to the returned
+   *    feature, and calls parseAttributes() to get attribute data out.
+   *    
+   * Parameters:
+   * node - {E4XElement} A GML feature node. 
+   */
+  parseFeature: function(node) {
+    // only accept one geometry per feature - look for highest "order"
+    var gmlns = Namespace(this.namespaces['gml']);
+    var order = ["MultiPolygon", "Polygon",
+                 "MultiLineString", "LineString",
+                 "MultiPoint", "Point", "Envelope", "Box"];
+    var type, nodeList, geometry, parser;
+    for(var i=0; i<order.length; ++i) {
+      type = order[i];
+      nodeList = node.descendants(QName(gmlns,type));
+      if (nodeList.length() > 0) {
+        var parser = this.parseGeometry[type.toLowerCase()];
+        if(parser) {
+          geometry = parser.apply(this, [nodeList[0]]);
+          if (this.internalProjection && this.externalProjection) {
+            geometry.transform(this.externalProjection, 
+                               this.internalProjection); 
+          }                       
+        }
+        // stop looking for different geometry types
+        break;
+      }
+    }
+    var attributes;
+    if(this.extractAttributes) {
+      attributes = this.parseAttributes(node);
+    }
+    var feature = new ZOO.Feature(geometry, attributes);
+    return feature;
+  },
+  /**
+   * Property: parseGeometry
+   * Properties of this object are the functions that parse geometries based
+   *     on their type.
+   */
+  parseGeometry: {
+    /**
+     * Method: parseGeometry.point
+     * Given a GML node representing a point geometry, create a ZOO
+     *     point geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A GML node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Point>} A point geometry.
+     */
+    'point': function(node) {
+      /**
+       * Three coordinate variations to consider:
+       * 1) <gml:pos>x y z</gml:pos>
+       * 2) <gml:coordinates>x, y, z</gml:coordinates>
+       * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord>
+       */
+      var nodeList, coordString;
+      var coords = [];
+      // look for <gml:pos>
+      var nodeList = node..*::pos;
+      if(nodeList.length() > 0) {
+        coordString = nodeList[0].toString();
+        coordString = coordString.replace(this.regExes.trimSpace, "");
+        coords = coordString.split(this.regExes.splitSpace);
+      }
+      // look for <gml:coordinates>
+      if(coords.length == 0) {
+        nodeList = node..*::coordinates;
+        if(nodeList.length() > 0) {
+          coordString = nodeList[0].toString();
+          coordString = coordString.replace(this.regExes.removeSpace,"");
+          coords = coordString.split(",");
+        }
+      }
+      // look for <gml:coord>
+      if(coords.length == 0) {
+        nodeList = node..*::coord;
+        if(nodeList.length() > 0) {
+          var xList = nodeList[0].*::X;
+          var yList = nodeList[0].*::Y;
+          if(xList.length() > 0 && yList.length() > 0)
+            coords = [xList[0].toString(),
+                      yList[0].toString()];
+        }
+      }
+      // preserve third dimension
+      if(coords.length == 2)
+        coords[2] = null;
+      if (this.xy)
+        return new ZOO.Geometry.Point(coords[0],coords[1],coords[2]);
+      else
+        return new ZOO.Geometry.Point(coords[1],coords[0],coords[2]);
+    },
+    /**
+     * Method: parseGeometry.multipoint
+     * Given a GML node representing a multipoint geometry, create a
+     *     ZOO multipoint geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A GML node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.MultiPoint>} A multipoint geometry.
+     */
+    'multipoint': function(node) {
+      var nodeList = node..*::Point;
+      var components = [];
+      if(nodeList.length() > 0) {
+        var point;
+        for(var i=0, len=nodeList.length(); i<len; ++i) {
+          point = this.parseGeometry.point.apply(this, [nodeList[i]]);
+          if(point)
+            components.push(point);
+        }
+      }
+      return new ZOO.Geometry.MultiPoint(components);
+    },
+    /**
+     * Method: parseGeometry.linestring
+     * Given a GML node representing a linestring geometry, create a
+     *     ZOO linestring geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A GML node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.LineString>} A linestring geometry.
+     */
+    'linestring': function(node, ring) {
+      /**
+       * Two coordinate variations to consider:
+       * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList>
+       * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates>
+       */
+      var nodeList, coordString;
+      var coords = [];
+      var points = [];
+      // look for <gml:posList>
+      nodeList = node..*::posList;
+      if(nodeList.length() > 0) {
+        coordString = nodeList[0].toString();
+        coordString = coordString.replace(this.regExes.trimSpace, "");
+        coords = coordString.split(this.regExes.splitSpace);
+        var dim = parseInt(nodeList[0].@dimension);
+        var j, x, y, z;
+        for(var i=0; i<coords.length/dim; ++i) {
+          j = i * dim;
+          x = coords[j];
+          y = coords[j+1];
+          z = (dim == 2) ? null : coords[j+2];
+          if (this.xy)
+            points.push(new ZOO.Geometry.Point(x, y, z));
+          else
+            points.push(new Z0O.Geometry.Point(y, x, z));
+        }
+      }
+      // look for <gml:coordinates>
+      if(coords.length == 0) {
+        nodeList = node..*::coordinates;
+        if(nodeList.length() > 0) {
+          coordString = nodeList[0].toString();
+          coordString = coordString.replace(this.regExes.trimSpace,"");
+          coordString = coordString.replace(this.regExes.trimComma,",");
+          var pointList = coordString.split(this.regExes.splitSpace);
+          for(var i=0; i<pointList.length; ++i) {
+            coords = pointList[i].split(",");
+            if(coords.length == 2)
+              coords[2] = null;
+            if (this.xy)
+              points.push(new ZOO.Geometry.Point(coords[0],coords[1],coords[2]));
+            else
+              points.push(new ZOO.Geometry.Point(coords[1],coords[0],coords[2]));
+          }
+        }
+      }
+      var line = null;
+      if(points.length != 0) {
+        if(ring)
+          line = new ZOO.Geometry.LinearRing(points);
+        else
+          line = new ZOO.Geometry.LineString(points);
+      }
+      return line;
+    },
+    /**
+     * Method: parseGeometry.multilinestring
+     * Given a GML node representing a multilinestring geometry, create a
+     *     ZOO multilinestring geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A GML node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.MultiLineString>} A multilinestring geometry.
+     */
+    'multilinestring': function(node) {
+      var nodeList = node..*::LineString;
+      var components = [];
+      if(nodeList.length() > 0) {
+        var line;
+        for(var i=0, len=nodeList.length(); i<len; ++i) {
+          line = this.parseGeometry.linestring.apply(this, [nodeList[i]]);
+          if(point)
+            components.push(point);
+        }
+      }
+      return new ZOO.Geometry.MultiLineString(components);
+    },
+    /**
+     * Method: parseGeometry.polygon
+     * Given a GML node representing a polygon geometry, create a
+     *     ZOO polygon geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A GML node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Polygon>} A polygon geometry.
+     */
+    'polygon': function(node) {
+      nodeList = node..*::LinearRing;
+      var components = [];
+      if(nodeList.length() > 0) {
+        // this assumes exterior ring first, inner rings after
+        var ring;
+        for(var i=0, len = nodeList.length(); i<len; ++i) {
+          ring = this.parseGeometry.linestring.apply(this,[nodeList[i], true]);
+          if(ring)
+            components.push(ring);
+        }
+      }
+      return new ZOO.Geometry.Polygon(components);
+    },
+    /**
+     * Method: parseGeometry.multipolygon
+     * Given a GML node representing a multipolygon geometry, create a
+     *     ZOO multipolygon geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A GML node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.MultiPolygon>} A multipolygon geometry.
+     */
+    'multipolygon': function(node) {
+      var nodeList = node..*::Polygon;
+      var components = [];
+      if(nodeList.length() > 0) {
+        var polygon;
+        for(var i=0, len=nodeList.length(); i<len; ++i) {
+          polygon = this.parseGeometry.polygon.apply(this, [nodeList[i]]);
+          if(polygon)
+            components.push(polygon);
+        }
+      }
+      return new ZOO.Geometry.MultiPolygon(components);
+    },
+    /**
+     * Method: parseGeometry.envelope
+     * Given a GML node representing an envelope, create a
+     *     ZOO polygon geometry.
+     *
+     * Parameters:
+     * node - {E4XElement} A GML node.
+     *
+     * Returns:
+     * {<ZOO.Geometry.Polygon>} A polygon geometry.
+     */
+    'envelope': function(node) {
+      var components = [];
+      var coordString;
+      var envelope;
+      var lpoint = node..*::lowerCorner;
+      if (lpoint.length() > 0) {
+        var coords = [];
+        if(lpoint.length() > 0) {
+          coordString = lpoint[0].toString();
+          coordString = coordString.replace(this.regExes.trimSpace, "");
+          coords = coordString.split(this.regExes.splitSpace);
+        }
+        if(coords.length == 2)
+          coords[2] = null;
+        if (this.xy)
+          var lowerPoint = new ZOO.Geometry.Point(coords[0], coords[1],coords[2]);
+        else
+          var lowerPoint = new ZOO.Geometry.Point(coords[1], coords[0],coords[2]);
+      }
+      var upoint = node..*::upperCorner;
+      if (upoint.length() > 0) {
+        var coords = [];
+        if(upoint.length > 0) {
+          coordString = upoint[0].toString();
+          coordString = coordString.replace(this.regExes.trimSpace, "");
+          coords = coordString.split(this.regExes.splitSpace);
+        }
+        if(coords.length == 2)
+          coords[2] = null;
+        if (this.xy)
+          var upperPoint = new ZOO.Geometry.Point(coords[0], coords[1],coords[2]);
+        else
+          var upperPoint = new ZOO.Geometry.Point(coords[1], coords[0],coords[2]);
+      }
+      if (lowerPoint && upperPoint) {
+        components.push(new ZOO.Geometry.Point(lowerPoint.x, lowerPoint.y));
+        components.push(new ZOO.Geometry.Point(upperPoint.x, lowerPoint.y));
+        components.push(new ZOO.Geometry.Point(upperPoint.x, upperPoint.y));
+        components.push(new ZOO.Geometry.Point(lowerPoint.x, upperPoint.y));
+        components.push(new ZOO.Geometry.Point(lowerPoint.x, lowerPoint.y));
+        var ring = new ZOO.Geometry.LinearRing(components);
+        envelope = new ZOO.Geometry.Polygon([ring]);
+      }
+      return envelope;
+    }
+  },
+  /**
+   * Method: parseAttributes
+   *
+   * Parameters:
+   * node - {<E4XElement>}
+   *
+   * Returns:
+   * {Object} An attributes object.
+   */
+  parseAttributes: function(node) {
+    var attributes = {};
+    // assume attributes are children of the first type 1 child
+    var childNode = node.*::*[0];
+    var child, grandchildren;
+    var children = childNode.*::*;
+    for(var i=0, len=children.length(); i<len; ++i) {
+      child = children[i];
+      grandchildren = child..*::*;
+      if(grandchildren.length() == 1) {
+        var name = child.localName();
+        var value = child.toString();
+        if (value) {
+          value = value.replace(this.regExes.trimSpace, "");
+          attributes[name] = value;
+        } else
+          attributes[name] = null;
+      }
+    }
+    return attributes;
+  },
+  /**
+   * Method: write
+   * Generate a GML document string given a list of features. 
+   * 
+   * Parameters:
+   * features - {Array(<ZOO.Feature>)} List of features to
+   *     serialize into a string.
+   *
+   * Returns:
+   * {String} A string representing the GML document.
+   */
+  write: function(features) {
+    if(!(features instanceof Array)) {
+      features = [features];
+    }
+    var pfx = this.defaultPrefix;
+    var name = pfx+':'+this.collectionName;
+    var gml = new XML('<'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'" xmlns:gml="'+this.namespaces['gml']+'" xmlns:xsi="'+this.namespaces['xsi']+'" xsi:schemaLocation="'+this.schemaLocation+'"></'+name+'>');
+    for(var i=0; i<features.length; i++) {
+      gml.*::*[i] = this.createFeature(features[i]);
+    }
+    return gml.toXMLString();
+  },
+  /** 
+   * Method: createFeature
+   * Accept an ZOO.Feature, and build a GML node for it.
+   *
+   * Parameters:
+   * feature - {<ZOO.Feature>} The feature to be built as GML.
+   *
+   * Returns:
+   * {E4XElement} A node reprensting the feature in GML.
+   */
+  createFeature: function(feature) {
+    var pfx = this.defaultPrefix;
+    var name = pfx+':'+this.featureName;
+    var fid = feature.fid || feature.id;
+    var gml = new XML('<gml:featureMember xmlns:gml="'+this.namespaces['gml']+'"><'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'" fid="'+fid+'"></'+name+'></gml:featureMember>');
+    var geometry = feature.geometry;
+    gml.*::*[0].*::* = this.buildGeometryNode(geometry);
+    for(var attr in feature.attributes) {
+      var attrNode = new XML('<'+pfx+':'+attr+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'">'+feature.attributes[attr]+'</'+pfx+':'+attr+'>');
+      gml.*::*[0].appendChild(attrNode);
+    }
+    return gml;
+  },
+  /**
+   * Method: buildGeometryNode
+   *
+   * Parameters:
+   * geometry - {<ZOO.Geometry>} The geometry to be built as GML.
+   *
+   * Returns:
+   * {E4XElement} A node reprensting the geometry in GML.
+   */
+  buildGeometryNode: function(geometry) {
+    if (this.externalProjection && this.internalProjection) {
+      geometry = geometry.clone();
+      geometry.transform(this.internalProjection, 
+          this.externalProjection);
+    }    
+    var className = geometry.CLASS_NAME;
+    var type = className.substring(className.lastIndexOf(".") + 1);
+    var builder = this.buildGeometry[type.toLowerCase()];
+    var pfx = this.defaultPrefix;
+    var name = pfx+':'+this.geometryName;
+    var gml = new XML('<'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'"></'+name+'>');
+    if (builder)
+      gml.*::* = builder.apply(this, [geometry]);
+    return gml;
+  },
+  /**
+   * Property: buildGeometry
+   * Object containing methods to do the actual geometry node building
+   *     based on geometry type.
+   */
+  buildGeometry: {
+    /**
+     * Method: buildGeometry.point
+     * Given a ZOO point geometry, create a GML point.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.Point>} A point geometry.
+     *
+     * Returns:
+     * {E4XElement} A GML point node.
+     */
+    'point': function(geometry) {
+      var gml = new XML('<gml:Point xmlns:gml="'+this.namespaces['gml']+'"></gml:Point>');
+      gml.*::*[0] = this.buildCoordinatesNode(geometry);
+      return gml;
+    },
+    /**
+     * Method: buildGeometry.multipoint
+     * Given a ZOO multipoint geometry, create a GML multipoint.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.MultiPoint>} A multipoint geometry.
+     *
+     * Returns:
+     * {E4XElement} A GML multipoint node.
+     */
+    'multipoint': function(geometry) {
+      var gml = new XML('<gml:MultiPoint xmlns:gml="'+this.namespaces['gml']+'"></gml:MultiPoint>');
+      var points = geometry.components;
+      var pointMember;
+      for(var i=0; i<points.length; i++) { 
+        pointMember = new XML('<gml:pointMember xmlns:gml="'+this.namespaces['gml']+'"></gml:pointMember>');
+        pointMember.*::* = this.buildGeometry.point.apply(this,[points[i]]);
+        gml.*::*[i] = pointMember;
+      }
+      return gml;            
+    },
+    /**
+     * Method: buildGeometry.linestring
+     * Given a ZOO linestring geometry, create a GML linestring.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.LineString>} A linestring geometry.
+     *
+     * Returns:
+     * {E4XElement} A GML linestring node.
+     */
+    'linestring': function(geometry) {
+      var gml = new XML('<gml:LineString xmlns:gml="'+this.namespaces['gml']+'"></gml:LineString>');
+      gml.*::*[0] = this.buildCoordinatesNode(geometry);
+      return gml;
+    },
+    /**
+     * Method: buildGeometry.multilinestring
+     * Given a ZOO multilinestring geometry, create a GML
+     *     multilinestring.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.MultiLineString>} A multilinestring
+     *     geometry.
+     *
+     * Returns:
+     * {E4XElement} A GML multilinestring node.
+     */
+    'multilinestring': function(geometry) {
+      var gml = new XML('<gml:MultiLineString xmlns:gml="'+this.namespaces['gml']+'"></gml:MultiLineString>');
+      var lines = geometry.components;
+      var lineMember;
+      for(var i=0; i<lines.length; i++) { 
+        lineMember = new XML('<gml:lineStringMember xmlns:gml="'+this.namespaces['gml']+'"></gml:lineStringMember>');
+        lineMember.*::* = this.buildGeometry.linestring.apply(this,[lines[i]]);
+        gml.*::*[i] = lineMember;
+      }
+      return gml;            
+    },
+    /**
+     * Method: buildGeometry.linearring
+     * Given a ZOO linearring geometry, create a GML linearring.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.LinearRing>} A linearring geometry.
+     *
+     * Returns:
+     * {E4XElement} A GML linearring node.
+     */
+    'linearring': function(geometry) {
+      var gml = new XML('<gml:LinearRing xmlns:gml="'+this.namespaces['gml']+'"></gml:LinearRing>');
+      gml.*::*[0] = this.buildCoordinatesNode(geometry);
+      return gml;
+    },
+    /**
+     * Method: buildGeometry.polygon
+     * Given an ZOO polygon geometry, create a GML polygon.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.Polygon>} A polygon geometry.
+     *
+     * Returns:
+     * {E4XElement} A GML polygon node.
+     */
+    'polygon': function(geometry) {
+      var gml = new XML('<gml:Polygon xmlns:gml="'+this.namespaces['gml']+'"></gml:Polygon>');
+      var rings = geometry.components;
+      var ringMember, type;
+      for(var i=0; i<rings.length; ++i) {
+        type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
+        var ringMember = new XML('<gml:'+type+' xmlns:gml="'+this.namespaces['gml']+'"></gml:'+type+'>');
+        ringMember.*::* = this.buildGeometry.linearring.apply(this,[rings[i]]);
+        gml.*::*[i] = ringMember;
+      }
+      return gml;
+    },
+    /**
+     * Method: buildGeometry.multipolygon
+     * Given a ZOO multipolygon geometry, create a GML multipolygon.
+     *
+     * Parameters:
+     * geometry - {<ZOO.Geometry.MultiPolygon>} A multipolygon
+     *     geometry.
+     *
+     * Returns:
+     * {E4XElement} A GML multipolygon node.
+     */
+    'multipolygon': function(geometry) {
+      var gml = new XML('<gml:MultiPolygon xmlns:gml="'+this.namespaces['gml']+'"></gml:MultiPolygon>');
+      var polys = geometry.components;
+      var polyMember;
+      for(var i=0; i<polys.length; i++) { 
+        polyMember = new XML('<gml:polygonMember xmlns:gml="'+this.namespaces['gml']+'"></gml:polygonMember>');
+        polyMember.*::* = this.buildGeometry.polygon.apply(this,[polys[i]]);
+        gml.*::*[i] = polyMember;
+      }
+      return gml;            
+    }
+  },
+  /**
+   * Method: buildCoordinatesNode
+   * builds the coordinates XmlNode
+   * (code)
+   * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates>
+   * (end)
+   * Parameters: 
+   * geometry - {<ZOO.Geometry>} 
+   *
+   * Returns:
+   * {E4XElement} created E4XElement
+   */
+  buildCoordinatesNode: function(geometry) {
+    var parts = [];
+    if(geometry instanceof ZOO.Bounds){
+      parts.push(geometry.left + "," + geometry.bottom);
+      parts.push(geometry.right + "," + geometry.top);
+    } else {
+      var points = (geometry.components) ? geometry.components : [geometry];
+      for(var i=0; i<points.length; i++) {
+        parts.push(points[i].x + "," + points[i].y);                
+      }            
+    }
+    return new XML('<gml:coordinates xmlns:gml="'+this.namespaces['gml']+'" decimal="." cs=", " ts=" ">'+parts.join(" ")+'</gml:coordinates>');
+  },
+  CLASS_NAME: 'ZOO.Format.GML'
+});
+/**
+ * Class: ZOO.Format.WPS
+ * Read/Write WPS. Create a new instance with the <ZOO.Format.WPS>
+ *     constructor. Supports only parseExecuteResponse.
+ * 
+ * Inherits from:
+ *  - <ZOO.Format>
+ */
+ZOO.Format.WPS = ZOO.Class(ZOO.Format, {
+  /**
+   * Property: schemaLocation
+   * {String} Schema location for a particular minor version.
+   */
+  schemaLocation: "http://www.opengis.net/wps/1.0.0/../wpsExecute_request.xsd",
+  /**
+   * Property: namespaces
+   * {Object} Mapping of namespace aliases to namespace URIs.
+   */
+  namespaces: {
+    ows: "http://www.opengis.net/ows/1.1",
+    wps: "http://www.opengis.net/wps/1.0.0",
+    xlink: "http://www.w3.org/1999/xlink",
+    xsi: "http://www.w3.org/2001/XMLSchema-instance",
+  },
+  /**
+   * Method: read
+   *
+   * Parameters:
+   * data - {String} A WPS xml document
+   *
+   * Returns:
+   * {Object} Execute response.
+   */
+  read:function(data) {
+    data = data.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, "");
+    data = new XML(data);
+    switch (data.localName()) {
+      case 'ExecuteResponse':
+        return this.parseExecuteResponse(data);
+      default:
+        return null;
+    }
+  },
+  /**
+   * Method: parseExecuteResponse
+   *
+   * Parameters:
+   * node - {E4XElement} A WPS ExecuteResponse document
+   *
+   * Returns:
+   * {Object} Execute response.
+   */
+  parseExecuteResponse: function(node) {
+    var outputs = node.*::ProcessOutputs.*::Output;
+    if (outputs.length() > 0) {
+      var res=[];
+      for(var i=0;i<outputs.length();i++){
+        var data = outputs[i].*::Data.*::*[0];
+	if(!data){
+          data = outputs[i].*::Reference;
+	}
+	var builder = this.parseData[data.localName().toLowerCase()];
+	if (builder){
+	  res.push(builder.apply(this,[data]));
+	}
+	else
+	  res.push(null);
+	data=null;
+      }
+      return res.length>1?res:res[0];
+    }
+    else{
+      var hasPercentCompleted=true;
+      var status = node.*::Status.*::ProcessStarted;
+      var msg = node.*::Status.*::ProcessStarted.*::*[0];
+      if(!status || !msg){
+        status = node.*::Status.*::ProcessAccepted;
+	msg = node.*::Status.*::ProcessAccepted.*::*[0];
+	msg=msg.toString();
+        hasPercentCompleted=false;
+      }else
+	  msg=msg.toString();
+      if(status!=null && node.@statusLocation){
+        var res={"status": node.@statusLocation.toXMLString(), "message": msg};
+	if(hasPercentCompleted)
+	  res["percentCompleted"]=status.@percentCompleted.toXMLString();
+        return res;
+      }else
+	return null;
+    }
+  },
+  /**
+   * Property: parseData
+   * Object containing methods to analyse data response.
+   */
+  parseData: {
+    /**
+     * Method: parseData.complexdata
+     * Given an Object representing the WPS complex data response.
+     *
+     * Parameters:
+     * node - {E4XElement} A WPS node.
+     *
+     * Returns:
+     * {Object} A WPS complex data response.
+     */
+    'complexdata': function(node) {
+      var result = {value:node.toString()};
+      if (node.@mimeType.length()>0)
+        result.mimeType = node.@mimeType;
+      if (node.@encoding.length()>0)
+        result.encoding = node.@encoding;
+      if (node.@schema.length()>0)
+        result.schema = node.@schema;
+      return result;
+    },
+    /**
+     * Method: parseData.literaldata
+     * Given an Object representing the WPS literal data response.
+     *
+     * Parameters:
+     * node - {E4XElement} A WPS node.
+     *
+     * Returns:
+     * {Object} A WPS literal data response.
+     */
+    'literaldata': function(node) {
+      var result = {value:node.toString()};
+      if (node.@dataType.length()>0)
+        result.dataType = node.@dataType;
+      if (node.@uom.length()>0)
+        result.uom = node.@uom;
+      return result;
+    },
+    /**
+     * Method: parseData.reference
+     * Given an Object representing the WPS reference response.
+     *
+     * Parameters:
+     * node - {E4XElement} A WPS node.
+     *
+     * Returns:
+     * {Object} A WPS reference response.
+     */
+    'reference': function(lnode) {
+      var lhref=lnode.@href;
+      var lmimeType=lnode.@mimeType;
+      var result = {type:'reference',value:lhref.toXMLString(),mimeType:lmimeType.toXMLString()};
+      return result;
+    }
+  },
+  CLASS_NAME: 'ZOO.Format.WPS'
+});
+
+/**
+ * Class: ZOO.Feature
+ * Vector features use the ZOO.Geometry classes as geometry description.
+ * They have an 'attributes' property, which is the data object
+ */
+ZOO.Feature = ZOO.Class({
+  /** 
+   * Property: fid 
+   * {String} 
+   */
+  fid: null,
+  /** 
+   * Property: geometry 
+   * {<ZOO.Geometry>} 
+   */
+  geometry: null,
+  /** 
+   * Property: attributes 
+   * {Object} This object holds arbitrary properties that describe the
+   *     feature.
+   */
+  attributes: null,
+  /**
+   * Property: bounds
+   * {<ZOO.Bounds>} The box bounding that feature's geometry, that
+   *     property can be set by an <ZOO.Format> object when
+   *     deserializing the feature, so in most cases it represents an
+   *     information set by the server. 
+   */
+  bounds: null,
+  /** 
+   * Constructor: ZOO.Feature
+   * Create a vector feature. 
+   * 
+   * Parameters:
+   * geometry - {<ZOO.Geometry>} The geometry that this feature
+   *     represents.
+   * attributes - {Object} An optional object that will be mapped to the
+   *     <attributes> property. 
+   */
+  initialize: function(geometry, attributes) {
+    this.geometry = geometry ? geometry : null;
+    this.attributes = {};
+    if (attributes)
+      this.attributes = ZOO.extend(this.attributes,attributes);
+  },
+  /** 
+   * Method: destroy
+   * nullify references to prevent circular references and memory leaks
+   */
+  destroy: function() {
+    this.geometry = null;
+  },
+  /**
+   * Method: clone
+   * Create a clone of this vector feature.  Does not set any non-standard
+   *     properties.
+   *
+   * Returns:
+   * {<ZOO.Feature>} An exact clone of this vector feature.
+   */
+  clone: function () {
+    return new ZOO.Feature(this.geometry ? this.geometry.clone() : null,
+            this.attributes);
+  },
+  /**
+   * Method: move
+   * Moves the feature and redraws it at its new location
+   *
+   * Parameters:
+   * x - {Float}
+   * y - {Float}
+   */
+  move: function(x, y) {
+    if(!this.geometry.move)
+      return;
+
+    this.geometry.move(x,y);
+    return this.geometry;
+  },
+  CLASS_NAME: 'ZOO.Feature'
+});
+
+/**
+ * Class: ZOO.Geometry
+ * A Geometry is a description of a geographic object. Create an instance
+ * of this class with the <ZOO.Geometry> constructor. This is a base class,
+ * typical geometry types are described by subclasses of this class.
+ */
+ZOO.Geometry = ZOO.Class({
+  /**
+   * Property: id
+   * {String} A unique identifier for this geometry.
+   */
+  id: null,
+  /**
+   * Property: parent
+   * {<ZOO.Geometry>}This is set when a Geometry is added as component
+   * of another geometry
+   */
+  parent: null,
+  /**
+   * Property: bounds 
+   * {<ZOO.Bounds>} The bounds of this geometry
+   */
+  bounds: null,
+  /**
+   * Constructor: ZOO.Geometry
+   * Creates a geometry object.  
+   */
+  initialize: function() {
+    //generate unique id
+  },
+  /**
+   * Method: destroy
+   * Destroy this geometry.
+   */
+  destroy: function() {
+    this.id = null;
+    this.bounds = null;
+  },
+  /**
+   * Method: clone
+   * Create a clone of this geometry.  Does not set any non-standard
+   *     properties of the cloned geometry.
+   * 
+   * Returns:
+   * {<ZOO.Geometry>} An exact clone of this geometry.
+   */
+  clone: function() {
+    return new ZOO.Geometry();
+  },
+  /**
+   * Method: extendBounds
+   * Extend the existing bounds to include the new bounds. 
+   * If geometry's bounds is not yet set, then set a new Bounds.
+   * 
+   * Parameters:
+   * newBounds - {<ZOO.Bounds>} 
+   */
+  extendBounds: function(newBounds){
+    var bounds = this.getBounds();
+    if (!bounds)
+      this.setBounds(newBounds);
+    else
+      this.bounds.extend(newBounds);
+  },
+  /**
+   * Set the bounds for this Geometry.
+   * 
+   * Parameters:
+   * bounds - {<ZOO.Bounds>} 
+   */
+  setBounds: function(bounds) {
+    if (bounds)
+      this.bounds = bounds.clone();
+  },
+  /**
+   * Method: clearBounds
+   * Nullify this components bounds and that of its parent as well.
+   */
+  clearBounds: function() {
+    this.bounds = null;
+    if (this.parent)
+      this.parent.clearBounds();
+  },
+  /**
+   * Method: getBounds
+   * Get the bounds for this Geometry. If bounds is not set, it 
+   * is calculated again, this makes queries faster.
+   * 
+   * Returns:
+   * {<ZOO.Bounds>}
+   */
+  getBounds: function() {
+    if (this.bounds == null) {
+      this.calculateBounds();
+    }
+    return this.bounds;
+  },
+  /** 
+   * Method: calculateBounds
+   * Recalculate the bounds for the geometry. 
+   */
+  calculateBounds: function() {
+    // This should be overridden by subclasses.
+    return this.bounds;
+  },
+  distanceTo: function(geometry, options) {
+  },
+  getVertices: function(nodes) {
+  },
+  getLength: function() {
+    return 0.0;
+  },
+  getArea: function() {
+    return 0.0;
+  },
+  getCentroid: function() {
+    return null;
+  },
+  /**
+   * Method: toString
+   * Returns the Well-Known Text representation of a geometry
+   *
+   * Returns:
+   * {String} Well-Known Text
+   */
+  toString: function() {
+    return ZOO.Format.WKT.prototype.write(
+        new ZOO.Feature(this)
+    );
+  },
+  CLASS_NAME: 'ZOO.Geometry'
+});
+/**
+ * Function: ZOO.Geometry.fromWKT
+ * Generate a geometry given a Well-Known Text string.
+ *
+ * Parameters:
+ * wkt - {String} A string representing the geometry in Well-Known Text.
+ *
+ * Returns:
+ * {<ZOO.Geometry>} A geometry of the appropriate class.
+ */
+ZOO.Geometry.fromWKT = function(wkt) {
+  var format = arguments.callee.format;
+  if(!format) {
+    format = new ZOO.Format.WKT();
+    arguments.callee.format = format;
+  }
+  var geom;
+  var result = format.read(wkt);
+  if(result instanceof ZOO.Feature) {
+    geom = result.geometry;
+  } else if(result instanceof Array) {
+    var len = result.length;
+    var components = new Array(len);
+    for(var i=0; i<len; ++i) {
+      components[i] = result[i].geometry;
+    }
+    geom = new ZOO.Geometry.Collection(components);
+  }
+  return geom;
+};
+ZOO.Geometry.segmentsIntersect = function(seg1, seg2, options) {
+  var point = options && options.point;
+  var tolerance = options && options.tolerance;
+  var intersection = false;
+  var x11_21 = seg1.x1 - seg2.x1;
+  var y11_21 = seg1.y1 - seg2.y1;
+  var x12_11 = seg1.x2 - seg1.x1;
+  var y12_11 = seg1.y2 - seg1.y1;
+  var y22_21 = seg2.y2 - seg2.y1;
+  var x22_21 = seg2.x2 - seg2.x1;
+  var d = (y22_21 * x12_11) - (x22_21 * y12_11);
+  var n1 = (x22_21 * y11_21) - (y22_21 * x11_21);
+  var n2 = (x12_11 * y11_21) - (y12_11 * x11_21);
+  if(d == 0) {
+    // parallel
+    if(n1 == 0 && n2 == 0) {
+      // coincident
+      intersection = true;
+    }
+  } else {
+    var along1 = n1 / d;
+    var along2 = n2 / d;
+    if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) {
+      // intersect
+      if(!point) {
+        intersection = true;
+      } else {
+        // calculate the intersection point
+        var x = seg1.x1 + (along1 * x12_11);
+        var y = seg1.y1 + (along1 * y12_11);
+        intersection = new ZOO.Geometry.Point(x, y);
+      }
+    }
+  }
+  if(tolerance) {
+    var dist;
+    if(intersection) {
+      if(point) {
+        var segs = [seg1, seg2];
+        var seg, x, y;
+        // check segment endpoints for proximity to intersection
+        // set intersection to first endpoint within the tolerance
+        outer: for(var i=0; i<2; ++i) {
+          seg = segs[i];
+          for(var j=1; j<3; ++j) {
+            x = seg["x" + j];
+            y = seg["y" + j];
+            dist = Math.sqrt(
+                Math.pow(x - intersection.x, 2) +
+                Math.pow(y - intersection.y, 2)
+            );
+            if(dist < tolerance) {
+              intersection.x = x;
+              intersection.y = y;
+              break outer;
+            }
+          }
+        }
+      }
+    } else {
+      // no calculated intersection, but segments could be within
+      // the tolerance of one another
+      var segs = [seg1, seg2];
+      var source, target, x, y, p, result;
+      // check segment endpoints for proximity to intersection
+      // set intersection to first endpoint within the tolerance
+      outer: for(var i=0; i<2; ++i) {
+        source = segs[i];
+        target = segs[(i+1)%2];
+        for(var j=1; j<3; ++j) {
+          p = {x: source["x"+j], y: source["y"+j]};
+          result = ZOO.Geometry.distanceToSegment(p, target);
+          if(result.distance < tolerance) {
+            if(point) {
+              intersection = new ZOO.Geometry.Point(p.x, p.y);
+            } else {
+              intersection = true;
+            }
+            break outer;
+          }
+        }
+      }
+    }
+  }
+  return intersection;
+};
+ZOO.Geometry.distanceToSegment = function(point, segment) {
+  var x0 = point.x;
+  var y0 = point.y;
+  var x1 = segment.x1;
+  var y1 = segment.y1;
+  var x2 = segment.x2;
+  var y2 = segment.y2;
+  var dx = x2 - x1;
+  var dy = y2 - y1;
+  var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) /
+               (Math.pow(dx, 2) + Math.pow(dy, 2));
+  var x, y;
+  if(along <= 0.0) {
+    x = x1;
+    y = y1;
+  } else if(along >= 1.0) {
+    x = x2;
+    y = y2;
+  } else {
+    x = x1 + along * dx;
+    y = y1 + along * dy;
+  }
+  return {
+    distance: Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)),
+    x: x, y: y
+  };
+};
+/**
+ * Class: ZOO.Geometry.Collection
+ * A Collection is exactly what it sounds like: A collection of different 
+ * Geometries. These are stored in the local parameter <components> (which
+ * can be passed as a parameter to the constructor). 
+ * 
+ * As new geometries are added to the collection, they are NOT cloned. 
+ * When removing geometries, they need to be specified by reference (ie you 
+ * have to pass in the *exact* geometry to be removed).
+ * 
+ * The <getArea> and <getLength> functions here merely iterate through
+ * the components, summing their respective areas and lengths.
+ *
+ * Create a new instance with the <ZOO.Geometry.Collection> constructor.
+ *
+ * Inerhits from:
+ *  - <ZOO.Geometry> 
+ */
+ZOO.Geometry.Collection = ZOO.Class(ZOO.Geometry, {
+  /**
+   * Property: components
+   * {Array(<ZOO.Geometry>)} The component parts of this geometry
+   */
+  components: null,
+  /**
+   * Property: componentTypes
+   * {Array(String)} An array of class names representing the types of
+   * components that the collection can include.  A null value means the
+   * component types are not restricted.
+   */
+  componentTypes: null,
+  /**
+   * Constructor: ZOO.Geometry.Collection
+   * Creates a Geometry Collection -- a list of geoms.
+   *
+   * Parameters: 
+   * components - {Array(<ZOO.Geometry>)} Optional array of geometries
+   *
+   */
+  initialize: function (components) {
+    ZOO.Geometry.prototype.initialize.apply(this, arguments);
+    this.components = [];
+    if (components != null) {
+      this.addComponents(components);
+    }
+  },
+  /**
+   * Method: destroy
+   * Destroy this geometry.
+   */
+  destroy: function () {
+    this.components.length = 0;
+    this.components = null;
+  },
+  /**
+   * Method: clone
+   * Clone this geometry.
+   *
+   * Returns:
+   * {<ZOO.Geometry.Collection>} An exact clone of this collection
+   */
+  clone: function() {
+    var geometry = eval("new " + this.CLASS_NAME + "()");
+    for(var i=0, len=this.components.length; i<len; i++) {
+      geometry.addComponent(this.components[i].clone());
+    }
+    return geometry;
+  },
+  /**
+   * Method: getComponentsString
+   * Get a string representing the components for this collection
+   * 
+   * Returns:
+   * {String} A string representation of the components of this geometry
+   */
+  getComponentsString: function(){
+    var strings = [];
+    for(var i=0, len=this.components.length; i<len; i++) {
+      strings.push(this.components[i].toShortString()); 
+    }
+    return strings.join(",");
+  },
+  /**
+   * Method: calculateBounds
+   * Recalculate the bounds by iterating through the components and 
+   * calling extendBounds() on each item.
+   */
+  calculateBounds: function() {
+    this.bounds = null;
+    if ( this.components && this.components.length > 0) {
+      this.setBounds(this.components[0].getBounds());
+      for (var i=1, len=this.components.length; i<len; i++) {
+        this.extendBounds(this.components[i].getBounds());
+      }
+    }
+    return this.bounds
+  },
+  /**
+   * APIMethod: addComponents
+   * Add components to this geometry.
+   *
+   * Parameters:
+   * components - {Array(<ZOO.Geometry>)} An array of geometries to add
+   */
+  addComponents: function(components){
+    if(!(components instanceof Array))
+      components = [components];
+    for(var i=0, len=components.length; i<len; i++) {
+      this.addComponent(components[i]);
+    }
+  },
+  /**
+   * Method: addComponent
+   * Add a new component (geometry) to the collection.  If this.componentTypes
+   * is set, then the component class name must be in the componentTypes array.
+   *
+   * The bounds cache is reset.
+   * 
+   * Parameters:
+   * component - {<ZOO.Geometry>} A geometry to add
+   * index - {int} Optional index into the array to insert the component
+   *
+   * Returns:
+   * {Boolean} The component geometry was successfully added
+   */
+  addComponent: function(component, index) {
+    var added = false;
+    if(component) {
+      if(this.componentTypes == null ||
+          (ZOO.indexOf(this.componentTypes,
+                       component.CLASS_NAME) > -1)) {
+        if(index != null && (index < this.components.length)) {
+          var components1 = this.components.slice(0, index);
+          var components2 = this.components.slice(index, 
+                                                  this.components.length);
+          components1.push(component);
+          this.components = components1.concat(components2);
+        } else {
+          this.components.push(component);
+        }
+        component.parent = this;
+        this.clearBounds();
+        added = true;
+      }
+    }
+    return added;
+  },
+  /**
+   * Method: removeComponents
+   * Remove components from this geometry.
+   *
+   * Parameters:
+   * components - {Array(<ZOO.Geometry>)} The components to be removed
+   */
+  removeComponents: function(components) {
+    if(!(components instanceof Array))
+      components = [components];
+    for(var i=components.length-1; i>=0; --i) {
+      this.removeComponent(components[i]);
+    }
+  },
+  /**
+   * Method: removeComponent
+   * Remove a component from this geometry.
+   *
+   * Parameters:
+   * component - {<ZOO.Geometry>} 
+   */
+  removeComponent: function(component) {      
+    ZOO.removeItem(this.components, component);
+    // clearBounds() so that it gets recalculated on the next call
+    // to this.getBounds();
+    this.clearBounds();
+  },
+  /**
+   * Method: getLength
+   * Calculate the length of this geometry
+   *
+   * Returns:
+   * {Float} The length of the geometry
+   */
+  getLength: function() {
+    var length = 0.0;
+    for (var i=0, len=this.components.length; i<len; i++) {
+      length += this.components[i].getLength();
+    }
+    return length;
+  },
+  /**
+   * APIMethod: getArea
+   * Calculate the area of this geometry. Note how this function is 
+   * overridden in <ZOO.Geometry.Polygon>.
+   *
+   * Returns:
+   * {Float} The area of the collection by summing its parts
+   */
+  getArea: function() {
+    var area = 0.0;
+    for (var i=0, len=this.components.length; i<len; i++) {
+      area += this.components[i].getArea();
+    }
+    return area;
+  },
+  /** 
+   * APIMethod: getGeodesicArea
+   * Calculate the approximate area of the polygon were it projected onto
+   *     the earth.
+   *
+   * Parameters:
+   * projection - {<ZOO.Projection>} The spatial reference system
+   *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
+   *     assumed.
+   * 
+   * Reference:
+   * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
+   *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
+   *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
+   *
+   * Returns:
+   * {float} The approximate geodesic area of the geometry in square meters.
+   */
+  getGeodesicArea: function(projection) {
+    var area = 0.0;
+    for(var i=0, len=this.components.length; i<len; i++) {
+      area += this.components[i].getGeodesicArea(projection);
+    }
+    return area;
+  },
+  /**
+   * Method: getCentroid
+   *
+   * Returns:
+   * {<ZOO.Geometry.Point>} The centroid of the collection
+   */
+  getCentroid: function() {
+    return this.components.length && this.components[0].getCentroid();
+  },
+  /**
+   * Method: getGeodesicLength
+   * Calculate the approximate length of the geometry were it projected onto
+   *     the earth.
+   *
+   * Parameters:
+   * projection - {<ZOO.Projection>} The spatial reference system
+   *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
+   *     assumed.
+   * 
+   * Returns:
+   * {Float} The appoximate geodesic length of the geometry in meters.
+   */
+  getGeodesicLength: function(projection) {
+    var length = 0.0;
+    for(var i=0, len=this.components.length; i<len; i++) {
+      length += this.components[i].getGeodesicLength(projection);
+    }
+    return length;
+  },
+  /**
+   * Method: move
+   * Moves a geometry by the given displacement along positive x and y axes.
+   *     This modifies the position of the geometry and clears the cached
+   *     bounds.
+   *
+   * Parameters:
+   * x - {Float} Distance to move geometry in positive x direction. 
+   * y - {Float} Distance to move geometry in positive y direction.
+   */
+  move: function(x, y) {
+    for(var i=0, len=this.components.length; i<len; i++) {
+      this.components[i].move(x, y);
+    }
+  },
+  /**
+   * Method: rotate
+   * Rotate a geometry around some origin
+   *
+   * Parameters:
+   * angle - {Float} Rotation angle in degrees (measured counterclockwise
+   *                 from the positive x-axis)
+   * origin - {<ZOO.Geometry.Point>} Center point for the rotation
+   */
+  rotate: function(angle, origin) {
+    for(var i=0, len=this.components.length; i<len; ++i) {
+      this.components[i].rotate(angle, origin);
+    }
+  },
+  /**
+   * Method: resize
+   * Resize a geometry relative to some origin.  Use this method to apply
+   *     a uniform scaling to a geometry.
+   *
+   * Parameters:
+   * scale - {Float} Factor by which to scale the geometry.  A scale of 2
+   *                 doubles the size of the geometry in each dimension
+   *                 (lines, for example, will be twice as long, and polygons
+   *                 will have four times the area).
+   * origin - {<ZOO.Geometry.Point>} Point of origin for resizing
+   * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
+   * 
+   * Returns:
+   * {ZOO.Geometry} - The current geometry. 
+   */
+  resize: function(scale, origin, ratio) {
+    for(var i=0; i<this.components.length; ++i) {
+      this.components[i].resize(scale, origin, ratio);
+    }
+    return this;
+  },
+  distanceTo: function(geometry, options) {
+    var edge = !(options && options.edge === false);
+    var details = edge && options && options.details;
+    var result, best;
+    var min = Number.POSITIVE_INFINITY;
+    for(var i=0, len=this.components.length; i<len; ++i) {
+      result = this.components[i].distanceTo(geometry, options);
+      distance = details ? result.distance : result;
+      if(distance < min) {
+        min = distance;
+        best = result;
+        if(min == 0)
+          break;
+      }
+    }
+    return best;
+  },
+  /** 
+   * Method: equals
+   * Determine whether another geometry is equivalent to this one.  Geometries
+   *     are considered equivalent if all components have the same coordinates.
+   * 
+   * Parameters:
+   * geom - {<ZOO.Geometry>} The geometry to test. 
+   *
+   * Returns:
+   * {Boolean} The supplied geometry is equivalent to this geometry.
+   */
+  equals: function(geometry) {
+    var equivalent = true;
+    if(!geometry || !geometry.CLASS_NAME ||
+       (this.CLASS_NAME != geometry.CLASS_NAME))
+      equivalent = false;
+    else if(!(geometry.components instanceof Array) ||
+             (geometry.components.length != this.components.length))
+      equivalent = false;
+    else
+      for(var i=0, len=this.components.length; i<len; ++i) {
+        if(!this.components[i].equals(geometry.components[i])) {
+          equivalent = false;
+          break;
+        }
+      }
+    return equivalent;
+  },
+  /**
+   * Method: transform
+   * Reproject the components geometry from source to dest.
+   * 
+   * Parameters:
+   * source - {<ZOO.Projection>} 
+   * dest - {<ZOO.Projection>}
+   * 
+   * Returns:
+   * {<ZOO.Geometry>} 
+   */
+  transform: function(source, dest) {
+    if (source && dest) {
+      for (var i=0, len=this.components.length; i<len; i++) {  
+        var component = this.components[i];
+        component.transform(source, dest);
+      }
+      this.bounds = null;
+    }
+    return this;
+  },
+  /**
+   * Method: intersects
+   * Determine if the input geometry intersects this one.
+   *
+   * Parameters:
+   * geometry - {<ZOO.Geometry>} Any type of geometry.
+   *
+   * Returns:
+   * {Boolean} The input geometry intersects this one.
+   */
+  intersects: function(geometry) {
+    var intersect = false;
+    for(var i=0, len=this.components.length; i<len; ++ i) {
+      intersect = geometry.intersects(this.components[i]);
+      if(intersect)
+        break;
+    }
+    return intersect;
+  },
+  /**
+   * Method: getVertices
+   * Return a list of all points in this geometry.
+   *
+   * Parameters:
+   * nodes - {Boolean} For lines, only return vertices that are
+   *     endpoints.  If false, for lines, only vertices that are not
+   *     endpoints will be returned.  If not provided, all vertices will
+   *     be returned.
+   *
+   * Returns:
+   * {Array} A list of all vertices in the geometry.
+   */
+  getVertices: function(nodes) {
+    var vertices = [];
+    for(var i=0, len=this.components.length; i<len; ++i) {
+      Array.prototype.push.apply(
+          vertices, this.components[i].getVertices(nodes)
+          );
+    }
+    return vertices;
+  },
+  CLASS_NAME: 'ZOO.Geometry.Collection'
+});
+/**
+ * Class: ZOO.Geometry.Point
+ * Point geometry class. 
+ * 
+ * Inherits from:
+ *  - <ZOO.Geometry> 
+ */
+ZOO.Geometry.Point = ZOO.Class(ZOO.Geometry, {
+  /** 
+   * Property: x 
+   * {float} 
+   */
+  x: null,
+  /** 
+   * Property: y 
+   * {float} 
+   */
+  y: null,
+  /**
+   * Constructor: ZOO.Geometry.Point
+   * Construct a point geometry.
+   *
+   * Parameters:
+   * x - {float} 
+   * y - {float}
+   * 
+   */
+  initialize: function(x, y) {
+    ZOO.Geometry.prototype.initialize.apply(this, arguments);
+    this.x = parseFloat(x);
+    this.y = parseFloat(y);
+  },
+  /**
+   * Method: clone
+   * 
+   * Returns:
+   * {<ZOO.Geometry.Point>} An exact clone of this ZOO.Geometry.Point
+   */
+  clone: function(obj) {
+    if (obj == null)
+      obj = new ZOO.Geometry.Point(this.x, this.y);
+    // catch any randomly tagged-on properties
+    // ZOO.Util.applyDefaults(obj, this);
+    return obj;
+  },
+  /** 
+   * Method: calculateBounds
+   * Create a new Bounds based on the x/y
+   */
+  calculateBounds: function () {
+    this.bounds = new ZOO.Bounds(this.x, this.y,
+                                        this.x, this.y);
+  },
+  distanceTo: function(geometry, options) {
+    var edge = !(options && options.edge === false);
+    var details = edge && options && options.details;
+    var distance, x0, y0, x1, y1, result;
+    if(geometry instanceof ZOO.Geometry.Point) {
+      x0 = this.x;
+      y0 = this.y;
+      x1 = geometry.x;
+      y1 = geometry.y;
+      distance = Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2));
+      result = !details ?
+        distance : {x0: x0, y0: y0, x1: x1, y1: y1, distance: distance};
+    } else {
+      result = geometry.distanceTo(this, options);
+      if(details) {
+        // switch coord order since this geom is target
+        result = {
+          x0: result.x1, y0: result.y1,
+          x1: result.x0, y1: result.y0,
+          distance: result.distance
+        };
+      }
+    }
+    return result;
+  },
+  /** 
+   * Method: equals
+   * Determine whether another geometry is equivalent to this one.  Geometries
+   *     are considered equivalent if all components have the same coordinates.
+   * 
+   * Parameters:
+   * geom - {<ZOO.Geometry.Point>} The geometry to test. 
+   *
+   * Returns:
+   * {Boolean} The supplied geometry is equivalent to this geometry.
+   */
+  equals: function(geom) {
+    var equals = false;
+    if (geom != null)
+      equals = ((this.x == geom.x && this.y == geom.y) ||
+                (isNaN(this.x) && isNaN(this.y) && isNaN(geom.x) && isNaN(geom.y)));
+    return equals;
+  },
+  /**
+   * Method: toShortString
+   *
+   * Returns:
+   * {String} Shortened String representation of Point object. 
+   *         (ex. <i>"5, 42"</i>)
+   */
+  toShortString: function() {
+    return (this.x + ", " + this.y);
+  },
+  /**
+   * Method: move
+   * Moves a geometry by the given displacement along positive x and y axes.
+   *     This modifies the position of the geometry and clears the cached
+   *     bounds.
+   *
+   * Parameters:
+   * x - {Float} Distance to move geometry in positive x direction. 
+   * y - {Float} Distance to move geometry in positive y direction.
+   */
+  move: function(x, y) {
+    this.x = this.x + x;
+    this.y = this.y + y;
+    this.clearBounds();
+  },
+  /**
+   * Method: rotate
+   * Rotate a point around another.
+   *
+   * Parameters:
+   * angle - {Float} Rotation angle in degrees (measured counterclockwise
+   *                 from the positive x-axis)
+   * origin - {<ZOO.Geometry.Point>} Center point for the rotation
+   */
+  rotate: function(angle, origin) {
+        angle *= Math.PI / 180;
+        var radius = this.distanceTo(origin);
+        var theta = angle + Math.atan2(this.y - origin.y, this.x - origin.x);
+        this.x = origin.x + (radius * Math.cos(theta));
+        this.y = origin.y + (radius * Math.sin(theta));
+        this.clearBounds();
+  },
+  /**
+   * Method: getCentroid
+   *
+   * Returns:
+   * {<ZOO.Geometry.Point>} The centroid of the collection
+   */
+  getCentroid: function() {
+    return new ZOO.Geometry.Point(this.x, this.y);
+  },
+  /**
+   * Method: resize
+   * Resize a point relative to some origin.  For points, this has the effect
+   *     of scaling a vector (from the origin to the point).  This method is
+   *     more useful on geometry collection subclasses.
+   *
+   * Parameters:
+   * scale - {Float} Ratio of the new distance from the origin to the old
+   *                 distance from the origin.  A scale of 2 doubles the
+   *                 distance between the point and origin.
+   * origin - {<ZOO.Geometry.Point>} Point of origin for resizing
+   * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
+   * 
+   * Returns:
+   * {ZOO.Geometry} - The current geometry. 
+   */
+  resize: function(scale, origin, ratio) {
+    ratio = (ratio == undefined) ? 1 : ratio;
+    this.x = origin.x + (scale * ratio * (this.x - origin.x));
+    this.y = origin.y + (scale * (this.y - origin.y));
+    this.clearBounds();
+    return this;
+  },
+  /**
+   * Method: intersects
+   * Determine if the input geometry intersects this one.
+   *
+   * Parameters:
+   * geometry - {<ZOO.Geometry>} Any type of geometry.
+   *
+   * Returns:
+   * {Boolean} The input geometry intersects this one.
+   */
+  intersects: function(geometry) {
+    var intersect = false;
+    if(geometry.CLASS_NAME == "ZOO.Geometry.Point") {
+      intersect = this.equals(geometry);
+    } else {
+      intersect = geometry.intersects(this);
+    }
+    return intersect;
+  },
+  /**
+   * Method: transform
+   * Translate the x,y properties of the point from source to dest.
+   * 
+   * Parameters:
+   * source - {<ZOO.Projection>} 
+   * dest - {<ZOO.Projection>}
+   * 
+   * Returns:
+   * {<ZOO.Geometry>} 
+   */
+  transform: function(source, dest) {
+    if ((source && dest)) {
+      ZOO.Projection.transform(
+          this, source, dest); 
+      this.bounds = null;
+    }       
+    return this;
+  },
+  /**
+   * Method: getVertices
+   * Return a list of all points in this geometry.
+   *
+   * Parameters:
+   * nodes - {Boolean} For lines, only return vertices that are
+   *     endpoints.  If false, for lines, only vertices that are not
+   *     endpoints will be returned.  If not provided, all vertices will
+   *     be returned.
+   *
+   * Returns:
+   * {Array} A list of all vertices in the geometry.
+   */
+  getVertices: function(nodes) {
+    return [this];
+  },
+  CLASS_NAME: 'ZOO.Geometry.Point'
+});
+/**
+ * Class: ZOO.Geometry.Surface
+ * Surface geometry class. 
+ * 
+ * Inherits from:
+ *  - <ZOO.Geometry> 
+ */
+ZOO.Geometry.Surface = ZOO.Class(ZOO.Geometry, {
+  initialize: function() {
+    ZOO.Geometry.prototype.initialize.apply(this, arguments);
+  },
+  CLASS_NAME: "ZOO.Geometry.Surface"
+});
+/**
+ * Class: ZOO.Geometry.MultiPoint
+ * MultiPoint is a collection of Points. Create a new instance with the
+ * <ZOO.Geometry.MultiPoint> constructor.
+ *
+ * Inherits from:
+ *  - <ZOO.Geometry.Collection>
+ */
+ZOO.Geometry.MultiPoint = ZOO.Class(
+  ZOO.Geometry.Collection, {
+  /**
+   * Property: componentTypes
+   * {Array(String)} An array of class names representing the types of
+   * components that the collection can include.  A null value means the
+   * component types are not restricted.
+   */
+  componentTypes: ["ZOO.Geometry.Point"],
+  /**
+   * Constructor: ZOO.Geometry.MultiPoint
+   * Create a new MultiPoint Geometry
+   *
+   * Parameters:
+   * components - {Array(<ZOO.Geometry.Point>)} 
+   *
+   * Returns:
+   * {<ZOO.Geometry.MultiPoint>}
+   */
+  initialize: function(components) {
+    ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments);
+  },
+  /**
+   * Method: addPoint
+   * Wrapper for <ZOO.Geometry.Collection.addComponent>
+   *
+   * Parameters:
+   * point - {<ZOO.Geometry.Point>} Point to be added
+   * index - {Integer} Optional index
+   */
+  addPoint: function(point, index) {
+    this.addComponent(point, index);
+  },
+  /**
+   * Method: removePoint
+   * Wrapper for <ZOO.Geometry.Collection.removeComponent>
+   *
+   * Parameters:
+   * point - {<ZOO.Geometry.Point>} Point to be removed
+   */
+  removePoint: function(point){
+    this.removeComponent(point);
+  },
+  CLASS_NAME: "ZOO.Geometry.MultiPoint"
+});
+/**
+ * Class: ZOO.Geometry.Curve
+ * A Curve is a MultiPoint, whose points are assumed to be connected. To 
+ * this end, we provide a "getLength()" function, which iterates through 
+ * the points, summing the distances between them. 
+ * 
+ * Inherits: 
+ *  - <ZOO.Geometry.MultiPoint>
+ */
+ZOO.Geometry.Curve = ZOO.Class(ZOO.Geometry.MultiPoint, {
+  /**
+   * Property: componentTypes
+   * {Array(String)} An array of class names representing the types of 
+   *                 components that the collection can include.  A null 
+   *                 value means the component types are not restricted.
+   */
+  componentTypes: ["ZOO.Geometry.Point"],
+  /**
+   * Constructor: ZOO.Geometry.Curve
+   * 
+   * Parameters:
+   * point - {Array(<ZOO.Geometry.Point>)}
+   */
+  initialize: function(points) {
+    ZOO.Geometry.MultiPoint.prototype.initialize.apply(this,arguments);
+  },
+  /**
+   * Method: getLength
+   * 
+   * Returns:
+   * {Float} The length of the curve
+   */
+  getLength: function() {
+    var length = 0.0;
+    if ( this.components && (this.components.length > 1)) {
+      for(var i=1, len=this.components.length; i<len; i++) {
+        length += this.components[i-1].distanceTo(this.components[i]);
+      }
+    }
+    return length;
+  },
+  /**
+     * APIMethod: getGeodesicLength
+     * Calculate the approximate length of the geometry were it projected onto
+     *     the earth.
+     *
+     * projection - {<ZOO.Projection>} The spatial reference system
+     *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
+     *     assumed.
+     * 
+     * Returns:
+     * {Float} The appoximate geodesic length of the geometry in meters.
+     */
+    getGeodesicLength: function(projection) {
+      var geom = this;  // so we can work with a clone if needed
+      if(projection) {
+        var gg = new ZOO.Projection("EPSG:4326");
+        if(!gg.equals(projection)) {
+          geom = this.clone().transform(projection, gg);
+       }
+     }
+     var length = 0.0;
+     if(geom.components && (geom.components.length > 1)) {
+       var p1, p2;
+       for(var i=1, len=geom.components.length; i<len; i++) {
+         p1 = geom.components[i-1];
+         p2 = geom.components[i];
+        // this returns km and requires x/y properties
+        length += ZOO.distVincenty(p1,p2);
+      }
+    }
+    // convert to m
+    return length * 1000;
+  },
+  CLASS_NAME: "ZOO.Geometry.Curve"
+});
+/**
+ * Class: ZOO.Geometry.LineString
+ * A LineString is a Curve which, once two points have been added to it, can 
+ * never be less than two points long.
+ * 
+ * Inherits from:
+ *  - <ZOO.Geometry.Curve>
+ */
+ZOO.Geometry.LineString = ZOO.Class(ZOO.Geometry.Curve, {
+  /**
+   * Constructor: ZOO.Geometry.LineString
+   * Create a new LineString geometry
+   *
+   * Parameters:
+   * points - {Array(<ZOO.Geometry.Point>)} An array of points used to
+   *          generate the linestring
+   *
+   */
+  initialize: function(points) {
+    ZOO.Geometry.Curve.prototype.initialize.apply(this, arguments);        
+  },
+  /**
+   * Method: removeComponent
+   * Only allows removal of a point if there are three or more points in 
+   * the linestring. (otherwise the result would be just a single point)
+   *
+   * Parameters: 
+   * point - {<ZOO.Geometry.Point>} The point to be removed
+   */
+  removeComponent: function(point) {
+    if ( this.components && (this.components.length > 2))
+      ZOO.Geometry.Collection.prototype.removeComponent.apply(this,arguments);
+  },
+  /**
+   * Method: intersects
+   * Test for instersection between two geometries.  This is a cheapo
+   *     implementation of the Bently-Ottmann algorigithm.  It doesn't
+   *     really keep track of a sweep line data structure.  It is closer
+   *     to the brute force method, except that segments are sorted and
+   *     potential intersections are only calculated when bounding boxes
+   *     intersect.
+   *
+   * Parameters:
+   * geometry - {<ZOO.Geometry>}
+   *
+   * Returns:
+   * {Boolean} The input geometry intersects this geometry.
+   */
+  intersects: function(geometry) {
+    var intersect = false;
+    var type = geometry.CLASS_NAME;
+    if(type == "ZOO.Geometry.LineString" ||
+       type == "ZOO.Geometry.LinearRing" ||
+       type == "ZOO.Geometry.Point") {
+      var segs1 = this.getSortedSegments();
+      var segs2;
+      if(type == "ZOO.Geometry.Point")
+        segs2 = [{
+          x1: geometry.x, y1: geometry.y,
+          x2: geometry.x, y2: geometry.y
+        }];
+      else
+        segs2 = geometry.getSortedSegments();
+      var seg1, seg1x1, seg1x2, seg1y1, seg1y2,
+          seg2, seg2y1, seg2y2;
+      // sweep right
+      outer: for(var i=0, len=segs1.length; i<len; ++i) {
+         seg1 = segs1[i];
+         seg1x1 = seg1.x1;
+         seg1x2 = seg1.x2;
+         seg1y1 = seg1.y1;
+         seg1y2 = seg1.y2;
+         inner: for(var j=0, jlen=segs2.length; j<jlen; ++j) {
+           seg2 = segs2[j];
+           if(seg2.x1 > seg1x2)
+             break;
+           if(seg2.x2 < seg1x1)
+             continue;
+           seg2y1 = seg2.y1;
+           seg2y2 = seg2.y2;
+           if(Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2))
+             continue;
+           if(Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2))
+             continue;
+           if(ZOO.Geometry.segmentsIntersect(seg1, seg2)) {
+             intersect = true;
+             break outer;
+           }
+         }
+      }
+    } else {
+      intersect = geometry.intersects(this);
+    }
+    return intersect;
+  },
+  /**
+   * Method: getSortedSegments
+   *
+   * Returns:
+   * {Array} An array of segment objects.  Segment objects have properties
+   *     x1, y1, x2, and y2.  The start point is represented by x1 and y1.
+   *     The end point is represented by x2 and y2.  Start and end are
+   *     ordered so that x1 < x2.
+   */
+  getSortedSegments: function() {
+    var numSeg = this.components.length - 1;
+    var segments = new Array(numSeg);
+    for(var i=0; i<numSeg; ++i) {
+      point1 = this.components[i];
+      point2 = this.components[i + 1];
+      if(point1.x < point2.x)
+        segments[i] = {
+          x1: point1.x,
+          y1: point1.y,
+          x2: point2.x,
+          y2: point2.y
+        };
+      else
+        segments[i] = {
+          x1: point2.x,
+          y1: point2.y,
+          x2: point1.x,
+          y2: point1.y
+        };
+    }
+    // more efficient to define this somewhere static
+    function byX1(seg1, seg2) {
+      return seg1.x1 - seg2.x1;
+    }
+    return segments.sort(byX1);
+  },
+  /**
+   * Method: splitWithSegment
+   * Split this geometry with the given segment.
+   *
+   * Parameters:
+   * seg - {Object} An object with x1, y1, x2, and y2 properties referencing
+   *     segment endpoint coordinates.
+   * options - {Object} Properties of this object will be used to determine
+   *     how the split is conducted.
+   *
+   * Valid options:
+   * edge - {Boolean} Allow splitting when only edges intersect.  Default is
+   *     true.  If false, a vertex on the source segment must be within the
+   *     tolerance distance of the intersection to be considered a split.
+   * tolerance - {Number} If a non-null value is provided, intersections
+   *     within the tolerance distance of one of the source segment's
+   *     endpoints will be assumed to occur at the endpoint.
+   *
+   * Returns:
+   * {Object} An object with *lines* and *points* properties.  If the given
+   *     segment intersects this linestring, the lines array will reference
+   *     geometries that result from the split.  The points array will contain
+   *     all intersection points.  Intersection points are sorted along the
+   *     segment (in order from x1,y1 to x2,y2).
+   */
+  splitWithSegment: function(seg, options) {
+    var edge = !(options && options.edge === false);
+    var tolerance = options && options.tolerance;
+    var lines = [];
+    var verts = this.getVertices();
+    var points = [];
+    var intersections = [];
+    var split = false;
+    var vert1, vert2, point;
+    var node, vertex, target;
+    var interOptions = {point: true, tolerance: tolerance};
+    var result = null;
+    for(var i=0, stop=verts.length-2; i<=stop; ++i) {
+      vert1 = verts[i];
+      points.push(vert1.clone());
+      vert2 = verts[i+1];
+      target = {x1: vert1.x, y1: vert1.y, x2: vert2.x, y2: vert2.y};
+      point = ZOO.Geometry.segmentsIntersect(seg, target, interOptions);
+      if(point instanceof ZOO.Geometry.Point) {
+        if((point.x === seg.x1 && point.y === seg.y1) ||
+           (point.x === seg.x2 && point.y === seg.y2) ||
+            point.equals(vert1) || point.equals(vert2))
+          vertex = true;
+        else
+          vertex = false;
+        if(vertex || edge) {
+          // push intersections different than the previous
+          if(!point.equals(intersections[intersections.length-1]))
+            intersections.push(point.clone());
+          if(i === 0) {
+            if(point.equals(vert1))
+              continue;
+          }
+          if(point.equals(vert2))
+            continue;
+          split = true;
+          if(!point.equals(vert1))
+            points.push(point);
+          lines.push(new ZOO.Geometry.LineString(points));
+          points = [point.clone()];
+        }
+      }
+    }
+    if(split) {
+      points.push(vert2.clone());
+      lines.push(new ZOO.Geometry.LineString(points));
+    }
+    if(intersections.length > 0) {
+      // sort intersections along segment
+      var xDir = seg.x1 < seg.x2 ? 1 : -1;
+      var yDir = seg.y1 < seg.y2 ? 1 : -1;
+      result = {
+        lines: lines,
+        points: intersections.sort(function(p1, p2) {
+           return (xDir * p1.x - xDir * p2.x) || (yDir * p1.y - yDir * p2.y);
+        })
+      };
+    }
+    return result;
+  },
+  /**
+   * Method: split
+   * Use this geometry (the source) to attempt to split a target geometry.
+   * 
+   * Parameters:
+   * target - {<ZOO.Geometry>} The target geometry.
+   * options - {Object} Properties of this object will be used to determine
+   *     how the split is conducted.
+   *
+   * Valid options:
+   * mutual - {Boolean} Split the source geometry in addition to the target
+   *     geometry.  Default is false.
+   * edge - {Boolean} Allow splitting when only edges intersect.  Default is
+   *     true.  If false, a vertex on the source must be within the tolerance
+   *     distance of the intersection to be considered a split.
+   * tolerance - {Number} If a non-null value is provided, intersections
+   *     within the tolerance distance of an existing vertex on the source
+   *     will be assumed to occur at the vertex.
+   * 
+   * Returns:
+   * {Array} A list of geometries (of this same type as the target) that
+   *     result from splitting the target with the source geometry.  The
+   *     source and target geometry will remain unmodified.  If no split
+   *     results, null will be returned.  If mutual is true and a split
+   *     results, return will be an array of two arrays - the first will be
+   *     all geometries that result from splitting the source geometry and
+   *     the second will be all geometries that result from splitting the
+   *     target geometry.
+   */
+  split: function(target, options) {
+    var results = null;
+    var mutual = options && options.mutual;
+    var sourceSplit, targetSplit, sourceParts, targetParts;
+    if(target instanceof ZOO.Geometry.LineString) {
+      var verts = this.getVertices();
+      var vert1, vert2, seg, splits, lines, point;
+      var points = [];
+      sourceParts = [];
+      for(var i=0, stop=verts.length-2; i<=stop; ++i) {
+        vert1 = verts[i];
+        vert2 = verts[i+1];
+        seg = {
+          x1: vert1.x, y1: vert1.y,
+          x2: vert2.x, y2: vert2.y
+        };
+        targetParts = targetParts || [target];
+        if(mutual)
+          points.push(vert1.clone());
+        for(var j=0; j<targetParts.length; ++j) {
+          splits = targetParts[j].splitWithSegment(seg, options);
+          if(splits) {
+            // splice in new features
+            lines = splits.lines;
+            if(lines.length > 0) {
+              lines.unshift(j, 1);
+              Array.prototype.splice.apply(targetParts, lines);
+              j += lines.length - 2;
+            }
+            if(mutual) {
+              for(var k=0, len=splits.points.length; k<len; ++k) {
+                point = splits.points[k];
+                if(!point.equals(vert1)) {
+                  points.push(point);
+                  sourceParts.push(new ZOO.Geometry.LineString(points));
+                  if(point.equals(vert2))
+                    points = [];
+                  else
+                    points = [point.clone()];
+                }
+              }
+            }
+          }
+        }
+      }
+      if(mutual && sourceParts.length > 0 && points.length > 0) {
+        points.push(vert2.clone());
+        sourceParts.push(new ZOO.Geometry.LineString(points));
+      }
+    } else {
+      results = target.splitWith(this, options);
+    }
+    if(targetParts && targetParts.length > 1)
+      targetSplit = true;
+    else
+      targetParts = [];
+    if(sourceParts && sourceParts.length > 1)
+      sourceSplit = true;
+    else
+      sourceParts = [];
+    if(targetSplit || sourceSplit) {
+      if(mutual)
+        results = [sourceParts, targetParts];
+      else
+        results = targetParts;
+    }
+    return results;
+  },
+  /**
+   * Method: splitWith
+   * Split this geometry (the target) with the given geometry (the source).
+   *
+   * Parameters:
+   * geometry - {<ZOO.Geometry>} A geometry used to split this
+   *     geometry (the source).
+   * options - {Object} Properties of this object will be used to determine
+   *     how the split is conducted.
+   *
+   * Valid options:
+   * mutual - {Boolean} Split the source geometry in addition to the target
+   *     geometry.  Default is false.
+   * edge - {Boolean} Allow splitting when only edges intersect.  Default is
+   *     true.  If false, a vertex on the source must be within the tolerance
+   *     distance of the intersection to be considered a split.
+   * tolerance - {Number} If a non-null value is provided, intersections
+   *     within the tolerance distance of an existing vertex on the source
+   *     will be assumed to occur at the vertex.
+   * 
+   * Returns:
+   * {Array} A list of geometries (of this same type as the target) that
+   *     result from splitting the target with the source geometry.  The
+   *     source and target geometry will remain unmodified.  If no split
+   *     results, null will be returned.  If mutual is true and a split
+   *     results, return will be an array of two arrays - the first will be
+   *     all geometries that result from splitting the source geometry and
+   *     the second will be all geometries that result from splitting the
+   *     target geometry.
+   */
+  splitWith: function(geometry, options) {
+    return geometry.split(this, options);
+  },
+  /**
+   * Method: getVertices
+   * Return a list of all points in this geometry.
+   *
+   * Parameters:
+   * nodes - {Boolean} For lines, only return vertices that are
+   *     endpoints.  If false, for lines, only vertices that are not
+   *     endpoints will be returned.  If not provided, all vertices will
+   *     be returned.
+   *
+   * Returns:
+   * {Array} A list of all vertices in the geometry.
+   */
+  getVertices: function(nodes) {
+    var vertices;
+    if(nodes === true)
+      vertices = [
+        this.components[0],
+        this.components[this.components.length-1]
+      ];
+    else if (nodes === false)
+      vertices = this.components.slice(1, this.components.length-1);
+    else
+      vertices = this.components.slice();
+    return vertices;
+  },
+  distanceTo: function(geometry, options) {
+    var edge = !(options && options.edge === false);
+    var details = edge && options && options.details;
+    var result, best = {};
+    var min = Number.POSITIVE_INFINITY;
+    if(geometry instanceof ZOO.Geometry.Point) {
+      var segs = this.getSortedSegments();
+      var x = geometry.x;
+      var y = geometry.y;
+      var seg;
+      for(var i=0, len=segs.length; i<len; ++i) {
+        seg = segs[i];
+        result = ZOO.Geometry.distanceToSegment(geometry, seg);
+        if(result.distance < min) {
+          min = result.distance;
+          best = result;
+          if(min === 0)
+            break;
+        } else {
+          // if distance increases and we cross y0 to the right of x0, no need to keep looking.
+          if(seg.x2 > x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2)))
+            break;
+        }
+      }
+      if(details)
+        best = {
+          distance: best.distance,
+          x0: best.x, y0: best.y,
+          x1: x, y1: y
+        };
+      else
+        best = best.distance;
+    } else if(geometry instanceof ZOO.Geometry.LineString) { 
+      var segs0 = this.getSortedSegments();
+      var segs1 = geometry.getSortedSegments();
+      var seg0, seg1, intersection, x0, y0;
+      var len1 = segs1.length;
+      var interOptions = {point: true};
+      outer: for(var i=0, len=segs0.length; i<len; ++i) {
+        seg0 = segs0[i];
+        x0 = seg0.x1;
+        y0 = seg0.y1;
+        for(var j=0; j<len1; ++j) {
+          seg1 = segs1[j];
+          intersection = ZOO.Geometry.segmentsIntersect(seg0, seg1, interOptions);
+          if(intersection) {
+            min = 0;
+            best = {
+              distance: 0,
+              x0: intersection.x, y0: intersection.y,
+              x1: intersection.x, y1: intersection.y
+            };
+            break outer;
+          } else {
+            result = ZOO.Geometry.distanceToSegment({x: x0, y: y0}, seg1);
+            if(result.distance < min) {
+              min = result.distance;
+              best = {
+                distance: min,
+                x0: x0, y0: y0,
+                x1: result.x, y1: result.y
+              };
+            }
+          }
+        }
+      }
+      if(!details)
+        best = best.distance;
+      if(min !== 0) {
+        // check the final vertex in this line's sorted segments
+        if(seg0) {
+          result = geometry.distanceTo(
+              new ZOO.Geometry.Point(seg0.x2, seg0.y2),
+              options
+              );
+          var dist = details ? result.distance : result;
+          if(dist < min) {
+            if(details)
+              best = {
+                distance: min,
+                x0: result.x1, y0: result.y1,
+                x1: result.x0, y1: result.y0
+              };
+            else
+              best = dist;
+          }
+        }
+      }
+    } else {
+      best = geometry.distanceTo(this, options);
+      // swap since target comes from this line
+      if(details)
+        best = {
+          distance: best.distance,
+          x0: best.x1, y0: best.y1,
+          x1: best.x0, y1: best.y0
+        };
+    }
+    return best;
+  },
+  CLASS_NAME: "ZOO.Geometry.LineString"
+});
+/**
+ * Class: ZOO.Geometry.LinearRing
+ * 
+ * A Linear Ring is a special LineString which is closed. It closes itself 
+ * automatically on every addPoint/removePoint by adding a copy of the first
+ * point as the last point. 
+ * 
+ * Also, as it is the first in the line family to close itself, a getArea()
+ * function is defined to calculate the enclosed area of the linearRing
+ * 
+ * Inherits:
+ *  - <ZOO.Geometry.LineString>
+ */
+ZOO.Geometry.LinearRing = ZOO.Class(
+  ZOO.Geometry.LineString, {
+  /**
+   * Property: componentTypes
+   * {Array(String)} An array of class names representing the types of 
+   *                 components that the collection can include.  A null 
+   *                 value means the component types are not restricted.
+   */
+  componentTypes: ["ZOO.Geometry.Point"],
+  /**
+   * Constructor: ZOO.Geometry.LinearRing
+   * Linear rings are constructed with an array of points.  This array
+   *     can represent a closed or open ring.  If the ring is open (the last
+   *     point does not equal the first point), the constructor will close
+   *     the ring.  If the ring is already closed (the last point does equal
+   *     the first point), it will be left closed.
+   * 
+   * Parameters:
+   * points - {Array(<ZOO.Geometry.Point>)} points
+   */
+  initialize: function(points) {
+    ZOO.Geometry.LineString.prototype.initialize.apply(this,arguments);
+  },
+  /**
+   * Method: addComponent
+   * Adds a point to geometry components.  If the point is to be added to
+   *     the end of the components array and it is the same as the last point
+   *     already in that array, the duplicate point is not added.  This has 
+   *     the effect of closing the ring if it is not already closed, and 
+   *     doing the right thing if it is already closed.  This behavior can 
+   *     be overridden by calling the method with a non-null index as the 
+   *     second argument.
+   *
+   * Parameter:
+   * point - {<ZOO.Geometry.Point>}
+   * index - {Integer} Index into the array to insert the component
+   * 
+   * Returns:
+   * {Boolean} Was the Point successfully added?
+   */
+  addComponent: function(point, index) {
+    var added = false;
+    //remove last point
+    var lastPoint = this.components.pop();
+    // given an index, add the point
+    // without an index only add non-duplicate points
+    if(index != null || !point.equals(lastPoint))
+      added = ZOO.Geometry.Collection.prototype.addComponent.apply(this,arguments);
+    //append copy of first point
+    var firstPoint = this.components[0];
+    ZOO.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);
+    return added;
+  },
+  /**
+   * APIMethod: removeComponent
+   * Removes a point from geometry components.
+   *
+   * Parameters:
+   * point - {<ZOO.Geometry.Point>}
+   */
+  removeComponent: function(point) {
+    if (this.components.length > 4) {
+      //remove last point
+      this.components.pop();
+      //remove our point
+      ZOO.Geometry.Collection.prototype.removeComponent.apply(this,arguments);
+      //append copy of first point
+      var firstPoint = this.components[0];
+      ZOO.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);
+    }
+  },
+  /**
+   * Method: move
+   * Moves a geometry by the given displacement along positive x and y axes.
+   *     This modifies the position of the geometry and clears the cached
+   *     bounds.
+   *
+   * Parameters:
+   * x - {Float} Distance to move geometry in positive x direction. 
+   * y - {Float} Distance to move geometry in positive y direction.
+   */
+  move: function(x, y) {
+    for(var i = 0, len=this.components.length; i<len - 1; i++) {
+      this.components[i].move(x, y);
+    }
+  },
+  /**
+   * Method: rotate
+   * Rotate a geometry around some origin
+   *
+   * Parameters:
+   * angle - {Float} Rotation angle in degrees (measured counterclockwise
+   *                 from the positive x-axis)
+   * origin - {<ZOO.Geometry.Point>} Center point for the rotation
+   */
+  rotate: function(angle, origin) {
+    for(var i=0, len=this.components.length; i<len - 1; ++i) {
+      this.components[i].rotate(angle, origin);
+    }
+  },
+  /**
+   * Method: resize
+   * Resize a geometry relative to some origin.  Use this method to apply
+   *     a uniform scaling to a geometry.
+   *
+   * Parameters:
+   * scale - {Float} Factor by which to scale the geometry.  A scale of 2
+   *                 doubles the size of the geometry in each dimension
+   *                 (lines, for example, will be twice as long, and polygons
+   *                 will have four times the area).
+   * origin - {<ZOO.Geometry.Point>} Point of origin for resizing
+   * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
+   * 
+   * Returns:
+   * {ZOO.Geometry} - The current geometry. 
+   */
+  resize: function(scale, origin, ratio) {
+    for(var i=0, len=this.components.length; i<len - 1; ++i) {
+      this.components[i].resize(scale, origin, ratio);
+    }
+    return this;
+  },
+  /**
+   * Method: transform
+   * Reproject the components geometry from source to dest.
+   *
+   * Parameters:
+   * source - {<ZOO.Projection>}
+   * dest - {<ZOO.Projection>}
+   * 
+   * Returns:
+   * {<ZOO.Geometry>} 
+   */
+  transform: function(source, dest) {
+    if (source && dest) {
+      for (var i=0, len=this.components.length; i<len - 1; i++) {
+        var component = this.components[i];
+        component.transform(source, dest);
+      }
+      this.bounds = null;
+    }
+    return this;
+  },
+  /**
+   * Method: getCentroid
+   *
+   * Returns:
+   * {<ZOO.Geometry.Point>} The centroid of the ring
+   */
+  getCentroid: function() {
+    if ( this.components && (this.components.length > 2)) {
+      var sumX = 0.0;
+      var sumY = 0.0;
+      for (var i = 0; i < this.components.length - 1; i++) {
+        var b = this.components[i];
+        var c = this.components[i+1];
+        sumX += (b.x + c.x) * (b.x * c.y - c.x * b.y);
+        sumY += (b.y + c.y) * (b.x * c.y - c.x * b.y);
+      }
+      var area = -1 * this.getArea();
+      var x = sumX / (6 * area);
+      var y = sumY / (6 * area);
+    }
+    return new ZOO.Geometry.Point(x, y);
+  },
+  /**
+   * Method: getArea
+   * Note - The area is positive if the ring is oriented CW, otherwise
+   *         it will be negative.
+   * 
+   * Returns:
+   * {Float} The signed area for a ring.
+   */
+  getArea: function() {
+    var area = 0.0;
+    if ( this.components && (this.components.length > 2)) {
+      var sum = 0.0;
+      for (var i=0, len=this.components.length; i<len - 1; i++) {
+        var b = this.components[i];
+        var c = this.components[i+1];
+        sum += (b.x + c.x) * (c.y - b.y);
+      }
+      area = - sum / 2.0;
+    }
+    return area;
+  },
+  /**
+   * Method: getGeodesicArea
+   * Calculate the approximate area of the polygon were it projected onto
+   *     the earth.  Note that this area will be positive if ring is oriented
+   *     clockwise, otherwise it will be negative.
+   *
+   * Parameters:
+   * projection - {<ZOO.Projection>} The spatial reference system
+   *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
+   *     assumed.
+   * 
+   * Reference:
+   * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
+   *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
+   *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
+   *
+   * Returns:
+   * {float} The approximate signed geodesic area of the polygon in square
+   *     meters.
+   */
+  getGeodesicArea: function(projection) {
+    var ring = this;  // so we can work with a clone if needed
+    if(projection) {
+      var gg = new ZOO.Projection("EPSG:4326");
+      if(!gg.equals(projection)) {
+        ring = this.clone().transform(projection, gg);
+      }
+    }
+    var area = 0.0;
+    var len = ring.components && ring.components.length;
+    if(len > 2) {
+      var p1, p2;
+      for(var i=0; i<len-1; i++) {
+        p1 = ring.components[i];
+        p2 = ring.components[i+1];
+        area += ZOO.rad(p2.x - p1.x) *
+                (2 + Math.sin(ZOO.rad(p1.y)) +
+                Math.sin(ZOO.rad(p2.y)));
+      }
+      area = area * 6378137.0 * 6378137.0 / 2.0;
+    }
+    return area;
+  },
+  /**
+   * Method: containsPoint
+   * Test if a point is inside a linear ring.  For the case where a point
+   *     is coincident with a linear ring edge, returns 1.  Otherwise,
+   *     returns boolean.
+   *
+   * Parameters:
+   * point - {<ZOO.Geometry.Point>}
+   *
+   * Returns:
+   * {Boolean | Number} The point is inside the linear ring.  Returns 1 if
+   *     the point is coincident with an edge.  Returns boolean otherwise.
+   */
+  containsPoint: function(point) {
+    var approx = OpenLayers.Number.limitSigDigs;
+    var digs = 14;
+    var px = approx(point.x, digs);
+    var py = approx(point.y, digs);
+    function getX(y, x1, y1, x2, y2) {
+      return (((x1 - x2) * y) + ((x2 * y1) - (x1 * y2))) / (y1 - y2);
+    }
+    var numSeg = this.components.length - 1;
+    var start, end, x1, y1, x2, y2, cx, cy;
+    var crosses = 0;
+    for(var i=0; i<numSeg; ++i) {
+      start = this.components[i];
+      x1 = approx(start.x, digs);
+      y1 = approx(start.y, digs);
+      end = this.components[i + 1];
+      x2 = approx(end.x, digs);
+      y2 = approx(end.y, digs);
+
+      /**
+       * The following conditions enforce five edge-crossing rules:
+       *    1. points coincident with edges are considered contained;
+       *    2. an upward edge includes its starting endpoint, and
+       *    excludes its final endpoint;
+       *    3. a downward edge excludes its starting endpoint, and
+       *    includes its final endpoint;
+       *    4. horizontal edges are excluded; and
+       *    5. the edge-ray intersection point must be strictly right
+       *    of the point P.
+       */
+      if(y1 == y2) {
+        // horizontal edge
+        if(py == y1) {
+          // point on horizontal line
+          if(x1 <= x2 && (px >= x1 && px <= x2) || // right or vert
+              x1 >= x2 && (px <= x1 && px >= x2)) { // left or vert
+            // point on edge
+            crosses = -1;
+            break;
+          }
+        }
+        // ignore other horizontal edges
+        continue;
+      }
+      cx = approx(getX(py, x1, y1, x2, y2), digs);
+      if(cx == px) {
+        // point on line
+        if(y1 < y2 && (py >= y1 && py <= y2) || // upward
+            y1 > y2 && (py <= y1 && py >= y2)) { // downward
+          // point on edge
+          crosses = -1;
+          break;
+        }
+      }
+      if(cx <= px) {
+        // no crossing to the right
+        continue;
+      }
+      if(x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) {
+        // no crossing
+        continue;
+      }
+      if(y1 < y2 && (py >= y1 && py < y2) || // upward
+          y1 > y2 && (py < y1 && py >= y2)) { // downward
+        ++crosses;
+      }
+    }
+    var contained = (crosses == -1) ?
+      // on edge
+      1 :
+      // even (out) or odd (in)
+      !!(crosses & 1);
+
+    return contained;
+  },
+  intersects: function(geometry) {
+    var intersect = false;
+    if(geometry.CLASS_NAME == "ZOO.Geometry.Point")
+      intersect = this.containsPoint(geometry);
+    else if(geometry.CLASS_NAME == "ZOO.Geometry.LineString")
+      intersect = geometry.intersects(this);
+    else if(geometry.CLASS_NAME == "ZOO.Geometry.LinearRing")
+      intersect = ZOO.Geometry.LineString.prototype.intersects.apply(
+          this, [geometry]
+          );
+    else
+      for(var i=0, len=geometry.components.length; i<len; ++ i) {
+        intersect = geometry.components[i].intersects(this);
+        if(intersect)
+          break;
+      }
+    return intersect;
+  },
+  getVertices: function(nodes) {
+    return (nodes === true) ? [] : this.components.slice(0, this.components.length-1);
+  },
+  CLASS_NAME: "ZOO.Geometry.LinearRing"
+});
+/**
+ * Class: ZOO.Geometry.MultiLineString
+ * A MultiLineString is a geometry with multiple <ZOO.Geometry.LineString>
+ * components.
+ * 
+ * Inherits from:
+ *  - <ZOO.Geometry.Collection>
+ */
+ZOO.Geometry.MultiLineString = ZOO.Class(
+  ZOO.Geometry.Collection, {
+  componentTypes: ["ZOO.Geometry.LineString"],
+  /**
+   * Constructor: ZOO.Geometry.MultiLineString
+   * Constructor for a MultiLineString Geometry.
+   *
+   * Parameters: 
+   * components - {Array(<ZOO.Geometry.LineString>)} 
+   *
+   */
+  initialize: function(components) {
+    ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments);        
+  },
+  split: function(geometry, options) {
+    var results = null;
+    var mutual = options && options.mutual;
+    var splits, sourceLine, sourceLines, sourceSplit, targetSplit;
+    var sourceParts = [];
+    var targetParts = [geometry];
+    for(var i=0, len=this.components.length; i<len; ++i) {
+      sourceLine = this.components[i];
+      sourceSplit = false;
+      for(var j=0; j < targetParts.length; ++j) { 
+        splits = sourceLine.split(targetParts[j], options);
+        if(splits) {
+          if(mutual) {
+            sourceLines = splits[0];
+            for(var k=0, klen=sourceLines.length; k<klen; ++k) {
+              if(k===0 && sourceParts.length)
+                sourceParts[sourceParts.length-1].addComponent(
+                  sourceLines[k]
+                );
+              else
+                sourceParts.push(
+                  new ZOO.Geometry.MultiLineString([
+                    sourceLines[k]
+                    ])
+                );
+            }
+            sourceSplit = true;
+            splits = splits[1];
+          }
+          if(splits.length) {
+            // splice in new target parts
+            splits.unshift(j, 1);
+            Array.prototype.splice.apply(targetParts, splits);
+            break;
+          }
+        }
+      }
+      if(!sourceSplit) {
+        // source line was not hit
+        if(sourceParts.length) {
+          // add line to existing multi
+          sourceParts[sourceParts.length-1].addComponent(
+              sourceLine.clone()
+              );
+        } else {
+          // create a fresh multi
+          sourceParts = [
+            new ZOO.Geometry.MultiLineString(
+                sourceLine.clone()
+                )
+            ];
+        }
+      }
+    }
+    if(sourceParts && sourceParts.length > 1)
+      sourceSplit = true;
+    else
+      sourceParts = [];
+    if(targetParts && targetParts.length > 1)
+      targetSplit = true;
+    else
+      targetParts = [];
+    if(sourceSplit || targetSplit) {
+      if(mutual)
+        results = [sourceParts, targetParts];
+      else
+        results = targetParts;
+    }
+    return results;
+  },
+  splitWith: function(geometry, options) {
+    var results = null;
+    var mutual = options && options.mutual;
+    var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts;
+    if(geometry instanceof ZOO.Geometry.LineString) {
+      targetParts = [];
+      sourceParts = [geometry];
+      for(var i=0, len=this.components.length; i<len; ++i) {
+        targetSplit = false;
+        targetLine = this.components[i];
+        for(var j=0; j<sourceParts.length; ++j) {
+          splits = sourceParts[j].split(targetLine, options);
+          if(splits) {
+            if(mutual) {
+              sourceLines = splits[0];
+              if(sourceLines.length) {
+                // splice in new source parts
+                sourceLines.unshift(j, 1);
+                Array.prototype.splice.apply(sourceParts, sourceLines);
+                j += sourceLines.length - 2;
+              }
+              splits = splits[1];
+              if(splits.length === 0) {
+                splits = [targetLine.clone()];
+              }
+            }
+            for(var k=0, klen=splits.length; k<klen; ++k) {
+              if(k===0 && targetParts.length) {
+                targetParts[targetParts.length-1].addComponent(
+                    splits[k]
+                    );
+              } else {
+                targetParts.push(
+                    new ZOO.Geometry.MultiLineString([
+                      splits[k]
+                      ])
+                    );
+              }
+            }
+            targetSplit = true;                    
+          }
+        }
+        if(!targetSplit) {
+          // target component was not hit
+          if(targetParts.length) {
+            // add it to any existing multi-line
+            targetParts[targetParts.length-1].addComponent(
+                targetLine.clone()
+                );
+          } else {
+            // or start with a fresh multi-line
+            targetParts = [
+              new ZOO.Geometry.MultiLineString([
+                  targetLine.clone()
+                  ])
+              ];
+          }
+
+        }
+      }
+    } else {
+      results = geometry.split(this);
+    }
+    if(sourceParts && sourceParts.length > 1)
+      sourceSplit = true;
+    else
+      sourceParts = [];
+    if(targetParts && targetParts.length > 1)
+      targetSplit = true;
+    else
+      targetParts = [];
+    if(sourceSplit || targetSplit) {
+      if(mutual)
+        results = [sourceParts, targetParts];
+      else
+        results = targetParts;
+    }
+    return results;
+  },
+  CLASS_NAME: "ZOO.Geometry.MultiLineString"
+});
+/**
+ * Class: ZOO.Geometry.Polygon 
+ * Polygon is a collection of <ZOO.Geometry.LinearRing>. 
+ * 
+ * Inherits from:
+ *  - <ZOO.Geometry.Collection> 
+ */
+ZOO.Geometry.Polygon = ZOO.Class(
+  ZOO.Geometry.Collection, {
+  componentTypes: ["ZOO.Geometry.LinearRing"],
+  /**
+   * Constructor: ZOO.Geometry.Polygon
+   * Constructor for a Polygon geometry. 
+   * The first ring (this.component[0])is the outer bounds of the polygon and 
+   * all subsequent rings (this.component[1-n]) are internal holes.
+   *
+   *
+   * Parameters:
+   * components - {Array(<ZOO.Geometry.LinearRing>)} 
+   */
+  initialize: function(components) {
+    ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments);
+  },
+  /** 
+   * Method: getArea
+   * Calculated by subtracting the areas of the internal holes from the 
+   *   area of the outer hole.
+   * 
+   * Returns:
+   * {float} The area of the geometry
+   */
+  getArea: function() {
+    var area = 0.0;
+    if ( this.components && (this.components.length > 0)) {
+      area += Math.abs(this.components[0].getArea());
+      for (var i=1, len=this.components.length; i<len; i++) {
+        area -= Math.abs(this.components[i].getArea());
+      }
+    }
+    return area;
+  },
+  /** 
+   * APIMethod: getGeodesicArea
+   * Calculate the approximate area of the polygon were it projected onto
+   *     the earth.
+   *
+   * Parameters:
+   * projection - {<ZOO.Projection>} The spatial reference system
+   *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
+   *     assumed.
+   * 
+   * Reference:
+   * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
+   *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
+   *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
+   *
+   * Returns:
+   * {float} The approximate geodesic area of the polygon in square meters.
+   */
+  getGeodesicArea: function(projection) {
+    var area = 0.0;
+    if(this.components && (this.components.length > 0)) {
+      area += Math.abs(this.components[0].getGeodesicArea(projection));
+      for(var i=1, len=this.components.length; i<len; i++) {
+          area -= Math.abs(this.components[i].getGeodesicArea(projection));
+      }
+    }
+    return area;
+  },
+  /**
+   * Method: containsPoint
+   * Test if a point is inside a polygon.  Points on a polygon edge are
+   *     considered inside.
+   *
+   * Parameters:
+   * point - {<ZOO.Geometry.Point>}
+   *
+   * Returns:
+   * {Boolean | Number} The point is inside the polygon.  Returns 1 if the
+   *     point is on an edge.  Returns boolean otherwise.
+   */
+  containsPoint: function(point) {
+    var numRings = this.components.length;
+    var contained = false;
+    if(numRings > 0) {
+    // check exterior ring - 1 means on edge, boolean otherwise
+      contained = this.components[0].containsPoint(point);
+      if(contained !== 1) {
+        if(contained && numRings > 1) {
+          // check interior rings
+          var hole;
+          for(var i=1; i<numRings; ++i) {
+            hole = this.components[i].containsPoint(point);
+            if(hole) {
+              if(hole === 1)
+                contained = 1;
+              else
+                contained = false;
+              break;
+            }
+          }
+        }
+      }
+    }
+    return contained;
+  },
+  intersects: function(geometry) {
+    var intersect = false;
+    var i, len;
+    if(geometry.CLASS_NAME == "ZOO.Geometry.Point") {
+      intersect = this.containsPoint(geometry);
+    } else if(geometry.CLASS_NAME == "ZOO.Geometry.LineString" ||
+              geometry.CLASS_NAME == "ZOO.Geometry.LinearRing") {
+      // check if rings/linestrings intersect
+      for(i=0, len=this.components.length; i<len; ++i) {
+        intersect = geometry.intersects(this.components[i]);
+        if(intersect) {
+          break;
+        }
+      }
+      if(!intersect) {
+        // check if this poly contains points of the ring/linestring
+        for(i=0, len=geometry.components.length; i<len; ++i) {
+          intersect = this.containsPoint(geometry.components[i]);
+          if(intersect) {
+            break;
+          }
+        }
+      }
+    } else {
+      for(i=0, len=geometry.components.length; i<len; ++ i) {
+        intersect = this.intersects(geometry.components[i]);
+        if(intersect)
+          break;
+      }
+    }
+    // check case where this poly is wholly contained by another
+    if(!intersect && geometry.CLASS_NAME == "ZOO.Geometry.Polygon") {
+      // exterior ring points will be contained in the other geometry
+      var ring = this.components[0];
+      for(i=0, len=ring.components.length; i<len; ++i) {
+        intersect = geometry.containsPoint(ring.components[i]);
+        if(intersect)
+          break;
+      }
+    }
+    return intersect;
+  },
+  distanceTo: function(geometry, options) {
+    var edge = !(options && options.edge === false);
+    var result;
+    // this is the case where we might not be looking for distance to edge
+    if(!edge && this.intersects(geometry))
+      result = 0;
+    else
+      result = ZOO.Geometry.Collection.prototype.distanceTo.apply(
+          this, [geometry, options]
+          );
+    return result;
+  },
+  CLASS_NAME: "ZOO.Geometry.Polygon"
+});
+/**
+ * Method: createRegularPolygon
+ * Create a regular polygon around a radius. Useful for creating circles 
+ * and the like.
+ *
+ * Parameters:
+ * origin - {<ZOO.Geometry.Point>} center of polygon.
+ * radius - {Float} distance to vertex, in map units.
+ * sides - {Integer} Number of sides. 20 approximates a circle.
+ * rotation - {Float} original angle of rotation, in degrees.
+ */
+ZOO.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {  
+    var angle = Math.PI * ((1/sides) - (1/2));
+    if(rotation) {
+        angle += (rotation / 180) * Math.PI;
+    }
+    var rotatedAngle, x, y;
+    var points = [];
+    for(var i=0; i<sides; ++i) {
+        rotatedAngle = angle + (i * 2 * Math.PI / sides);
+        x = origin.x + (radius * Math.cos(rotatedAngle));
+        y = origin.y + (radius * Math.sin(rotatedAngle));
+        points.push(new ZOO.Geometry.Point(x, y));
+    }
+    var ring = new ZOO.Geometry.LinearRing(points);
+    return new ZOO.Geometry.Polygon([ring]);
+};
+/**
+ * Class: ZOO.Geometry.MultiPolygon
+ * MultiPolygon is a geometry with multiple <ZOO.Geometry.Polygon>
+ * components.  Create a new instance with the <ZOO.Geometry.MultiPolygon>
+ * constructor.
+ * 
+ * Inherits from:
+ *  - <ZOO.Geometry.Collection>
+ */
+ZOO.Geometry.MultiPolygon = ZOO.Class(
+  ZOO.Geometry.Collection, {
+  componentTypes: ["ZOO.Geometry.Polygon"],
+  /**
+   * Constructor: ZOO.Geometry.MultiPolygon
+   * Create a new MultiPolygon geometry
+   *
+   * Parameters:
+   * components - {Array(<ZOO.Geometry.Polygon>)} An array of polygons
+   *              used to generate the MultiPolygon
+   *
+   */
+  initialize: function(components) {
+    ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments);
+  },
+  CLASS_NAME: "ZOO.Geometry.MultiPolygon"
+});
+/**
+ * Class: ZOO.Process
+ * Used to query OGC WPS process defined by its URL and its identifier. 
+ * Usefull for chaining localhost process.
+ */
+ZOO.Process = ZOO.Class({
+  /**
+   * Property: schemaLocation
+   * {String} Schema location for a particular minor version.
+   */
+  schemaLocation: "http://www.opengis.net/wps/1.0.0/../wpsExecute_request.xsd",
+  /**
+   * Property: namespaces
+   * {Object} Mapping of namespace aliases to namespace URIs.
+   */
+  namespaces: {
+    ows: "http://www.opengis.net/ows/1.1",
+    wps: "http://www.opengis.net/wps/1.0.0",
+    xlink: "http://www.w3.org/1999/xlink",
+    xsi: "http://www.w3.org/2001/XMLSchema-instance",
+  },
+  /**
+   * Property: url
+   * {String} The OGC's Web PRocessing Service URL, 
+   *          default is http://localhost/zoo.
+   */
+  url: 'http://localhost/zoo',
+  /**
+   * Property: identifier
+   * {String} Process identifier in the OGC's Web Processing Service.
+   */
+  identifier: null,
+  /**
+   * Property: async
+   * {Bool} Define if the process should run asyncrhonously (true) or not (false, default).
+   */
+  async: null,
+  /**
+   * Constructor: ZOO.Process
+   * Create a new Process
+   *
+   * Parameters:
+   * url - {String} The OGC's Web Processing Service URL.
+   * identifier - {String} The process identifier in the OGC's Web Processing Service.
+   *
+   */
+  initialize: function(url,identifier) {
+    this.url = url;
+    this.identifier = identifier;
+    this.async = (arguments.length>2?arguments[2]:false);
+  },
+  /**
+   * Method: Execute
+   * Query the OGC's Web PRocessing Servcie to Execute the process.
+   *
+   * Parameters:
+   * inputs - {Object}
+   *
+   * Returns:
+   * {String} The OGC's Web processing Service XML response. The result 
+   *          needs to be interpreted.
+   */
+  Execute: function(inputs,outputs) {
+    if (this.identifier == null)
+      return null;
+      var body = new XML('<wps:Execute service="WPS" version="1.0.0" xmlns:wps="'+this.namespaces['wps']+'" xmlns:ows="'+this.namespaces['ows']+'" xmlns:xlink="'+this.namespaces['xlink']+'" xmlns:xsi="'+this.namespaces['xsi']+'" xsi:schemaLocation="'+this.schemaLocation+'"><ows:Identifier>'+this.identifier+'</ows:Identifier>'+this.buildDataInputsNode(inputs)+this.buildDataOutputsNode(outputs)+'</wps:Execute>');
+    body = body.toXMLString();
+    var headers=['Content-Type: text/xml; charset=UTF-8'];
+    if(arguments.length>2){
+      headers[headers.length]=arguments[2];
+    }
+    var response = ZOO.Request.Post(this.url,body,headers);
+    return response;
+  },
+  buildOutput:{
+    /**
+     * Method: buildOutput.ResponseDocument
+     * Given an E4XElement representing the WPS ResponseDocument output.
+     *
+     * Parameters:
+     * identifier - {String} the input indetifier
+     * data - {Object} A WPS complex data input.
+     *
+     * Returns:
+     * {E4XElement} A WPS Input node.
+     */
+    'ResponseDocument': function(identifier,obj) {
+      var output = new XML('<wps:Output xmlns:wps="'+this.namespaces['wps']+'" '+(obj["mimeType"]?' mimeType="'+obj["mimeType"]+'" ':'')+(obj["encoding"]?' encoding="'+obj["encoding"]+'" ':'')+(obj["asReference"]?' asReference="'+obj["asReference"]+'" ':'')+'><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier></wps:Output>');
+      output = output.toXMLString();
+      return output;
+    },
+    'RawDataOutput': function(identifier,obj) {
+      var output = new XML('<wps:RawDataOutput xmlns:wps="'+this.namespaces['wps']+'" '+(obj["mimeType"]?' mimeType="'+obj["mimeType"]+'" ':'')+(obj["encoding"]?' encoding="'+obj["encoding"]+'" ':'')+'><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier></wps:RawDataOutput>');
+      if (obj.encoding)
+        output.*::Data.*::ComplexData.@encoding = obj.encoding;
+      if (obj.schema)
+        output.*::Data.*::ComplexData.@schema = obj.schema;
+      output = output.toXMLString();
+      return output;
+    }
+
+  },
+  /**
+   * Property: buildInput
+   * Object containing methods to build WPS inputs.
+   */
+  buildInput: {
+    /**
+     * Method: buildInput.complex
+     * Given an E4XElement representing the WPS complex data input.
+     *
+     * Parameters:
+     * identifier - {String} the input indetifier
+     * data - {Object} A WPS complex data input.
+     *
+     * Returns:
+     * {E4XElement} A WPS Input node.
+     */
+    'complex': function(identifier,data) {
+      var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier>'+(data.value?'<wps:Data><wps:ComplexData '+(data.mimeType?'mimeType="'+data.mimeType+'"':"")+'><![CDATA['+data.value+']]></wps:ComplexData></wps:Data>':(data.xlink?'<wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.xlink+'" mimeType="'+data.mimeType+'" />':''))+'</wps:Input>');
+      if(data.xlink)
+        input.*::Reference.@mimeType = data.mimetype ? data.mimetype : 'application/json';
+      else
+        input.*::Data.*::ComplexData.@mimeType = data.mimetype ? data.mimetype : 'application/json';
+      if (data.encoding)
+        input.*::Data.*::ComplexData.@encoding = data.encoding;
+      if (data.schema)
+        input.*::Data.*::ComplexData.@schema = data.schema;
+      input = input.toXMLString();
+      if(data.value)
+        return (('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier>'+(data.value?'<wps:Data><wps:ComplexData '+(data.mimeType?'mimeType="'+data.mimeType+'"':"")+'><![CDATA['+data.value+']]></wps:ComplexData></wps:Data>':(data.xlink?'<wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.xlink+'" mimeType="'+data.mimeType+'" />':''))+'</wps:Input>'));
+      else
+        return input;
+    },
+    /**
+     * Method: buildInput.reference
+     * Given an E4XElement representing the WPS reference input.
+     *
+     * Parameters:
+     * identifier - {String} the input indetifier
+     * data - {Object} A WPS reference input.
+     *
+     * Returns:
+     * {E4XElement} A WPS Input node.
+     */
+    'reference': function(identifier,data) {
+      return '<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.value.replace('&','&amp;','gi')+'"/></wps:Input>';
+    },
+    /**
+     * Method: buildInput.literal
+     * Given an E4XElement representing the WPS literal data input.
+     *
+     * Parameters:
+     * identifier - {String} the input indetifier
+     * data - {Object} A WPS literal data input.
+     *
+     * Returns:
+     * {E4XElement} The WPS Input node.
+     */
+    'literal': function(identifier,data) {
+      if(data && !eval(data["isArray"])){
+        var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:LiteralData>'+data.value+'</wps:LiteralData></wps:Data></wps:Input>');
+        if (data.type)
+	  input.*::Data.*::LiteralData.@dataType = data.type;
+        if (data.uom)
+	  input.*::Data.*::LiteralData.@uom = data.uom;
+        input = input.toXMLString();
+        return input;
+      }else if(data){
+        var inputf="";
+        for(i=0;i<parseInt(data["length"]);i++){
+	  var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:LiteralData>'+data.value[i]+'</wps:LiteralData></wps:Data></wps:Input>');
+	  if (data.type)
+	    input.*::Data.*::LiteralData.@dataType = data.type;
+	  if (data.uom)
+	    input.*::Data.*::LiteralData.@uom = data.uom;
+	  inputf += input.toXMLString();
+	}
+        return inputf;
+      }	
+    }
+  },
+  /**
+   * Method: buildDataInputsNode
+   * Method to build the WPS DataInputs element.
+   *
+   * Parameters:
+   * inputs - {Object}
+   *
+   * Returns:
+   * {E4XElement} The WPS DataInputs node for Execute query.
+   */
+  buildDataInputsNode:function(inputs){
+    var data, builder, inputsArray=[];
+    for (var attr in inputs) {
+      data = inputs[attr];
+	if (data && (data.mimetype || data.type == 'complex'))
+        builder = this.buildInput['complex'];
+	else if (data && (data.type == 'reference' || data.type == 'url'))
+        builder = this.buildInput['reference'];
+      else
+        builder = this.buildInput['literal'];
+      inputsArray.push(builder.apply(this,[attr,data]));
+    }
+    return '<wps:DataInputs xmlns:wps="'+this.namespaces['wps']+'">'+inputsArray.join('\n')+'</wps:DataInputs>';
+  },
+
+  buildDataOutputsNode:function(outputs){
+    var data, builder, outputsArray=[[],[]];
+    for (var attr in outputs) {
+      data = outputs[attr];
+      builder = this.buildOutput[data.type];
+      if(data.type=="ResponseDocument")
+        outputsArray[0].push(builder.apply(this,[attr,data]));
+      else
+        outputsArray[1].push(builder.apply(this,[attr,data]));	    
+    }
+    var responseDocuments=(outputsArray[0].length>0?
+			   new XML('<wps:ResponseDocument  '+(this.async?'storeExecuteResponse="true" status="true"':'')+' xmlns:wps="'+this.namespaces['wps']+'">'+
+				   outputsArray[0].join('\n')+
+				   '</wps:ResponseDocument>')
+			   :
+			   null);
+    var rawDataOutputs=(outputsArray[1].length>0?
+			outputsArray[1].join('\n')
+			:
+			null);
+    var res=new XML('<wps:ResponseForm xmlns:wps="'+this.namespaces['wps']+'">'+
+		    (responseDocuments!=null?responseDocuments.toXMLString():"")+
+		    (rawDataOutputs!=null?rawDataOutputs:"")+
+		    '</wps:ResponseForm>');
+    return res.toXMLString();
+  },
+
+  CLASS_NAME: "ZOO.Process"
+});
Index: /tags/rel-1.7.0/zoo-project/zoo-api/js/ZOO-proj4js.js
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/js/ZOO-proj4js.js	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/js/ZOO-proj4js.js	(revision 942)
@@ -0,0 +1,258 @@
+/*
+  proj4js.js -- Javascript reprojection library. 
+  
+  Authors:      Mike Adair madairATdmsolutions.ca
+                Richard Greenwood richATgreenwoodmap.com
+                Didier Richard didier.richardATign.fr
+                Stephen Irons
+  License:      MIT as per: http://trac.osgeo.org/proj4js/browser/trunk/LICENSE
+                Note: This program is an almost direct port of the C library
+                Proj4.
+*/
+
+/**
+ * Author : René-Luc D'Hont
+ *
+ * Copyright 2010 3liz SARL. All rights reserved.
+ */
+
+Proj4js={defaultDatum:'WGS84',transform:function(source,dest,point){if(!source.readyToUse||!dest.readyToUse){this.reportError("Proj4js initialization for "+source.srsCode+" not yet complete");return point;}
+if((source.srsProjNumber=="900913"&&dest.datumCode!="WGS84")||(dest.srsProjNumber=="900913"&&source.datumCode!="WGS84")){var wgs84=Proj4js.WGS84;this.transform(source,wgs84,point);source=wgs84;}
+if(source.projName=="longlat"){point.x*=Proj4js.common.D2R;point.y*=Proj4js.common.D2R;}else{if(source.to_meter){point.x*=source.to_meter;point.y*=source.to_meter;}
+source.inverse(point);}
+if(source.from_greenwich){point.x+=source.from_greenwich;}
+point=this.datum_transform(source.datum,dest.datum,point);if(dest.from_greenwich){point.x-=dest.from_greenwich;}
+if(dest.projName=="longlat"){point.x*=Proj4js.common.R2D;point.y*=Proj4js.common.R2D;}else{dest.forward(point);if(dest.to_meter){point.x/=dest.to_meter;point.y/=dest.to_meter;}}
+return point;},datum_transform:function(source,dest,point){if(source.compare_datums(dest)){return point;}
+if(source.datum_type==Proj4js.common.PJD_NODATUM||dest.datum_type==Proj4js.common.PJD_NODATUM){return point;}
+if(source.datum_type==Proj4js.common.PJD_GRIDSHIFT)
+{alert("ERROR: Grid shift transformations are not implemented yet.");}
+if(dest.datum_type==Proj4js.common.PJD_GRIDSHIFT)
+{alert("ERROR: Grid shift transformations are not implemented yet.");}
+if(source.es!=dest.es||source.a!=dest.a||source.datum_type==Proj4js.common.PJD_3PARAM||source.datum_type==Proj4js.common.PJD_7PARAM||dest.datum_type==Proj4js.common.PJD_3PARAM||dest.datum_type==Proj4js.common.PJD_7PARAM)
+{source.geodetic_to_geocentric(point);if(source.datum_type==Proj4js.common.PJD_3PARAM||source.datum_type==Proj4js.common.PJD_7PARAM){source.geocentric_to_wgs84(point);}
+if(dest.datum_type==Proj4js.common.PJD_3PARAM||dest.datum_type==Proj4js.common.PJD_7PARAM){dest.geocentric_from_wgs84(point);}
+dest.geocentric_to_geodetic(point);}
+if(dest.datum_type==Proj4js.common.PJD_GRIDSHIFT)
+{alert("ERROR: Grid shift transformations are not implemented yet.");}
+return point;},reportError:function(msg){},extend:function(destination,source){destination=destination||{};if(source){for(var property in source){var value=source[property];if(value!==undefined){destination[property]=value;}}}
+return destination;},Class:function(){var Class=function(){this.initialize.apply(this,arguments);};var extended={};var parent;for(var i=0;i<arguments.length;++i){if(typeof arguments[i]=="function"){parent=arguments[i].prototype;}else{parent=arguments[i];}
+Proj4js.extend(extended,parent);}
+Class.prototype=extended;return Class;},bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},scriptName:"proj4js-compressed.js",defsLookupService:'http://spatialreference.org/ref',libPath:null,getScriptLocation:function(){if(this.libPath)return this.libPath;var scriptName=this.scriptName;var scriptNameLen=scriptName.length;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);if((index>-1)&&(index+scriptNameLen==src.length)){this.libPath=src.slice(0,-scriptNameLen);break;}}}
+return this.libPath||"";},
+  loadScript:function(url,onload,onfail,loadCheck){
+    var script = [];
+  var script = ZOORequest('GET',url);
+  try {
+    eval(script);
+    onload();
+  } catch (e) {
+    onfail();
+  }
+    /*
+    var script=document.createElement('script');
+    script.defer=false;
+    script.type="text/javascript";
+    script.id=url;
+    script.src=url;
+    script.onload=onload;
+    script.onerror=onfail;
+    script.loadCheck=loadCheck;
+    if(/MSIE/.test(navigator.userAgent)){script.onreadystatechange=this.checkReadyState;}
+    document.getElementsByTagName('head')[0].appendChild(script);
+    */
+  },
+  checkReadyState:function(){if(this.readyState=='loaded'){if(!this.loadCheck()){this.onerror();}else{this.onload();}}}};Proj4js.Proj=Proj4js.Class({readyToUse:false,title:null,projName:null,units:null,datum:null,x0:0,y0:0,initialize:function(srsCode){this.srsCodeInput=srsCode;if(srsCode.indexOf('urn:')==0){var urn=srsCode.split(':');if((urn[1]=='ogc'||urn[1]=='x-ogc')&&(urn[2]=='def')&&(urn[3]=='crs')){srsCode=urn[4]+':'+urn[urn.length-1];}}else if(srsCode.indexOf('http://')==0){var url=srsCode.split('#');if(url[0].match(/epsg.org/)){srsCode='EPSG:'+url[1];}else if(url[0].match(/RIG.xml/)){srsCode='IGNF:'+url[1];}}
+this.srsCode=srsCode.toUpperCase();if(this.srsCode.indexOf("EPSG")==0){this.srsCode=this.srsCode;this.srsAuth='epsg';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("IGNF")==0){this.srsCode=this.srsCode;this.srsAuth='IGNF';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("CRS")==0){this.srsCode=this.srsCode;this.srsAuth='CRS';this.srsProjNumber=this.srsCode.substring(4);}else{this.srsAuth='';this.srsProjNumber=this.srsCode;}
+this.loadProjDefinition();},
+  loadProjDefinition:function(){
+    if(Proj4js.defs[this.srsCode]){this.defsLoaded();return;}
+    this.loadFromService();
+  /*
+    var url=Proj4js.getScriptLocation()+'defs/'+this.srsAuth.toUpperCase()+this.srsProjNumber+'.js';
+    Proj4js.loadScript(url,Proj4js.bind(this.defsLoaded,this),Proj4js.bind(this.loadFromService,this),Proj4js.bind(this.checkDefsLoaded,this));
+    */
+  },
+  loadFromService:function(){var url=Proj4js.defsLookupService+'/'+this.srsAuth+'/'+this.srsProjNumber+'/proj4js/';Proj4js.loadScript(url,Proj4js.bind(this.defsLoaded,this),Proj4js.bind(this.defsFailed,this),Proj4js.bind(this.checkDefsLoaded,this));},defsLoaded:function(){this.parseDefs();this.loadProjCode(this.projName);},checkDefsLoaded:function(){if(Proj4js.defs[this.srsCode]){return true;}else{return false;}},defsFailed:function(){Proj4js.reportError('failed to load projection definition for: '+this.srsCode);Proj4js.defs[this.srsCode]=Proj4js.defs['WGS84'];this.defsLoaded();},
+  loadProjCode:function(projName){
+    if(Proj4js.Proj[projName]){this.initTransforms();return;}
+    var url=Proj4js.getScriptLocation()+'projCode/'+projName+'.js';
+    Proj4js.loadScript(url,Proj4js.bind(this.loadProjCodeSuccess,this,projName),Proj4js.bind(this.loadProjCodeFailure,this,projName),Proj4js.bind(this.checkCodeLoaded,this,projName));
+  },
+  loadProjCodeSuccess:function(projName){if(Proj4js.Proj[projName].dependsOn){this.loadProjCode(Proj4js.Proj[projName].dependsOn);}else{this.initTransforms();}},loadProjCodeFailure:function(projName){Proj4js.reportError("failed to find projection file for: "+projName);},checkCodeLoaded:function(projName){if(Proj4js.Proj[projName]){return true;}else{return false;}},initTransforms:function(){Proj4js.extend(this,Proj4js.Proj[this.projName]);this.init();this.readyToUse=true;},parseDefs:function(){this.defData=Proj4js.defs[this.srsCode];var paramName,paramVal;if(!this.defData){return;}
+var paramArray=this.defData.split("+");for(var prop=0;prop<paramArray.length;prop++){var property=paramArray[prop].split("=");paramName=property[0].toLowerCase();paramVal=property[1];switch(paramName.replace(/\s/gi,"")){case"":break;case"title":this.title=paramVal;break;case"proj":this.projName=paramVal.replace(/\s/gi,"");break;case"units":this.units=paramVal.replace(/\s/gi,"");break;case"datum":this.datumCode=paramVal.replace(/\s/gi,"");break;case"nadgrids":this.nagrids=paramVal.replace(/\s/gi,"");break;case"ellps":this.ellps=paramVal.replace(/\s/gi,"");break;case"a":this.a=parseFloat(paramVal);break;case"b":this.b=parseFloat(paramVal);break;case"rf":this.rf=parseFloat(paramVal);break;case"lat_0":this.lat0=paramVal*Proj4js.common.D2R;break;case"lat_1":this.lat1=paramVal*Proj4js.common.D2R;break;case"lat_2":this.lat2=paramVal*Proj4js.common.D2R;break;case"lat_ts":this.lat_ts=paramVal*Proj4js.common.D2R;break;case"lon_0":this.long0=paramVal*Proj4js.common.D2R;break;case"alpha":this.alpha=parseFloat(paramVal)*Proj4js.common.D2R;break;case"lonc":this.longc=paramVal*Proj4js.common.D2R;break;case"x_0":this.x0=parseFloat(paramVal);break;case"y_0":this.y0=parseFloat(paramVal);break;case"k_0":this.k0=parseFloat(paramVal);break;case"k":this.k0=parseFloat(paramVal);break;case"r_a":this.R_A=true;break;case"zone":this.zone=parseInt(paramVal);break;case"south":this.utmSouth=true;break;case"towgs84":this.datum_params=paramVal.split(",");break;case"to_meter":this.to_meter=parseFloat(paramVal);break;case"from_greenwich":this.from_greenwich=paramVal*Proj4js.common.D2R;break;case"pm":paramVal=paramVal.replace(/\s/gi,"");this.from_greenwich=Proj4js.PrimeMeridian[paramVal]?Proj4js.PrimeMeridian[paramVal]:parseFloat(paramVal);this.from_greenwich*=Proj4js.common.D2R;break;case"no_defs":break;default:}}
+this.deriveConstants();},deriveConstants:function(){if(this.nagrids=='@null')this.datumCode='none';if(this.datumCode&&this.datumCode!='none'){var datumDef=Proj4js.Datum[this.datumCode];if(datumDef){this.datum_params=datumDef.towgs84?datumDef.towgs84.split(','):null;this.ellps=datumDef.ellipse;this.datumName=datumDef.datumName?datumDef.datumName:this.datumCode;}}
+if(!this.a){var ellipse=Proj4js.Ellipsoid[this.ellps]?Proj4js.Ellipsoid[this.ellps]:Proj4js.Ellipsoid['WGS84'];Proj4js.extend(this,ellipse);}
+if(this.rf&&!this.b)this.b=(1.0-1.0/this.rf)*this.a;if(Math.abs(this.a-this.b)<Proj4js.common.EPSLN){this.sphere=true;this.b=this.a;}
+this.a2=this.a*this.a;this.b2=this.b*this.b;this.es=(this.a2-this.b2)/this.a2;this.e=Math.sqrt(this.es);if(this.R_A){this.a*=1.-this.es*(Proj4js.common.SIXTH+this.es*(Proj4js.common.RA4+this.es*Proj4js.common.RA6));this.a2=this.a*this.a;this.b2=this.b*this.b;this.es=0.;}
+this.ep2=(this.a2-this.b2)/this.b2;if(!this.k0)this.k0=1.0;this.datum=new Proj4js.datum(this);}});Proj4js.Proj.longlat={init:function(){},forward:function(pt){return pt;},inverse:function(pt){return pt;}};Proj4js.defs={'WGS84':"+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4326':"+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4269':"+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees",'EPSG:3785':"+title= Google Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"};Proj4js.defs['GOOGLE']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:900913']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:102113']=Proj4js.defs['EPSG:3785'];Proj4js.common={PI:3.141592653589793238,HALF_PI:1.570796326794896619,TWO_PI:6.283185307179586477,FORTPI:0.78539816339744833,R2D:57.29577951308232088,D2R:0.01745329251994329577,SEC_TO_RAD:4.84813681109535993589914102357e-6,EPSLN:1.0e-10,MAX_ITER:20,COS_67P5:0.38268343236508977,AD_C:1.0026000,PJD_UNKNOWN:0,PJD_3PARAM:1,PJD_7PARAM:2,PJD_GRIDSHIFT:3,PJD_WGS84:4,PJD_NODATUM:5,SRS_WGS84_SEMIMAJOR:6378137.0,SIXTH:.1666666666666666667,RA4:.04722222222222222222,RA6:.02215608465608465608,RV4:.06944444444444444444,RV6:.04243827160493827160,msfnz:function(eccent,sinphi,cosphi){var con=eccent*sinphi;return cosphi/(Math.sqrt(1.0-con*con));},tsfnz:function(eccent,phi,sinphi){var con=eccent*sinphi;var com=.5*eccent;con=Math.pow(((1.0-con)/(1.0+con)),com);return(Math.tan(.5*(this.HALF_PI-phi))/con);},phi2z:function(eccent,ts){var eccnth=.5*eccent;var con,dphi;var phi=this.HALF_PI-2*Math.atan(ts);for(i=0;i<=15;i++){con=eccent*Math.sin(phi);dphi=this.HALF_PI-2*Math.atan(ts*(Math.pow(((1.0-con)/(1.0+con)),eccnth)))-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001)return phi;}
+alert("phi2z has NoConvergence");return(-9999);},qsfnz:function(eccent,sinphi){var con;if(eccent>1.0e-7){con=eccent*sinphi;return((1.0-eccent*eccent)*(sinphi/(1.0-con*con)-(.5/eccent)*Math.log((1.0-con)/(1.0+con))));}else{return(2.0*sinphi);}},asinz:function(x){if(Math.abs(x)>1.0){x=(x>1.0)?1.0:-1.0;}
+return Math.asin(x);},e0fn:function(x){return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));},e1fn:function(x){return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));},e2fn:function(x){return(0.05859375*x*x*(1.0+0.75*x));},e3fn:function(x){return(x*x*x*(35.0/3072.0));},mlfn:function(e0,e1,e2,e3,phi){return(e0*phi-e1*Math.sin(2.0*phi)+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi));},srat:function(esinp,exp){return(Math.pow((1.0-esinp)/(1.0+esinp),exp));},sign:function(x){if(x<0.0)return(-1);else return(1);},adjust_lon:function(x){x=(Math.abs(x)<this.PI)?x:(x-(this.sign(x)*this.TWO_PI));return x;},adjust_lat:function(x){x=(Math.abs(x)<this.HALF_PI)?x:(x-(this.sign(x)*this.PI));return x;},latiso:function(eccent,phi,sinphi){if(Math.abs(phi)>this.HALF_PI)return+Number.NaN;if(phi==this.HALF_PI)return Number.POSITIVE_INFINITY;if(phi==-1.0*this.HALF_PI)return-1.0*Number.POSITIVE_INFINITY;var con=eccent*sinphi;return Math.log(Math.tan((this.HALF_PI+phi)/2.0))+eccent*Math.log((1.0-con)/(1.0+con))/2.0;},fL:function(x,L){return 2.0*Math.atan(x*Math.exp(L))-this.HALF_PI;},invlatiso:function(eccent,ts){var phi=this.fL(1.0,ts);var Iphi=0.0;var con=0.0;do{Iphi=phi;con=eccent*Math.sin(Iphi);phi=this.fL(Math.exp(eccent*Math.log((1.0+con)/(1.0-con))/2.0),ts)}while(Math.abs(phi-Iphi)>1.0e-12);return phi;},sinh:function(x)
+{var r=Math.exp(x);r=(r-1.0/r)/2.0;return r;},cosh:function(x)
+{var r=Math.exp(x);r=(r+1.0/r)/2.0;return r;},tanh:function(x)
+{var r=Math.exp(x);r=(r-1.0/r)/(r+1.0/r);return r;},asinh:function(x)
+{var s=(x>=0?1.0:-1.0);return s*(Math.log(Math.abs(x)+Math.sqrt(x*x+1.0)));},acosh:function(x)
+{return 2.0*Math.log(Math.sqrt((x+1.0)/2.0)+Math.sqrt((x-1.0)/2.0));},atanh:function(x)
+{return Math.log((x-1.0)/(x+1.0))/2.0;},gN:function(a,e,sinphi)
+{var temp=e*sinphi;return a/Math.sqrt(1.0-temp*temp);}};Proj4js.datum=Proj4js.Class({initialize:function(proj){this.datum_type=Proj4js.common.PJD_WGS84;if(proj.datumCode&&proj.datumCode=='none'){this.datum_type=Proj4js.common.PJD_NODATUM;}
+if(proj&&proj.datum_params){for(var i=0;i<proj.datum_params.length;i++){proj.datum_params[i]=parseFloat(proj.datum_params[i]);}
+if(proj.datum_params[0]!=0||proj.datum_params[1]!=0||proj.datum_params[2]!=0){this.datum_type=Proj4js.common.PJD_3PARAM;}
+if(proj.datum_params.length>3){if(proj.datum_params[3]!=0||proj.datum_params[4]!=0||proj.datum_params[5]!=0||proj.datum_params[6]!=0){this.datum_type=Proj4js.common.PJD_7PARAM;proj.datum_params[3]*=Proj4js.common.SEC_TO_RAD;proj.datum_params[4]*=Proj4js.common.SEC_TO_RAD;proj.datum_params[5]*=Proj4js.common.SEC_TO_RAD;proj.datum_params[6]=(proj.datum_params[6]/1000000.0)+1.0;}}}
+if(proj){this.a=proj.a;this.b=proj.b;this.es=proj.es;this.ep2=proj.ep2;this.datum_params=proj.datum_params;}},compare_datums:function(dest){if(this.datum_type!=dest.datum_type){return false;}else if(this.a!=dest.a||Math.abs(this.es-dest.es)>0.000000000050){return false;}else if(this.datum_type==Proj4js.common.PJD_3PARAM){return(this.datum_params[0]==dest.datum_params[0]&&this.datum_params[1]==dest.datum_params[1]&&this.datum_params[2]==dest.datum_params[2]);}else if(this.datum_type==Proj4js.common.PJD_7PARAM){return(this.datum_params[0]==dest.datum_params[0]&&this.datum_params[1]==dest.datum_params[1]&&this.datum_params[2]==dest.datum_params[2]&&this.datum_params[3]==dest.datum_params[3]&&this.datum_params[4]==dest.datum_params[4]&&this.datum_params[5]==dest.datum_params[5]&&this.datum_params[6]==dest.datum_params[6]);}else if(this.datum_type==Proj4js.common.PJD_GRIDSHIFT){return strcmp(pj_param(this.params,"snadgrids").s,pj_param(dest.params,"snadgrids").s)==0;}else{return true;}},geodetic_to_geocentric:function(p){var Longitude=p.x;var Latitude=p.y;var Height=p.z?p.z:0;var X;var Y;var Z;var Error_Code=0;var Rn;var Sin_Lat;var Sin2_Lat;var Cos_Lat;if(Latitude<-Proj4js.common.HALF_PI&&Latitude>-1.001*Proj4js.common.HALF_PI){Latitude=-Proj4js.common.HALF_PI;}else if(Latitude>Proj4js.common.HALF_PI&&Latitude<1.001*Proj4js.common.HALF_PI){Latitude=Proj4js.common.HALF_PI;}else if((Latitude<-Proj4js.common.HALF_PI)||(Latitude>Proj4js.common.HALF_PI)){Proj4js.reportError('geocent:lat out of range:'+Latitude);return null;}
+if(Longitude>Proj4js.common.PI)Longitude-=(2*Proj4js.common.PI);Sin_Lat=Math.sin(Latitude);Cos_Lat=Math.cos(Latitude);Sin2_Lat=Sin_Lat*Sin_Lat;Rn=this.a/(Math.sqrt(1.0e0-this.es*Sin2_Lat));X=(Rn+Height)*Cos_Lat*Math.cos(Longitude);Y=(Rn+Height)*Cos_Lat*Math.sin(Longitude);Z=((Rn*(1-this.es))+Height)*Sin_Lat;p.x=X;p.y=Y;p.z=Z;return Error_Code;},geocentric_to_geodetic:function(p){var genau=1.E-12;var genau2=(genau*genau);var maxiter=30;var P;var RR;var CT;var ST;var RX;var RK;var RN;var CPHI0;var SPHI0;var CPHI;var SPHI;var SDPHI;var At_Pole;var iter;var X=p.x;var Y=p.y;var Z=p.z?p.z:0.0;var Longitude;var Latitude;var Height;At_Pole=false;P=Math.sqrt(X*X+Y*Y);RR=Math.sqrt(X*X+Y*Y+Z*Z);if(P/this.a<genau){At_Pole=true;Longitude=0.0;if(RR/this.a<genau){Latitude=Proj4js.common.HALF_PI;Height=-this.b;return;}}else{Longitude=Math.atan2(Y,X);}
+CT=Z/RR;ST=P/RR;RX=1.0/Math.sqrt(1.0-this.es*(2.0-this.es)*ST*ST);CPHI0=ST*(1.0-this.es)*RX;SPHI0=CT*RX;iter=0;do
+{iter++;RN=this.a/Math.sqrt(1.0-this.es*SPHI0*SPHI0);Height=P*CPHI0+Z*SPHI0-RN*(1.0-this.es*SPHI0*SPHI0);RK=this.es*RN/(RN+Height);RX=1.0/Math.sqrt(1.0-RK*(2.0-RK)*ST*ST);CPHI=ST*(1.0-RK)*RX;SPHI=CT*RX;SDPHI=SPHI*CPHI0-CPHI*SPHI0;CPHI0=CPHI;SPHI0=SPHI;}
+while(SDPHI*SDPHI>genau2&&iter<maxiter);Latitude=Math.atan(SPHI/Math.abs(CPHI));p.x=Longitude;p.y=Latitude;p.z=Height;return p;},geocentric_to_geodetic_noniter:function(p){var X=p.x;var Y=p.y;var Z=p.z?p.z:0;var Longitude;var Latitude;var Height;var W;var W2;var T0;var T1;var S0;var S1;var Sin_B0;var Sin3_B0;var Cos_B0;var Sin_p1;var Cos_p1;var Rn;var Sum;var At_Pole;X=parseFloat(X);Y=parseFloat(Y);Z=parseFloat(Z);At_Pole=false;if(X!=0.0)
+{Longitude=Math.atan2(Y,X);}
+else
+{if(Y>0)
+{Longitude=Proj4js.common.HALF_PI;}
+else if(Y<0)
+{Longitude=-Proj4js.common.HALF_PI;}
+else
+{At_Pole=true;Longitude=0.0;if(Z>0.0)
+{Latitude=Proj4js.common.HALF_PI;}
+else if(Z<0.0)
+{Latitude=-Proj4js.common.HALF_PI;}
+else
+{Latitude=Proj4js.common.HALF_PI;Height=-this.b;return;}}}
+W2=X*X+Y*Y;W=Math.sqrt(W2);T0=Z*Proj4js.common.AD_C;S0=Math.sqrt(T0*T0+W2);Sin_B0=T0/S0;Cos_B0=W/S0;Sin3_B0=Sin_B0*Sin_B0*Sin_B0;T1=Z+this.b*this.ep2*Sin3_B0;Sum=W-this.a*this.es*Cos_B0*Cos_B0*Cos_B0;S1=Math.sqrt(T1*T1+Sum*Sum);Sin_p1=T1/S1;Cos_p1=Sum/S1;Rn=this.a/Math.sqrt(1.0-this.es*Sin_p1*Sin_p1);if(Cos_p1>=Proj4js.common.COS_67P5)
+{Height=W/Cos_p1-Rn;}
+else if(Cos_p1<=-Proj4js.common.COS_67P5)
+{Height=W/-Cos_p1-Rn;}
+else
+{Height=Z/Sin_p1+Rn*(this.es-1.0);}
+if(At_Pole==false)
+{Latitude=Math.atan(Sin_p1/Cos_p1);}
+p.x=Longitude;p.y=Latitude;p.z=Height;return p;},geocentric_to_wgs84:function(p){if(this.datum_type==Proj4js.common.PJD_3PARAM)
+{p.x+=this.datum_params[0];p.y+=this.datum_params[1];p.z+=this.datum_params[2];}
+else if(this.datum_type==Proj4js.common.PJD_7PARAM)
+{var Dx_BF=this.datum_params[0];var Dy_BF=this.datum_params[1];var Dz_BF=this.datum_params[2];var Rx_BF=this.datum_params[3];var Ry_BF=this.datum_params[4];var Rz_BF=this.datum_params[5];var M_BF=this.datum_params[6];var x_out=M_BF*(p.x-Rz_BF*p.y+Ry_BF*p.z)+Dx_BF;var y_out=M_BF*(Rz_BF*p.x+p.y-Rx_BF*p.z)+Dy_BF;var z_out=M_BF*(-Ry_BF*p.x+Rx_BF*p.y+p.z)+Dz_BF;p.x=x_out;p.y=y_out;p.z=z_out;}},geocentric_from_wgs84:function(p){if(this.datum_type==Proj4js.common.PJD_3PARAM)
+{p.x-=this.datum_params[0];p.y-=this.datum_params[1];p.z-=this.datum_params[2];}
+else if(this.datum_type==Proj4js.common.PJD_7PARAM)
+{var Dx_BF=this.datum_params[0];var Dy_BF=this.datum_params[1];var Dz_BF=this.datum_params[2];var Rx_BF=this.datum_params[3];var Ry_BF=this.datum_params[4];var Rz_BF=this.datum_params[5];var M_BF=this.datum_params[6];var x_tmp=(p.x-Dx_BF)/M_BF;var y_tmp=(p.y-Dy_BF)/M_BF;var z_tmp=(p.z-Dz_BF)/M_BF;p.x=x_tmp+Rz_BF*y_tmp-Ry_BF*z_tmp;p.y=-Rz_BF*x_tmp+y_tmp+Rx_BF*z_tmp;p.z=Ry_BF*x_tmp-Rx_BF*y_tmp+z_tmp;}}});Proj4js.Point=Proj4js.Class({initialize:function(x,y,z){if(typeof x=='object'){this.x=x[0];this.y=x[1];this.z=x[2]||0.0;}else if(typeof x=='string'){var coords=x.split(',');this.x=parseFloat(coords[0]);this.y=parseFloat(coords[1]);this.z=parseFloat(coords[2])||0.0;}else{this.x=x;this.y=y;this.z=z||0.0;}},clone:function(){return new Proj4js.Point(this.x,this.y,this.z);},toString:function(){return("x="+this.x+",y="+this.y);},toShortString:function(){return(this.x+", "+this.y);}});Proj4js.PrimeMeridian={"greenwich":0.0,"lisbon":-9.131906111111,"paris":2.337229166667,"bogota":-74.080916666667,"madrid":-3.687938888889,"rome":12.452333333333,"bern":7.439583333333,"jakarta":106.807719444444,"ferro":-17.666666666667,"brussels":4.367975,"stockholm":18.058277777778,"athens":23.7163375,"oslo":10.722916666667};Proj4js.Ellipsoid={"MERIT":{a:6378137.0,rf:298.257,ellipseName:"MERIT 1983"},"SGS85":{a:6378136.0,rf:298.257,ellipseName:"Soviet Geodetic System 85"},"GRS80":{a:6378137.0,rf:298.257222101,ellipseName:"GRS 1980(IUGG, 1980)"},"IAU76":{a:6378140.0,rf:298.257,ellipseName:"IAU 1976"},"airy":{a:6377563.396,b:6356256.910,ellipseName:"Airy 1830"},"APL4.":{a:6378137,rf:298.25,ellipseName:"Appl. Physics. 1965"},"NWL9D":{a:6378145.0,rf:298.25,ellipseName:"Naval Weapons Lab., 1965"},"mod_airy":{a:6377340.189,b:6356034.446,ellipseName:"Modified Airy"},"andrae":{a:6377104.43,rf:300.0,ellipseName:"Andrae 1876 (Den., Iclnd.)"},"aust_SA":{a:6378160.0,rf:298.25,ellipseName:"Australian Natl & S. Amer. 1969"},"GRS67":{a:6378160.0,rf:298.2471674270,ellipseName:"GRS 67(IUGG 1967)"},"bessel":{a:6377397.155,rf:299.1528128,ellipseName:"Bessel 1841"},"bess_nam":{a:6377483.865,rf:299.1528128,ellipseName:"Bessel 1841 (Namibia)"},"clrk66":{a:6378206.4,b:6356583.8,ellipseName:"Clarke 1866"},"clrk80":{a:6378249.145,rf:293.4663,ellipseName:"Clarke 1880 mod."},"CPM":{a:6375738.7,rf:334.29,ellipseName:"Comm. des Poids et Mesures 1799"},"delmbr":{a:6376428.0,rf:311.5,ellipseName:"Delambre 1810 (Belgium)"},"engelis":{a:6378136.05,rf:298.2566,ellipseName:"Engelis 1985"},"evrst30":{a:6377276.345,rf:300.8017,ellipseName:"Everest 1830"},"evrst48":{a:6377304.063,rf:300.8017,ellipseName:"Everest 1948"},"evrst56":{a:6377301.243,rf:300.8017,ellipseName:"Everest 1956"},"evrst69":{a:6377295.664,rf:300.8017,ellipseName:"Everest 1969"},"evrstSS":{a:6377298.556,rf:300.8017,ellipseName:"Everest (Sabah & Sarawak)"},"fschr60":{a:6378166.0,rf:298.3,ellipseName:"Fischer (Mercury Datum) 1960"},"fschr60m":{a:6378155.0,rf:298.3,ellipseName:"Fischer 1960"},"fschr68":{a:6378150.0,rf:298.3,ellipseName:"Fischer 1968"},"helmert":{a:6378200.0,rf:298.3,ellipseName:"Helmert 1906"},"hough":{a:6378270.0,rf:297.0,ellipseName:"Hough"},"intl":{a:6378388.0,rf:297.0,ellipseName:"International 1909 (Hayford)"},"kaula":{a:6378163.0,rf:298.24,ellipseName:"Kaula 1961"},"lerch":{a:6378139.0,rf:298.257,ellipseName:"Lerch 1979"},"mprts":{a:6397300.0,rf:191.0,ellipseName:"Maupertius 1738"},"new_intl":{a:6378157.5,b:6356772.2,ellipseName:"New International 1967"},"plessis":{a:6376523.0,rf:6355863.0,ellipseName:"Plessis 1817 (France)"},"krass":{a:6378245.0,rf:298.3,ellipseName:"Krassovsky, 1942"},"SEasia":{a:6378155.0,b:6356773.3205,ellipseName:"Southeast Asia"},"walbeck":{a:6376896.0,b:6355834.8467,ellipseName:"Walbeck"},"WGS60":{a:6378165.0,rf:298.3,ellipseName:"WGS 60"},"WGS66":{a:6378145.0,rf:298.25,ellipseName:"WGS 66"},"WGS72":{a:6378135.0,rf:298.26,ellipseName:"WGS 72"},"WGS84":{a:6378137.0,rf:298.257223563,ellipseName:"WGS 84"},"sphere":{a:6370997.0,b:6370997.0,ellipseName:"Normal Sphere (r=6370997)"}};Proj4js.Datum={"WGS84":{towgs84:"0,0,0",ellipse:"WGS84",datumName:"WGS84"},"GGRS87":{towgs84:"-199.87,74.79,246.62",ellipse:"GRS80",datumName:"Greek_Geodetic_Reference_System_1987"},"NAD83":{towgs84:"0,0,0",ellipse:"GRS80",datumName:"North_American_Datum_1983"},"NAD27":{nadgrids:"@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",ellipse:"clrk66",datumName:"North_American_Datum_1927"},"potsdam":{towgs84:"606.0,23.0,413.0",ellipse:"bessel",datumName:"Potsdam Rauenberg 1950 DHDN"},"carthage":{towgs84:"-263.0,6.0,431.0",ellipse:"clark80",datumName:"Carthage 1934 Tunisia"},"hermannskogel":{towgs84:"653.0,-212.0,449.0",ellipse:"bessel",datumName:"Hermannskogel"},"ire65":{towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"mod_airy",datumName:"Ireland 1965"},"nzgd49":{towgs84:"59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",ellipse:"intl",datumName:"New Zealand Geodetic Datum 1949"},"OSGB36":{towgs84:"446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",ellipse:"airy",datumName:"Airy 1830"}};Proj4js.WGS84=new Proj4js.Proj('WGS84');Proj4js.Datum['OSB36']=Proj4js.Datum['OSGB36'];Proj4js.Proj.aea={init:function(){if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("aeaInitEqualLatitudes");return;}
+this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e3=Math.sqrt(this.es);this.sin_po=Math.sin(this.lat1);this.cos_po=Math.cos(this.lat1);this.t1=this.sin_po;this.con=this.sin_po;this.ms1=Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);this.qs1=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);this.sin_po=Math.sin(this.lat2);this.cos_po=Math.cos(this.lat2);this.t2=this.sin_po;this.ms2=Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);this.qs2=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);this.sin_po=Math.sin(this.lat0);this.cos_po=Math.cos(this.lat0);this.t3=this.sin_po;this.qs0=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);if(Math.abs(this.lat1-this.lat2)>Proj4js.common.EPSLN){this.ns0=(this.ms1*this.ms1-this.ms2*this.ms2)/(this.qs2-this.qs1);}else{this.ns0=this.con;}
+this.c=this.ms1*this.ms1+this.ns0*this.qs1;this.rh=this.a*Math.sqrt(this.c-this.ns0*this.qs0)/this.ns0;},forward:function(p){var lon=p.x;var lat=p.y;this.sin_phi=Math.sin(lat);this.cos_phi=Math.cos(lat);var qs=Proj4js.common.qsfnz(this.e3,this.sin_phi,this.cos_phi);var rh1=this.a*Math.sqrt(this.c-this.ns0*qs)/this.ns0;var theta=this.ns0*Proj4js.common.adjust_lon(lon-this.long0);var x=rh1*Math.sin(theta)+this.x0;var y=this.rh-rh1*Math.cos(theta)+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var rh1,qs,con,theta,lon,lat;p.x-=this.x0;p.y=this.rh-p.y+this.y0;if(this.ns0>=0){rh1=Math.sqrt(p.x*p.x+p.y*p.y);con=1.0;}else{rh1=-Math.sqrt(p.x*p.x+p.y*p.y);con=-1.0;}
+theta=0.0;if(rh1!=0.0){theta=Math.atan2(con*p.x,con*p.y);}
+con=rh1*this.ns0/this.a;qs=(this.c-con*con)/this.ns0;if(this.e3>=1e-10){con=1-.5*(1.0-this.es)*Math.log((1.0-this.e3)/(1.0+this.e3))/this.e3;if(Math.abs(Math.abs(con)-Math.abs(qs))>.0000000001){lat=this.phi1z(this.e3,qs);}else{if(qs>=0){lat=.5*PI;}else{lat=-.5*PI;}}}else{lat=this.phi1z(e3,qs);}
+lon=Proj4js.common.adjust_lon(theta/this.ns0+this.long0);p.x=lon;p.y=lat;return p;},phi1z:function(eccent,qs){var con,com,dphi;var phi=Proj4js.common.asinz(.5*qs);if(eccent<Proj4js.common.EPSLN)return phi;var eccnts=eccent*eccent;for(var i=1;i<=25;i++){sinphi=Math.sin(phi);cosphi=Math.cos(phi);con=eccent*sinphi;com=1.0-con*con;dphi=.5*com*com/cosphi*(qs/(1.0-eccnts)-sinphi/com+.5/eccent*Math.log((1.0-con)/(1.0+con)));phi=phi+dphi;if(Math.abs(dphi)<=1e-7)return phi;}
+Proj4js.reportError("aea:phi1z:Convergence error");return null;}};Proj4js.Proj.sterea={dependsOn:'gauss',init:function(){Proj4js.Proj['gauss'].init.apply(this);if(!this.rc){Proj4js.reportError("sterea:init:E_ERROR_0");return;}
+this.sinc0=Math.sin(this.phic0);this.cosc0=Math.cos(this.phic0);this.R2=2.0*this.rc;if(!this.title)this.title="Oblique Stereographic Alternative";},forward:function(p){p.x=Proj4js.common.adjust_lon(p.x-this.long0);Proj4js.Proj['gauss'].forward.apply(this,[p]);sinc=Math.sin(p.y);cosc=Math.cos(p.y);cosl=Math.cos(p.x);k=this.k0*this.R2/(1.0+this.sinc0*sinc+this.cosc0*cosc*cosl);p.x=k*cosc*Math.sin(p.x);p.y=k*(this.cosc0*sinc-this.sinc0*cosc*cosl);p.x=this.a*p.x+this.x0;p.y=this.a*p.y+this.y0;return p;},inverse:function(p){var lon,lat;p.x=(p.x-this.x0)/this.a;p.y=(p.y-this.y0)/this.a;p.x/=this.k0;p.y/=this.k0;if((rho=Math.sqrt(p.x*p.x+p.y*p.y))){c=2.0*Math.atan2(rho,this.R2);sinc=Math.sin(c);cosc=Math.cos(c);lat=Math.asin(cosc*this.sinc0+p.y*sinc*this.cosc0/rho);lon=Math.atan2(p.x*sinc,rho*this.cosc0*cosc-p.y*this.sinc0*sinc);}else{lat=this.phic0;lon=0.;}
+p.x=lon;p.y=lat;Proj4js.Proj['gauss'].inverse.apply(this,[p]);p.x=Proj4js.common.adjust_lon(p.x+this.long0);return p;}};function phi4z(eccent,e0,e1,e2,e3,a,b,c,phi){var sinphi,sin2ph,tanph,ml,mlp,con1,con2,con3,dphi,i;phi=a;for(i=1;i<=15;i++){sinphi=Math.sin(phi);tanphi=Math.tan(phi);c=tanphi*Math.sqrt(1.0-eccent*sinphi*sinphi);sin2ph=Math.sin(2.0*phi);ml=e0*phi-e1*sin2ph+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi);mlp=e0-2.0*e1*Math.cos(2.0*phi)+4.0*e2*Math.cos(4.0*phi)-6.0*e3*Math.cos(6.0*phi);con1=2.0*ml+c*(ml*ml+b)-2.0*a*(c*ml+1.0);con2=eccent*sin2ph*(ml*ml+b-2.0*a*ml)/(2.0*c);con3=2.0*(a-ml)*(c*mlp-2.0/sin2ph)-2.0*mlp;dphi=con1/(con2+con3);phi+=dphi;if(Math.abs(dphi)<=.0000000001)return(phi);}
+Proj4js.reportError("phi4z: No convergence");return null;}
+function e4fn(x){var con,com;con=1.0+x;com=1.0-x;return(Math.sqrt((Math.pow(con,con))*(Math.pow(com,com))));}
+Proj4js.Proj.poly={init:function(){var temp;if(this.lat0=0)this.lat0=90;this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e=Math.sqrt(this.es);this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.ml0=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);},forward:function(p){var sinphi,cosphi;var al;var c;var con,ml;var ms;var x,y;var lon=p.x;var lat=p.y;con=Proj4js.common.adjust_lon(lon-this.long0);if(Math.abs(lat)<=.0000001){x=this.x0+this.a*con;y=this.y0-this.a*this.ml0;}else{sinphi=Math.sin(lat);cosphi=Math.cos(lat);ml=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);ms=Proj4js.common.msfnz(this.e,sinphi,cosphi);con=sinphi;x=this.x0+this.a*ms*Math.sin(con)/sinphi;y=this.y0+this.a*(ml-this.ml0+ms*(1.0-Math.cos(con))/sinphi);}
+p.x=x;p.y=y;return p;},inverse:function(p){var sin_phi,cos_phi;var al;var b;var c;var con,ml;var iflg;var lon,lat;p.x-=this.x0;p.y-=this.y0;al=this.ml0+p.y/this.a;iflg=0;if(Math.abs(al)<=.0000001){lon=p.x/this.a+this.long0;lat=0.0;}else{b=al*al+(p.x/this.a)*(p.x/this.a);iflg=phi4z(this.es,this.e0,this.e1,this.e2,this.e3,this.al,b,c,lat);if(iflg!=1)return(iflg);lon=Proj4js.common.adjust_lon((Proj4js.common.asinz(p.x*c/this.a)/Math.sin(lat))+this.long0);}
+p.x=lon;p.y=lat;return p;}};Proj4js.Proj.equi={init:function(){if(!this.x0)this.x0=0;if(!this.y0)this.y0=0;if(!this.lat0)this.lat0=0;if(!this.long0)this.long0=0;},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon*Math.cos(this.lat0);var y=this.y0+this.a*lat;this.t1=x;this.t2=Math.cos(this.lat0);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lat=p.y/this.a;if(Math.abs(lat)>Proj4js.common.HALF_PI){Proj4js.reportError("equi:Inv:DataError");}
+var lon=Proj4js.common.adjust_lon(this.long0+p.x/(this.a*Math.cos(this.lat0)));p.x=lon;p.y=lat;}};Proj4js.Proj.merc={init:function(){if(this.lat_ts){if(this.sphere){this.k0=Math.cos(this.lat_ts);}else{this.k0=Proj4js.common.msfnz(this.es,Math.sin(this.lat_ts),Math.cos(this.lat_ts));}}},forward:function(p){var lon=p.x;var lat=p.y;if(lat*Proj4js.common.R2D>90.0&&lat*Proj4js.common.R2D<-90.0&&lon*Proj4js.common.R2D>180.0&&lon*Proj4js.common.R2D<-180.0){Proj4js.reportError("merc:forward: llInputOutOfRange: "+lon+" : "+lat);return null;}
+var x,y;if(Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI)<=Proj4js.common.EPSLN){Proj4js.reportError("merc:forward: ll2mAtPoles");return null;}else{if(this.sphere){x=this.x0+this.a*this.k0*Proj4js.common.adjust_lon(lon-this.long0);y=this.y0+this.a*this.k0*Math.log(Math.tan(Proj4js.common.FORTPI+0.5*lat));}else{var sinphi=Math.sin(lat);var ts=Proj4js.common.tsfnz(this.e,lat,sinphi);x=this.x0+this.a*this.k0*Proj4js.common.adjust_lon(lon-this.long0);y=this.y0-this.a*this.k0*Math.log(ts);}
+p.x=x;p.y=y;return p;}},inverse:function(p){var x=p.x-this.x0;var y=p.y-this.y0;var lon,lat;if(this.sphere){lat=Proj4js.common.HALF_PI-2.0*Math.atan(Math.exp(-y/this.a*this.k0));}else{var ts=Math.exp(-y/(this.a*this.k0));lat=Proj4js.common.phi2z(this.e,ts);if(lat==-9999){Proj4js.reportError("merc:inverse: lat = -9999");return null;}}
+lon=Proj4js.common.adjust_lon(this.long0+x/(this.a*this.k0));p.x=lon;p.y=lat;return p;}};Proj4js.Proj.utm={dependsOn:'tmerc',init:function(){if(!this.zone){Proj4js.reportError("utm:init: zone must be specified for UTM");return;}
+this.lat0=0.0;this.long0=((6*Math.abs(this.zone))-183)*Proj4js.common.D2R;this.x0=500000.0;this.y0=this.utmSouth?10000000.0:0.0;this.k0=0.9996;Proj4js.Proj['tmerc'].init.apply(this);this.forward=Proj4js.Proj['tmerc'].forward;this.inverse=Proj4js.Proj['tmerc'].inverse;}};Proj4js.Proj.eqdc={init:function(){if(!this.mode)this.mode=0;this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e=Math.sqrt(this.es);this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.sinphi=Math.sin(this.lat1);this.cosphi=Math.cos(this.lat1);this.ms1=Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);this.ml1=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat1);if(this.mode!=0){if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("eqdc:Init:EqualLatitudes");}
+this.sinphi=Math.sin(this.lat2);this.cosphi=Math.cos(this.lat2);this.ms2=Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);this.ml2=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat2);if(Math.abs(this.lat1-this.lat2)>=Proj4js.common.EPSLN){this.ns=(this.ms1-this.ms2)/(this.ml2-this.ml1);}else{this.ns=this.sinphi;}}else{this.ns=this.sinphi;}
+this.g=this.ml1+this.ms1/this.ns;this.ml0=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);this.rh=this.a*(this.g-this.ml0);},forward:function(p){var lon=p.x;var lat=p.y;var ml=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);var rh1=this.a*(this.g-ml);var theta=this.ns*Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+rh1*Math.sin(theta);var y=this.y0+this.rh-rh1*Math.cos(theta);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y=this.rh-p.y+this.y0;var con,rh1;if(this.ns>=0){var rh1=Math.sqrt(p.x*p.x+p.y*p.y);var con=1.0;}else{rh1=-Math.sqrt(p.x*p.x+p.y*p.y);con=-1.0;}
+var theta=0.0;if(rh1!=0.0)theta=Math.atan2(con*p.x,con*p.y);var ml=this.g-rh1/this.a;var lat=this.phi3z(this.ml,this.e0,this.e1,this.e2,this.e3);var lon=Proj4js.common.adjust_lon(this.long0+theta/this.ns);p.x=lon;p.y=lat;return p;},phi3z:function(ml,e0,e1,e2,e3){var phi;var dphi;phi=ml;for(var i=0;i<15;i++){dphi=(ml+e1*Math.sin(2.0*phi)-e2*Math.sin(4.0*phi)+e3*Math.sin(6.0*phi))/e0-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001){return phi;}}
+Proj4js.reportError("PHI3Z-CONV:Latitude failed to converge after 15 iterations");return null;}};Proj4js.Proj.tmerc={init:function(){this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.ml0=this.a*Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);},forward:function(p){var lon=p.x;var lat=p.y;var delta_lon=Proj4js.common.adjust_lon(lon-this.long0);var con;var x,y;var sin_phi=Math.sin(lat);var cos_phi=Math.cos(lat);if(this.sphere){var b=cos_phi*Math.sin(delta_lon);if((Math.abs(Math.abs(b)-1.0))<.0000000001){Proj4js.reportError("tmerc:forward: Point projects into infinity");return(93);}else{x=.5*this.a*this.k0*Math.log((1.0+b)/(1.0-b));con=Math.acos(cos_phi*Math.cos(delta_lon)/Math.sqrt(1.0-b*b));if(lat<0)con=-con;y=this.a*this.k0*(con-this.lat0);}}else{var al=cos_phi*delta_lon;var als=Math.pow(al,2);var c=this.ep2*Math.pow(cos_phi,2);var tq=Math.tan(lat);var t=Math.pow(tq,2);con=1.0-this.es*Math.pow(sin_phi,2);var n=this.a/Math.sqrt(con);var ml=this.a*Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);x=this.k0*n*al*(1.0+als/6.0*(1.0-t+c+als/20.0*(5.0-18.0*t+Math.pow(t,2)+72.0*c-58.0*this.ep2)))+this.x0;y=this.k0*(ml-this.ml0+n*tq*(als*(0.5+als/24.0*(5.0-t+9.0*c+4.0*Math.pow(c,2)+als/30.0*(61.0-58.0*t+Math.pow(t,2)+600.0*c-330.0*this.ep2)))))+this.y0;}
+p.x=x;p.y=y;return p;},inverse:function(p){var con,phi;var delta_phi;var i;var max_iter=6;var lat,lon;if(this.sphere){var f=Math.exp(p.x/(this.a*this.k0));var g=.5*(f-1/f);var temp=this.lat0+p.y/(this.a*this.k0);var h=Math.cos(temp);con=Math.sqrt((1.0-h*h)/(1.0+g*g));lat=Proj4js.common.asinz(con);if(temp<0)
+lat=-lat;if((g==0)&&(h==0)){lon=this.long0;}else{lon=Proj4js.common.adjust_lon(Math.atan2(g,h)+this.long0);}}else{var x=p.x-this.x0;var y=p.y-this.y0;con=(this.ml0+y/this.k0)/this.a;phi=con;for(i=0;true;i++){delta_phi=((con+this.e1*Math.sin(2.0*phi)-this.e2*Math.sin(4.0*phi)+this.e3*Math.sin(6.0*phi))/this.e0)-phi;phi+=delta_phi;if(Math.abs(delta_phi)<=Proj4js.common.EPSLN)break;if(i>=max_iter){Proj4js.reportError("tmerc:inverse: Latitude failed to converge");return(95);}}
+if(Math.abs(phi)<Proj4js.common.HALF_PI){var sin_phi=Math.sin(phi);var cos_phi=Math.cos(phi);var tan_phi=Math.tan(phi);var c=this.ep2*Math.pow(cos_phi,2);var cs=Math.pow(c,2);var t=Math.pow(tan_phi,2);var ts=Math.pow(t,2);con=1.0-this.es*Math.pow(sin_phi,2);var n=this.a/Math.sqrt(con);var r=n*(1.0-this.es)/con;var d=x/(n*this.k0);var ds=Math.pow(d,2);lat=phi-(n*tan_phi*ds/r)*(0.5-ds/24.0*(5.0+3.0*t+10.0*c-4.0*cs-9.0*this.ep2-ds/30.0*(61.0+90.0*t+298.0*c+45.0*ts-252.0*this.ep2-3.0*cs)));lon=Proj4js.common.adjust_lon(this.long0+(d*(1.0-ds/6.0*(1.0+2.0*t+c-ds/20.0*(5.0-2.0*c+28.0*t-3.0*cs+8.0*this.ep2+24.0*ts)))/cos_phi));}else{lat=Proj4js.common.HALF_PI*Proj4js.common.sign(y);lon=this.long0;}}
+p.x=lon;p.y=lat;return p;}};Proj4js.defs["GOOGLE"]="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";Proj4js.defs["EPSG:900913"]=Proj4js.defs["GOOGLE"];Proj4js.Proj.gstmerc={init:function(){var temp=this.b/this.a;this.e=Math.sqrt(1.0-temp*temp);this.lc=this.long0;this.rs=Math.sqrt(1.0+this.e*this.e*Math.pow(Math.cos(this.lat0),4.0)/(1.0-this.e*this.e));var sinz=Math.sin(this.lat0);var pc=Math.asin(sinz/this.rs);var sinzpc=Math.sin(pc);this.cp=Proj4js.common.latiso(0.0,pc,sinzpc)-this.rs*Proj4js.common.latiso(this.e,this.lat0,sinz);this.n2=this.k0*this.a*Math.sqrt(1.0-this.e*this.e)/(1.0-this.e*this.e*sinz*sinz);this.xs=this.x0;this.ys=this.y0-this.n2*pc;if(!this.title)this.title="Gauss Schreiber transverse mercator";},forward:function(p){var lon=p.x;var lat=p.y;var L=this.rs*(lon-this.lc);var Ls=this.cp+(this.rs*Proj4js.common.latiso(this.e,lat,Math.sin(lat)));var lat1=Math.asin(Math.sin(L)/Proj4js.common.cosh(Ls));var Ls1=Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));p.x=this.xs+(this.n2*Ls1);p.y=this.ys+(this.n2*Math.atan(Proj4js.common.sinh(Ls)/Math.cos(L)));return p;},inverse:function(p){var x=p.x;var y=p.y;var L=Math.atan(Proj4js.common.sinh((x-this.xs)/this.n2)/Math.cos((y-this.ys)/this.n2));var lat1=Math.asin(Math.sin((y-this.ys)/this.n2)/Proj4js.common.cosh((x-this.xs)/this.n2));var LC=Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));p.x=this.lc+L/this.rs;p.y=Proj4js.common.invlatiso(this.e,(LC-this.cp)/this.rs);return p;}};Proj4js.Proj.ortho={init:function(def){;this.sin_p14=Math.sin(this.lat0);this.cos_p14=Math.cos(this.lat0);},forward:function(p){var sinphi,cosphi;var dlon;var coslon;var ksp;var g;var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslon=Math.cos(dlon);g=this.sin_p14*sinphi+this.cos_p14*cosphi*coslon;ksp=1.0;if((g>0)||(Math.abs(g)<=Proj4js.common.EPSLN)){var x=this.a*ksp*cosphi*Math.sin(dlon);var y=this.y0+this.a*ksp*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon);}else{Proj4js.reportError("orthoFwdPointError");}
+p.x=x;p.y=y;return p;},inverse:function(p){var rh;var z;var sinz,cosz;var temp;var con;var lon,lat;p.x-=this.x0;p.y-=this.y0;rh=Math.sqrt(p.x*p.x+p.y*p.y);if(rh>this.a+.0000001){Proj4js.reportError("orthoInvDataError");}
+z=Proj4js.common.asinz(rh/this.a);sinz=Math.sin(z);cosz=Math.cos(z);lon=this.long0;if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.lat0;}
+lat=Proj4js.common.asinz(cosz*this.sin_p14+(p.y*sinz*this.cos_p14)/rh);con=Math.abs(lat0)-Proj4js.common.HALF_PI;if(Math.abs(con)<=Proj4js.common.EPSLN){if(this.lat0>=0){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x,-p.y));}else{lon=Proj4js.common.adjust_lon(this.long0-Math.atan2(-p.x,p.y));}}
+con=cosz-this.sin_p14*Math.sin(lat);if((Math.abs(con)>=Proj4js.common.EPSLN)||(Math.abs(x)>=Proj4js.common.EPSLN)){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2((p.x*sinz*this.cos_p14),(con*rh)));}
+p.x=lon;p.y=lat;return p;}};Proj4js.Proj.somerc={init:function(){var phy0=this.lat0;this.lambda0=this.long0;var sinPhy0=Math.sin(phy0);var semiMajorAxis=this.a;var invF=this.rf;var flattening=1/invF;var e2=2*flattening-Math.pow(flattening,2);var e=this.e=Math.sqrt(e2);this.R=semiMajorAxis*Math.sqrt(1-e2)/(1-e2*Math.pow(sinPhy0,2.0));this.alpha=Math.sqrt(1+e2/(1-e2)*Math.pow(Math.cos(phy0),4.0));this.b0=Math.asin(sinPhy0/this.alpha);this.K=Math.log(Math.tan(Math.PI/4.0+this.b0/2.0))
+-this.alpha*Math.log(Math.tan(Math.PI/4.0+phy0/2.0))
++this.alpha*e/2*Math.log((1+e*sinPhy0)/(1-e*sinPhy0));},forward:function(p){var Sa1=Math.log(Math.tan(Math.PI/4.0-p.y/2.0));var Sa2=this.e/2.0*Math.log((1+this.e*Math.sin(p.y))/(1-this.e*Math.sin(p.y)));var S=-this.alpha*(Sa1+Sa2)+this.K;var b=2.0*(Math.atan(Math.exp(S))-Math.PI/4.0);var I=this.alpha*(p.x-this.lambda0);var rotI=Math.atan(Math.sin(I)/(Math.sin(this.b0)*Math.tan(b)+
+Math.cos(this.b0)*Math.cos(I)));var rotB=Math.asin(Math.cos(this.b0)*Math.sin(b)-
+Math.sin(this.b0)*Math.cos(b)*Math.cos(I));p.y=this.R/2.0*Math.log((1+Math.sin(rotB))/(1-Math.sin(rotB)))
++this.y0;p.x=this.R*rotI+this.x0;return p;},inverse:function(p){var Y=p.x-this.x0;var X=p.y-this.y0;var rotI=Y/this.R;var rotB=2*(Math.atan(Math.exp(X/this.R))-Math.PI/4.0);var b=Math.asin(Math.cos(this.b0)*Math.sin(rotB)
++Math.sin(this.b0)*Math.cos(rotB)*Math.cos(rotI));var I=Math.atan(Math.sin(rotI)/(Math.cos(this.b0)*Math.cos(rotI)-Math.sin(this.b0)*Math.tan(rotB)));var lambda=this.lambda0+I/this.alpha;var S=0.0;var phy=b;var prevPhy=-1000.0;var iteration=0;while(Math.abs(phy-prevPhy)>0.0000001)
+{if(++iteration>20)
+{Proj4js.reportError("omercFwdInfinity");return;}
+S=1.0/this.alpha*(Math.log(Math.tan(Math.PI/4.0+b/2.0))-this.K)
++this.e*Math.log(Math.tan(Math.PI/4.0
++Math.asin(this.e*Math.sin(phy))/2.0));prevPhy=phy;phy=2.0*Math.atan(Math.exp(S))-Math.PI/2.0;}
+p.x=lambda;p.y=phy;return p;}};Proj4js.Proj.stere={ssfn_:function(phit,sinphi,eccen){sinphi*=eccen;return(Math.tan(.5*(Proj4js.common.HALF_PI+phit))*Math.pow((1.-sinphi)/(1.+sinphi),.5*eccen));},TOL:1.e-8,NITER:8,CONV:1.e-10,S_POLE:0,N_POLE:1,OBLIQ:2,EQUIT:3,init:function(){this.phits=this.lat_ts?this.lat_ts:Proj4js.common.HALF_PI;var t=Math.abs(this.lat0);if((Math.abs(t)-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.mode=this.lat0<0.?this.S_POLE:this.N_POLE;}else{this.mode=t>Proj4js.common.EPSLN?this.OBLIQ:this.EQUIT;}
+this.phits=Math.abs(this.phits);if(this.es){var X;switch(this.mode){case this.N_POLE:case this.S_POLE:if(Math.abs(this.phits-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.akm1=2.*this.k0/Math.sqrt(Math.pow(1+this.e,1+this.e)*Math.pow(1-this.e,1-this.e));}else{t=Math.sin(this.phits);this.akm1=Math.cos(this.phits)/Proj4js.common.tsfnz(this.e,this.phits,t);t*=this.e;this.akm1/=Math.sqrt(1.-t*t);}
+break;case this.EQUIT:this.akm1=2.*this.k0;break;case this.OBLIQ:t=Math.sin(this.lat0);X=2.*Math.atan(this.ssfn_(this.lat0,t,this.e))-Proj4js.common.HALF_PI;t*=this.e;this.akm1=2.*this.k0*Math.cos(this.lat0)/Math.sqrt(1.-t*t);this.sinX1=Math.sin(X);this.cosX1=Math.cos(X);break;}}else{switch(this.mode){case this.OBLIQ:this.sinph0=Math.sin(this.lat0);this.cosph0=Math.cos(this.lat0);case this.EQUIT:this.akm1=2.*this.k0;break;case this.S_POLE:case this.N_POLE:this.akm1=Math.abs(this.phits-Proj4js.common.HALF_PI)>=Proj4js.common.EPSLN?Math.cos(this.phits)/Math.tan(Proj4js.common.FORTPI-.5*this.phits):2.*this.k0;break;}}},forward:function(p){var lon=p.x;lon=Proj4js.common.adjust_lon(lon-this.long0);var lat=p.y;var x,y;if(this.sphere){var sinphi,cosphi,coslam,sinlam;sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslam=Math.cos(lon);sinlam=Math.sin(lon);switch(this.mode){case this.EQUIT:y=1.+cosphi*coslam;if(y<=Proj4js.common.EPSLN){F_ERROR;}
+y=this.akm1/y;x=y*cosphi*sinlam;y*=sinphi;break;case this.OBLIQ:y=1.+this.sinph0*sinphi+this.cosph0*cosphi*coslam;if(y<=Proj4js.common.EPSLN){F_ERROR;}
+y=this.akm1/y;x=y*cosphi*sinlam;y*=this.cosph0*sinphi-this.sinph0*cosphi*coslam;break;case this.N_POLE:coslam=-coslam;lat=-lat;case this.S_POLE:if(Math.abs(lat-Proj4js.common.HALF_PI)<this.TOL){F_ERROR;}
+y=this.akm1*Math.tan(Proj4js.common.FORTPI+.5*lat);x=sinlam*y;y*=coslam;break;}}else{coslam=Math.cos(lon);sinlam=Math.sin(lon);sinphi=Math.sin(lat);if(this.mode==this.OBLIQ||this.mode==this.EQUIT){X=2.*Math.atan(this.ssfn_(lat,sinphi,this.e));sinX=Math.sin(X-Proj4js.common.HALF_PI);cosX=Math.cos(X);}
+switch(this.mode){case this.OBLIQ:A=this.akm1/(this.cosX1*(1.+this.sinX1*sinX+this.cosX1*cosX*coslam));y=A*(this.cosX1*sinX-this.sinX1*cosX*coslam);x=A*cosX;break;case this.EQUIT:A=2.*this.akm1/(1.+cosX*coslam);y=A*sinX;x=A*cosX;break;case this.S_POLE:lat=-lat;coslam=-coslam;sinphi=-sinphi;case this.N_POLE:x=this.akm1*Proj4js.common.tsfnz(this.e,lat,sinphi);y=-x*coslam;break;}
+x=x*sinlam;}
+p.x=x*this.a+this.x0;p.y=y*this.a+this.y0;return p;},inverse:function(p){var x=(p.x-this.x0)/this.a;var y=(p.y-this.y0)/this.a;var lon,lat;var cosphi,sinphi,tp=0.0,phi_l=0.0,rho,halfe=0.0,pi2=0.0;var i;if(this.sphere){var c,rh,sinc,cosc;rh=Math.sqrt(x*x+y*y);c=2.*Math.atan(rh/this.akm1);sinc=Math.sin(c);cosc=Math.cos(c);lon=0.;switch(this.mode){case this.EQUIT:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=0.;}else{lat=Math.asin(y*sinc/rh);}
+if(cosc!=0.||x!=0.)lon=Math.atan2(x*sinc,cosc*rh);break;case this.OBLIQ:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.phi0;}else{lat=Math.asin(cosc*sinph0+y*sinc*cosph0/rh);}
+c=cosc-sinph0*Math.sin(lat);if(c!=0.||x!=0.){lon=Math.atan2(x*sinc*cosph0,c*rh);}
+break;case this.N_POLE:y=-y;case this.S_POLE:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.phi0;}else{lat=Math.asin(this.mode==this.S_POLE?-cosc:cosc);}
+lon=(x==0.&&y==0.)?0.:Math.atan2(x,y);break;}}else{rho=Math.sqrt(x*x+y*y);switch(this.mode){case this.OBLIQ:case this.EQUIT:tp=2.*Math.atan2(rho*this.cosX1,this.akm1);cosphi=Math.cos(tp);sinphi=Math.sin(tp);if(rho==0.0){phi_l=Math.asin(cosphi*this.sinX1);}else{phi_l=Math.asin(cosphi*this.sinX1+(y*sinphi*this.cosX1/rho));}
+tp=Math.tan(.5*(Proj4js.common.HALF_PI+phi_l));x*=sinphi;y=rho*this.cosX1*cosphi-y*this.sinX1*sinphi;pi2=Proj4js.common.HALF_PI;halfe=.5*this.e;break;case this.N_POLE:y=-y;case this.S_POLE:tp=-rho/this.akm1;phi_l=Proj4js.common.HALF_PI-2.*Math.atan(tp);pi2=-Proj4js.common.HALF_PI;halfe=-.5*this.e;break;}
+for(i=this.NITER;i--;phi_l=lat){sinphi=this.e*Math.sin(phi_l);lat=2.*Math.atan(tp*Math.pow((1.+sinphi)/(1.-sinphi),halfe))-pi2;if(Math.abs(phi_l-lat)<this.CONV){if(this.mode==this.S_POLE)lat=-lat;lon=(x==0.&&y==0.)?0.:Math.atan2(x,y);p.x=Proj4js.common.adjust_lon(lon+this.long0);p.y=lat;return p;}}}}};Proj4js.Proj.nzmg={iterations:1,init:function(){this.A=new Array();this.A[1]=+0.6399175073;this.A[2]=-0.1358797613;this.A[3]=+0.063294409;this.A[4]=-0.02526853;this.A[5]=+0.0117879;this.A[6]=-0.0055161;this.A[7]=+0.0026906;this.A[8]=-0.001333;this.A[9]=+0.00067;this.A[10]=-0.00034;this.B_re=new Array();this.B_im=new Array();this.B_re[1]=+0.7557853228;this.B_im[1]=0.0;this.B_re[2]=+0.249204646;this.B_im[2]=+0.003371507;this.B_re[3]=-0.001541739;this.B_im[3]=+0.041058560;this.B_re[4]=-0.10162907;this.B_im[4]=+0.01727609;this.B_re[5]=-0.26623489;this.B_im[5]=-0.36249218;this.B_re[6]=-0.6870983;this.B_im[6]=-1.1651967;this.C_re=new Array();this.C_im=new Array();this.C_re[1]=+1.3231270439;this.C_im[1]=0.0;this.C_re[2]=-0.577245789;this.C_im[2]=-0.007809598;this.C_re[3]=+0.508307513;this.C_im[3]=-0.112208952;this.C_re[4]=-0.15094762;this.C_im[4]=+0.18200602;this.C_re[5]=+1.01418179;this.C_im[5]=+1.64497696;this.C_re[6]=+1.9660549;this.C_im[6]=+2.5127645;this.D=new Array();this.D[1]=+1.5627014243;this.D[2]=+0.5185406398;this.D[3]=-0.03333098;this.D[4]=-0.1052906;this.D[5]=-0.0368594;this.D[6]=+0.007317;this.D[7]=+0.01220;this.D[8]=+0.00394;this.D[9]=-0.0013;},forward:function(p){var lon=p.x;var lat=p.y;var delta_lat=lat-this.lat0;var delta_lon=lon-this.long0;var d_phi=delta_lat/Proj4js.common.SEC_TO_RAD*1E-5;var d_lambda=delta_lon;var d_phi_n=1;var d_psi=0;for(n=1;n<=10;n++){d_phi_n=d_phi_n*d_phi;d_psi=d_psi+this.A[n]*d_phi_n;}
+var th_re=d_psi;var th_im=d_lambda;var th_n_re=1;var th_n_im=0;var th_n_re1;var th_n_im1;var z_re=0;var z_im=0;for(n=1;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;z_re=z_re+this.B_re[n]*th_n_re-this.B_im[n]*th_n_im;z_im=z_im+this.B_im[n]*th_n_re+this.B_re[n]*th_n_im;}
+x=(z_im*this.a)+this.x0;y=(z_re*this.a)+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var x=p.x;var y=p.y;var delta_x=x-this.x0;var delta_y=y-this.y0;var z_re=delta_y/this.a;var z_im=delta_x/this.a;var z_n_re=1;var z_n_im=0;var z_n_re1;var z_n_im1;var th_re=0;var th_im=0;for(n=1;n<=6;n++){z_n_re1=z_n_re*z_re-z_n_im*z_im;z_n_im1=z_n_im*z_re+z_n_re*z_im;z_n_re=z_n_re1;z_n_im=z_n_im1;th_re=th_re+this.C_re[n]*z_n_re-this.C_im[n]*z_n_im;th_im=th_im+this.C_im[n]*z_n_re+this.C_re[n]*z_n_im;}
+for(i=0;i<this.iterations;i++){var th_n_re=th_re;var th_n_im=th_im;var th_n_re1;var th_n_im1;var num_re=z_re;var num_im=z_im;for(n=2;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;num_re=num_re+(n-1)*(this.B_re[n]*th_n_re-this.B_im[n]*th_n_im);num_im=num_im+(n-1)*(this.B_im[n]*th_n_re+this.B_re[n]*th_n_im);}
+th_n_re=1;th_n_im=0;var den_re=this.B_re[1];var den_im=this.B_im[1];for(n=2;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;den_re=den_re+n*(this.B_re[n]*th_n_re-this.B_im[n]*th_n_im);den_im=den_im+n*(this.B_im[n]*th_n_re+this.B_re[n]*th_n_im);}
+var den2=den_re*den_re+den_im*den_im;th_re=(num_re*den_re+num_im*den_im)/den2;th_im=(num_im*den_re-num_re*den_im)/den2;}
+var d_psi=th_re;var d_lambda=th_im;var d_psi_n=1;var d_phi=0;for(n=1;n<=9;n++){d_psi_n=d_psi_n*d_psi;d_phi=d_phi+this.D[n]*d_psi_n;}
+var lat=this.lat0+(d_phi*Proj4js.common.SEC_TO_RAD*1E5);var lon=this.long0+d_lambda;p.x=lon;p.y=lat;return p;}};Proj4js.Proj.mill={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon;var y=this.y0+this.a*Math.log(Math.tan((Proj4js.common.PI/4.0)+(lat/2.5)))*1.25;p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lon=Proj4js.common.adjust_lon(this.long0+p.x/this.a);var lat=2.5*(Math.atan(Math.exp(0.8*p.y/this.a))-Proj4js.common.PI/4.0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.gnom={init:function(def){this.sin_p14=Math.sin(this.lat0);this.cos_p14=Math.cos(this.lat0);this.infinity_dist=1000*this.a;},forward:function(p){var sinphi,cosphi;var dlon;var coslon;var ksp;var g;var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslon=Math.cos(dlon);g=this.sin_p14*sinphi+this.cos_p14*cosphi*coslon;ksp=1.0;if((g>0)||(Math.abs(g)<=Proj4js.common.EPSLN)){x=this.x0+this.a*ksp*cosphi*Math.sin(dlon)/g;y=this.y0+this.a*ksp*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon)/g;}else{Proj4js.reportError("orthoFwdPointError");x=this.x0+this.infinity_dist*cosphi*Math.sin(dlon);y=this.y0+this.infinity_dist*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon);}
+p.x=x;p.y=y;return p;},inverse:function(p){var rh;var z;var sinc,cosc;var c;var lon,lat;p.x=(p.x-this.x0)/this.a;p.y=(p.y-this.y0)/this.a;p.x/=this.k0;p.y/=this.k0;if((rh=Math.sqrt(p.x*p.x+p.y*p.y))){c=Math.atan2(rh,this.rc);sinc=Math.sin(c);cosc=Math.cos(c);lat=Proj4js.common.asinz(cosc*this.sin_p14+(p.y*sinc*this.cos_p14)/rh);lon=Math.atan2(p.x*sinc,rh*this.cos_p14*cosc-p.y*this.sin_p14*sinc);lon=Proj4js.common.adjust_lon(this.long0+lon);}else{lat=this.phic0;lon=0.0;}
+p.x=lon;p.y=lat;return p;}};Proj4js.Proj.sinu={init:function(){this.R=6370997.0;},forward:function(p){var x,y,delta_lon;var lon=p.x;var lat=p.y;delta_lon=Proj4js.common.adjust_lon(lon-this.long0);x=this.R*delta_lon*Math.cos(lat)+this.x0;y=this.R*lat+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var lat,temp,lon;p.x-=this.x0;p.y-=this.y0;lat=p.y/this.R;if(Math.abs(lat)>Proj4js.common.HALF_PI){Proj4js.reportError("sinu:Inv:DataError");}
+temp=Math.abs(lat)-Proj4js.common.HALF_PI;if(Math.abs(temp)>Proj4js.common.EPSLN){temp=this.long0+p.x/(this.R*Math.cos(lat));lon=Proj4js.common.adjust_lon(temp);}else{lon=this.long0;}
+p.x=lon;p.y=lat;return p;}};Proj4js.Proj.vandg={init:function(){this.R=6370997.0;},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x,y;if(Math.abs(lat)<=Proj4js.common.EPSLN){x=this.x0+this.R*dlon;y=this.y0;}
+var theta=Proj4js.common.asinz(2.0*Math.abs(lat/Proj4js.common.PI));if((Math.abs(dlon)<=Proj4js.common.EPSLN)||(Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI)<=Proj4js.common.EPSLN)){x=this.x0;if(lat>=0){y=this.y0+Proj4js.common.PI*this.R*Math.tan(.5*theta);}else{y=this.y0+Proj4js.common.PI*this.R*-Math.tan(.5*theta);}}
+var al=.5*Math.abs((Proj4js.common.PI/dlon)-(dlon/Proj4js.common.PI));var asq=al*al;var sinth=Math.sin(theta);var costh=Math.cos(theta);var g=costh/(sinth+costh-1.0);var gsq=g*g;var m=g*(2.0/sinth-1.0);var msq=m*m;var con=Proj4js.common.PI*this.R*(al*(g-msq)+Math.sqrt(asq*(g-msq)*(g-msq)-(msq+asq)*(gsq-msq)))/(msq+asq);if(dlon<0){con=-con;}
+x=this.x0+con;con=Math.abs(con/(Proj4js.common.PI*this.R));if(lat>=0){y=this.y0+Proj4js.common.PI*this.R*Math.sqrt(1.0-con*con-2.0*al*con);}else{y=this.y0-Proj4js.common.PI*this.R*Math.sqrt(1.0-con*con-2.0*al*con);}
+p.x=x;p.y=y;return p;},inverse:function(p){var dlon;var xx,yy,xys,c1,c2,c3;var al,asq;var a1;var m1;var con;var th1;var d;p.x-=this.x0;p.y-=this.y0;con=Proj4js.common.PI*this.R;xx=p.x/con;yy=p.y/con;xys=xx*xx+yy*yy;c1=-Math.abs(yy)*(1.0+xys);c2=c1-2.0*yy*yy+xx*xx;c3=-2.0*c1+1.0+2.0*yy*yy+xys*xys;d=yy*yy/c3+(2.0*c2*c2*c2/c3/c3/c3-9.0*c1*c2/c3/c3)/27.0;a1=(c1-c2*c2/3.0/c3)/c3;m1=2.0*Math.sqrt(-a1/3.0);con=((3.0*d)/a1)/m1;if(Math.abs(con)>1.0){if(con>=0.0){con=1.0;}else{con=-1.0;}}
+th1=Math.acos(con)/3.0;if(p.y>=0){lat=(-m1*Math.cos(th1+Proj4js.common.PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;}else{lat=-(-m1*Math.cos(th1+PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;}
+if(Math.abs(xx)<Proj4js.common.EPSLN){lon=this.long0;}
+lon=Proj4js.common.adjust_lon(this.long0+Proj4js.common.PI*(xys-1.0+Math.sqrt(1.0+2.0*(xx*xx-yy*yy)+xys*xys))/2.0/xx);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.cea={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon*Math.cos(this.lat_ts);var y=this.y0+this.a*Math.sin(lat)/Math.cos(this.lat_ts);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lon=Proj4js.common.adjust_lon(this.long0+(p.x/this.a)/Math.cos(this.lat_ts));var lat=Math.asin((p.y/this.a)*Math.cos(this.lat_ts));p.x=lon;p.y=lat;return p;}};Proj4js.Proj.eqc={init:function(){if(!this.x0)this.x0=0;if(!this.y0)this.y0=0;if(!this.lat0)this.lat0=0;if(!this.long0)this.long0=0;if(!this.lat_ts)this.lat_ts=0;if(!this.title)this.title="Equidistant Cylindrical (Plate Carre)";this.rc=Math.cos(this.lat_ts);},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var dlat=Proj4js.common.adjust_lat(lat-this.lat0);p.x=this.x0+(this.a*dlon*this.rc);p.y=this.y0+(this.a*dlat);return p;},inverse:function(p){var x=p.x;var y=p.y;p.x=Proj4js.common.adjust_lon(this.long0+((x-this.x0)/(this.a*this.rc)));p.y=Proj4js.common.adjust_lat(this.lat0+((y-this.y0)/(this.a)));return p;}};Proj4js.Proj.cass={init:function(){if(!this.sphere){this.en=this.pj_enfn(this.es)
+this.m0=this.pj_mlfn(this.lat0,Math.sin(this.lat0),Math.cos(this.lat0),this.en);}},C1:.16666666666666666666,C2:.00833333333333333333,C3:.04166666666666666666,C4:.33333333333333333333,C5:.06666666666666666666,forward:function(p){var x,y;var lam=p.x;var phi=p.y;lam=Proj4js.common.adjust_lon(lam-this.long0);if(this.sphere){x=Math.asin(Math.cos(phi)*Math.sin(lam));y=Math.atan2(Math.tan(phi),Math.cos(lam))-this.phi0;}else{this.n=Math.sin(phi);this.c=Math.cos(phi);y=this.pj_mlfn(phi,this.n,this.c,this.en);this.n=1./Math.sqrt(1.-this.es*this.n*this.n);this.tn=Math.tan(phi);this.t=this.tn*this.tn;this.a1=lam*this.c;this.c*=this.es*this.c/(1-this.es);this.a2=this.a1*this.a1;x=this.n*this.a1*(1.-this.a2*this.t*(this.C1-(8.-this.t+8.*this.c)*this.a2*this.C2));y-=this.m0-this.n*this.tn*this.a2*(.5+(5.-this.t+6.*this.c)*this.a2*this.C3);}
+p.x=this.a*x+this.x0;p.y=this.a*y+this.y0;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var x=p.x/this.a;var y=p.y/this.a;if(this.sphere){this.dd=y+this.lat0;phi=Math.asin(Math.sin(this.dd)*Math.cos(x));lam=Math.atan2(Math.tan(x),Math.cos(this.dd));}else{ph1=this.pj_inv_mlfn(this.m0+y,this.es,this.en);this.tn=Math.tan(ph1);this.t=this.tn*this.tn;this.n=Math.sin(ph1);this.r=1./(1.-this.es*this.n*this.n);this.n=Math.sqrt(this.r);this.r*=(1.-this.es)*this.n;this.dd=x/this.n;this.d2=this.dd*this.dd;phi=ph1-(this.n*this.tn/this.r)*this.d2*(.5-(1.+3.*this.t)*this.d2*this.C3);lam=this.dd*(1.+this.t*this.d2*(-this.C4+(1.+3.*this.t)*this.d2*this.C5))/Math.cos(ph1);}
+p.x=Proj4js.common.adjust_lon(this.long0+lam);p.y=phi;return p;},pj_enfn:function(es){en=new Array();en[0]=this.C00-es*(this.C02+es*(this.C04+es*(this.C06+es*this.C08)));en[1]=es*(this.C22-es*(this.C04+es*(this.C06+es*this.C08)));var t=es*es;en[2]=t*(this.C44-es*(this.C46+es*this.C48));t*=es;en[3]=t*(this.C66-es*this.C68);en[4]=t*es*this.C88;return en;},pj_mlfn:function(phi,sphi,cphi,en){cphi*=sphi;sphi*=sphi;return(en[0]*phi-cphi*(en[1]+sphi*(en[2]+sphi*(en[3]+sphi*en[4]))));},pj_inv_mlfn:function(arg,es,en){k=1./(1.-es);phi=arg;for(i=Proj4js.common.MAX_ITER;i;--i){s=Math.sin(phi);t=1.-es*s*s;t=(this.pj_mlfn(phi,s,Math.cos(phi),en)-arg)*(t*Math.sqrt(t))*k;phi-=t;if(Math.abs(t)<Proj4js.common.EPSLN)
+return phi;}
+Proj4js.reportError("cass:pj_inv_mlfn: Convergence error");return phi;},C00:1.0,C02:.25,C04:.046875,C06:.01953125,C08:.01068115234375,C22:.75,C44:.46875,C46:.01302083333333333333,C48:.00712076822916666666,C66:.36458333333333333333,C68:.00569661458333333333,C88:.3076171875}
+Proj4js.Proj.gauss={init:function(){sphi=Math.sin(this.lat0);cphi=Math.cos(this.lat0);cphi*=cphi;this.rc=Math.sqrt(1.0-this.es)/(1.0-this.es*sphi*sphi);this.C=Math.sqrt(1.0+this.es*cphi*cphi/(1.0-this.es));this.phic0=Math.asin(sphi/this.C);this.ratexp=0.5*this.C*this.e;this.K=Math.tan(0.5*this.phic0+Proj4js.common.FORTPI)/(Math.pow(Math.tan(0.5*this.lat0+Proj4js.common.FORTPI),this.C)*Proj4js.common.srat(this.e*sphi,this.ratexp));},forward:function(p){var lon=p.x;var lat=p.y;p.y=2.0*Math.atan(this.K*Math.pow(Math.tan(0.5*lat+Proj4js.common.FORTPI),this.C)*Proj4js.common.srat(this.e*Math.sin(lat),this.ratexp))-Proj4js.common.HALF_PI;p.x=this.C*lon;return p;},inverse:function(p){var DEL_TOL=1e-14;var lon=p.x/this.C;var lat=p.y;num=Math.pow(Math.tan(0.5*lat+Proj4js.common.FORTPI)/this.K,1./this.C);for(var i=Proj4js.common.MAX_ITER;i>0;--i){lat=2.0*Math.atan(num*Proj4js.common.srat(this.e*Math.sin(p.y),-0.5*this.e))-Proj4js.common.HALF_PI;if(Math.abs(lat-p.y)<DEL_TOL)break;p.y=lat;}
+if(!i){Proj4js.reportError("gauss:inverse:convergence failed");return null;}
+p.x=lon;p.y=lat;return p;}};Proj4js.Proj.omerc={init:function(){if(!this.mode)this.mode=0;if(!this.lon1){this.lon1=0;this.mode=1;}
+if(!this.lon2)this.lon2=0;if(!this.lat2)this.lat2=0;var temp=this.b/this.a;var es=1.0-Math.pow(temp,2);var e=Math.sqrt(es);this.sin_p20=Math.sin(this.lat0);this.cos_p20=Math.cos(this.lat0);this.con=1.0-this.es*this.sin_p20*this.sin_p20;this.com=Math.sqrt(1.0-es);this.bl=Math.sqrt(1.0+this.es*Math.pow(this.cos_p20,4.0)/(1.0-es));this.al=this.a*this.bl*this.k0*this.com/this.con;if(Math.abs(this.lat0)<Proj4js.common.EPSLN){this.ts=1.0;this.d=1.0;this.el=1.0;}else{this.ts=Proj4js.common.tsfnz(this.e,this.lat0,this.sin_p20);this.con=Math.sqrt(this.con);this.d=this.bl*this.com/(this.cos_p20*this.con);if((this.d*this.d-1.0)>0.0){if(this.lat0>=0.0){this.f=this.d+Math.sqrt(this.d*this.d-1.0);}else{this.f=this.d-Math.sqrt(this.d*this.d-1.0);}}else{this.f=this.d;}
+this.el=this.f*Math.pow(this.ts,this.bl);}
+if(this.mode!=0){this.g=.5*(this.f-1.0/this.f);this.gama=Proj4js.common.asinz(Math.sin(this.alpha)/this.d);this.longc=this.longc-Proj4js.common.asinz(this.g*Math.tan(this.gama))/this.bl;this.con=Math.abs(this.lat0);if((this.con>Proj4js.common.EPSLN)&&(Math.abs(this.con-Proj4js.common.HALF_PI)>Proj4js.common.EPSLN)){this.singam=Math.sin(this.gama);this.cosgam=Math.cos(this.gama);this.sinaz=Math.sin(this.alpha);this.cosaz=Math.cos(this.alpha);if(this.lat0>=0){this.u=(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}else{this.u=-(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}}else{Proj4js.reportError("omerc:Init:DataError");}}else{this.sinphi=Math.sin(this.at1);this.ts1=Proj4js.common.tsfnz(this.e,this.lat1,this.sinphi);this.sinphi=Math.sin(this.lat2);this.ts2=Proj4js.common.tsfnz(this.e,this.lat2,this.sinphi);this.h=Math.pow(this.ts1,this.bl);this.l=Math.pow(this.ts2,this.bl);this.f=this.el/this.h;this.g=.5*(this.f-1.0/this.f);this.j=(this.el*this.el-this.l*this.h)/(this.el*this.el+this.l*this.h);this.p=(this.l-this.h)/(this.l+this.h);this.dlon=this.lon1-this.lon2;if(this.dlon<-Proj4js.common.PI)this.lon2=this.lon2-2.0*Proj4js.common.PI;if(this.dlon>Proj4js.common.PI)this.lon2=this.lon2+2.0*Proj4js.common.PI;this.dlon=this.lon1-this.lon2;this.longc=.5*(this.lon1+this.lon2)-Math.atan(this.j*Math.tan(.5*this.bl*this.dlon)/this.p)/this.bl;this.dlon=Proj4js.common.adjust_lon(this.lon1-this.longc);this.gama=Math.atan(Math.sin(this.bl*this.dlon)/this.g);this.alpha=Proj4js.common.asinz(this.d*Math.sin(this.gama));if(Math.abs(this.lat1-this.lat2)<=Proj4js.common.EPSLN){Proj4js.reportError("omercInitDataError");}else{this.con=Math.abs(this.lat1);}
+if((this.con<=Proj4js.common.EPSLN)||(Math.abs(this.con-HALF_PI)<=Proj4js.common.EPSLN)){Proj4js.reportError("omercInitDataError");}else{if(Math.abs(Math.abs(this.lat0)-Proj4js.common.HALF_PI)<=Proj4js.common.EPSLN){Proj4js.reportError("omercInitDataError");}}
+this.singam=Math.sin(this.gam);this.cosgam=Math.cos(this.gam);this.sinaz=Math.sin(this.alpha);this.cosaz=Math.cos(this.alpha);if(this.lat0>=0){this.u=(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}else{this.u=-(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}}},forward:function(p){var theta;var sin_phi,cos_phi;var b;var c,t,tq;var con,n,ml;var q,us,vl;var ul,vs;var s;var dlon;var ts1;var lon=p.x;var lat=p.y;sin_phi=Math.sin(lat);dlon=Proj4js.common.adjust_lon(lon-this.longc);vl=Math.sin(this.bl*dlon);if(Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI)>Proj4js.common.EPSLN){ts1=Proj4js.common.tsfnz(this.e,lat,sin_phi);q=this.el/(Math.pow(ts1,this.bl));s=.5*(q-1.0/q);t=.5*(q+1.0/q);ul=(s*this.singam-vl*this.cosgam)/t;con=Math.cos(this.bl*dlon);if(Math.abs(con)<.0000001){us=this.al*this.bl*dlon;}else{us=this.al*Math.atan((s*this.cosgam+vl*this.singam)/con)/this.bl;if(con<0)us=us+Proj4js.common.PI*this.al/this.bl;}}else{if(lat>=0){ul=this.singam;}else{ul=-this.singam;}
+us=this.al*lat/this.bl;}
+if(Math.abs(Math.abs(ul)-1.0)<=Proj4js.common.EPSLN){Proj4js.reportError("omercFwdInfinity");}
+vs=.5*this.al*Math.log((1.0-ul)/(1.0+ul))/this.bl;us=us-this.u;var x=this.x0+vs*this.cosaz+us*this.sinaz;var y=this.y0+us*this.cosaz-vs*this.sinaz;p.x=x;p.y=y;return p;},inverse:function(p){var delta_lon;var theta;var delta_theta;var sin_phi,cos_phi;var b;var c,t,tq;var con,n,ml;var vs,us,q,s,ts1;var vl,ul,bs;var dlon;var flag;p.x-=this.x0;p.y-=this.y0;flag=0;vs=p.x*this.cosaz-p.y*this.sinaz;us=p.y*this.cosaz+p.x*this.sinaz;us=us+this.u;q=Math.exp(-this.bl*vs/this.al);s=.5*(q-1.0/q);t=.5*(q+1.0/q);vl=Math.sin(this.bl*us/this.al);ul=(vl*this.cosgam+s*this.singam)/t;if(Math.abs(Math.abs(ul)-1.0)<=Proj4js.common.EPSLN)
+{lon=this.longc;if(ul>=0.0){lat=Proj4js.common.HALF_PI;}else{lat=-Proj4js.common.HALF_PI;}}else{con=1.0/this.bl;ts1=Math.pow((this.el/Math.sqrt((1.0+ul)/(1.0-ul))),con);lat=Proj4js.common.phi2z(this.e,ts1);theta=this.longc-Math.atan2((s*this.cosgam-vl*this.singam),con)/this.bl;lon=Proj4js.common.adjust_lon(theta);}
+p.x=lon;p.y=lat;return p;}};Proj4js.Proj.lcc={init:function(){if(!this.lat2){this.lat2=this.lat0;}
+if(!this.k0)this.k0=1.0;if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("lcc:init: Equal Latitudes");return;}
+var temp=this.b/this.a;this.e=Math.sqrt(1.0-temp*temp);var sin1=Math.sin(this.lat1);var cos1=Math.cos(this.lat1);var ms1=Proj4js.common.msfnz(this.e,sin1,cos1);var ts1=Proj4js.common.tsfnz(this.e,this.lat1,sin1);var sin2=Math.sin(this.lat2);var cos2=Math.cos(this.lat2);var ms2=Proj4js.common.msfnz(this.e,sin2,cos2);var ts2=Proj4js.common.tsfnz(this.e,this.lat2,sin2);var ts0=Proj4js.common.tsfnz(this.e,this.lat0,Math.sin(this.lat0));if(Math.abs(this.lat1-this.lat2)>Proj4js.common.EPSLN){this.ns=Math.log(ms1/ms2)/Math.log(ts1/ts2);}else{this.ns=sin1;}
+this.f0=ms1/(this.ns*Math.pow(ts1,this.ns));this.rh=this.a*this.f0*Math.pow(ts0,this.ns);if(!this.title)this.title="Lambert Conformal Conic";},forward:function(p){var lon=p.x;var lat=p.y;if(lat<=90.0&&lat>=-90.0&&lon<=180.0&&lon>=-180.0){}else{Proj4js.reportError("lcc:forward: llInputOutOfRange: "+lon+" : "+lat);return null;}
+var con=Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI);var ts,rh1;if(con>Proj4js.common.EPSLN){ts=Proj4js.common.tsfnz(this.e,lat,Math.sin(lat));rh1=this.a*this.f0*Math.pow(ts,this.ns);}else{con=lat*this.ns;if(con<=0){Proj4js.reportError("lcc:forward: No Projection");return null;}
+rh1=0;}
+var theta=this.ns*Proj4js.common.adjust_lon(lon-this.long0);p.x=this.k0*(rh1*Math.sin(theta))+this.x0;p.y=this.k0*(this.rh-rh1*Math.cos(theta))+this.y0;return p;},inverse:function(p){var rh1,con,ts;var lat,lon;x=(p.x-this.x0)/this.k0;y=(this.rh-(p.y-this.y0)/this.k0);if(this.ns>0){rh1=Math.sqrt(x*x+y*y);con=1.0;}else{rh1=-Math.sqrt(x*x+y*y);con=-1.0;}
+var theta=0.0;if(rh1!=0){theta=Math.atan2((con*x),(con*y));}
+if((rh1!=0)||(this.ns>0.0)){con=1.0/this.ns;ts=Math.pow((rh1/(this.a*this.f0)),con);lat=Proj4js.common.phi2z(this.e,ts);if(lat==-9999)return null;}else{lat=-Proj4js.common.HALF_PI;}
+lon=Proj4js.common.adjust_lon(theta/this.ns+this.long0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.laea={S_POLE:1,N_POLE:2,EQUIT:3,OBLIQ:4,init:function(){var t=Math.abs(this.lat0);if(Math.abs(t-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.mode=this.lat0<0.?this.S_POLE:this.N_POLE;}else if(Math.abs(t)<Proj4js.common.EPSLN){this.mode=this.EQUIT;}else{this.mode=this.OBLIQ;}
+if(this.es>0){var sinphi;this.qp=Proj4js.common.qsfnz(this.e,1.0);this.mmf=.5/(1.-this.es);this.apa=this.authset(this.es);switch(this.mode){case this.N_POLE:case this.S_POLE:this.dd=1.;break;case this.EQUIT:this.rq=Math.sqrt(.5*this.qp);this.dd=1./this.rq;this.xmf=1.;this.ymf=.5*this.qp;break;case this.OBLIQ:this.rq=Math.sqrt(.5*this.qp);sinphi=Math.sin(this.lat0);this.sinb1=Proj4js.common.qsfnz(this.e,sinphi)/this.qp;this.cosb1=Math.sqrt(1.-this.sinb1*this.sinb1);this.dd=Math.cos(this.lat0)/(Math.sqrt(1.-this.es*sinphi*sinphi)*this.rq*this.cosb1);this.ymf=(this.xmf=this.rq)/this.dd;this.xmf*=this.dd;break;}}else{if(this.mode==this.OBLIQ){this.sinph0=Math.sin(this.lat0);this.cosph0=Math.cos(this.lat0);}}},forward:function(p){var x,y;var lam=p.x;var phi=p.y;lam=Proj4js.common.adjust_lon(lam-this.long0);if(this.sphere){var coslam,cosphi,sinphi;sinphi=Math.sin(phi);cosphi=Math.cos(phi);coslam=Math.cos(lam);switch(this.mode){case this.EQUIT:y=(this.mode==this.EQUIT)?1.+cosphi*coslam:1.+this.sinph0*sinphi+this.cosph0*cosphi*coslam;if(y<=Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:y less than eps");return null;}
+y=Math.sqrt(2./y);x=y*cosphi*Math.sin(lam);y*=(this.mode==this.EQUIT)?sinphi:this.cosph0*sinphi-this.sinph0*cosphi*coslam;break;case this.N_POLE:coslam=-coslam;case this.S_POLE:if(Math.abs(phi+this.phi0)<Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:phi < eps");return null;}
+y=Proj4js.common.FORTPI-phi*.5;y=2.*((this.mode==this.S_POLE)?Math.cos(y):Math.sin(y));x=y*Math.sin(lam);y*=coslam;break;}}else{var coslam,sinlam,sinphi,q,sinb=0.0,cosb=0.0,b=0.0;coslam=Math.cos(lam);sinlam=Math.sin(lam);sinphi=Math.sin(phi);q=Proj4js.common.qsfnz(this.e,sinphi);if(this.mode==this.OBLIQ||this.mode==this.EQUIT){sinb=q/this.qp;cosb=Math.sqrt(1.-sinb*sinb);}
+switch(this.mode){case this.OBLIQ:b=1.+this.sinb1*sinb+this.cosb1*cosb*coslam;break;case this.EQUIT:b=1.+cosb*coslam;break;case this.N_POLE:b=Proj4js.common.HALF_PI+phi;q=this.qp-q;break;case this.S_POLE:b=phi-Proj4js.common.HALF_PI;q=this.qp+q;break;}
+if(Math.abs(b)<Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:b < eps");return null;}
+switch(this.mode){case this.OBLIQ:case this.EQUIT:b=Math.sqrt(2./b);if(this.mode==this.OBLIQ){y=this.ymf*b*(this.cosb1*sinb-this.sinb1*cosb*coslam);}else{y=(b=Math.sqrt(2./(1.+cosb*coslam)))*sinb*this.ymf;}
+x=this.xmf*b*cosb*sinlam;break;case this.N_POLE:case this.S_POLE:if(q>=0.){x=(b=Math.sqrt(q))*sinlam;y=coslam*((this.mode==this.S_POLE)?b:-b);}else{x=y=0.;}
+break;}}
+p.x=this.a*x+this.x0;p.y=this.a*y+this.y0;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var x=p.x/this.a;var y=p.y/this.a;if(this.sphere){var cosz=0.0,rh,sinz=0.0;rh=Math.sqrt(x*x+y*y);var phi=rh*.5;if(phi>1.){Proj4js.reportError("laea:Inv:DataError");return null;}
+phi=2.*Math.asin(phi);if(this.mode==this.OBLIQ||this.mode==this.EQUIT){sinz=Math.sin(phi);cosz=Math.cos(phi);}
+switch(this.mode){case this.EQUIT:phi=(Math.abs(rh)<=Proj4js.common.EPSLN)?0.:Math.asin(y*sinz/rh);x*=sinz;y=cosz*rh;break;case this.OBLIQ:phi=(Math.abs(rh)<=Proj4js.common.EPSLN)?this.phi0:Math.asin(cosz*sinph0+y*sinz*cosph0/rh);x*=sinz*cosph0;y=(cosz-Math.sin(phi)*sinph0)*rh;break;case this.N_POLE:y=-y;phi=Proj4js.common.HALF_PI-phi;break;case this.S_POLE:phi-=Proj4js.common.HALF_PI;break;}
+lam=(y==0.&&(this.mode==this.EQUIT||this.mode==this.OBLIQ))?0.:Math.atan2(x,y);}else{var cCe,sCe,q,rho,ab=0.0;switch(this.mode){case this.EQUIT:case this.OBLIQ:x/=this.dd;y*=this.dd;rho=Math.sqrt(x*x+y*y);if(rho<Proj4js.common.EPSLN){p.x=0.;p.y=this.phi0;return p;}
+sCe=2.*Math.asin(.5*rho/this.rq);cCe=Math.cos(sCe);x*=(sCe=Math.sin(sCe));if(this.mode==this.OBLIQ){ab=cCe*this.sinb1+y*sCe*this.cosb1/rho
+q=this.qp*ab;y=rho*this.cosb1*cCe-y*this.sinb1*sCe;}else{ab=y*sCe/rho;q=this.qp*ab;y=rho*cCe;}
+break;case this.N_POLE:y=-y;case this.S_POLE:q=(x*x+y*y);if(!q){p.x=0.;p.y=this.phi0;return p;}
+ab=1.-q/this.qp;if(this.mode==this.S_POLE){ab=-ab;}
+break;}
+lam=Math.atan2(x,y);phi=this.authlat(Math.asin(ab),this.apa);}
+p.x=Proj4js.common.adjust_lon(this.long0+lam);p.y=phi;return p;},P00:.33333333333333333333,P01:.17222222222222222222,P02:.10257936507936507936,P10:.06388888888888888888,P11:.06640211640211640211,P20:.01641501294219154443,authset:function(es){var t;var APA=new Array();APA[0]=es*this.P00;t=es*es;APA[0]+=t*this.P01;APA[1]=t*this.P10;t*=es;APA[0]+=t*this.P02;APA[1]+=t*this.P11;APA[2]=t*this.P20;return APA;},authlat:function(beta,APA){var t=beta+beta;return(beta+APA[0]*Math.sin(t)+APA[1]*Math.sin(t+t)+APA[2]*Math.sin(t+t+t));}};Proj4js.Proj.aeqd={init:function(){this.sin_p12=Math.sin(this.lat0);this.cos_p12=Math.cos(this.lat0);},forward:function(p){var lon=p.x;var lat=p.y;var ksp;var sinphi=Math.sin(p.y);var cosphi=Math.cos(p.y);var dlon=Proj4js.common.adjust_lon(lon-this.long0);var coslon=Math.cos(dlon);var g=this.sin_p12*sinphi+this.cos_p12*cosphi*coslon;if(Math.abs(Math.abs(g)-1.0)<Proj4js.common.EPSLN){ksp=1.0;if(g<0.0){Proj4js.reportError("aeqd:Fwd:PointError");return;}}else{var z=Math.acos(g);ksp=z/Math.sin(z);}
+p.x=this.x0+this.a*ksp*cosphi*Math.sin(dlon);p.y=this.y0+this.a*ksp*(this.cos_p12*sinphi-this.sin_p12*cosphi*coslon);return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var rh=Math.sqrt(p.x*p.x+p.y*p.y);if(rh>(2.0*Proj4js.common.HALF_PI*this.a)){Proj4js.reportError("aeqdInvDataError");return;}
+var z=rh/this.a;var sinz=Math.sin(z);var cosz=Math.cos(z);var lon=this.long0;var lat;if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.lat0;}else{lat=Proj4js.common.asinz(cosz*this.sin_p12+(p.y*sinz*this.cos_p12)/rh);var con=Math.abs(this.lat0)-Proj4js.common.HALF_PI;if(Math.abs(con)<=Proj4js.common.EPSLN){if(lat0>=0.0){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x,-p.y));}else{lon=Proj4js.common.adjust_lon(this.long0-Math.atan2(-p.x,p.y));}}else{con=cosz-this.sin_p12*Math.sin(lat);if((Math.abs(con)<Proj4js.common.EPSLN)&&(Math.abs(p.x)<Proj4js.common.EPSLN)){}else{var temp=Math.atan2((p.x*sinz*this.cos_p12),(con*rh));lon=Proj4js.common.adjust_lon(this.long0+Math.atan2((p.x*sinz*this.cos_p12),(con*rh)));}}}
+p.x=lon;p.y=lat;return p;}};Proj4js.Proj.moll={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;var delta_lon=Proj4js.common.adjust_lon(lon-this.long0);var theta=lat;var con=Proj4js.common.PI*Math.sin(lat);for(var i=0;true;i++){var delta_theta=-(theta+Math.sin(theta)-con)/(1.0+Math.cos(theta));theta+=delta_theta;if(Math.abs(delta_theta)<Proj4js.common.EPSLN)break;if(i>=50){Proj4js.reportError("moll:Fwd:IterationError");}}
+theta/=2.0;if(Proj4js.common.PI/2-Math.abs(lat)<Proj4js.common.EPSLN)delta_lon=0;var x=0.900316316158*this.a*delta_lon*Math.cos(theta)+this.x0;var y=1.4142135623731*this.a*Math.sin(theta)+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var theta;var arg;p.x-=this.x0;var arg=p.y/(1.4142135623731*this.a);if(Math.abs(arg)>0.999999999999)arg=0.999999999999;var theta=Math.asin(arg);var lon=Proj4js.common.adjust_lon(this.long0+(p.x/(0.900316316158*this.a*Math.cos(theta))));if(lon<(-Proj4js.common.PI))lon=-Proj4js.common.PI;if(lon>Proj4js.common.PI)lon=Proj4js.common.PI;arg=(2.0*theta+Math.sin(2.0*theta))/Proj4js.common.PI;if(Math.abs(arg)>1.0)arg=1.0;var lat=Math.asin(arg);p.x=lon;p.y=lat;return p;}};
Index: /tags/rel-1.7.0/zoo-project/zoo-api/mono/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/mono/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/mono/Makefile	(revision 942)
@@ -0,0 +1,7 @@
+all: ZMaps.dll
+
+ZMaps.dll: ZMaps.cs
+	mcs /target:library ZMaps.cs
+
+clean:
+	rm ZMaps.dll
Index: /tags/rel-1.7.0/zoo-project/zoo-api/mono/ZMaps.cs
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/mono/ZMaps.cs	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/mono/ZMaps.cs	(revision 942)
@@ -0,0 +1,133 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2016 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+public static class ZOO_API{
+    public static int SERVICE_SUCCEEDED=3;
+    public static int SERVICE_FAILED=4;
+    [MethodImplAttribute(MethodImplOptions.InternalCall)]
+    extern public static string Translate(string str);
+    [MethodImplAttribute(MethodImplOptions.InternalCall)]
+    extern public static void UpdateStatus([In] ZooGenerics.ZMaps obj,string str,int p);
+};
+
+namespace ZooGenerics
+{
+    public class KeysList : List<String> { };
+    public class ZMap : Dictionary<String,String> {
+	public int getKeysCount(){
+	    List<String> tmp=new List<String>(this.Keys);
+	    return tmp.Count;
+	}
+	public String getKey(int i){
+	    List<String> tmp=new List<String>(this.Keys);
+	    return tmp[i];
+	}
+	public void addToMap(String name,String value){
+	    this.Add(name,value);
+	}
+	public String getMap(String name){
+	    String test;
+	    if(this.TryGetValue(name, out test)){
+		return test;
+	    }
+	    return null;
+	}
+	public byte[] getMapAsBytes(String name){
+	    String test;
+	    if(this.TryGetValue(name, out test)){
+		return System.Text.Encoding.UTF8.GetBytes(test);
+	    }
+	    return null;
+	}
+	public int getSize(){
+	    String test;
+	    if(this.TryGetValue("size", out test)){
+		return int.Parse(test);
+	    }
+	    return -1;
+	}
+    };
+    public class _ZMaps
+    {
+	private ZMap content; 
+	private Dictionary<string,_ZMaps> child;
+	public _ZMaps(){
+	    this.content=null;
+	    this.child=null;
+	}
+	public void setContent(ZMap content){
+	    this.content=content;
+	}
+	public void setChild(Dictionary<string,_ZMaps> content){
+	    this.child=content;
+	}
+	public void AddContent(String key,String value){
+	    this.content.Add(key,value);
+	}
+	public ZMap getContent(){
+	    return this.content;
+	}
+	public Dictionary<string,_ZMaps> getChild(){
+	    return this.child;
+	}
+    }
+    public class ZMaps : Dictionary<String,_ZMaps> {
+	public int getKeysCount(){
+	    List<String> tmp=new List<String>(this.Keys);
+	    return tmp.Count;
+	}
+	public String getKey(int i){
+	    List<String> tmp=new List<String>(this.Keys);
+	    return tmp[i];
+	}
+	public _ZMaps getValue(String key){
+	    return this[key];
+	}
+	public List<String> getKeys(){
+	    return new List<String>(this.Keys);
+	}
+	public void addToMaps(String name,_ZMaps content){
+	    this.Add(name,content);
+	}
+	public void setMapsInMaps(String mname,String name,String value){
+	    _ZMaps test;
+	    if (this.TryGetValue(mname, out test)) // Returns true.
+	    {
+		ZMap content=test.getContent();
+		content.addToMap(name,value);
+	    }
+	}
+	public _ZMaps getMaps(String name){
+	    _ZMaps test;
+	    if(this.TryGetValue(name, out test)){
+		return test;
+	    }
+	    return null;
+	}
+    };
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-api/mono/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/mono/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/mono/makefile.vc	(revision 942)
@@ -0,0 +1,9 @@
+!INCLUDE ../../zoo-kernel/nmake.opt
+
+all: ZMaps.dll
+
+ZMaps.dll: ZMaps.cs
+	$(MONO_DIR)\bin\mcs /target:library ZMaps.cs
+
+clean:
+	erase ZMaps.dll
Index: /tags/rel-1.7.0/zoo-project/zoo-api/r/minimal.r
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-api/r/minimal.r	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-api/r/minimal.r	(revision 942)
@@ -0,0 +1,7 @@
+ZOOTranslate <- function(a) {
+    return (.Call("ZOOTranslate",a))
+}
+
+ZOOUpdateStatus <- function(a,b) {
+    .Call("ZOOUpdateStatus",a,as.numeric(b))
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/utils.js
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/utils.js	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/utils.js	(revision 942)
@@ -0,0 +1,74 @@
+define([
+], function() {
+    
+    
+    // parseUri 1.2.2
+    // (c) Steven Levithan <stevenlevithan.com>
+    // MIT License
+
+    function parseUri (str) {
+    	var	o   = parseUri.options,
+    		m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
+    		uri = {},
+    		i   = 14;
+
+    	while (i--) uri[o.key[i]] = m[i] || "";
+
+    	uri[o.q.name] = {};
+    	uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
+    		if ($1) uri[o.q.name][$1] = $2;
+    	});
+
+    	return uri;
+    };
+
+    parseUri.options = {
+    	strictMode: false,
+    	key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
+    	q:   {
+    		name:   "queryKey",
+    		parser: /(?:^|&)([^&=]*)=?([^&]*)/g
+    	},
+    	parser: {
+    		strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
+    		loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
+    	}
+    };
+    
+    
+    //
+    function xmlToString(data) {
+        //data.xml check for IE
+        var xmlstr = data.xml ? data.xml : (new XMLSerializer()).serializeToString(data);
+        return xmlstr;
+    }
+
+    function equalsString(a, b) {
+    	if (!a) {
+    		return false;
+    	}
+
+    	if (!b) {
+    		return false;
+    	}
+
+    	return jQuery.trim(a).localeCompare(jQuery.trim(b)) == 0;
+    }
+
+    function encodeXML(str) {
+        return str.replace(/&/g, '&amp;')
+                   .replace(/</g, '&lt;')
+                   .replace(/>/g, '&gt;')
+                   .replace(/"/g, '&quot;')
+                   .replace(/'/g, '&apos;');
+    };
+    
+    return {
+        parseUri: parseUri,
+        xmlToString: xmlToString,
+        equalsString: equalsString,
+        encodeXML: encodeXML,
+    };
+    
+    
+});
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/wps-payload.js
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/wps-payload.js	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/wps-payload.js	(revision 942)
@@ -0,0 +1,292 @@
+/**
+ * Author : Samuel Souk aloun
+ *
+ * Copyright (c) 2014 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+define([
+    'jquery', 'utils'
+], function($, utils) {
+    
+    /**
+     * The wpsPayload module is using the 
+     * [Hogan.js]{@link http://twitter.github.io/hogan.js/} templating engine to
+     * generate XML requests to be sent to a WPS Server.
+     * In the ZOO-Client API, the Hogan.js templates have to be compiled before
+     * you can use them from you application. Please refer to the ZOO-Client 
+     * installation documentation for more information.
+     * 
+     * @module wpsPayload 
+     * @requires payloads
+     * @requires jquery
+     * @requires utils
+     */
+    
+    return {
+
+	/** @exports wpsPayload */
+        
+        /**
+	 * The getPayload function uses the mustache 
+	 * templates and the parameters provided to generate a valid WPS XML 
+	 * request.
+	 * 
+	 * @static
+	 * @param {Object} params - The object representing the request.
+	 * @returns {string} - The corresponding XML request
+	 * @example
+	 * // GetCapabilities
+	 * var request_params = {
+         *     request: 'GetCapabilities',
+	 *     language: 'en-US'
+         * };
+	 * console.wpsPayload.getPayload(request_params));
+	 * @example
+	 * // DescribeProcess with Identifier value set to "all".
+	 * var request_params = {
+         *     request: 'DescribeProcess',
+	 *     identifier: ["all"]
+         * };
+	 * console.log(wpsPayload.getPayload(request_params));
+	 * @example
+	 * //
+	 * var request_params = {
+	 *     request: 'Execute',
+	 *     Identifier: "Buffer",
+	 *     DataInputs: [{"identifier":"InputPolygon","href":"http://features.org/toto.xml","mimeType":"text/xml"}],
+	 *     DataOutputs: [{"identifier":"Result","mimeType":"application/json"}], 
+	 *     language: 'en-US'
+	 * };
+	 * console.log(wpsPayload.getPayload(request_params));
+	 */
+        getPayload: function(params) {
+            if (params.request == 'DescribeProcess') {
+                return this.getPayload_DescribeProcess(params);
+            } else if (params.request == 'GetCapabilities') {
+                return this.getPayload_GetCapabilities(params);
+            } else if (params.request == 'Execute') {
+                return this.getPayload_Execute(params);
+            } else if (params.request == 'Dismiss') {
+                return this.getPayload_Dismiss(params);
+            } else {
+                console.log("#### UNKNOWN REQUEST ####");
+            }
+        },
+
+        /**
+	 * The getPayload_GetCapabilities function is used to generate a valid 
+	 * WPS XML GetCapabilities request using the 
+	 * [payload_GetCapabilities.mustache]{@link http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-client/lib/tpl/payload_GetCapabilities.mustache} 
+	 * template.
+	 * 
+	 * @static
+	 * @param {Object} params - The object representing the request.
+	 * @returns {string} - The corresponding XML request
+	 * @example
+	 * // log the XML request in console
+	 * var request_params = {
+	 *     language: 'en-US'
+         * };
+	 * console.log(wpsPayload.getPayload_GetCapabilities(request_params));
+	 */
+        getPayload_GetCapabilities: function(params) {
+	    var id="payload_GetCapabilities";
+	    if(params.version=="2.0.0")
+		id+="2";
+	    return templates[id].render(params);
+        },
+        
+        /**
+	 * The getPayload_DescribeProcess function is used to generate a valid 
+	 * WPS XML DescribeProcess  request using the 
+	 * [payload_DescribeProcess.mustache]{@link http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-client/lib/tpl/payload_DescribeProcess.mustache} 
+	 * template.
+	 * 
+	 * @static
+	 * @param {Object} params - The object representing the request.
+	 * @returns {string} - The corresponding XML request
+	 * @example
+	 * // log the XML request in console
+	 * var request_params = {
+	 *     Identifier: ["Buffer","Centroid"],
+	 *     language: 'en-US'
+         * };
+	 * console.log(wpsPayload.getPayload_DescribeProcess(request_params));
+	 */
+        getPayload_DescribeProcess: function(params) {
+	    var id="payload_DescribeProcess";
+	    if(params.version=="2.0.0")
+		id+="2";
+            if (params.Identifier) {
+                if ($.isArray(params.Identifier)) {
+                    return templates[id].render({identifiers: params.Identifier,language: params.language});
+                }
+                else {
+                    return templates[id].render({identifiers: [params.Identifier],language: params.language});
+                }
+            }
+            // TODO: no Identifier
+        },
+
+        /**
+	 * The getPayload_Dismiss function is used to generate a valid 
+	 * WPS XML Dimiss request using the 
+	 * [payload_Dismiss.mustache]{@link http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-client/lib/tpl/payload_Dismiss.mustache} 
+	 * template.
+	 * 
+	 * @static
+	 * @param {Object} params - The object representing the request.
+	 * @returns {string} - The corresponding XML request
+	 * @example
+	 * // log the XML request in console
+	 * var request_params = {
+	 *     jobId: ["XXXX","XXX"]
+         * };
+	 * console.log(wpsPayload.getPayload_DescribeProcess(request_params));
+	 */
+        getPayload_Dismiss: function(params) {
+	    var id="payload_Dismiss";
+	    params.version="2.0.0";
+            if (params.jobid) {
+                if ($.isArray(params.jobid)) {
+                    return templates[id].render({jobid: params.jobid});
+                }
+                else {
+                    return templates[id].render({jobid: [params.jobid]});
+                }
+            }
+            // TODO: no Identifier
+        },
+
+
+        /**
+	 * The getPayload_Execute function is used to generate a valid WPS XML 
+	 * Excute request using the 
+	 * [payload_Execute.mustache]{@link http://zoo-project.org/trac/browser/trunk/zoo-project/zoo-client/lib/tpl/payload_Execute.mustache}
+	 * template.
+	 * 
+	 * @static
+	 * @param {Object} params - The object representing the request.
+	 * @returns {string} - The corresponding XML request
+	 * @example
+	 * // log the XML request in console
+	 * var request_params = {
+	 *     Identifier: "Buffer",
+	 *     DataInputs: [{"identifier":"InputPolygon","href":"http://features.org/toto.xml","mimeType":"text/xml"}],
+	 *     DataOutputs: [{"identifier":"Result","mimeType":"application/json"}], 
+	 *     language: 'en-US'
+	 * };
+	 * console.log(wpsPayload.getPayload_Execute(request_params));
+	 */
+        getPayload_Execute: function(params) {
+	    var id="payload_Execute";
+	    if(params.version=="2.0.0")
+		id+="2";
+            if (params.DataInputs) {
+                for (var i = 0; i < params.DataInputs.length; i++) {
+		    /**
+		     * Define inputs type depending on presence of mimeType, 
+		     * dataType and crs or dimension for ComplexData, 
+		     * LiteralData and BoundingBox data respectively
+		     */
+		    var hasType=false;
+		    var lp={"data":"literal","mime":"complex"};
+		    for(j in lp){
+			if (params.DataInputs[i][j+"Type"]) {
+			    params.DataInputs[i]['is_'+lp[j]] = true;
+			    params.DataInputs[i].type=lp[j];
+			    if(j=="mime"){
+				params.DataInputs[i].is_XML=(params.DataInputs[i][j+"Type"]=="text/xml");
+				if(!params.DataInputs[i].is_XML){
+				    var tmp=params.DataInputs[i][j+"Type"].split(";");
+				    params.DataInputs[i].is_XML=(tmp[0]=="text/xml");
+				}
+			    }
+			    hasType=true;
+			}
+                    }
+		    if(!hasType){
+			if (params.DataInputs[i]["type"]=="bbox" || 
+			    params.DataInputs[i]["dimension"] || 
+			    params.DataInputs[i]["crs"]){
+
+			    params.DataInputs[i]['is_bbox'] = true;
+			    params.DataInputs[i].type='bbox';
+			    hasType=true;
+			    
+			}
+			if(!hasType){
+			    params.DataInputs[i]['is_literal'] = true;
+			    params.DataInputs[i].type = "literal";
+			}
+		    }
+                    /*
+                     * Set some default values and flags.
+                     */
+                    if (params.DataInputs[i].type == 'bbox') {
+                	if (!params.DataInputs[i].crs) {
+                    	    params.DataInputs[i].crs = "EPSG:4326";
+                    	}
+                    	if (!params.DataInputs[i].dimension) {
+                    	    params.DataInputs[i].dimension = 2;
+                    	}
+            	    }
+                    
+                    // Complex data from payload callback.
+                    if (params.DataInputs[i].complexPayload_callback) {
+                        params.DataInputs[i].value = window[params.DataInputs[i].complexPayload_callback];
+                    }
+                    
+                    // Complex data from reference.
+                    if (params.DataInputs[i].href) {
+                        params.DataInputs[i].is_reference = true;
+                        //params.DataInputs[i].href = utils.encodeXML(params.DataInputs[i].href);
+                        if (params.DataInputs[i].method == 'POST') {
+                            params.DataInputs[i].is_post = true;
+                        } else {
+                            params.DataInputs[i].is_get = true;
+                        }
+                    }
+                    else {                        
+                        // Complex data, embeded
+                    }
+                } // for i loop
+            }
+
+            //console.log("==== OUTPUTS ====");
+            if (params.DataOutputs || params.storeExecuteResponse || params.status || params.lineage) {
+                
+                for (var i = 0; i < params.DataOutputs.length; i++) {
+                    //console.log(params.DataOutputs[i]);
+                    
+                    if (params.DataOutputs[i].type) {
+                        params.DataOutputs[i]['is_'+params.DataOutputs[i].type] = true;
+                    }
+                }
+            }
+            
+            return templates[id].render(params);
+        },
+        
+
+    };
+
+});
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/zoo.js
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/zoo.js	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/js/wps-client/zoo.js	(revision 942)
@@ -0,0 +1,1003 @@
+/**
+ * Author : Samuel Souk aloun
+ *
+ * Copyright (c) 2014 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+define([
+    'xml2json', 'queryString', 'wpsPayload', 'utils'
+], function(X2JS, qs, wpsPayload, utils) {
+
+    /** 
+     * The ZooProcess Class
+     * @constructs ZooProcess
+     * @param {Object} params Parameters
+     * @example
+     * var myZooObject = new ZooProcess({
+     *     url: "http://localhost/cgi-bin/zoo_loader.cgi",
+     *     delay: 2500
+     * });
+     */
+    var ZooProcess = function(params) {
+        
+        /**
+	 * Object configuring the xml2json use.
+	 *
+         * @access private
+	 * @memberof ZooProcess#
+	 * @var _x2js {x2js}
+         */         
+        var _x2js = new X2JS({
+            arrayAccessFormPaths: [
+            'ProcessDescriptions.ProcessDescription.DataInputs.Input',
+            'ProcessDescriptions.ProcessDescription.DataInputs.Input.ComplexData.Supported.Format',
+            'ProcessDescriptions.ProcessDescription.ProcessOutputs.Output',
+            'ProcessDescriptions.ProcessDescription.ProcessOutputs.Output.ComplexOutput.Supported.Format',
+            'Capabilities.ServiceIdentification.Keywords'
+            ],   
+        });
+
+       
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var debug {Boolean} true if verbose messages should be displayed on the console
+	 * @default false
+         */         
+        this.debug = false;
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var url {String} The WPS Server URL
+	 */
+        this.url = params.url;
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var version {String} The WPS version
+	 */
+        this.version = params.version?params.version:"1.0.0";
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var language {String} The language to be used to request the WPS Server
+	 * @default "en-US"
+	 */
+        this.language = params.language?params.language:"en-US";
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var statusLocation {Object} An object to store the statusLocation 
+	 * URLs when running request including both the storeExecuteResponse and
+	 * the status parameters set to true.
+	 */
+        this.statusLocation = {};
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var launched {Object} An object to store the running asynchrone services.
+	 */
+        this.launched = {};
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var terminated {Object} An object to store the finished services.
+	 */
+        this.terminated = {};
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var percent {Object} An object to store the percentage of completude of services.
+	 */
+        this.percent = {};
+        /**
+         * @access public
+	 * @memberof ZooProcess#
+	 * @var delay {Integer} The time (in milliseconds) between each polling requests.
+	 * @default 2000
+	 */
+        this.delay = params.delay || 2000;
+        
+	/**
+	 * The getCapabilities method run the GetCapabilities request by calling {@link ZooProcess#request}.
+	 * 
+	 * @method getCapabilities
+	 * @memberof ZooProcess#
+	 * @param {Object} params The parameter for the request and callback functions to call on success or
+	 * on failure.
+	 * @example
+	 * // Log the array of available processes in console
+	 * myZooObject.getCapabilities({
+	 *     type: 'POST',
+	 *     success: function(data){
+	 *         console.log(data["Capabilities"]["ProcessOfferings"]["Process"]);
+	 *     }
+	 * });
+	 */
+        this.getCapabilities = function(params) {
+            var closure = this;
+
+            if (!params.hasOwnProperty('type')) {
+                params.type = 'GET';
+            }
+
+            var zoo_request_params = {
+                request: 'GetCapabilities',
+                service: 'WPS',
+                version: (params.hasOwnProperty('version')?params.version:closure.version),
+            }
+
+            this.request(zoo_request_params, params.success, params.error, params.type);
+        };
+        
+	/**
+	 * The describeProcess method run the DescribeProcess request by calling {@link ZooProcess#request}.
+	 * 
+	 * @method describeProcess
+	 * @memberof ZooProcess#
+	 * @param {Object} params 
+	 * @example
+	 * // Log x2js representation of all available services in console
+	 * myZooObject.describeProcess({
+	 *     type: 'POST',
+	 *     identifier: "all"
+	 *     success: function(data){
+	 *         console.log(data);
+	 *     }
+	 * });
+	 */
+        this.describeProcess = function(params) {
+            var closure = this;
+
+            if (!params.hasOwnProperty('type')) {
+                params.type = 'GET';
+            }
+
+            var zoo_request_params = {
+                Identifier: params.identifier,
+                request: 'DescribeProcess',
+                service: 'WPS',
+                version: (params.hasOwnProperty('version')?params.version:closure.version),
+            }
+
+            this.request(zoo_request_params, params.success, params.error, params.type);
+        };
+        
+	/**
+	 * The convertParams method convert parameters for Execute requests
+	 *
+	 * @method convertParams
+	 * @memberof ZooProcess#
+	 * @param {Object} params The original object
+	 * @returns {Object} The converted object
+	 */
+	this.convertParams = function(params){
+	    var closure = this;
+	    if(closure.debug){
+		console.log("======== Execute "+params.identifier);
+		console.log(params);
+	    }
+
+            if (!params.hasOwnProperty('type')) {
+                params.type = 'GET';
+            }
+
+            var zoo_request_params = {
+                request: 'Execute',
+                service: 'WPS',
+                version: (params.hasOwnProperty('version')?params.version:closure.version),
+                Identifier: params.identifier,
+                DataInputs: params.dataInputs ? params.dataInputs : '',
+                DataOutputs: params.dataOutputs ? params.dataOutputs : '',
+            }
+
+	    console.log(zoo_request_params);
+
+            if (params.hasOwnProperty('responseDocument')) {
+                zoo_request_params.ResponseDocument = params.responseDocument;
+            }
+            if (params.hasOwnProperty('mode')) {
+                zoo_request_params.mode = params.mode;
+            }
+            if (params.hasOwnProperty('storeExecuteResponse') &&  params.storeExecuteResponse) {
+                zoo_request_params.storeExecuteResponse = 'true';
+            }
+            if (params.hasOwnProperty('status') &&  params.status) {
+                zoo_request_params.status = 'true';
+            }
+            if (params.hasOwnProperty('lineage') &&  params.lineage) {
+                zoo_request_params.lineage = 'true';
+            }
+	    return zoo_request_params;
+	};
+
+	/**
+	 * The buildRequest method is building the object expected by
+	 * [jQuery.ajax]{@link http://api.jquery.com/jquery.ajax/}.
+	 * In case of GET request, it will use {@link ZooProcess#getQueryString}.
+	 * In case of POST request, it will use {@link module:wpsPayload} getPayload.
+	 *
+	 * @method buildRequest
+	 * @memberof ZooProcess#
+	 * @param {Object} params the request parameters
+	 * @param {String} type the request method ("GET" or "POST")
+	 * @returns {Object} The expected object to give as input for the 
+	 * [jQuery.ajax]{@link http://api.jquery.com/jquery.ajax/} function.
+	 */
+	this.buildRequest = function(params,type){
+            var closure = this;
+	    if(closure.debug){
+		console.log('======== REQUEST method='+type);
+		console.log(params);
+	    }
+            var url = this.url;
+            var payload;
+            var headers;
+	    if(params.hasOwnProperty('DataOutputs'))
+		for(var i=0;i<params.DataOutputs.length;i++)
+		    if(params.DataOutputs[i].type==="raw"){
+			params["RawDataOutput"]=params.DataOutputs[i];
+			break;
+		    }
+
+	    params["language"]=this.language;
+            if (type == 'GET') {
+                url += '?' + this.getQueryString(params);
+            } else if (type == 'POST') {
+                payload = wpsPayload.getPayload(params);
+		if(closure.debug){
+                    console.log("======== POST PAYLOAD ========");
+                    console.log(payload);
+		    console.log(params);
+		}
+
+                headers = {
+                    "Content-Type": "text/xml"        
+                };
+            }
+	    
+            if(closure.debug){
+		console.log("ajax url: "+url);
+	    }
+	    return {"url":url,"headers": headers,"data": payload,"type":type};
+	};
+
+	/**
+	 * The getRequest method call the {@link ZooProcess#buildRequest} method
+	 * by giving the {@link ZooProcess#convertParams} result as first 
+	 * argument and the detected type (default is 'GET') defined in params.
+	 * 
+	 * @method getRequest
+	 * @memberof ZooProcess#
+	 * @params {Object} params The request parameters
+	 */
+	this.getRequest = function(params){
+	    var closure = this;
+	    var type = 'GET';
+	    if(params.hasOwnProperty("type"))
+		type=params["type"];
+	    return closure.buildRequest(closure.convertParams(params),type);
+	};
+
+	/**
+	 * The execute method run the Execute request by calling {@link ZooProcess#request}
+	 * with the params converted by {@link ZooProcess#convertParams}.
+	 *
+	 * @method execute
+	 * @memberof ZooProcess#
+	 * @param {Object} param Parameters
+	 * @example
+	 * myZooObject.execute({
+	 *     identifier: "Buffer",
+	 *     dataInputs: [{"identifier":"InputPolygon","href":"http://features.org/toto.xml","mimeType":"text/xml"}],
+	 *     dataOutputs: [{"identifier":"Result","mimeType":"application/json","type":"raw"}],
+	 *     type: 'POST',
+	 *     success: function(data) {
+	 *         console.log(data);
+	 *     }
+	 * });
+	 */
+        this.execute = function(params) {
+            var closure = this;
+            this.request(closure.convertParams(params), params.success, params.error, params.type);
+        };
+
+        
+	/**
+	 * The request method call {@link ZooProcess#buildRequest} method to
+	 * to build parameters to give to 
+	 * [jQuery.ajax]{@link http://api.jquery.com/jquery.ajax/}.
+	 * If the request succeed and if the content-type of the response is 
+	 * "text/xml" then xml2json is called on the resulting data and passed 
+	 * to the onSuccess callback function given in parameter. In case the
+	 * request failed, the WPS Exception Repport will be parsed with 
+	 * xml2json and given as parameter to the onError callback function.
+	 *
+	 * @method request
+	 * @memberof ZooProcess#
+	 * @param {Object} params The object used as parameter for
+	 * [jQuery.ajax]{@link http://api.jquery.com/jquery.ajax/}
+	 * @param {Function} onSuccess The callback function called if the request succeed
+	 * @param {Function} onError The callback function called if the request failed 
+	 * @param {String} type The request method ('GET' or 'POST')
+	 */
+        this.request = function(params, onSuccess, onError, type) {
+            var closure = this;
+
+	    var obj;
+	    obj=closure.buildRequest(params,type);
+            $.ajax(obj)
+		.always(
+                    function() {
+			//console.log("ALWAYS");
+                    }
+		)
+		.fail(
+                    function(jqXHR, textStatus, errorThrown) {
+			if(closure.debug){
+			    console.log("======== ERROR ========");
+			}
+			var robj=_x2js.xml2json( jqXHR.responseXML );
+			if(closure.debug){
+			    console.log(robj);
+			}
+			if(onError)
+			    onError(robj);
+                    }
+		)
+		.done(
+                    function(data, textStatus, jqXHR) {
+			if(closure.debug){
+			    console.log("======== SUCCESS ========2");
+			    console.log(data);
+			}
+			var ctype=jqXHR.getResponseHeader("Content-Type").split(";")[0];
+			if( ctype=="text/xml" )
+			{
+			    var tmpD=data;
+			    data = _x2js.xml2json( data );
+			    data._origin=tmpD;
+			}
+			var launched;
+			var version=(params.version?params.version:closure.version);
+			if(version=="1.0.0"){
+			    if (params.storeExecuteResponse == 'true' && params.status == 'true') {
+				launched = closure.parseStatusLocation(data);            
+				closure.statusLocation[launched.sid] = launched.statusLocation;
+				
+				if ( launched.hasOwnProperty('sid') && 
+				     !closure.launched.hasOwnProperty(launched.sid)) {
+				    closure.launched[launched.sid] = launched.statusLocation;
+				}
+			    }
+			}
+			else{
+			    if (params.mode == 'async') {
+				launched = closure.parseJobID(data);
+				closure.statusLocation[launched.sid] = closure.url+"?request=GetStatus&service=WPS&version=2.0.0&JobID="+launched.jobid;
+				if ( launched.hasOwnProperty('sid') && 
+				     !closure.launched.hasOwnProperty(launched.sid)) {
+				    closure.launched[launched.sid] = launched.jobid;
+				}
+			    }	    
+			}
+
+			if(onSuccess)
+			    onSuccess(data, launched);
+		    });
+        };
+        
+	/**
+	 * The watch method should be used from the success callback function
+	 * passed to {@link ZooProcess#execute} when both status and 
+	 * storeExecuteResponse parameters are set to 'true', so when the 
+	 * service should be called asynchronously. This function is
+	 * responsible for polling the WPS server until the service end (success
+	 * or failure). It call the {@link ZooProcess#getStatus} method every
+	 * {@link ZooProcess#delay} milliseconds.
+	 *
+	 * @method watch
+	 * @memberof ZooProcess#
+	 * @param {Integer} sid The identifier of the running service
+	 * @param {Object} handlers The callback function definitions 
+	 * (onPercentCompleted, onProcessSucceeded, onError)
+	 * @example
+	 * zoo.execute({
+	 *     identifier: 'MyIdentifier',
+	 *     type: 'POST',
+	 *     dataInputs: myInputs,
+	 *     dataOutputs: myOupts,
+	 *     storeExecuteResponse: true,
+	 *     status: true,
+	 *     success: function(data, launched) {
+	 *         zoo.watch(launched.sid, {
+         *             onPercentCompleted: function(data) {
+	 *                 console.log("**** PercentCompleted ****");
+	 *                 console.log(data);
+         *                 progress.text(data.text+' : '+(data.percentCompleted)+'%');
+         *             },
+	 *             onProcessSucceeded: function(data) {
+         *                 progress.css('width', (100)+'%');
+	 *                 progress.text(data.text+' : '+(100)+'%');
+	 *                     if (data.result.ExecuteResponse.ProcessOutputs) {
+	 *                         console.log("**** onSuccess ****");
+	 *                         console.log(data.result);
+	 *                     }
+	 *             },
+	 *             onError: function(data) {
+	 *                 console.log("**** onError ****");
+	 *                 console.log(data);
+	 *             },
+         *         });
+	 *     },
+	 *     error: function(data) {
+	 *         console.log("**** ERROR ****");
+	 *         console.log(data);
+	 *         notify("Execute asynchrone failed", 'danger');
+	 *     }
+	 * });
+	 */
+        this.watch = function(sid, handlers) {
+            //onPercentCompleted, onProcessSucceeded, onError
+            var closure = this;
+	    if(closure.debug){
+		console.log("WATCH: "+sid);
+	    }
+
+            function onSuccess(data) {
+		if(closure.debug){
+                    console.log("++++ getStatus SUCCESS "+sid);
+                    console.log(data);
+		}
+
+		if(data.StatusInfo || data.Result){
+		    if (data.Result) {
+
+			var ret = {
+                            sid: sid,
+                            text: "",
+                            result: data
+			};
+
+			if (handlers.onProcessSucceeded instanceof Function) {
+                            handlers.onProcessSucceeded(ret);
+			}
+
+			return;
+		    }
+		    if (data.StatusInfo.Status == "Running") {
+			if(closure.debug){
+			    console.log("#### ProcessStarted");
+			}
+			
+			var message="";
+			for(index=0;index<data._origin.childNodes[0].childNodes.length;index++){
+			    if(data._origin.childNodes[0].childNodes[index].nodeType==8){
+				message=data._origin.childNodes[0].childNodes[index].textContent;
+			    }
+			}
+			var ret = {
+                            sid: sid,
+                            percentCompleted: (data.StatusInfo.PercentCompleted?data.StatusInfo.PercentCompleted:0),
+                            text: message,
+                            creationTime: "",
+			};
+
+			if (handlers.onPercentCompleted instanceof Function) {
+                            handlers.onPercentCompleted(ret);
+			}
+                    }
+                    else if (data.StatusInfo.Status == "Succeeded") {
+			if(closure.debug){
+			    console.log("#### ProcessSucceeded");
+			}
+
+			var text = "";
+			closure.terminated[sid] = true;
+
+			ret = {
+                            sid: sid,
+                            text: text,
+                            result: data
+			};
+			
+			closure.getResult(sid, onSuccess, onError);
+                    }
+                    else {
+			if(closure.debug){
+			    console.log("#### UNHANDLED EXCEPTION");
+			}
+			closure.terminated[sid] = true;
+			ret = {
+                            sid: sid,
+                            code: 'BAD',
+                            text: 'UNHANDLED EXCEPTION'
+			};
+			
+			//closure.emit('exception', ret);
+			if (handlers.onError instanceof Function) {
+                            handlers.onError(ret);
+			}
+                    }
+
+		    return
+		}
+
+		if (data.ExecuteResponse.Status.ProcessAccepted) {
+                    var ret = {
+                        sid: sid,
+                        percentCompleted: 0,
+                        text: data.ExecuteResponse.Status.ProcessAccepted.__text,
+                        creationTime: data.ExecuteResponse.Status._creationTime,
+                    };
+
+                    closure.percent[sid] = ret.percentCompleted;
+                    //closure.emit('percent', ret);
+
+                    if (handlers.onPercentCompleted instanceof Function) {
+                        handlers.onPercentCompleted(ret);
+                    }
+
+		}
+                else if (data.ExecuteResponse.Status.ProcessStarted) {
+		    if(closure.debug){
+			console.log("#### ProcessStarted");
+		    }
+
+                    var ret = {
+                        sid: sid,
+                        percentCompleted: data.ExecuteResponse.Status.ProcessStarted._percentCompleted,
+                        text: data.ExecuteResponse.Status.ProcessStarted.__text,
+                        creationTime: data.ExecuteResponse.Status._creationTime,
+                    };
+
+                    closure.percent[sid] = ret.percentCompleted;
+                    //closure.emit('percent', ret);
+
+                    if (handlers.onPercentCompleted instanceof Function) {
+                        handlers.onPercentCompleted(ret);
+                    }
+                }
+                else if (data.ExecuteResponse.Status.ProcessSucceeded) {
+		    if(closure.debug){
+			console.log("#### ProcessSucceeded");
+		    }
+
+                    var text = data.ExecuteResponse.Status.ProcessSucceeded.__text;
+                    closure.terminated[sid] = true;
+
+                    ret = {
+                        sid: sid,
+                        text: text,
+                        result: data
+                    };
+
+                    //closure.emit('success', ret);
+                    if (handlers.onProcessSucceeded instanceof Function) {
+                        handlers.onProcessSucceeded(ret);
+                    }
+                }
+                else {
+		    if(closure.debug){
+			console.log("#### UNHANDLED EXCEPTION");
+		    }
+                    closure.terminated[sid] = true;
+                    ret = {
+                        sid: sid,
+                        code: 'BAD',
+                        text: 'UNHANDLED EXCEPTION'
+                    };
+
+                    //closure.emit('exception', ret);
+                    if (handlers.onError instanceof Function) {
+                        handlers.onError(ret);
+                    }
+                }    
+            }
+
+            function onError(data) {
+		if(closure.debug){
+                    console.log("++++ getStatus ERROR "+sid);
+                    console.log(data);
+		}
+            }
+
+            function ping(sid) {
+		if(closure.debug){
+                    console.log("PING: "+sid);
+		}
+
+                closure.getStatus(sid, onSuccess, onError);
+                if (closure.terminated[sid]) {
+		    if(closure.debug){
+			console.log("++++ getStatus TERMINATED "+sid);
+		    }
+                }
+                else if (!closure.percent.hasOwnProperty(sid) || closure.percent[sid]<100) {
+                    setTimeout( function() {
+                        ping(sid);
+                     }, closure.delay);
+                } else {
+		    if(closure.debug){
+			console.log(closure.percent);
+		    }
+                }
+            }
+
+            ping(sid);
+        };
+        
+	/**
+	 * The getStatus method call 
+	 * [jQuery.ajax]{@link http://api.jquery.com/jquery.ajax/} to fecth the
+	 * ExecuteResponse document which contains a Status node and
+	 * potentially the result (when the asynch service end). This method is
+	 * used by {@link ZooProcess#watch} to get the ongoing status of 
+	 * services called asynchronously.
+	 * 
+	 * @method getStatus
+	 * @memberof ZooProcess#
+	 * @param {Integer} sid Service Identifier
+	 * @param {Function} onSuccess callback 
+	 * @param {Function} onError callback 
+	 */
+        this.getStatus = function(sid, onSuccess, onError) {
+            var closure = this;
+	    if(closure.debug){
+		console.log("GET STATUS: "+sid);
+	    }
+            if (closure.terminated[sid]) {
+		if(closure.debug){
+                    console.log("DEBUG TERMINATED");
+		}
+                return;
+            }
+            if (!closure.launched[sid]) {
+		if(closure.debug){
+                    console.log("DEBUG LAUNCHED");
+		}
+                return;
+            }
+
+            $.ajax({
+		url: closure.statusLocation[sid]+"&timestamp="++(new Date()).getTime()
+	    })
+		.fail(
+                    function(jqXHR, textStatus, errorThrown) {
+			if(closure.debug){
+			    console.log("======== ERROR ========");
+			}
+			var robj=_x2js.xml2json( jqXHR.responseXML );
+			if(closure.debug){
+			    console.log(robj);
+			}
+			if(onError)
+			    onError(robj);
+                    }
+		)
+		.done(
+                    function(data, textStatus, jqXHR) {
+			if(closure.debug){
+			    console.log("======== SUCCESS ========2");
+			    console.log(data);
+			}
+			var ctype=jqXHR.getResponseHeader("Content-Type").split(";")[0];
+			if( ctype=="text/xml" ){
+			    var tmpD=data;
+			    data = _x2js.xml2json( data );
+			    data._origin=tmpD;
+			}
+			if(onSuccess)
+			    onSuccess(data);
+		    });
+        };
+
+	/**
+	 * The getResult method is used by {@link ZooProcess#watch} to get the
+	 * final result of services called asynchronously.
+	 * 
+	 * @method getResult
+	 * @memberof ZooProcess#
+	 * @param {Integer} sid Service Identifier
+	 * @param {Function} onSuccess callback 
+	 * @param {Function} onError callback 
+	 */
+        this.getResult = function(sid, onSuccess, onError) {
+            var closure = this;
+	    if(closure.debug){
+		console.log("GET STATUS: "+sid);
+		console.log(closure.statusLocation[sid].replace(/GetStatus/g,"GetResult"));
+	    }
+            $.ajax({
+		url: closure.statusLocation[sid].replace(/GetStatus/g,"GetResult")
+	    })
+		.fail(
+                    function(jqXHR, textStatus, errorThrown) {
+			if(closure.debug){
+			    console.log("======== ERROR ========");
+			}
+			var robj=_x2js.xml2json( jqXHR.responseXML );
+			if(closure.debug){
+			    console.log(robj);
+			}
+			if(onError)
+			    onError(robj);
+                    }
+		)
+		.done(
+                    function(data, textStatus, jqXHR) {
+			if(closure.debug){
+			    console.log("======== SUCCESS ========2");
+			    console.log(data);
+			}
+			var ctype=jqXHR.getResponseHeader("Content-Type").split(";")[0];
+			if( ctype=="text/xml" ){
+			    var tmpD=data;
+			    data = _x2js.xml2json( data );
+			    data._origin=tmpD;
+			}
+			if(onSuccess)
+			    onSuccess(data);
+		    });
+        };
+        
+	/**
+	 * The getQueryString method generate a KVP GET request which can be 
+	 * used to request a WPS server.
+	 *
+	 * @method getQueryString
+	 * @memberof ZooProcess#
+	 * @param {Object} params The WPS requests parameters
+	 * @returns {String} The GET WPS request
+	 * @example
+	 * // Log GetCapabilities GET request in console
+	 * var request_params = {
+	 *     request: 'GetCapabilities',
+         *     service: 'WPS',
+         *     version: '1.0.0',
+	 *     language; 'en-US'
+         * }
+	 * console.log(myZooObject.getQueryString(request_params));
+	 */
+        this.getQueryString = function(params) {
+	    var closure = this;
+            var ret = '';
+
+            serializeInputs = function(obj) {
+		if(closure.debug){
+		    console.log("SERIALIZE dataInputs");
+		    console.log(obj);
+		}
+		var lt=$.type(obj);
+		if(lt === "string") {
+                    return obj;
+		}
+		var str = [];
+		for(var p in obj){
+		    if(lt === "array"){
+			if(obj[p].hasOwnProperty("href"))
+			    str.push(obj[p]["identifier"] + "=Reference");
+			else
+			    str.push(obj[p]["identifier"] + "=" + obj[p]["value"]);
+			for(var q in obj[p]){
+			    if(q!="identifier" && q!="value" && q!="href")
+				str.push("@" + q + "=" + obj[p][q]);
+			    else
+				if(q=="href")
+				    str.push("@xlink:" + q + "=" + encodeURIComponent(obj[p][q]));
+			}
+			str.push(";");
+		    }
+		    else
+			if (obj.hasOwnProperty(p)) {
+			    if(p=="href")
+				str.push(p + "=" + encodeURIComponent(obj[p]));
+			    else
+				str.push(p + "=" + obj[p]);
+			}
+		}
+		return str.join("");
+            }
+
+            serializeOutputs = function(obj) {
+		if(closure.debug){
+		    console.log("SERIALIZE dataOutputs");
+		    console.log(obj);
+		}
+		var lt=$.type(obj);
+		if(lt === "string") {
+                    return obj;
+		}
+		var str = [];
+		for(var p in obj){
+		    str.push(obj[p]["identifier"]);
+		    for(var q in obj[p]){
+			if(q!="identifier" && q!="type")
+			    str.push("@" + q + "=" + obj[p][q]);
+		    }
+		    str.push(";");
+		}
+		return str.join("");
+            }
+	    
+            var responseDocument = params.ResponseDocument;
+            var tmp_params = {};
+
+            var objectKeys = Object.keys || function (obj) {
+                var keys = [];
+                for (var key in obj) keys.push(key);
+                return keys;
+            };
+
+            var skip = {
+                'DataInputs': true,
+                'DataOutputs': true,
+                'ResponseDocument': true,
+                'RawDataOutput': true,
+            }
+            var keys = objectKeys(params);
+            for (var i = 0; i < keys.length; i++) {
+                var key = keys[i];
+                if (skip.hasOwnProperty(key) && skip[key]) {
+                    continue;
+                }
+                if (params.hasOwnProperty(key)) {
+                    tmp_params[key] = params[key];
+                }
+            }
+            ret = qs.stringify(tmp_params);
+
+            //req_options.path = req_options.path.replace("&DataInputs=sid%3D", "&DataInputs=sid=")
+            if (params.hasOwnProperty('DataInputs')) {
+              //var dataInputs = params.DataInputs;
+		var dataInputs = serializeInputs(params.DataInputs);
+		if(closure.debug){
+		    console.log("dataInputs: "+dataInputs);
+		}
+		ret += '&DataInputs=' + dataInputs;
+            }
+            
+            if (params.hasOwnProperty('DataOutputs')) {
+		var dataOutputs = serializeOutputs(params.DataOutputs);
+		if(closure.debug){
+		    console.log("dataOutputs: "+dataOutputs);
+		}
+		if(dataOutputs!=""){
+		    var displayInputs=true;
+		    for(var i=0;i<params.DataOutputs.length;i++)
+			if(params.DataOutputs[i].type==="raw"){
+			    ret += '&RawDataOutput=' + dataOutputs;
+			    displayInputs=false;
+			    break;
+			}
+		    if(displayInputs)
+			ret += '&ResponseDocument=' + dataOutputs;
+		}
+            }else{
+		if (params.hasOwnProperty('RawDataOutput')) {
+		    ret+="&RawDataOutput="+params['RawDataOutput']+";";
+		}else{
+		    if (params.hasOwnProperty('ResponseDocument')) {
+			var lt=$.type(params['ResponseDocument']);
+			if(lt === "string") {
+			    ret+="&ResponseDocument="+params['ResponseDocument']+";";
+			}else{
+			    var tmp_ret=serializeOutputs(params['ResponseDocument']);
+			    ret+="&ResponseDocument="+tmp;
+			}
+		    }
+		}
+	    }
+            
+            return ret;
+        };
+        
+	/**
+	 * The parseStatusLocation method parse the statusLocation and return an
+	 * object with sid and statusLocation attributes which contains
+	 * respectively: a unique identifier named sid and the statusLocation
+	 * value returned by the WPS server.
+	 * 
+	 * @method parseStatusLocation
+	 * @memberof ZooProcess#
+	 * @param {Object} data The XML response parsed by x2js.xml2json
+	 * @returns {Object} The result is an object with sid and statusLocation
+	 */
+        this.parseStatusLocation = function(data) {
+            var closure = this;
+
+            if (statusLocation = data.ExecuteResponse._statusLocation) {
+		if(closure.debug){
+                    console.log("statusLocation: "+statusLocation);
+		}
+
+		var lsid=0;
+		for(i in closure.statusLocation)
+		    lsid++;
+		
+                return {sid: lsid, statusLocation: statusLocation};
+            }
+        };        
+
+	/**
+	 * The parseJobID method parse the JobID and return an
+	 * object with sid and the JobID attributes which contains
+	 * respectively: a unique identifier named sid and the JobID
+	 * value returned by the WPS server.
+	 * 
+	 * @method parseJobID
+	 * @memberof ZooProcess#
+	 * @param {Object} data The XML response parsed by x2js.xml2json
+	 * @returns {Object} The result is an object with sid and jobID
+	 */
+        this.parseJobID = function(data) {
+            var closure = this;
+
+            if (jobID = data.StatusInfo.JobID) {
+
+		var lsid=0;
+		for(i in closure.statusLocation)
+		    lsid++;
+		
+                return {sid: lsid, jobid: jobID};
+            }
+        }; 
+
+	/**
+	 * The dismiss method run the Dismiss request by calling {@link ZooProcess#request}.
+	 * 
+	 * @method dismiss
+	 * @memberof ZooProcess#
+	 * @param {Object} params 
+	 * @example
+	 * // Log x2js representation of all available services in console
+	 * myZooObject.dismiss({
+	 *     type: 'POST',
+	 *     jobid: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
+	 *     success: function(data){
+	 *         console.log(data);
+	 *     }
+	 * });
+	 */
+        this.dismiss = function(params) {
+            var closure = this;
+
+            if (!params.hasOwnProperty('type')) {
+                params.type = 'GET';
+            }
+
+            var zoo_request_params = {
+                Identifier: params.identifier,
+                request: 'Dismiss',
+                service: 'WPS',
+		jobid: params.jobid,
+                version: "2.0.0",
+            }
+
+            this.request(zoo_request_params, params.success, params.error, params.type);
+        };
+
+    };
+    
+
+    return ZooProcess;
+
+});
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_DescribeProcess.mustache
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_DescribeProcess.mustache	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_DescribeProcess.mustache	(revision 942)
@@ -0,0 +1,5 @@
+<DescribeProcess xmlns="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsDescribeProcess_request.xsd" service="WPS" version="1.0.0" language="{{language}}">
+{{#identifiers}}
+  <ows:Identifier>{{.}}</ows:Identifier>
+{{/identifiers}}
+</DescribeProcess>
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_DescribeProcess2.mustache
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_DescribeProcess2.mustache	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_DescribeProcess2.mustache	(revision 942)
@@ -0,0 +1,14 @@
+<wps:DescribeProcess
+	xmlns:ows="http://www.opengis.net/ows/2.0"
+	xmlns:wps="http://www.opengis.net/wps/2.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.opengis.net/wps/2.0 ../wps.xsd"
+	
+	service="WPS"
+	version="2.0.0">
+	
+{{#identifiers}}
+  <ows:Identifier>{{.}}</ows:Identifier>
+{{/identifiers}}
+	
+</wps:DescribeProcess>
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Dismiss.mustache
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Dismiss.mustache	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Dismiss.mustache	(revision 942)
@@ -0,0 +1,10 @@
+<wps:Dismiss
+	xmlns:wps="http://www.opengis.net/wps/2.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.opengis.net/wps/2.0 ../wps.xsd"
+	service="WPS"
+	version="2.0.0">
+{{#jobid}}
+	<wps:JobID>{{.}}</wps:JobID>
+{{/jobid}}
+</wps:Dismiss>
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Execute.mustache
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Execute.mustache	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Execute.mustache	(revision 942)
@@ -0,0 +1,82 @@
+<wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0
+../wpsExecute_request.xsd" language="{{language}}">
+  <!-- template-version: 0.21 -->
+  <ows:Identifier>{{Identifier}}</ows:Identifier>
+  <wps:DataInputs>
+{{#DataInputs}}
+{{#is_literal}}
+    <wps:Input>
+      <ows:Identifier>{{identifier}}</ows:Identifier>
+      <wps:Data>
+        <wps:LiteralData{{#dataType}} dataType="{{dataType}}"{{/dataType}}>{{value}}</wps:LiteralData>
+      </wps:Data>
+    </wps:Input>
+{{/is_literal}}
+{{#is_bbox}}
+    <wps:Input>
+      <ows:Identifier>{{identifier}}</ows:Identifier>
+      <wps:Data>
+        <wps:BoundingBoxData ows:crs="{{crs}}" ows:dimensions="{{dimension}}">
+          <ows:LowerCorner>{{lowerCorner}}</ows:LowerCorner>
+          <ows:UpperCorner>{{upperCorner}}</ows:UpperCorner>
+        </wps:BoundingBoxData>
+      </wps:Data>
+    </wps:Input>
+{{/is_bbox}}
+{{#is_complex}}
+{{#is_reference}}
+{{#is_get}}
+    <wps:Input>
+      <ows:Identifier>{{identifier}}</ows:Identifier>
+      <wps:Reference xlink:href="{{href}}"{{#schema}} schema="{{shema}}"{{/schema}}{{#mimeType}} mimeType="{{mimeType}}"{{/mimeType}}{{#encoding}} encoding="{{encoding}}"{{/encoding}}/>
+    </wps:Input>
+{{/is_get}}
+{{#is_post}}
+    <wps:Input>
+      <ows:Identifier>{{identifier}}</ows:Identifier>
+      <wps:Reference xlink:href="{{href}}" method="{{method}}" {{#schema}} schema="{{shema}}"{{/schema}}{{#mimeType}} mimeType="{{mimeType}}"{{/mimeType}}{{#encoding}} encoding="{{encoding}}"{{/encoding}}>
+{{#headers}}
+        <wps:Header key="{{key}}" value="{{value}}" />
+{{/headers}}
+        <wps:Body>{{{value}}}</wps:Body>
+      </wps:Reference>
+    </wps:Input>
+{{/is_post}}
+{{/is_reference}}
+{{^is_reference}}
+    <wps:Input>
+      <ows:Identifier>{{identifier}}</ows:Identifier>
+      <wps:Data>
+        <wps:ComplexData{{#schema}} schema="{{shema}}"{{/schema}}{{#mimeType}} mimeType="{{mimeType}}"{{/mimeType}}{{#encoding}} encoding="{{encoding}}"{{/encoding}}>{{#is_XML}}{{{value}}}{{/is_XML}}{{^is_XML}}<![CDATA[{{{value}}}]]>{{/is_XML}}</wps:ComplexData>
+      </wps:Data>
+    </wps:Input>
+{{/is_reference}}
+{{/is_complex}}
+{{/DataInputs}}
+  </wps:DataInputs>	
+  <wps:ResponseForm>
+{{#RawDataOutput}}
+{{#DataOutputs}}
+    <wps:RawDataOutput {{#mimeType}}mimeType="{{mimeType}}"{{/mimeType}}>
+      <ows:Identifier>{{identifier}}</ows:Identifier>
+    </wps:RawDataOutput>
+{{/DataOutputs}}
+{{/RawDataOutput}}
+{{^RawDataOutput}}
+    <wps:ResponseDocument{{#storeExecuteResponse}} storeExecuteResponse="{{storeExecuteResponse}}"{{/storeExecuteResponse}}{{#lineage}} lineage="{{lineage}}"{{/lineage}}{{#status}} status="{{status}}"{{/status}}>
+{{#DataOutputs}}
+{{#is_literal}}
+      <wps:Output{{#dataType}} dataType="{{dataType}}"{{/dataType}}{{#uom}} uom="{{uom}}"{{/uom}}>
+        <ows:Identifier>{{identifier}}</ows:Identifier>
+      </wps:Output>
+{{/is_literal}}
+{{^is_literal}}
+      <wps:Output{{#asReference}} asReference="{{asReference}}"{{/asReference}}{{#schema}} schema="{{schema}}"{{/schema}}{{#mimeType}} mimeType="{{mimeType}}"{{/mimeType}}{{#encoding}} encoding="{{encoding}}"{{/encoding}}>
+        <ows:Identifier>{{identifier}}</ows:Identifier>
+      </wps:Output>
+{{/is_literal}}
+{{/DataOutputs}}
+    </wps:ResponseDocument>
+{{/RawDataOutput}}
+  </wps:ResponseForm>	
+</wps:Execute>
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Execute2.mustache
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Execute2.mustache	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_Execute2.mustache	(revision 942)
@@ -0,0 +1,62 @@
+<wps:Execute
+	xmlns:wps="http://www.opengis.net/wps/2.0"
+	xmlns:ows="http://www.opengis.net/ows/2.0"
+	xmlns:xlink="http://www.w3.org/1999/xlink"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.opengis.net/wps/2.0 ../wps.xsd"
+	
+	service="WPS"
+	version="2.0.0"
+	response="{{#RawDataOutput}}{{/RawDataOutput}}{{^RawDataOutput}}document{{/RawDataOutput}}"
+	mode="{{#mode}}{{mode}}{{/mode}}{{^mode}}sync{{/mode}}">
+
+	<ows:Identifier>{{Identifier}}</ows:Identifier>
+{{#DataInputs}}
+{{#is_literal}}
+		<wps:Input id="{{identifier}}">
+			<wps:Data>{{value}}</wps:Data>
+		</wps:Input>
+{{/is_literal}}
+{{#is_bbox}}
+		<wps:Input id="{{identifier}}">
+			<wps:Data>
+				<wps:BoundingBoxData ows:crs="{{crs}}" ows:dimensions="{{dimension}}">
+            <ows:LowerCorner>{{lowerCorner}}</ows:LowerCorner>
+            <ows:UpperCorner>{{upperCorner}}</ows:UpperCorner>
+         </wps:BoundingBoxData>
+			</wps:Data>
+		</wps:Input>
+{{/is_bbox}}
+{{#is_complex}}
+{{#is_reference}}
+{{#is_get}}
+		<wps:Input id="{{identifier}}">
+			<wps:Reference xlink:href="{{href}}"/>
+		</wps:Input>
+{{/is_get}}
+{{#is_post}}
+		<wps:Input id="{{identifier}}">
+			<wps:Reference xlink:href="{{href}}" method="{{method}}">
+{{#mimeType}}
+			  <wps:Header key="Content-type" value="{{mimeType}}" />
+{{/mimeType}}
+			  <wps:Body>{{{complexPayload}}}</wps:Body>
+			</wps:Reference>
+		</wps:Input>
+{{/is_post}}
+{{/is_reference}}
+{{^is_reference}}
+		<wps:Input id="{{identifier}}">
+      <wps:Data>
+        <wps:ComplexData{{#schema}} schema="{{shema}}"{{/schema}}{{#mimeType}} mimeType="{{mimeType}}"{{/mimeType}}{{#encoding}} encoding="{{encoding}}"{{/encoding}}>
+        	{{{complexPayload}}}
+        </wps:ComplexData>
+      </wps:Data>
+    </wps:Input>
+{{/is_reference}}
+{{/is_complex}}
+{{/DataInputs}}
+{{#DataOutputs}}
+      <wps:Output id="{{identifier}}" transmission="{{#asReference}}{{asReference}}{{/asReference}}{{^asReference}}value{{/asReference}}"{{#schema}} schema="{{schema}}"{{/schema}}{{#mimeType}} mimeType="{{mimeType}}"{{/mimeType}}{{#encoding}} encoding="{{encoding}}"{{/encoding}}{{#uom}} uom="{{uom}}"{{/uom}} />
+{{/DataOutputs}}
+</wps:Execute>
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_GetCapabilities.mustache
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_GetCapabilities.mustache	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_GetCapabilities.mustache	(revision 942)
@@ -0,0 +1,5 @@
+<wps:GetCapabilities xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsGetCapabilities_request.xsd" language="{{language}}" service="WPS">
+    <wps:AcceptVersions>
+        <ows:Version>1.0.0</ows:Version>
+    </wps:AcceptVersions>
+</wps:GetCapabilities>
Index: /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_GetCapabilities2.mustache
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_GetCapabilities2.mustache	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-client/lib/tpl/payload_GetCapabilities2.mustache	(revision 942)
@@ -0,0 +1,7 @@
+<wps:GetCapabilities
+	xmlns:wps="http://www.opengis.net/wps/2.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.opengis.net/wps/2.0 ../wps.xsd"
+	service="WPS">
+	
+</wps:GetCapabilities>
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/Doxyfile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/Doxyfile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/Doxyfile	(revision 942)
@@ -0,0 +1,2303 @@
+# Doxyfile 1.8.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "ZOO-Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      = y=C 
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = YES
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.dox *.y *.c *.cxx *.h 
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all refrences to function-like macros that are alone on a line, have an
+# all uppercase name, and do not end with a semicolon. Such function macros are
+# typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/LICENSE
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/LICENSE	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/LICENSE	(revision 942)
@@ -0,0 +1,21 @@
+ZOO-Kernel License
+
+Copyright (c) 2009-2013 GeoLabs SARL
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights 
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies of this Software or works derived from this Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/Makefile.in
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/Makefile.in	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/Makefile.in	(revision 942)
@@ -0,0 +1,145 @@
+include ZOOMakefile.opts
+
+all: version.h zoo_loader.cgi ${YAML_FILE1}
+
+version.h: Makefile
+	echo "#define ZOO_VERSION \"1.7.0 `svnversion`\"" > version.h
+	echo "@ETC_DEF@" >> version.h
+	echo "#define LOCALEDIR \"@localedir@\"" >>  version.h
+
+service.o: service.c service.h
+	g++ ${YAML_CFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service.c
+
+main_conf_read.tab.c: main_conf_read.y service.h
+	bison -p cr -d main_conf_read.y
+
+main_conf_read.tab.o: main_conf_read.tab.c service.h
+	g++ ${CFLAGS} -c main_conf_read.tab.c
+
+lex.cr.c: main_conf_read.y main_conf_read.l main_conf_read.tab.c service.h
+	flex -P cr --header-file main_conf_read.l
+
+lex.cr.o: lex.cr.c service.h
+	g++ ${CFLAGS} -c lex.cr.c
+
+service_conf.tab.c: service_conf.y service.h
+	bison -p sr -d service_conf.y
+
+service_conf.tab.o: service_conf.tab.c service.h
+	g++ ${CFLAGS} -c service_conf.tab.c
+
+lex.sr.c: service_conf.y service_conf.l service_conf.tab.c service.h
+	flex -P sr --header-file service_conf.l
+
+lex.sr.o: lex.sr.c service.h
+	g++ ${CFLAGS} -c lex.sr.c
+
+ulinet.o: ulinet.c
+	gcc -fPIC ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c ulinet.c
+
+sshapi.o: sshapi.c
+	g++ -fPIC ${CFLAGS} -c sshapi.c
+
+service_json.o: service_json.c
+	g++ -fPIC ${JSON_CFLAGS} ${CFLAGS} -c service_json.c
+
+service_callback.o: service_callback.c
+	g++ -fPIC ${XML2CFLAGS} ${GDAL_CFLAGS} ${JSON_CFLAGS} ${CFLAGS} -c service_callback.c
+
+request_parser.o: request_parser.c request_parser.h
+	g++ -fPIC ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c request_parser.c
+
+sqlapi.o: sqlapi.c sqlapi.h
+	g++ -fPIC ${METADB_ENABLED} ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c sqlapi.c
+
+caching.o: caching.c
+	g++ -fPIC ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c caching.c
+
+response_print.o: response_print.c response_print.h
+	g++ -fPIC ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} ${HPC_ENABLED} -c response_print.c
+
+server_internal.o: server_internal.c server_internal.h service.h mimetypes.h
+	g++ ${JSON_CFLAGS} ${GDAL_CFLAGS} ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c server_internal.c
+
+service_internal.o: service_internal.c service_internal.h service.h
+	gcc ${JSON_CFLAGS} ${GDAL_CFLAGS} ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_internal.c
+
+service_yaml.o: service_yaml.c service.h
+	gcc ${YAML_CFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_yaml.c
+
+meta_sql.o: meta_sql.c meta_sql.h service.h
+	g++  ${METADB_ENABLED} ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} -c meta_sql.c
+
+service_internal_ms.o: service_internal_ms.c
+	gcc ${JS_ENABLED} ${GDAL_CFLAGS}  ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_internal_ms.c
+	echo "SYMBOLSET\nEND" > symbols.sym
+
+service_internal_python.o: service_internal_python.c service.h
+	g++ ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} -c service_internal_python.c
+
+service_internal_r.o: service_internal_r.c service.h
+	g++ ${XML2CFLAGS} ${RCFLAGS} ${CFLAGS} -c service_internal_r.c
+
+service_internal_otb.o: service_internal_otb.c service_internal_otb.h service.h
+	g++ ${XML2CFLAGS} ${OTBCFLAGS} ${CFLAGS} -c service_internal_otb.c
+
+service_internal_hpc.o: service_internal_hpc.c service_internal_hpc.h service.h
+	g++  ${JSON_CFLAGS} ${XML2CFLAGS} ${HPCCFLAGS} ${CFLAGS} -c service_internal_hpc.c
+
+service_internal_saga.o: service_internal_saga.c service_internal_saga.h service.h
+	g++ ${XML2CFLAGS} ${SAGA_CFLAGS} ${CFLAGS} -c service_internal_saga.c
+
+otbZooWatcher.o: otbZooWatcher.cxx otbZooWatcher.h  service.h
+	g++ ${OTBCFLAGS} ${CFLAGS} -c otbZooWatcher.cxx
+
+service_internal_php.o: service_internal_php.c service.h
+	g++ -c ${XML2CFLAGS} ${PHPCFLAGS} ${CFLAGS}  ${PHP_ENABLED} service_internal_php.c
+
+service_internal_php7.o: service_internal_php7.c service.h
+	g++ -c ${XML2CFLAGS} ${PHPCFLAGS} ${CFLAGS}  ${PHP_ENABLED} service_internal_php7.c
+
+service_internal_perl.o: service_internal_perl.c service.h
+	gcc -c ${XML2CFLAGS} ${PERLCFLAGS} ${CFLAGS}  ${PERL_ENABLED} service_internal_perl.c
+
+service_internal_java.o: service_internal_java.c service.h
+	gcc -c ${XML2CFLAGS} ${JAVACFLAGS} ${CFLAGS} ${JAVA_ENABLED} service_internal_java.c
+
+service_internal_js.o: service_internal_js.c service_internal_js.h
+	gcc -fPIC ${XML2CFLAGS} ${JSCFLAGS} ${CFLAGS} ${JS_ENABLED} -c service_internal_js.c
+
+service_internal_mono.o: service_internal_mono.h service_internal_mono.c service.h
+	gcc -c ${XML2CFLAGS} ${MONO_CFLAGS} ${CFLAGS} ${MONO_ENABLED} service_internal_mono.c
+
+service_internal_ruby.o: service_internal_ruby.c service_internal_ruby.h
+	g++ ${XML2CFLAGS} ${RUBYCFLAGS} ${CFLAGS} ${JSCFLAGS} ${JS_ENABLED} -c service_internal_ruby.c
+
+service_loader.o: service_loader.c service.h
+	g++ -c ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} service_loader.c
+
+zoo_service_loader.o: zoo_service_loader.c service.h version.h ${MS_FILE} ${R_FILE} ${PYTHON_FILE} ${PHP_FILE} ${JAVA_FILE} ${JS_FILE} ${PERL_FILE} ${RUBY_FILE} ${YAML_FILE} ${OTB_FILE} ${SAGA_FILE} ${MONO_FILE} ${HPC_FILES} ${METADB_FILE}
+	g++ -g -O2 ${JSON_CFLAGS} ${GDAL_CFLAGS} ${XML2CFLAGS} ${CFLAGS} ${MONO_CFLAGS} ${SAGA_CFLAGS} ${OTBCFLAGS} ${RCFLAGS} ${PYTHONCFLAGS} ${JAVACFLAGS} ${JSCFLAGS} ${PERLCFLAGS} ${PHPCFLAGS} ${SAGA_ENABLED} ${OTB_ENABLED} ${HPC_ENABLED} ${PYTHON_ENABLED} ${R_ENABLED} ${JS_ENABLED} ${PHP_ENABLED} ${PERL_ENABLED} ${JAVA_ENABLED} ${MONO_ENABLED} ${METADB_ENABLED} -c zoo_service_loader.c  -fno-common -DPIC -o zoo_service_loader.o
+
+libzoo_service.${EXT}: version.h service_internal.o service.o sqlapi.o
+	g++ -shared  ${GDAL_CFLAGS} ${DEFAULT_OPTS} -fpic -o libzoo_service.${EXT} ${CFLAGS}  service_internal.o service.o sqlapi.o ${FCGI_LDFLAGS} ${GDAL_LIBS} ${ZOO_LDFLAGS} ${MACOS_LD_FLAGS}
+
+zoo_loader.cgi: version.h libzoo_service.${EXT} zoo_loader.c zoo_service_loader.o  ulinet.o service.h lex.sr.o service_conf.tab.o service_conf.y ulinet.o main_conf_read.tab.o lex.cr.o request_parser.o response_print.o server_internal.o caching.o ${MS_FILE} ${PYTHON_FILE} ${PHP_FILE} ${JAVA_FILE} ${JS_FILE} ${PERL_FILE} ${RUBY_FILE} ${YAML_FILE} ${OTB_FILE} ${R_FILE} ${SAGA_FILE} ${HPC_FILES} ${METADB_FILE} ${JSON_FILE} ${CALLBACK_FILE}
+	g++ -g -O2 ${JSON_CFLAGS} ${JSCFLAGS} ${PHPCFLAGS}  ${PERLCFLAGS} ${RUBYCFLAGS}  ${JAVACFLAGS} ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} -c zoo_loader.c  -fno-common -DPIC -o zoo_loader.o
+	g++  ${JSON_CFLAGS} ${JSCFLAGS} ${SAGA_CFLAGS} ${OTBCFLAGS} ${GDAL_CFLAGS} ${XML2CFLAGS} ${PHPCFLAGS} ${PERLCFLAGS} ${JAVACFLAGS} ${PYTHONCFLAGS} ${CFLAGS} zoo_loader.o zoo_service_loader.o ${MS_FILE} ${PYTHON_FILE}  ${PERL_FILE} ${PHP_FILE}  ${JS_FILE} ${JAVA_FILE} ${YAML_FILE} ${OTB_FILE} ${SAGA_FILE} ${MONO_FILE} ${HPC_FILES} ${METADB_FILE} ${JSON_FILE} ${R_FILE} ${CALLBACK_FILE} response_print.o server_internal.o caching.o request_parser.o ulinet.o lex.cr.o lex.sr.o service_conf.tab.o main_conf_read.tab.o -o zoo_loader.cgi -L. ${LDFLAGS}
+
+zcfg2yaml: zcfg2yaml.c service.h lex.sr.o service_conf.tab.o service_conf.y main_conf_read.tab.o lex.cr.o response_print.o server_internal.o service_internal.o ${MS_FILE} ${YAML_FILE} ${CALLBACK_FILE}
+	g++ -g -O2 ${JSCFLAGS} ${RUBYCFLAGS} ${XML2CFLAGS} ${CFLAGS} -c zcfg2yaml.c  -fno-common -DPIC -o zcfg2yaml.o
+	g++  ${XML2CFLAGS} ${CFLAGS} zcfg2yaml.o caching.o ulinet.o ${CALLBACK_FILE} server_internal.o service_internal.o ${MS_FILE} response_print.o lex.cr.o lex.sr.o service_conf.tab.o main_conf_read.tab.o  ${YAML_FILE} -o zcfg2yaml -L. ${LDFLAGS}
+
+install: zoo_loader.cgi
+	install -d ${DESTDIR}${CGI_DIR}
+	install zoo_loader.cgi ${DESTDIR}${CGI_DIR}/
+	install libzoo_service.${EXT} ${DESTDIR}${INST_LIB}/${LIBZOO_SERVICE}
+	(cd ${DESTDIR}${INST_LIB} ; \
+	 if [ -e "libzoo_service.${EXT}" ]; then rm  libzoo_service.${EXT}; fi ; \
+	 ln -s ${LIBZOO_SERVICE} libzoo_service.${EXT})
+	if [ -z "${MS_FILE}" ] ; then echo "No symbols.sym" ; else install -d ${DESTDIR}${SHAREDSTATEDIR}; install -m644 symbols.sym ${DESTDIR}${SHAREDSTATEDIR}; fi
+	install -d ${DESTDIR}${INST_INCLUDE}/zoo
+	install sqlapi.h service.h service_internal.h ${DESTDIR}${INST_INCLUDE}/zoo
+
+clean:
+	rm -f version.h symbols.sym *.o *.cgi *.eo *.tab.c *.tab.h *.sr.c* service_loader lex.* *.lreg *.sibling service_loader.dSYM *${EXT}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/README
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/README	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/README	(revision 942)
@@ -0,0 +1,3 @@
+For information on how to compile and install the ZOO Kernel, please refer to:
+
+http://zoo-project.org/docs/kernel/installation.html
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/ZOOMakefile.opts.in
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/ZOOMakefile.opts.in	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/ZOOMakefile.opts.in	(revision 942)
@@ -0,0 +1,127 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+PREFIX=@prefix@
+INST_LIB=@libdir@
+INST_INCLUDE=@includedir@
+VERSION=1.5
+REVISION=0
+EXT=so
+DEFAULT_OPTS=-Wl,-soname,libzoo_service.so.${VERSION}
+OS:=$(shell uname -s)
+ifeq ($(OS),Darwin)
+	MACOS_LD_FLAGS=-lintl
+	MACOS_LD_NET_FLAGS=-framework SystemConfiguration -framework CoreFoundation
+	MACOS_CFLAGS=-arch $(shell uname -m)
+	EXT=dylib
+	DEFAULT_OPTS=-Wl,-compatibility_version,${VERSION},-current_version,${VERSION},-install_name,${DESTDIR}${INST_LIB}/libzoo_service.${VERSION}.${REVISION}.dylib
+	LIBZOO_SERVICE=libzoo_service.${VERSION}.${REVISION}.${EXT}
+else
+	LIBZOO_SERVICE=libzoo_service.${EXT}.${VERSION}
+endif
+
+CGI_DIR=@CGI_DIR@
+
+FCGI_CFLAGS=@FCGI_CPPFLAGS@
+FCGI_LDFLAGS=@FCGI_LDFLAGS@
+
+YAML_CFLAGS=@YAML_CPPFLAGS@
+YAML_LDFLAGS=@YAML_LDFLAGS@
+YAML_FILE=@YAML_FILE@
+YAML_FILE1=@YAML_FILE1@
+
+JSON_CFLAGS=@JSON_CPPFLAGS@
+JSON_LDFLAGS=@JSON_LDFLAGS@
+JSON_FILE=@JSON_FILE@
+
+METADB_ENABLED=@METADB@
+METADB_FILE=@METADB_FILE@
+
+
+GDAL_CFLAGS=@GDAL_CFLAGS@
+GDAL_LIBS=@GDAL_LIBS@
+
+XML2CFLAGS=@XML2_CPPFLAGS@
+XML2LDFLAGS=@XML2_LDFLAGS@
+
+XSLT_CFLAGS=@XSLT_CPPFLAGS@
+XSLT_LDFLAGS=@XSLT_LDFLAGS@
+
+GEOS_CFLAGS=@GEOS_CPPFLAGS@
+GEOS_LDFLAGS=@GEOS_LDFLAGS@
+
+CGAL_CFLAGS=@CGAL_CPPFLAGS@
+CGAL_LDFLAGS=@CGAL_LDFLAGS@
+
+PYTHONCFLAGS=@PYTHON_CPPFLAGS@
+PYTHONLDFLAGS=@PYTHON_LDFLAGS@
+PYTHON_ENABLED=@PYTHON_ENABLED@
+PYTHON_FILE=@PYTHON_FILE@
+
+RCFLAGS=@R_CPPFLAGS@
+RLDFLAGS=@R_LDFLAGS@
+R_ENABLED=@R_ENABLED@
+R_FILE=@R_FILE@
+
+RUBYCFLAGS=@RUBY_CPPFLAGS@
+RUBYLDFLAGS=@RUBY_LDFLAGS@
+RUBY_ENABLED=@RUBY_ENABLED@
+RUBY_FILE=@RUBY_FILE@
+
+JS_ENABLED=@JS_ENABLED@
+JSCFLAGS=@JS_CPPFLAGS@
+JSLDFLAGS=@JS_LDFLAGS@
+JS_FILE=@JS_FILE@
+ifeq ($(JS_ENABLED),-DUSE_JS)
+     JS_LDFLAGS=${ZRPATH}/zoo-kernel/ulinet.o ${ZRPATH}/zoo-kernel/service_internal_js.o -lcurl 
+endif
+
+MS_CFLAGS=@MS_CFLAGS@
+MS_LDFLAGS=@MS_LIBS@
+MS_FILE=@MS_FILE@
+
+ZOO_CFLAGS=-I${ZRPATH}/../thirds/cgic206/ -I${ZRPATH}/zoo-kernel/
+ZOO_LDFLAGS=@OPENSSL_LDFLAGS@ @UUID_LDFLAGS@
+
+JAVACFLAGS=@JAVA_CPPFLAGS@
+JAVALDFLAGS=@JAVA_LDFLAGS@
+JAVA_ENABLED=@JAVA_ENABLED@
+JAVA_FILE=@JAVA_FILE@
+
+PHPCFLAGS=@PHP_CPPFLAGS@
+PHPLDFLAGS=@PHP_LDFLAGS@
+PHP_ENABLED=@PHP_ENABLED@
+PHP_FILE=@PHP_FILE@
+
+PERLCFLAGS=@PERL_CPPFLAGS@
+PERLLDFLAGS=@PERL_LDFLAGS@
+PERL_ENABLED=@PERL_ENABLED@
+PERL_FILE=@PERL_FILE@
+
+HPCCFLAGS=@SSH2_CPPFLAGS@ @HPC_CPPFLAGS@
+HPCLDFLAGS=@SSH2_LDFLAGS@ @HPC_LDFLAGS@
+HPC_ENABLED=@HPC_ENABLED@
+HPC_FILES=@HPC_FILES@
+
+CALLBACK_FILE=@CALLBACK_FILE@
+CALLBACK_USE=@CALLBACK_USE@
+
+OTBCFLAGS=@OTB_CPPFLAGS@
+OTBLDFLAGS=@OTB_LDFLAGS@
+OTB_ENABLED=@OTB_ENABLED@
+OTB_FILE=@OTB_FILE@
+
+SAGA_CFLAGS=@SAGA_CPPFLAGS@
+SAGA_LDFLAGS=@SAGA_LDFLAGS@
+SAGA_ENABLED=@SAGA_ENABLED@
+SAGA_FILE=@SAGA_FILE@
+
+MONO_CFLAGS=@MONO_CFLAGS@
+MONO_LDFLAGS=@MONO_LDFLAGS@
+MONO_ENABLED=@MONO_ENABLED@
+MONO_FILE=@MONO_FILE@
+
+CFLAGS=@CALLBACK_USE@ @SSH2_CPPFLAGS@ @PROJ_CPPFLAGS@ @RELY_ON_DB@ @DEB_DEF@ -fpic @OPENSSL_CFLAGS@ @UUID_CFLAGS@ ${FCGI_CFLAGS} ${YAML_CFLAGS} ${MACOS_CFLAGS} ${MS_CFLAGS} -I../../thirds/cgic206 -I. -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
+LDFLAGS=-lzoo_service @SSH2_LDFLAGS@ @PROJ_LDFLAGS@ @DEFAULT_LIBS@ -L../../thirds/cgic206 -lcgic ${GDAL_LIBS} ${XML2LDFLAGS} ${PYTHONLDFLAGS} ${PERLLDFLAGS} ${PHPLDFLAGS} ${JAVALDFLAGS} ${JSLDFLAGS}  ${FCGI_LDFLAGS} @OPENSSL_LDFLAGS@ @UUID_LDFLAGS@ ${MS_LDFLAGS} ${MACOS_LD_FLAGS} ${MACOS_LD_NET_FLAGS} ${YAML_LDFLAGS} ${OTBLDFLAGS} ${SAGA_LDFLAGS} ${MONO_LDFLAGS} ${RLDFLAGS} @JSON_LDFLAGS@ @XSLT_LDFLAGS@
+
+DATAROOTDIR=@datarootdir@/zoo-project
+SHAREDSTATEDIR=@sharedstatedir@/zoo-project
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/caching.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/caching.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/caching.c	(revision 942)
@@ -0,0 +1,794 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <openssl/md5.h>
+#include <openssl/evp.h>
+#include "caching.h"
+#include "service.h"
+#include "service_internal.h"
+#include "response_print.h"
+#ifdef MS_FORCE_LOCAL_FILE_USE
+#include "ogr_api.h"
+#include "mapserver.h"
+#endif
+/**
+ * Compute md5
+ * 
+ * @param url the char* 
+ * @return a char* representing the md5 of the url
+ * @warning make sure to free resources returned by this function
+ */
+char* getMd5(char* url){
+  EVP_MD_CTX *md5ctx=EVP_MD_CTX_create();
+  char* fresult=(char*)malloc((EVP_MAX_MD_SIZE+1)*sizeof(char));
+  unsigned char result[EVP_MAX_MD_SIZE];
+  unsigned int len;
+  EVP_DigestInit(md5ctx, EVP_md5());
+  EVP_DigestUpdate(md5ctx, url, strlen(url));
+  EVP_DigestFinal_ex(md5ctx,result,&len);
+  EVP_MD_CTX_destroy(md5ctx);
+  int i;
+  for(i = 0; i < len; i++){
+    if(i>0){
+      char *tmp=zStrdup(fresult);
+      sprintf(fresult,"%s%02x", tmp,result[i]);
+      free(tmp);
+    }
+    else
+      sprintf(fresult,"%02x",result[i]);
+  }
+  return fresult;
+}
+
+/**
+ * Compute md5 of a file
+ * 
+ * @param file the char* 
+ * @return a char* representing the md5 of the url
+ * @warning make sure to free resources returned by this function
+ */
+char* getMd5f(char* file){
+  EVP_MD_CTX *md5ctx=EVP_MD_CTX_create();
+  char* fresult=(char*)malloc((EVP_MAX_MD_SIZE+1)*sizeof(char));
+  unsigned char result[EVP_MAX_MD_SIZE];
+  unsigned int len;
+  int bytes;
+  int dlen=65536;
+  unsigned char data[65537];
+  FILE *inFile = fopen (file, "rb");
+  EVP_DigestInit(md5ctx, EVP_md5());
+  while ((bytes = fread (data, sizeof(unsigned char), dlen, inFile)) != 0)
+    EVP_DigestUpdate(md5ctx, data, bytes);
+  EVP_DigestFinal_ex(md5ctx,result,&len);
+  EVP_MD_CTX_destroy(md5ctx);
+  int i;
+  for(i = 0; i < len; i++){
+    if(i>0){
+      char *tmp=zStrdup(fresult);
+      sprintf(fresult,"%s%02x", tmp,result[i]);
+      free(tmp);
+    }
+    else
+      sprintf(fresult,"%02x",result[i]);
+  }
+  fclose (inFile);
+  return fresult;
+}
+
+
+
+/**
+ * Create a URL by appending every request header listed in the security 
+ * section.This imply that the URL will contain any authentication 
+ * informations that should be fowarded to the server from which de input
+ * was download.
+ * @param conf the main configuration maps
+ * @param request the URL to transform.
+ * @return a char* that contain the original URL plus potential header (only for
+ * hosts that are not shared).
+ * @warning Be sure to free the memory returned by this function.
+ */
+char* getFilenameForRequest(maps* conf, const char* request){
+  map* passThrough=getMapFromMaps(conf,"security","attributes");
+  map* targetHosts=getMapFromMaps(conf,"security","hosts");
+  char* passedHeader[10];
+  int cnt=0;
+  char *res=zStrdup(request);
+  char *toAppend=NULL;
+  if(passThrough!=NULL && targetHosts!=NULL){
+    char *tmp=zStrdup(passThrough->value);
+    char *token, *saveptr;
+    token = strtok_r (tmp, ",", &saveptr);
+    int i;
+    if((strstr(targetHosts->value,"*")!=NULL || isProtectedHost(targetHosts->value,request)==1) && strncasecmp(getProvenance(conf,request),"SHARED",6)!=0){
+      while (token != NULL){
+	int length=strlen(token)+6;
+	char* tmp1=(char*)malloc(length*sizeof(char));
+	map* tmpMap;
+	snprintf(tmp1,6,"HTTP_");
+	int j;
+	for(j=0;token[j]!='\0';j++){
+	  if(token[j]!='-')
+	    tmp1[5+j]=toupper(token[j]);
+	  else
+	    tmp1[5+j]='_';
+	  tmp1[5+j+1]='\0';
+	}
+	tmpMap = getMapFromMaps(conf,"renv",tmp1);
+	if(tmpMap!=NULL){
+	  if(toAppend==NULL){
+	    toAppend=(char*)malloc((strlen(tmpMap->value)+1)*sizeof(char));
+	    sprintf(toAppend,"%s",tmpMap->value);
+	  }else{
+	    char *tmp3=zStrdup(toAppend);
+	    toAppend=(char*)realloc(toAppend,(strlen(tmpMap->value)+strlen(tmp3)+2)*sizeof(char));
+	    sprintf(toAppend,"%s,%s",tmp3,tmpMap->value);
+	    free(tmp3);
+	  }
+	}
+	free(tmp1);
+	cnt+=1;
+	token = strtok_r (NULL, ",", &saveptr);
+      }
+    }
+    free(tmp);
+  }
+  if(toAppend!=NULL){
+    char *tmp3=zStrdup(res);
+    res=(char*)realloc(res,(strlen(tmp3)+strlen(toAppend)+1)*sizeof(char));
+    sprintf(res,"%s%s",tmp3,toAppend);
+    free(tmp3);
+    free(toAppend);
+  }
+  return res;
+}
+
+/**
+ * Store MD5 of the content of a file
+ * @file char* the full path of the file
+ */
+int storeMd5(char* file){
+  char* storage=zStrdup(file);
+  char* md5fstr=getMd5f(file);
+  storage[strlen(storage)-2]='m';
+  storage[strlen(storage)-1]='d';
+  FILE* fo=fopen(storage,"w+");
+  if(fo==NULL)
+    return 1;
+  fwrite(md5fstr,sizeof(char),strlen(md5fstr),fo);
+  free(md5fstr);
+  free(storage);
+  fclose(fo);
+  return 0;
+}
+
+/**
+ * Cache a file for a given request.
+ * For each cached file, the are two files stored, a .zca and a .zcm containing
+ * the downloaded content and the mimeType respectively. 
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param request the url used too fetch the content
+ * @param content the downloaded content
+ * @param mimeType the content mimeType 
+ * @param length the content size
+ * @param filepath a buffer for storing the path of the cached file; may be NULL
+ * @param max_path the size of the allocated filepath buffer  
+ */
+void cacheFile(maps* conf,char* request,char* mimeType,int length,char* filename){
+  map* tmp=getMapFromMaps(conf,"main","cacheDir");
+  char contentr[4096];
+  int cred=0;
+  if(tmp!=NULL){
+    char* myRequest=getFilenameForRequest(conf,request);
+    char* md5str=getMd5(myRequest);
+    free(myRequest);
+    char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+    // Store md5
+    char* md5fstr=getMd5f(filename);
+    sprintf(fname,"%s/%s.zmd",tmp->value,md5str);
+    FILE* fo=fopen(fname,"w+");
+#ifdef DEBUG
+    fprintf(stderr,"filename: %s\n",filename);
+    fprintf(stderr,"MD5: %s\n",md5fstr);
+#endif
+    fwrite(md5fstr,sizeof(char),strlen(md5fstr),fo);
+    free(md5fstr);
+    fclose(fo);
+    
+    sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+    zooLock* lck=lockFile(conf,fname,'w');
+    if(lck!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"Cache list : %s\n",fname);
+      fflush(stderr);
+#endif
+      FILE* fi=fopen(filename,"rb");
+      sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+      if(fo==NULL){
+#ifdef DEBUG
+	fprintf (stderr, "Failed to open %s for writing: %s\n",fname, strerror(errno));
+#endif
+	unlockFile(conf,lck);
+	return;
+      }
+      if(fi==NULL){
+#ifdef DEBUG
+	fprintf (stderr, "Failed to open %s for reading: %s\n",filename, strerror(errno));
+#endif
+	unlockFile(conf,lck);
+	return;
+      }
+      memset(contentr,0,4096);
+      while((cred=fread(contentr,sizeof(char),4096,fi))>0){
+	fwrite(contentr,sizeof(char),cred,fo);
+	fflush(fo);
+	memset(contentr,0,4096);
+      }
+      unlockFile(conf,lck);
+      fclose(fo);
+      fclose(fi);
+
+      // Store mimeType
+      sprintf(fname,"%s/%s.zcm",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+#ifdef DEBUG
+      fprintf(stderr,"MIMETYPE: %s\n",mimeType);
+#endif
+      fwrite(mimeType,sizeof(char),strlen(mimeType),fo);
+      fclose(fo);
+
+      // Store provenance
+      sprintf(fname,"%s/%s.zcp",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+      char* origin=getProvenance(conf,request);
+#ifdef DEBUG
+      fprintf(stderr,"ORIGIN: %s\n",mimeType);
+#endif
+      fwrite(origin,sizeof(char),strlen(origin),fo);
+      fclose(fo);
+
+      free(md5str);
+
+    }
+    free(fname);
+  }
+}
+
+/**
+ * Cache a file for a given request.
+ * For each cached file, the are two files stored, a .zca and a .zcm containing
+ * the downloaded content and the mimeType respectively. 
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param request the url used too fetch the content
+ * @param content the downloaded content
+ * @param mimeType the content mimeType 
+ * @param length the content size
+ * @param filepath a buffer for storing the path of the cached file; may be NULL
+ * @param max_path the size of the allocated filepath buffer  
+ */
+void addToCache(maps* conf,char* request,char* content,char* mimeType,int length, 
+                char* filepath, size_t max_path){
+  map* tmp=getMapFromMaps(conf,"main","cacheDir");
+  if(tmp!=NULL){
+    char* myRequest=getFilenameForRequest(conf,request);
+    char* md5str=getMd5(myRequest);
+    free(myRequest);
+    char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+    sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+    zooLock* lck=lockFile(conf,fname,'w');
+    if(lck!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"Cache list : %s\n",fname);
+      fflush(stderr);
+#endif
+      FILE* fo=fopen(fname,"w+");
+      if(fo==NULL){
+#ifdef DEBUG
+	fprintf (stderr, "Failed to open %s for writing: %s\n",fname, strerror(errno));
+#endif
+	filepath = NULL;
+	unlockFile(conf,lck);
+	return;
+      }
+      fwrite(content,sizeof(char),length,fo);
+      unlockFile(conf,lck);
+      fclose(fo);
+	
+      if (filepath != NULL) {
+	strncpy(filepath, fname, max_path);
+      }
+
+      sprintf(fname,"%s/%s.zcm",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+#ifdef DEBUG
+      fprintf(stderr,"MIMETYPE: %s\n",mimeType);
+#endif
+      fwrite(mimeType,sizeof(char),strlen(mimeType),fo);
+      fclose(fo);
+
+      sprintf(fname,"%s/%s.zcp",tmp->value,md5str);
+      fo=fopen(fname,"w+");
+      char* origin=getProvenance(conf,request);
+#ifdef DEBUG
+      fprintf(stderr,"ORIGIN: %s\n",mimeType);
+#endif
+      fwrite(origin,sizeof(char),strlen(origin),fo);
+      fclose(fo);
+
+      free(md5str);
+      free(fname);
+    }
+  }
+  else {
+    filepath = NULL;
+  }	  
+}
+
+/**
+ * Verify if a url is available in the cache
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param request the url
+ * @return the full name of the cached file if any, NULL in other case
+ * @warning make sure to free resources returned by this function (if not NULL)
+ */
+char* isInCache(maps* conf,char* request){
+  map* tmpUrl=getMapFromMaps(conf,"main","tmpUrl");
+  map* tmpM=getMapFromMaps(conf,"main","cacheDir");
+  if(tmpM==NULL)
+    tmpM=getMapFromMaps(conf,"main","tmpPath");
+  if(strstr(request,tmpUrl->value)!=NULL){
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+    char* tmpStr=strstr(request,tmpUrl->value);
+    char* tmpStr1=zStrdup(tmpStr+strlen(tmpUrl->value));
+    char* res=(char*) malloc((strlen(tmpPath->value)+strlen(tmpStr1)+2)*sizeof(char));
+    sprintf(res,"%s/%s",tmpPath->value,tmpStr1);
+    free(tmpStr1);
+    return res;
+  }
+#ifdef MS_FORCE_LOCAL_FILE_USE
+  map* msUrl=getMapFromMaps(conf,"main","mapserverAddress");
+  if(msUrl!=NULL && strstr(request,msUrl->value)!=NULL){
+    char *tmpStr=strstr(request,"?");
+    char *cursor=zStrdup(tmpStr+1);
+    char *token, *saveptr;
+    token = strtok_r (cursor, "&", &saveptr);
+    while(token!=NULL){
+      char *token1, *saveptr1;
+      token1 = strtok_r (token, "=", &saveptr1);
+      char *name=NULL;
+      while(token1!=NULL){
+	if(name==NULL)
+	  name=zStrdup(token1);
+	else
+	  if(strcasecmp(name,"map")==0){
+	    mapObj *myMap=msLoadMap(token1,NULL);
+	    char * res=zStrdup(myMap->layers[0]->data);
+	    free(name);
+	    free(cursor);
+	    msFreeMap(myMap);
+	    return res;
+	  }
+	token1 = strtok_r (NULL, "=", &saveptr1);
+      }
+      token = strtok_r (NULL, "&", &saveptr);
+    }
+    free(cursor);
+  }
+#endif  
+  if(strncasecmp(request,"file://",7)==0){
+    char* tmpStr=zStrdup(request+7);
+    fprintf(stderr,"**** %s %d %s \n",__FILE__,__LINE__,tmpStr);
+    return tmpStr;
+  }
+  else{
+    char* myRequest=getFilenameForRequest(conf,request);
+    char* md5str=getMd5(myRequest);
+    free(myRequest);
+#ifdef DEBUG
+    fprintf(stderr,"MD5STR : (%s)\n\n",md5str);
+#endif
+    char* fname=(char*)malloc(sizeof(char)*(strlen(tmpM->value)+strlen(md5str)+6));
+    sprintf(fname,"%s/%s.zca",tmpM->value,md5str);
+    zStatStruct f_status;
+    int s=zStat(fname, &f_status);
+    if(s==0 && f_status.st_size>0){
+      free(md5str);
+      return fname;
+    }
+    free(md5str);
+    free(fname);
+  }
+  return NULL;
+}
+
+/**
+ * Read the downloaded file for a specific input
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param in the input
+ * @param index the input index
+ * @param hInternet the internet connection
+ * @param error the error map pointer
+ * @return 0 in case of success, -1 in case of failure
+ */
+int readCurrentInput(maps** m,maps** in,int* index,HINTERNET* hInternet,map** error){
+  
+  int shouldClean=-1;
+  map* tmp1;
+  char sindex[5];
+  maps* content=*in;
+  map* length=getMap(content->content,"length");
+  map* memUse=getMapFromMaps(*m,"main","memory");
+  if(length==NULL){
+    length=createMap("length","1");
+    shouldClean=1;
+  }
+  for(int i=0;i<atoi(length->value);i++){
+    char* fcontent;
+    char *mimeType=NULL;
+    int fsize=0;
+    char oriname[12];
+    char cname[15];
+    char vname[11];
+    char vname1[11];
+    char sname[9];
+    char mname[15];
+    char icname[14];
+    char xname[16];
+    char bname[8];
+    char hname[11];
+    char oname[12];
+    char ufile[12];    
+    if(*index>0)
+      sprintf(vname1,"value_%d",*index);
+    else
+      sprintf(vname1,"value");
+    
+    if(i>0){
+      sprintf(cname,"cache_file_%d",i);
+      tmp1=getMap(content->content,cname);
+      sprintf(oriname,"origin_%d",i);
+      sprintf(vname,"value_%d",i);
+      sprintf(sname,"size_%d",i);
+      sprintf(mname,"mimeType_%d",i);
+      sprintf(icname,"isCached_%d",i);
+      sprintf(xname,"Reference_%d",i);
+      sprintf(bname,"body_%d",i);
+      sprintf(hname,"headers_%d",i);
+      sprintf(oname,"Order_%d",i);
+      sprintf(ufile,"use_file_%d",i);
+    }else{
+      sprintf(cname,"cache_file");
+      sprintf(oriname,"origin");
+      sprintf(vname,"value");
+      sprintf(sname,"size");
+      sprintf(mname,"mimeType");
+      sprintf(icname,"isCached");
+      sprintf(xname,"Reference");
+      sprintf(bname,"body");
+      sprintf(hname,"headers");
+      sprintf(oname,"Order");
+      sprintf(ufile,"use_file");
+    }
+    
+    map* tmap=getMap(content->content,oname);
+    sprintf(sindex,"%d",*index+1);
+    if((tmp1=getMap(content->content,xname))!=NULL && tmap!=NULL && strcasecmp(tmap->value,sindex)==0){
+
+      if(getMap(content->content,icname)==NULL) {
+	if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	  fcontent=(char*)malloc((hInternet->ihandle[*index].nDataLen+1)*sizeof(char));
+	  if(fcontent == NULL){
+	    errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
+	    return -1;
+	  }
+	  size_t dwRead;
+	  InternetReadFile(hInternet->ihandle[*index], 
+			   (LPVOID)fcontent, 
+			   hInternet->ihandle[*index].nDataLen, 
+			   &dwRead);
+	  fcontent[hInternet->ihandle[*index].nDataLen]=0;
+	}
+	fsize=hInternet->ihandle[*index].nDataLen;
+	if(hInternet->ihandle[*index].mimeType==NULL)
+	  mimeType=zStrdup("none");
+	else
+	  mimeType=zStrdup(hInternet->ihandle[*index].mimeType);	      
+	
+	map* tmpMap=getMapOrFill(&(*in)->content,vname,"");
+	if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	  free(tmpMap->value);
+	  tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
+	  if(tmpMap->value==NULL){
+	    return errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
+	  }
+	  memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+	}else
+	  addToMap((*in)->content,ufile,"true");
+	if(hInternet->ihandle[*index].code!=200){
+	  const char *error_rep_str=_("Unable to download the file for the input <%s>, response code was : %d.");
+	  char *error_msg=(char*)malloc((strlen(error_rep_str)+strlen(content->name)+4)*sizeof(char));
+	  sprintf(error_msg,error_rep_str,content->name,hInternet->ihandle[*index].code);
+	  if(*error==NULL){
+	    *error=createMap("text",error_msg);
+	    addToMap(*error,"locator",content->name);
+	    addToMap(*error,"code","InvalidParameterValue");
+	  }else{
+	    int nb=1;
+	    map* tmpMap=getMap(*error,"length");
+	    if(tmpMap!=NULL)
+	      nb=atoi(tmpMap->value);
+	    setMapArray(*error,"text",nb,error_msg);
+	    setMapArray(*error,"locator",nb,content->name);
+	    setMapArray(*error,"code",nb,"InvalidParameterValue");
+	  }
+	  return -1;
+	}
+	
+	char ltmp1[256];
+	sprintf(ltmp1,"%d",fsize);
+	map* tmp=getMapFromMaps(*m,"main","cacheDir");
+	char *request=NULL;
+	if(tmp!=NULL){
+	  map* tmp2;
+	  char* md5str=NULL;
+	  if((tmp2=getMap(content->content,bname))!=NULL){
+	    char *tmpStr=(char*)malloc((strlen(tmp1->value)+strlen(tmp2->value)+1)*sizeof(char));
+	    sprintf(tmpStr,"%s%s",tmp1->value,tmp2->value);
+	    if((tmp2=getMap(content->content,"headers"))!=NULL){
+	      char *tmpStr2=zStrdup(tmpStr);
+	      free(tmpStr);
+	      tmpStr=(char*)malloc((strlen(tmpStr2)+strlen(tmp2->value)+1)*sizeof(char));
+	      sprintf(tmpStr,"%s%s",tmpStr2,tmp2->value);
+	      free(tmpStr2);
+	    }
+	    md5str=getMd5(tmpStr);
+	    request=zStrdup(tmpStr);
+	    free(tmpStr);
+	  }else{
+	    char *myRequest=getFilenameForRequest(*m,tmp1->value);
+	    md5str=getMd5(myRequest);
+	    request=zStrdup(tmp1->value);
+	    free(myRequest);
+	  }
+	  char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+	  sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+	  addToMap((*in)->content,cname,fname);
+	  free(fname);
+	}
+	addToMap((*in)->content,sname,ltmp1);
+	addToMap((*in)->content,mname,mimeType);
+	char* origin=getProvenance(*m,request);
+	addToMap((*in)->content,oriname,origin);
+	if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	  addToCache(*m,request,fcontent,mimeType,fsize, NULL, 0);
+	  free(fcontent);
+	}else{
+	  addToMap((*in)->content,ufile,"true");
+	  cacheFile(*m,request,mimeType,fsize,hInternet->ihandle[*index].filename);
+	}
+	free(mimeType);
+	free(request);
+	(*index)++;
+      }
+    }
+  }
+  if(shouldClean>0){
+    freeMap(&length);
+    free(length);
+  }
+  return 0;
+}
+
+/**
+ * Effectively run all the HTTP requests in the queue
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param inputs the maps containing the inputs (defined in the requests+added
+ *  per default based on the zcfg file)
+ * @param hInternet the HINTERNET pointer
+ * @param error the error map pointer
+ * @return 0 on success, -1 on failure
+ */
+int runHttpRequests(maps** m,maps** inputs,HINTERNET* hInternet,map** error){
+  int hasAFailure=0;
+  if(hInternet!=NULL && hInternet->nb>0){
+    AddHeaderEntries(hInternet,*m);
+    processDownloads(hInternet);
+    maps* content=*inputs;
+    int index=0;
+    while(content!=NULL){
+      if(content->child!=NULL){
+	maps* cursor=content->child;
+	while(cursor!=NULL){
+	  int red=readCurrentInput(m,&cursor,&index,hInternet,error);
+	  if(red<0)
+	    hasAFailure=red;
+	  cursor=cursor->next;
+	}
+      }
+      else{
+	int red=readCurrentInput(m,&content,&index,hInternet,error);
+	if(red<0)
+	  hasAFailure=red;
+      }
+      content=content->next;
+    }
+  }
+  return hasAFailure;
+}
+
+/**
+ * Add a request in the download queue
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param url the url to add to the queue
+ */
+void addRequestToQueue(maps** m,HINTERNET* hInternet,const char* url,bool req){
+  hInternet->waitingRequests[hInternet->nb]=zStrdup(url);
+  if(req)
+    InternetOpenUrl(hInternet,hInternet->waitingRequests[hInternet->nb],NULL,0,INTERNET_FLAG_NO_CACHE_WRITE,0,*m);
+  maps *oreq=getMaps(*m,"orequests");
+  if(oreq==NULL){
+    oreq=createMaps("orequests");
+    oreq->content=createMap("value",url);
+    addMapsToMaps(m,oreq);
+    freeMaps(&oreq);
+    free(oreq);
+  }else{
+    setMapArray(oreq->content,"value",hInternet->nb,url);
+  }
+}
+
+/**
+ * Try to load file from cache or download a remote file if not in cache
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param content the map to update
+ * @param hInternet the HINTERNET pointer
+ * @param url the url to fetch
+ * @return 0
+ */
+int loadRemoteFile(maps** m,map** content,HINTERNET* hInternet,char *url){
+  char* fcontent = NULL;
+  char* cached=isInCache(*m,url);
+  char *mimeType=NULL;
+  char *origin=NULL;
+  long long fsize=0;
+  map* memUse=getMapFromMaps(*m,"main","memory");
+
+  map* t=getMap(*content,"xlink:href");
+  if(t==NULL){
+    t=getMap((*content),"href");
+    addToMap(*content,"xlink:href",url);
+  }
+
+  if(cached!=NULL){
+    zStatStruct f_status;
+    int s=zStat(cached, &f_status);
+    if(s==0){
+      zooLock* lck=lockFile(*m,cached,'r');
+      if(lck==NULL)
+	return -1;
+      fsize=f_status.st_size;
+      if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(cached,"rb");
+	if(f!=NULL){
+	  fread(fcontent,f_status.st_size,1,f);
+	  fcontent[fsize]=0;
+	  fclose(f);
+	}
+      }
+      addToMap(*content,"cache_file",cached);
+      unlockFile(*m,lck);
+    }
+    cached[strlen(cached)-1]='m';
+    s=zStat(cached, &f_status);
+    if(s==0){
+      zooLock* lck=lockFile(*m,cached,'r');
+      if(lck==NULL)
+	return -1;
+      mimeType=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(cached,"rb");
+      fread(mimeType,f_status.st_size,1,f);
+      mimeType[f_status.st_size]=0;
+      fclose(f);
+      unlockFile(*m,lck);
+    }
+    cached[strlen(cached)-1]='p';
+    s=zStat(cached, &f_status);
+    if(s==0){
+      zooLock* lck=lockFile(*m,cached,'r');
+      if(lck==NULL)
+	return -1;
+      origin=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(cached,"rb");
+      fread(origin,f_status.st_size,1,f);
+      mimeType[f_status.st_size]=0;
+      fclose(f);
+      unlockFile(*m,lck);
+    }
+  }else{    
+    addRequestToQueue(m,hInternet,url,true);
+    return 0;
+  }
+  if(fsize==0){
+    return errorException(*m, _("Unable to download the file."), "InternalError",NULL);
+  }
+  if(mimeType!=NULL){
+    addToMap(*content,"fmimeType",mimeType);
+  }
+  if(origin!=NULL){
+    addToMap(*content,"origin",origin);
+  }
+
+  map* tmpMap=getMapOrFill(content,"value","");
+  if(memUse==NULL || strcasecmp(memUse->value,"load")==0){
+    free(tmpMap->value);
+    tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
+    if(tmpMap->value==NULL || fcontent == NULL)
+      return errorException(*m, _("Unable to allocate memory"), "InternalError",NULL);
+    memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+  }
+  
+  char ltmp1[256];
+  sprintf(ltmp1,"%lld",fsize);
+  addToMap(*content,"size",ltmp1);
+  if(cached==NULL){
+    if(memUse==NULL || strcasecmp(memUse->value,"load")==0)
+      addToCache(*m,url,fcontent,mimeType,fsize, NULL, 0);
+    else
+      cacheFile(*m,url,mimeType,fsize,hInternet->ihandle[hInternet->nb-1].filename);
+  }
+  else{
+    addToMap(*content,"isCached","true");
+    map* tmp=getMapFromMaps(*m,"main","cacheDir");
+    map* tmp1=getMap((*content),"cache_file");
+    if(tmp!=NULL && tmp1==NULL){
+      map *c=getMap((*content),"xlink:href");
+      if(strncasecmp(c->value,"file://",7)!=0){
+	char *myRequest=getFilenameForRequest(*m,c->value);
+	char* md5str=getMd5(myRequest);
+	free(myRequest);
+	char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+	sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+	addToMap(*content,"cache_file",fname);
+	free(fname);
+	free(md5str);
+      }
+    }
+  }
+  if(fcontent!=NULL)
+    free(fcontent);
+  if(mimeType!=NULL)
+    free(mimeType);
+  if(cached!=NULL)
+    free(cached);
+  return 0;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/caching.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/caching.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/caching.h	(revision 942)
@@ -0,0 +1,42 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ulinet.h"
+#include "service.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  void addToCache(maps*,char*,char*,char*,int,char*,size_t);
+  char* isInCache(maps*,char*);
+  int runHttpRequests(maps**,maps**,HINTERNET*,map**);
+  void addRequestToQueue(maps**,HINTERNET*,const char*,bool);
+  int loadRemoteFile(maps**,map**,HINTERNET*,char*);
+  char* getMd5f(char*);
+  int storeMd5(char*);
+  
+#ifdef __cplusplus
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/configure.ac
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/configure.ac	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/configure.ac	(revision 942)
@@ -0,0 +1,1112 @@
+AC_INIT([ZOO Kernel], [1.7.0], [bugs@zoo-project.org])
+
+AC_CONFIG_MACRO_DIR([macros])
+
+# Checks for programs.
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_LEX
+AC_PROG_CXX
+AC_PROG_SED
+
+# Checks for libraries.
+AC_CHECK_LIB([curl], [curl_easy_init,curl_easy_setopt,curl_easy_cleanup,curl_easy_perform])
+AC_CHECK_LIB([dl], [dlopen,dlsym,dlerror,dlclose])
+AC_CHECK_LIB([crypto], [EVP_DigestInit,EVP_md5,EVP_DigestUpdate,BIO_f_base64,BIO_new])
+
+DEFAULT_LIBS="$LIBS"
+AC_SUBST([DEFAULT_LIBS])
+
+
+# Checks for header files.
+AC_FUNC_ALLOCA
+AC_CHECK_HEADERS([fcntl.h inttypes.h malloc.h stddef.h stdlib.h string.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_TYPE_INT16_T
+AC_TYPE_INT32_T
+AC_TYPE_INT8_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT8_T
+
+# Checks for library functions.
+AC_FUNC_FORK
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([dup2 getcwd memset setenv strdup strstr])
+
+#============================================================================
+# Detect if uuid is available
+#============================================================================
+
+AC_ARG_WITH([uuid],
+    [AS_HELP_STRING([--with-uuid=PATH], [Specifies an alternative location for the ossp-uuid library])],
+    [UUID_DIR="$withval"], [UUID_DIR="/usr/"])
+UUID_CFLAGS="-I$UUID_DIR/include"
+UUID_LDFLAGS="-L$UUID_DIR/lib -luuid"
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$UUID_CFLAGS"
+LIBS_SAVE="$LIBS"
+LIBS="$UUID_LDFLAGS"
+AC_CHECK_HEADERS([uuid/uuid.h],
+			[], [AC_MSG_ERROR([could not find header file uuid.h])])
+AC_CHECK_LIB([uuid], [uuid_generate_time],
+			[], [AC_MSG_ERROR([could not find function in uuid library])])
+CPPFLAGS="$CPPFLAGS_SAVE"
+AC_SUBST([UUID_CFLAGS])
+AC_SUBST([UUID_LDFLAGS])
+
+#============================================================================
+# Detect if json-c is available
+#============================================================================
+
+AC_ARG_WITH([callback],
+    [AS_HELP_STRING([--with-callback=yes], [Activate callback invocation during HPC execution])],
+    [CALLBACK_ACTIVATED="$withval"], [CALLBACK_ACTIVATED="no"])
+    
+AC_ARG_WITH([json],
+    [AS_HELP_STRING([--with-json=PATH], [Specifies an alternative location for the json-c library])],
+    [JSON_DIR="$withval"], [JSON_DIR="/usr/"])
+if test "x$JSON_DIR" != "x" && test "x$CALLBACK_ACTIVATED" == "xyes"
+then
+	JSON_CPPFLAGS="-I$JSON_DIR/include/json-c/"
+	JSON_LDFLAGS="-L$JSON_DIR/lib -ljson-c"
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$JSON_CPPFLAGS"
+	LIBS_SAVE="$LIBS"
+	LIBS="$JSON_LDFLAGS"
+	AC_CHECK_HEADERS([json_object.h],
+		[], [AC_MSG_ERROR([could not find header file json_object.h])])
+	AC_CHECK_LIB([json-c], [json_object_new_object],
+		[], [AC_MSG_ERROR([could not find function in json-c library])])
+	CPPFLAGS="$CPPFLAGS_SAVE"
+	JSON_FILE="service_json.o"
+	JSON_ENABLED="-DJSON"
+	CALLBACK_FILE="service_callback.o"
+	CALLBACK_USE="-DUSE_CALLBACK"
+fi
+AC_SUBST([JSON_CPPFLAGS])
+AC_SUBST([JSON_LDFLAGS])
+AC_SUBST([JSON_FILE])
+AC_SUBST([JSON_ENABLED])
+AC_SUBST([CALLBACK_FILE])
+AC_SUBST([CALLBACK_USE])
+
+#============================================================================
+# Detect if openssl is available
+#============================================================================
+
+AC_ARG_WITH([openssl],
+    [AS_HELP_STRING([--with-openssl=PATH], [Specifies an alternative location for the openssl library])],
+    [OPENSSL_DIR="$withval"], [OPENSSL_DIR="/usr/"])
+OPENSSL_CFLAGS="-I$OPENSSL_DIR/include"
+OPENSSL_LDFLAGS="-lcrypto -L$OPENSSL_DIR/lib -lssl"
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$OPENSSL_CFLAGS"
+LIBS_SAVE="$LIBS"
+LIBS="$OPENSSL_LDFLAGS"
+AC_CHECK_HEADERS([openssl/md5.h openssl/hmac.h openssl/evp.h openssl/bio.h openssl/buffer.h],
+			[], [AC_MSG_ERROR([could not find header file $i related to openssl])])
+AC_CHECK_LIB(crypto, BIO_f_base64,
+			[], [AC_MSG_ERROR([could not find $i function in openssl library])])
+CPPFLAGS="$CPPFLAGS_SAVE"
+AC_SUBST([OPENSSL_CFLAGS])
+AC_SUBST([OPENSSL_LDFLAGS])
+
+#============================================================================
+# Detect if gettext is available
+#============================================================================
+
+#AC_ARG_WITH([gettext],
+#    [AS_HELP_STRING([--with-gettext=PATH], [Specifies an alternative location for the openssl library])],
+#    [GETTEXT_DIR="$withval"], [GETTEXT_DIR="/usr/"])
+
+#GETTEXT_CFLAGS="-I$GETTEXT_DIR/include"
+#GETTEXT_LDFLAGS="-L$GETTEXT_DIR/lib -lintl"
+#CFLAGS_SAVE="$CFLAGS"
+#CFLAGS="$GETTEXT_CFLAGS"
+#LIBS_SAVE="$LIBS"
+#LIBS="$GETTEXT_LDFLAGS"
+#AM_GNU_GETTEXT([external], [], [])
+#AC_CHECK_LIB(intl,
+#			[dgettext], [] , [AC_MSG_ERROR([could not find $i function in gettext library])])
+#AC_SUBST([GETTEXT_CFLAGS])
+#AC_SUBST([GETTEXT_LDFLAGS])
+
+#============================================================================
+# Detect if run on debian / ubuntu
+#============================================================================
+if test -f "/usr/bin/dpkg"
+then
+	DEB_DEF=-DDEB
+fi
+AC_SUBST([DEB_DEF])
+
+AC_ARG_WITH([etc-dir],
+    [AS_HELP_STRING([--with-etc-dir=PATH], [Specifies an alternative path to store the main.cfg file ( default: ZOO-Kernel location) ])],
+    [ETC_DEF="#define ETC_DIR \\\"${sysconfdir}\\\""], [ETC_DEF=""])
+AC_SUBST([ETC_DEF])
+
+AC_ARG_WITH([cgi-dir],
+    [AS_HELP_STRING([--with-cgi-dir=PATH], [Specifies an alternative cgi directory path ( default: /usr/lib/cgi-bin) ])],
+    [CGI_DIR="$withval"], [CGI_DIR="/usr/lib/cgi-bin"])
+AC_SUBST([CGI_DIR])
+
+AC_ARG_WITH([db-backend],
+    [AS_HELP_STRING([--with-db-backend], [Relies on a database for storing status messages and response files ])],
+    [RELY_ON_DB="-DRELY_ON_DB"], [RELY_ON_DB=""])
+AC_SUBST([RELY_ON_DB])
+
+
+# ===========================================================================
+# Detect if libyaml is available
+# ===========================================================================
+
+AC_ARG_WITH([yaml],
+        [AS_HELP_STRING([--with-yaml=PATH], [Specifies an alternative location for the yaml library])],
+        [YAMLPATH="$withval"], [YAMLPATH=""])
+
+if test -z "$YAMLPATH"
+then
+	YAML_LDFLAGS=""
+	YAML_CPPFLAGS=""
+	YAML_FILE=""
+	YAML_FILE1=""
+else
+
+	# Extract the linker and include flags
+	YAML_LDFLAGS="-L$YAMLPATH/lib -lyaml"
+	YAML_CPPFLAGS="-I$YAMLPATH/include -DYAML"
+	YAML_FILE="service_yaml.o"
+	YAML_FILE1="zcfg2yaml"
+	
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$YAML_CPPFLAGS"
+	LIBS_SAVE="$LIBS"
+	LIBS="$YAML_LDFLAGS"
+	AC_CHECK_LIB([yaml], [yaml_parser_initialize,yaml_parser_set_input_file,yaml_parser_scan])
+	AC_CHECK_HEADERS([yaml.h],
+                 [], [AC_MSG_ERROR([could not find headers include related to YAML])])
+	LIBS="$LIBS_SAVE"
+fi
+AC_SUBST([YAML_CPPFLAGS])
+AC_SUBST([YAML_LDFLAGS])
+AC_SUBST([YAML_FILE])
+AC_SUBST([YAML_FILE1])
+
+# ===========================================================================
+# Detect if fastcgi is available
+# ===========================================================================
+
+AC_ARG_WITH([fastcgi],
+        [AS_HELP_STRING([--with-fastcgi=PATH], [Specifies an alternative location for the fastcgi library])],
+        [FCGIPATH="$withval"], [FCGIPATH="/usr"])
+
+# Extract the linker and include flags
+FCGI_LDFLAGS="-L$FCGIPATH/lib -lfcgi"
+FCGI_CPPFLAGS="-I$FCGIPATH/include"
+
+# Check headers file
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$FCGI_CPPFLAGS"
+LIBS_SAVE="$LIBS"
+LIBS="$FCGI_LDFLAGS"
+AC_CHECK_LIB([fcgi], [main])
+AC_CHECK_HEADERS([fcgi_stdio.h],
+                 [], [AC_MSG_ERROR([could not find headers include related to fastcgi])])
+LIBS="$LIBS_SAVE"
+AC_SUBST([FCGI_CPPFLAGS])
+AC_SUBST([FCGI_LDFLAGS])
+
+AC_ARG_WITH([metadb],
+        [AS_HELP_STRING([--with-metadb=yes], [Activates the metadata database support])],
+        [WITHMETADB="$withval"], [WITHMETADB=""])
+
+if test "x$WITHMETADB" = "xyes"; then
+   	METADB="-DMETA_DB"
+	METADB_FILE="meta_sql.o sqlapi.o"
+else
+	METADB=""
+	METADB_FILE=""
+fi
+
+AC_SUBST([METADB])
+AC_SUBST([METADB_FILE])
+
+AC_ARG_WITH([hpc],
+        [AS_HELP_STRING([--with-hpc=yes], [Specifies if you need to activate HPC support])],
+        [HPCWITH="$withval"], [HPCWITH="no"])
+
+
+AC_ARG_WITH([ssh2],
+        [AS_HELP_STRING([--with-ssh2=PATH], [Specifies an alternative location for the ssh2 library])],
+        [SSH2PATH="$withval"], [SSH2PATH="/usr"])
+
+if test "x$HPCWITH" = "xyes"; then
+   	HPC_FILES="service_internal_hpc.o sshapi.o"
+	HPC_ENABLED="-DUSE_HPC"
+	HPC_CPPFLAGS=""
+	HPC_LDFLAGS=""
+	# Extract the linker and include flags
+	SSH2_LDFLAGS="-L$SSH2PATH/lib -lssh2"
+	SSH2_CPPFLAGS="-I$SSH2PATH/include"
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$SSH2_CPPFLAGS"
+	LIBS_SAVE="$LIBS"
+	LIBS="$SSH2_LDFLAGS"
+	
+	AC_CHECK_HEADERS([libssh2.h],
+                 [], [AC_MSG_ERROR([could not find headers related to libssh2])])
+	AC_CHECK_LIB([ssh2], [libssh2_session_init])
+
+	LIBS="$LIBS_SAVE"
+fi
+
+AC_SUBST([HPC_CPPFLAGS])
+AC_SUBST([HPC_LDFLAGS])
+AC_SUBST([HPC_ENABLED])
+AC_SUBST([HPC_FILES])
+
+AC_SUBST([SSH2_CPPFLAGS])
+AC_SUBST([SSH2_LDFLAGS])
+
+# ===========================================================================
+# Detect if libxml2 is installed
+# ===========================================================================
+
+AC_ARG_WITH([xml2config], 
+	[AS_HELP_STRING([--with-xml2config=FILE], [Specifies an alternative xml2-config file])], 
+	[XML2CONFIG="$withval"], [XML2CONFIG=""])
+
+if test "x$XML2CONFIG" = "x"; then
+	# XML2CONFIG was not specified, so search within the current path
+	AC_PATH_PROG([XML2CONFIG], [xml2-config])
+
+	# If we couldn't find xml2-config, display a warning
+	if test "x$XML2CONFIG" = "x"; then
+		AC_MSG_ERROR([could not find xml2-config from libxml2 within the current path. You may need to try re-running configure with a --with-xml2config parameter.])
+	fi
+else
+	# XML2CONFIG was specified; display a message to the user
+	if test "x$XML2CONFIG" = "xyes"; then
+		AC_MSG_ERROR([you must Specifies a parameter to --with-xml2config, e.g. --with-xml2config=/path/to/xml2-config])
+	else
+		if test -f $XML2CONFIG; then
+			AC_MSG_RESULT([Using user-specified xml2-config file: $XML2CONFIG])
+		else
+			AC_MSG_ERROR([the user-specified xml2-config file $XML2CONFIG does not exist])
+		fi	
+	fi
+fi
+
+# Extract the linker and include flags 
+XML2_LDFLAGS=`$XML2CONFIG --libs`
+XML2_CPPFLAGS=`$XML2CONFIG --cflags`
+
+# Check headers file
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$XML2_CPPFLAGS"
+AC_CHECK_HEADERS([libxml/tree.h libxml/parser.h libxml/xpath.h libxml/xpathInternals.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to libxml2])])
+
+# Ensure we can link against libxml2
+LIBS_SAVE="$LIBS"
+LIBS="$XML2_LDFLAGS"
+AC_CHECK_LIB([xml2], [xmlInitParser], [], [AC_MSG_ERROR([could not find libxml2])], [])
+
+AC_SUBST([XML2_CPPFLAGS])
+AC_SUBST([XML2_LDFLAGS])
+LIBS="$LIBS_SAVE"
+
+
+# ===========================================================================
+# Detect if libxslt is installed
+# ===========================================================================
+
+AC_ARG_WITH([xsltconfig], 
+	[AS_HELP_STRING([--with-xsltconfig=FILE], [Specifies an alternative xslt-config file])], 
+	[XSLTCONFIG="$withval"], [XSLTCONFIG=""])
+
+if test "x$XSLTCONFIG" = "x"; then
+	# XSLTCONFIG was not specified, so search within the current path
+	AC_PATH_PROG([XSLTCONFIG], [xslt-config])
+
+	# If we couldn't find xslt-config, display a warning
+	if test "x$XSLTCONFIG" = "x"; then
+		AC_MSG_ERROR([could not find xslt-config from libxslt within the current path. You may need to try re-running configure with a --with-xtltconfig parameter.])
+	fi
+else
+	# XSLTCONFIG was specified; display a message to the user
+	if test "x$XSLTCONFIG" = "xyes"; then
+		AC_MSG_ERROR([you must Specifies a parameter to --with-xsltconfig, e.g. --with-xsltconfig=/path/to/xslt-config])
+	else
+		if test -f $XSLTCONFIG; then
+			AC_MSG_RESULT([Using user-specified xslt-config file: $XSLTCONFIG])
+		else
+			AC_MSG_ERROR([the user-specified xslt-config file $XSLTCONFIG does not exist])
+		fi	
+	fi
+fi
+
+# Extract the linker and include flags 
+XSLT_LDFLAGS=`$XSLTCONFIG --libs`
+XSLT_CPPFLAGS=`$XSLTCONFIG --cflags`
+
+# Check headers file
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$XSLT_CPPFLAGS"
+AC_CHECK_HEADERS([libxslt/xslt.h libxslt/xsltInternals.h libxslt/transform.h libxslt/xsltutils.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to libxlst])])
+
+AC_SUBST([XSLT_CPPFLAGS])
+AC_SUBST([XSLT_LDFLAGS])
+
+#============================================================================
+# Detect if gdal is installed
+#============================================================================
+
+AC_ARG_WITH([gdal-config], 
+	[AS_HELP_STRING([--with-gdal-config=FILE], [Specifies an alternative gdal-config file])], 
+	[GDAL_CONFIG="$withval"], [GDAL_CONFIG=""])
+if test -z $GDAL_CONFIG;
+then
+	AC_PATH_PROG([GDAL_CONFIG], [gdal-config])
+	if test -z $GDAL_CONFIG; 
+	then
+		AC_MSG_ERROR([could not find gdal-config from libgdal within the current path. You may need to try re-running configure with a --with-gdal-config parameter.])
+	fi
+	
+else
+	if test -f $GDAL_CONFIG; then
+		AC_MSG_RESULT([Using user-specified gdal-config file: $GDAL_CONFIG])
+	else
+		AC_MSG_ERROR([the user-specified gdal-config file $GDAL_CONFIG does not exist])
+	fi
+fi
+
+GDAL_CFLAGS="`$GDAL_CONFIG --cflags`"
+GDAL_LIBS="`$GDAL_CONFIG --libs`"
+
+AC_SUBST([GDAL_CFLAGS])
+AC_SUBST([GDAL_LIBS])
+
+# ===========================================================================
+# Detect if proj is installed
+# ===========================================================================
+
+AC_ARG_WITH([proj],
+        [AS_HELP_STRING([--with-proj=PATH], [Specifies an alternative location for PROJ4 setup])],
+        [PROJPATH="$withval"], [PROJPATH=""])
+
+# Extract the linker and include flags
+PROJ_LDFLAGS="-L$PROJPATH/lib"
+PROJ_CPPFLAGS="-I$PROJPATH/include"
+
+# Check headers file
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$PROJ_CPPFLAGS"
+AC_CHECK_HEADERS([proj_api.h],
+                 [], [AC_MSG_ERROR([could not find headers include related to PROJ4])])
+
+AC_SUBST([PROJ_CPPFLAGS])
+AC_SUBST([PROJ_LDFLAGS])
+
+# ===========================================================================
+# Detect if libgeos is installed
+# ===========================================================================
+
+AC_ARG_WITH([geosconfig], 
+	[AS_HELP_STRING([--with-geosconfig=FILE], [Specifies an alternative geos-config file])], 
+	[GEOSCONFIG="$withval"], [GEOSCONFIG=""])
+
+if test "x$GEOSCONFIG" = "x"; then
+	# GEOSCONFIG was not specified, so search within the current path
+	AC_PATH_PROG([GEOSCONFIG], [geos-config])
+
+	# If we couldn't find geos-config, display a warning
+	if test "x$GEOSCONFIG" = "x"; then
+		AC_MSG_WARN([could not find geos-config from libgeos within the current path. You may need to try re-running configure with a --with-geosconfig parameter.])
+	fi
+else
+	# GEOSCONFIG was specified; display a message to the user
+	if test "x$GEOSCONFIG" = "xyes"; then
+		AC_MSG_WARN([you must Specifies a parameter to --with-geosconfig, e.g. --with-geosconfig=/path/to/geos-config])
+	else
+		if test -f $GEOSCONFIG; then
+			AC_MSG_RESULT([Using user-specified geos-config file: $GEOSCONFIG])
+		else
+			AC_MSG_ERROR([the user-specified geos-config file $GEOSCONFIG does not exist])
+		fi	
+	fi
+fi
+
+GEOS_LDFLAGS=`$GEOSCONFIG --libs`
+GEOS_CPPFLAGS=`$GEOSCONFIG --cflags`
+
+# Check headers file
+CPPFLAGS_SAVE="$CPPFLAGS"
+CPPFLAGS="$GEOS_CPPFLAGS"
+AC_CHECK_HEADERS([geos_c.h],
+		 [], [AC_MSG_WARN([could not find headers include related to libgeos])])
+
+AC_SUBST([GEOS_CPPFLAGS])
+AC_SUBST([GEOS_LDFLAGS])
+
+
+# ===========================================================================
+# Detect if cgal is installed
+# ===========================================================================
+
+AC_ARG_WITH([cgal],
+        [AS_HELP_STRING([--with-cgal=PATH], [Specifies an alternative location for CGAL setup])],
+        [CGALPATH="$withval"], [CGALPATH="/usr"])
+
+
+# Check headers file
+CPPFLAGS_SAVE="$CPPFLAGS"
+CGAL_CPPFLAGS="-I$CGALPATH/include"
+CPPFLAGS="$CGAL_CPPFLAGS"
+AC_CHECK_HEADERS([CGAL/Delaunay_triangulation_2.h],
+         [], [AC_MSG_WARN([could not find headers include related to libCGAL])])
+
+# Extract the linker and include flags
+CGAL_LDFLAGS="-L$CGALPATH/lib"
+CGAL_CPPFLAGS="-I$CGALPATH/include"
+
+
+AC_SUBST([CGAL_CPPFLAGS])
+AC_SUBST([CGAL_LDFLAGS])
+#============================================================================
+# Detect if mapserver is installed
+#============================================================================
+
+AC_ARG_WITH([mapserver], 
+       [AS_HELP_STRING([--with-mapserver=PATH], [Specifies the path for MapServer compiled source tree])], 
+       [MS_SRC_PATH="$withval"], [MS_SRC_PATH=""])
+
+AC_ARG_WITH([ms-version], 
+       [AS_HELP_STRING([--with-ms-version=VERSION], [Specifies the MapServer version to build against])], 
+       [MS_VERSION="$withval"], [MS_VERSION=""])
+
+if test -z $MS_SRC_PATH;
+then
+	MS_CPPFLAGS=""
+	MS_LDFLAGS=""
+else
+       if test "x$MS_SRC_PATH" = "xmacos";
+       then
+               MS_LDFLAGS="/Library/Frameworks/MapServer.framework//Versions/6.0/MapServer -lintl"
+               MS_CPPFLAGS="-DUSE_MS `/Library/Frameworks/MapServer.framework/Programs/mapserver-config --includes` -I/Library/Frameworks/MapServer.framework/Versions/Current/Headers/ -I../mapserver "
+               AC_MSG_WARN([Please make sure that ../mapserver exists and contains MapServer source tree])
+               AC_MSG_RESULT([Using MacOS X Framework for MapServer])
+       else
+	if test "x$MS_VERSION" = "x7";
+	then
+		MS_LDFLAGS="-L$MS_SRC_PATH/lib -lmapserver"
+		MS_CPPFLAGS="-DUSE_MS -I$MS_SRC_PATH/include/mapserver "
+               	AC_MSG_RESULT([Using user-specified MapServer src path: $MS_SRC_PATH])
+        else
+               if test -d $MS_SRC_PATH; then
+                       MS_LDFLAGS="-L$MS_SRC_PATH -lmapserver `$MS_SRC_PATH/mapserver-config --libs`"
+                       MS_CPPFLAGS="-DUSE_MS `$MS_SRC_PATH/mapserver-config --includes` `$MS_SRC_PATH/mapserver-config --cflags` -I$MS_SRC_PATH "
+               
+                       AC_MSG_RESULT([Using user-specified MapServer src path: $MS_SRC_PATH])
+               else
+                       AC_MSG_ERROR([the user-specified mapserver-config file $MS_SRC_PATH does not exist])
+               fi
+        fi
+       fi
+       MS_FILE="service_internal_ms.o"
+fi
+
+MS_CFLAGS="$MS_CPPFLAGS"
+MS_LIBS="$MS_LDFLAGS"
+
+AC_SUBST([MS_CFLAGS])
+AC_SUBST([MS_LIBS])
+AC_SUBST([MS_FILE])
+AC_SUBST([MS_VERSION])
+
+# ===========================================================================
+# Detect if R is installed
+# ===========================================================================
+
+AC_ARG_WITH([r], 
+	[AS_HELP_STRING([--with-r=PATH], [To enable python support or Specifies an alternative directory for R installation,  disabled by default])], 
+	[R_PATH="$withval"; R_ENABLED="-DUSE_R"], [R_ENABLED=""])
+
+if test -z "$R_ENABLED"
+then
+	R_FILE=""
+else
+	R_FILE="service_internal_r.o"
+	# Extract the linker and include flags 
+	R_LDFLAGS="-L$R_PATH/lib/ -lR"
+	R_CPPFLAGS="-I$R_PATH/include/ -I$R_PATH/share/R/include/"
+
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$R_CPPFLAGS"
+	AC_CHECK_HEADERS([Rinternals.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to R])])
+
+	# Ensure we can link against libphp
+	#LIBS_SAVE="$LIBS"
+	#LIBS="$R_LDFLAGS"
+	#AC_CHECK_LIB([$LIBS], [R_tryEval], [], [AC_MSG_ERROR([could not find libR])], [])
+	#LIBS="$LIBS_SAVE"
+fi
+
+AC_SUBST([R_CPPFLAGS])
+AC_SUBST([R_LDFLAGS])
+AC_SUBST([R_ENABLED])
+AC_SUBST([R_FILE])
+
+
+# ===========================================================================
+# Detect if python is installed
+# ===========================================================================
+
+AC_ARG_WITH([python], 
+	[AS_HELP_STRING([--with-python=PATH], [To enable python support or Specifies an alternative directory for python installation,  disabled by default])], 
+	[PYTHON_PATH="$withval"; PYTHON_ENABLED="-DUSE_PYTHON"], [PYTHON_ENABLED=""])
+
+AC_ARG_WITH([pyvers], 
+	[AS_HELP_STRING([--with-pyvers=NUM], [To use a specific python version])], 
+	[PYTHON_VERS="$withval"], [PYTHON_VERS=""])
+
+
+if test -z "$PYTHON_ENABLED"
+then
+	PYTHON_FILE=""
+else
+	PYTHONCONFIG="$PYTHON_PATH/bin/python${PYTHON_VERS}-config"
+	PYTHON_FILE="service_internal_python.o"
+	if test  "$PYTHON_PATH" = "yes"
+	then
+		# PYTHON was not specified, so search within the current path
+		PYTHONCFG_PATH=`which python${PYTHON_VERS}-config`
+		if test -z "${PYTHONCFG_PATH}" ; then
+		AC_PATH_PROG([PYTHONCONFIG], [python-config-${PYTHON_VERS}])
+		else
+		AC_PATH_PROG([PYTHONCONFIG], [python${PYTHON_VERS}-config])
+		fi
+	else
+		PYTHONCONFIG="$PYTHON_PATH/bin/python${PYTHON_VERS}-config"
+	fi
+
+	# Extract the linker and include flags 
+	PYTHON_LDFLAGS=`$PYTHONCONFIG --ldflags`
+	PYTHON_CPPFLAGS=`$PYTHONCONFIG --includes`
+
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$PYTHON_CPPFLAGS"
+	AC_CHECK_HEADERS([Python.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to libpython])])
+
+	# Ensure we can link against libphp
+	LIBS_SAVE="$LIBS"
+	LIBS="$PYTHON_LDFLAGS"
+	PY_LIB=`$PYTHONCONFIG --libs | sed \
+			      -e 's/.*\(python[[0-9]]\.[[0-9]]\).*/\1/'`
+	AC_CHECK_LIB([$PY_LIB], [PyObject_CallObject], [], [AC_MSG_ERROR([could not find libpython])], [])
+	LIBS="$LIBS_SAVE"
+fi
+
+AC_SUBST([PYTHON_CPPFLAGS])
+AC_SUBST([PYTHON_LDFLAGS])
+AC_SUBST([PYTHON_ENABLED])
+AC_SUBST([PYTHON_FILE])
+
+# ===========================================================================
+# Detect if spidermonkey is installed
+# ===========================================================================
+
+AC_ARG_WITH([js], 
+	[AS_HELP_STRING([--with-js=PATH], [Specifies --with-js=path-to-js to enable js support, specify --with-js on linux debian like, js support is disabled by default ])], 
+	[JSHOME="$withval";JS_ENABLED="-DUSE_JS"], [JS_ENABLED=""])
+
+if test -z "$JS_ENABLED"
+then
+	JS_FILE=""
+else
+	JS_FILE="service_internal_js.o"
+	if test "$JSHOME" = "yes"
+	then
+
+		#on teste si on est sous debian like 
+		if test -f "/usr/bin/dpkg"
+		then
+			if test -n "`dpkg -l | grep libmozjs185-dev`"
+			then
+				JS_CPPFLAGS="-I/usr/include/js/"
+                        	JS_LDFLAGS="-L/usr/lib -lmozjs185 -lm"
+                        	JS_LIB="mozjs185"
+			else 
+				XUL_VERSION="`dpkg -l | grep xulrunner | grep dev | head -1| awk '{print $3;}' | cut -d'+' -f1`"
+				if test -n "$XUL_VERSION"
+				then
+					JS_CPPFLAGS="-I/usr/include/xulrunner-$XUL_VERSION"
+					JS_LDFLAGS="-L/usr/lib/xulrunner-$XUL_VERSION -lmozjs -lm"
+					JS_LIB="mozjs"
+				else
+					AC_MSG_ERROR([You must install libmozjs185-dev or xulrunner-dev ])
+				fi
+			fi
+		else
+			AC_MSG_ERROR([You must  specify your custom install of libmozjs185])
+		fi
+	else
+		JS_CPPFLAGS="-I$JSHOME/include/js/"
+                JS_LDFLAGS="-L$JSHOME/lib -lmozjs185 -lm"
+                JS_LIB="mozjs185"
+
+	fi 
+	CPPFLAGS_SAVE="$CPPFLAGS"
+        CPPFLAGS="$JS_CPPFLAGS"
+	AC_LANG_PUSH([C++])
+	AC_CHECK_HEADERS([jsapi.h],
+                        [], [AC_MSG_ERROR([could not find headers include related to libjs])])
+
+	AC_LANG_POP([C++])
+	LIBS_SAVE="$LIBS"
+        LIBS="$JS_LDFLAGS"
+
+        AC_CHECK_LIB([$JS_LIB], [JS_CompileFile,JS_CallFunctionName], [], [AC_MSG_ERROR([could not find $JS_LIB])], [])
+	LIBS="$LIBS_SAVE"
+	
+        AC_SUBST([JS_CPPFLAGS])
+        AC_SUBST([JS_LDFLAGS])
+fi
+
+AC_SUBST([JS_ENABLED])
+AC_SUBST([JS_FILE])
+
+# ===========================================================================
+# Detect if php is installed
+# ===========================================================================
+
+AC_ARG_WITH([php], 
+	[AS_HELP_STRING([--with-php=PATH], [To enable php support or specify an alternative directory for php installation,  disabled by default])], 
+	[PHP_PATH="$withval"; PHP_ENABLED="-DUSE_PHP"], [PHP_ENABLED=""])
+
+AC_ARG_WITH([php-version], 
+	[AS_HELP_STRING([--with-phpvers=NUM], [To use a specific php version])], 
+	[PHP_VERS="$withval"], [PHP_VERS=""])
+
+
+if test -z "$PHP_ENABLED"
+then
+	PHP_FILE=""
+else
+	PHPCONFIG="$PHP_PATH/bin/php-config"
+	if test "x$PHP_VERS" = "x7"
+	then
+		PHP_FILE="service_internal_php7.o"
+	else
+		PHP_FILE="service_internal_php.o"
+	fi
+	if test  "$PHP_PATH" = "yes"
+	then
+		# PHP was not specified, so search within the current path
+		AC_PATH_PROG([PHPCONFIG], [php-config])
+	else
+		PHPCONFIG="$PHP_PATH/bin/php-config"
+	fi
+
+	# Extract the linker and include flags 
+	if test "x$PHP_VERS" = "x7"
+	then
+		PHP_LDFLAGS="-L/`$PHPCONFIG --prefix`/lib64 -lphp7"
+	else
+		PHP_LDFLAGS="-L/`$PHPCONFIG --prefix`/lib -lphp5"
+	fi
+	PHP_CPPFLAGS=`$PHPCONFIG --includes`
+
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$PHP_CPPFLAGS"
+	AC_CHECK_HEADERS([sapi/embed/php_embed.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to libphp])])
+
+	# Ensure we can link against libphp
+	LIBS_SAVE="$LIBS"
+	LIBS="$PHP_LDFLAGS"
+	# Shouldn't we get php here rather than php5 :) ??
+	if test "x$PHP_VERS" = "x7"
+	then
+		echo $LIBS
+		#AC_CHECK_LIB([php7], [call_user_function], [], [AC_MSG_ERROR([could not find libphp])], [])
+	else
+		AC_CHECK_LIB([php5], [call_user_function], [], [AC_MSG_ERROR([could not find libphp])], [])
+	fi
+	LIBS="$LIBS_SAVE"
+	AC_SUBST([PHP_CPPFLAGS])
+	AC_SUBST([PHP_LDFLAGS])
+fi
+
+AC_SUBST([PHP_ENABLED])
+AC_SUBST([PHP_FILE])
+
+# ===========================================================================
+# Detect if java is installed
+# ===========================================================================
+
+AC_ARG_WITH([java], 
+	[AS_HELP_STRING([--with-java=PATH], [To enable java support, specify a JDK_HOME,  disabled by default])], 
+	[JDKHOME="$withval"; JAVA_ENABLED="-DUSE_JAVA"], [JAVA_ENABLED=""])
+
+AC_ARG_WITH([java-rpath], 
+	[AS_HELP_STRING([--with-java-rpath=yes], [To set rpath for java support, disabled by default])], 
+	[JAVA_RPATH="$withval"], [JAVA_RPATH=""])
+
+if test -z "$JAVA_ENABLED"
+then
+	JAVA_FILE=""
+else
+	JAVA_FILE="service_internal_java.o"
+	if test "x$JDKHOME" = "x"; 
+	then
+		AC_MSG_ERROR([could not find java installation path within the current path. You may need to try re-running configure with a --with-java parameter.])
+	fi	# JAVA was specified; display a message to the user
+	if test "x$JDKHOME" = "xyes"; 
+	then
+		AC_MSG_ERROR([you must specify a parameter to --with-java, e.g. --with-java=/path/to/java])
+	fi
+
+	# Extract the linker and include flags
+	if test "x$JDKHOME" = "xmacos";
+	then
+		JAVA_LDFLAGS="-framework JavaVM"
+		for i in `ls /Applications/Xcode.app/Contents/Developer//Platforms/MacOSX.platform/Developer/SDKs/`; do
+		    JAVA_CPPFLAGS="-I/Applications/Xcode.app/Contents/Developer//Platforms/MacOSX.platform/Developer/SDKs/$i/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/"
+		done
+	else
+		if test -d "$JDKHOME/jre/lib/i386";
+		then
+			JAVA_LDFLAGS="-L$JDKHOME/jre/lib/i386/server/ -ljvm -lpthread"
+			JAVA_CPPFLAGS="-I$JDKHOME/include -I$JDKHOME/include/linux"
+			if test x$JAVA_RPATH = "xyes"; then
+			   JAVA_LDFLAGS="$JAVA_LDFLAGS -Wl,-rpath,$JDKHOME/jre/lib/i386/server/"
+			fi
+		else
+			if test -d "$JDKHOME/jre/lib/amd64"; then
+			   JAVA_LDFLAGS="-L$JDKHOME/jre/lib/amd64/server/ -ljvm -lpthread"
+			   JAVA_CPPFLAGS="-I$JDKHOME/include -I$JDKHOME/include/linux"
+			   if test x$JAVA_RPATH = "xyes"; then
+			      JAVA_LDFLAGS="$JAVA_LDFLAGS -Wl,-rpath,$JDKHOME/jre/lib/amd64/server/"
+			   fi
+			else
+			   JAVA_LDFLAGS="-L$JDKHOME/jre/lib/server/ -ljvm -lpthread"
+			   JAVA_CPPFLAGS="-I$JDKHOME/include/ -I$JDKHOME/include/darwin"
+			   if test x$JAVA_RPATH = "xyes"; then
+			      JAVA_LDFLAGS="$JAVA_LDFLAGS -Wl,-rpath,$JDKHOME/jre/lib/server/"
+			   fi
+			fi
+		fi
+	fi
+
+	AC_LANG([C++])
+	#echo $JAVA_CPPFLAGS
+	# Check headers file (second time we check that in fact)
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$JAVA_CPPFLAGS"
+	AC_CHECK_HEADERS([jni.h],
+			 [], [AC_MSG_ERROR([could not find jni.h file])])
+	CPPFLAGS="$CPPFLAGS_SAVE"
+	# Ensure we can link against libjava
+	LIBS_SAVE="$LIBS"
+	LIBS="$JAVA_LDFLAGS"
+	if test "x$JDKHOME" != "xmacos";
+	then
+		AC_CHECK_LIB([jvm], [JNI_CreateJavaVM], [], [AC_MSG_ERROR([could not find libjvm])], [])
+	fi
+	LIBS="$LIBS_SAVE"
+
+	AC_SUBST([JAVA_CPPFLAGS])
+	AC_SUBST([JAVA_LDFLAGS])
+fi 
+
+AC_SUBST([JAVA_ENABLED])
+AC_SUBST([JAVA_FILE])
+
+# ===========================================================================
+# Detect if mono is installed
+# ===========================================================================
+
+AC_ARG_WITH([mono], 
+	[AS_HELP_STRING([--with-mono=PATH], [To enable mono support, specify the path to find pkg-config,  disabled by default])], 
+	[MONOHOME="$withval"; MONO_ENABLED="-DUSE_MONO"], [MONO_ENABLED=""])
+
+if test -z "$MONO_ENABLED"
+then
+	MONO_FILE=""
+else
+	MONO_FILE="service_internal_mono.o"
+	if test "x$MONOHOME" = "x"; 
+	then
+		MONOHOME="/usr"
+	fi
+	if test "x$MONOHOME" = "xyes"; 
+	then
+		MONOHOME="/usr"
+	fi
+
+	# Extract the linker and include flags
+	MONO_CFLAGS=`$MONOHOME/bin/pkg-config --cflags mono-2`
+	MONO_LDFLAGS=`$MONOHOME/bin/pkg-config --libs mono-2`
+
+	AC_LANG([C++])
+	#echo $JAVA_CPPFLAGS
+	# Check headers file (second time we check that in fact)
+	CPPFLAGS_SAVE="$CFLAGS"
+	CPPFLAGS="$MONO_CFLAGS"
+	AC_CHECK_HEADERS([mono/jit/jit.h],
+			 [], [AC_MSG_ERROR([could not find jit.h file])])
+	CPPFLAGS="$CPPFLAGS_SAVE"
+	# Ensure we can link against libmono-2.0
+	LIBS_SAVE="$LIBS"
+	LIBS="$MONO_LDFLAGS"
+	AC_CHECK_LIB([mono-2.0], [mono_runtime_invoke], [], [AC_MSG_ERROR([could not find libmono])], [])
+	LIBS="$LIBS_SAVE"
+
+	AC_SUBST([MONO_CFLAGS])
+	AC_SUBST([MONO_LDFLAGS])
+fi 
+
+AC_SUBST([MONO_ENABLED])
+AC_SUBST([MONO_FILE])
+
+# ===========================================================================
+# Detect if ruby is installed
+# ===========================================================================
+AC_ARG_WITH([ruby], 
+	[AS_HELP_STRING([--with-ruby=PATH], [To enable ruby support or specify an alternative directory for ruby installation,  disabled by default])], 
+	[RUBY_PATH="$withval"; RUBY_ENABLED="-DUSE_RUBY"], [RUBY_ENABLED=""])
+
+AC_ARG_WITH([rvers], 
+	[AS_HELP_STRING([--with-rvers=NUM], [To use a specific ruby version])], 
+	[RUBY_VERS="$withval"], [RUBY_VERS=""])
+
+
+if test -z "$RUBY_ENABLED"
+then
+	RUBY_FILE=""
+else
+	RUBY_FILE="service_internal_ruby.o"
+
+	# Extract the linker and include flags 
+	RUBY_LDFLAGS="-lruby"
+	RUBY_CPPFLAGS="-I$RUBY_PATH -I$RUBY_PATH/x86_64-darwin13.0/ -DZRUBY_VERSION=$RUBY_VERS"
+
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$RUBY_CPPFLAGS"
+	AC_CHECK_HEADERS([ruby.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to libruby])])
+
+	# Ensure we can link against libphp
+	LIBS_SAVE="$LIBS"
+	LIBS="$RUBY_LDFLAGS"
+	# AC_CHECK_LIB([lruby], [PyObject_CallObject], [], [AC_MSG_ERROR([could not find libpython])], [])
+	LIBS="$LIBS_SAVE"
+	AC_SUBST([RUBY_CPPFLAGS])
+	AC_SUBST([RUBY_LDFLAGS])
+fi
+
+AC_SUBST([RUBY_ENABLED])
+AC_SUBST([RUBY_FILE])
+
+# ===========================================================================
+# Detect if perl is installed
+# ===========================================================================
+
+AC_ARG_WITH([perl], 
+	[AS_HELP_STRING([--with-perl=PATH], [To enable perl support or specify an alternative directory for perl installation,  disabled by default])], 
+	[PERL_PATH="$withval"; PERL_ENABLED="-DUSE_PERL"], [PERL_ENABLED=""])
+
+
+if test -z "$PERL_ENABLED"
+then
+	PERL_FILE=""
+else
+	PERL_FILE="service_internal_perl.o"
+	if test  "$PERL_PATH" = "yes"
+	then
+		# Perl was not specified, so search within the current path
+		AC_PATH_PROG([PERLCONFIG], [perl])
+	else
+		PERLCONFIG="$PERL_PATH/bin/perl"
+	fi
+
+	# Extract the linker and include flags 
+	PERL_LDFLAGS=`$PERLCONFIG -MExtUtils::Embed -e ldopts`
+	PERL_CPPFLAGS=`$PERLCONFIG -MExtUtils::Embed -e ccopts`
+
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$PERL_CPPFLAGS"
+	AC_CHECK_HEADERS([EXTERN.h],
+		 [], [AC_MSG_ERROR([could not find headers include related to libperl])])
+
+	AC_SUBST([PERL_CPPFLAGS])
+	AC_SUBST([PERL_LDFLAGS])
+fi
+
+AC_SUBST([PERL_ENABLED])
+AC_SUBST([PERL_FILE])
+
+# ===========================================================================
+# Detect if otb is available
+# ===========================================================================
+
+AC_ARG_WITH([itk],
+        [AS_HELP_STRING([--with-itk=PATH], [Specifies an alternative location for the itk library])],
+        [ITKPATH="$withval"], [ITKPATH=""])
+
+AC_ARG_WITH([itk-version],
+        [AS_HELP_STRING([--with-itk-version=VERSION], [Specifies an alternative version for the itk library])],
+        [ITKVERS="$withval"], [ITKVERS=""])
+
+AC_ARG_WITH([otb],
+        [AS_HELP_STRING([--with-otb=PATH], [Specifies an alternative location for the otb library])],
+        [OTBPATH="$withval"], [OTBPATH=""])
+
+AC_ARG_WITH([otb-version],
+        [AS_HELP_STRING([--with-otb-version=PATH], [Specifies an alternative location for the otb library])],
+        [OTBVERS="$withval"], [OTBVERS=""])
+
+if test -z "$OTBPATH"
+then
+	OTB_LDFLAGS=""
+	OTB_CPPFLAGS=""
+	OTB_FILE=""
+	OTB_ENABLED=""
+else
+	if test -z "$ITKVERS" 
+    	then
+		ITKVERS="4.5"
+    	fi
+	OTB_ENABLED="-DUSE_OTB"
+	IVERS="$(echo -e '4.10\n$ITKVERS' | sort -r | head -n1)"
+	if test "$IVERS" == "$ITKVERS"; then
+	   ITK_LDFLAGS="-lITKBiasCorrection-$ITKVERS -lITKCommon-$ITKVERS -lITKIOImageBase-$ITKVERS -lITKKLMRegionGrowing-$ITKVERS -lITKLabelMap-$ITKVERS -lITKMesh-$ITKVERS -lITKMetaIO-$ITKVERS -lITKOptimizers-$ITKVERS -lITKPath-$ITKVERS -lITKPolynomials-$ITKVERS -lITKQuadEdgeMesh-$ITKVERS -lITKSpatialObjects-$ITKVERS -lITKStatistics-$ITKVERS -lITKVNLInstantiation-$ITKVERS -lITKWatersheds-$ITKVERS -litkNetlibSlatec-$ITKVERS -litksys-$ITKVERS -litkv3p_netlib-$ITKVERS -litkvcl-$ITKVERS -litkvnl-$ITKVERS"
+	else
+		ITK_LDFLAGS="-lITKBiasCorrection-$ITKVERS -lITKCommon-$ITKVERS -lITKIOImageBase-$ITKVERS -lITKKLMRegionGrowing-$ITKVERS -lITKLabelMap-$ITKVERS -lITKMesh-$ITKVERS -lITKMetaIO-$ITKVERS -lITKOptimizers-$ITKVERS -lITKPath-$ITKVERS -lITKPolynomials-$ITKVERS -lITKQuadEdgeMesh-$ITKVERS -lITKSpatialObjects-$ITKVERS -lITKStatistics-$ITKVERS -lITKVNLInstantiation-$ITKVERS -lITKWatersheds-$ITKVERS -litkNetlibSlatec-$ITKVERS -litksys-$ITKVERS -litkv3p_lsqr-$ITKVERS -litkv3p_netlib-$ITKVERS -litkvcl-$ITKVERS -litkvnl-$ITKVERS -litkvnl_algo-$ITKVERS"
+	fi
+
+	if test -a "${OTBPATH}/include/OTB-${OTBVERS}" ; then 
+		OTB_RPATH="$OTBPATH/include/OTB-${OTBVERS}/"
+		OTB_CPPFLAGS="-I${OTB_RPATH}ApplicationEngine -I$OTB_RPATH/Common -I$ITKPATH/include/ITK-$ITKVERS -I$OTB_RPATH/Utilities/ITK -I$OTB_RPATH/ -I$OTB_RPATH/IO -I$OTB_RPATH/UtilitiesAdapters/OssimAdapters -I$OTB_RPATH/UtilitiesAdapters/CurlAdapters -I$OTB_RPATH/Utilities/BGL -I$OTB_RPATH/UtilitiesAdapters/ITKPendingPatches -I$OTB_RPATH/Utilities/otbconfigfile $GDAL_CFLAGS"
+		OTB_LDFLAGS="-L/usr/lib/x86_64-linux-gnu/ -lOTBImageIO-$OTBVERS -lOTBCommon-$OTBVERS -lOTBApplicationEngine-$OTBVERS -L$ITKPATH/lib $ITK_LDFLAGS"
+	else
+		OTB_CPPFLAGS="-I$OTBPATH/include/otb/ApplicationEngine -I$OTBPATH/include/otb/Common -I$ITKPATH/include/ITK-$ITKVERS -I$OTBPATH/include/otb/Utilities/ITK -I$OTBPATH/include/otb/ -I$OTBPATH/include/otb/IO -I$OTBPATH/include/otb/UtilitiesAdapters/OssimAdapters -I$OTBPATH/include/otb/UtilitiesAdapters/CurlAdapters -I$OTBPATH/include/otb/Utilities/BGL -I$OTBPATH/include/otb/UtilitiesAdapters/ITKPendingPatches -I$OTBPATH/include/otb/Utilities/otbconfigfile $GDAL_CFLAGS"
+		OTB_LDFLAGS="-L$OTBPATH/lib/otb -lOTBIO -lOTBCommon -lOTBApplicationEngine -L$ITKPATH/lib $ITK_LDFLAGS"
+
+	fi
+	OTB_FILE="otbZooWatcher.o service_internal_otb.o"
+	
+	AC_LANG_PUSH([C++])
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$OTB_CPPFLAGS"
+	LDFLAGS_SAVE="$LDFLAGS"
+	LIBS="$LIBS_SAVE $OTB_LDFLAGS"
+	#echo $OTB_CPPFLAGS
+	AC_CHECK_HEADERS([otbWrapperApplication.h otbWrapperInputImageListParameter.h otbWrapperApplicationRegistry.h],
+			[], [AC_MSG_ERROR([could not find header file $i related to OTB])])
+	LDFLAGS_SAVE="$LDFLAGS"
+	LDFLAGS="$OTB_LDFLAGS"
+	#echo $OTB_LDFLAGS
+	#UVERS="$(echo -e '5.8\n$OTBVERS' | sort -r | head -n1)"
+	#if test "$OTBVERS" ==  "$UVERS" ; then 
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "otbWrapperApplicationRegistry.h"]],[[std::vector<std::string> list = otb::Wrapper::ApplicationRegistry::GetAvailableApplications();]])],
+			[AC_MSG_RESULT([checking for GetAvailableApplications... yes])],[AC_MSG_ERROR([checking for GetAvailableApplications... failed])])
+	#else
+	#	AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "otbWrapperApplication.h"]],[[std::vector<std::string> list = otb::Wrapper::ApplicationRegistry::GetAvailableApplication();]])],
+	#						   [AC_MSG_RESULT([checking for GetAvailableApplication... yes])],[AC_MSG_ERROR([checking for GetAvailableApplication... failed])])
+	#fi
+							   			
+	LDFLAGS="$LDFLAGS_SAVE"
+	AC_LANG_POP([C++])
+	AC_LANG(C++)
+			
+fi
+AC_SUBST([OTB_CPPFLAGS])
+AC_SUBST([OTB_LDFLAGS])
+AC_SUBST([OTB_FILE])
+AC_SUBST([OTB_ENABLED])
+
+# ===========================================================================
+# Detect if saga-gis is available
+# ===========================================================================
+
+AC_ARG_WITH([wx-config],
+        [AS_HELP_STRING([--with-wx-config=PATH], [Specifies an alternative path for the wx-config tool])],
+        [WXCFG="$withval"], [WXCFG=""])
+
+AC_ARG_WITH([saga],
+        [AS_HELP_STRING([--with-saga=PATH], [Specifies an alternative location for the SAGA-GIS library])],
+        [SAGAPATH="$withval"], [SAGAPATH=""])
+
+AC_ARG_WITH([saga-version],
+        [AS_HELP_STRING([--with-saga-version=VERSION], [Specifies the SAGA-GIS version number])],
+        [SAGAVERS="$withval"], [SAGAVERS="2"])
+
+if test -z "$SAGAPATH"
+then
+	SAGA_LDFLAGS=""
+	SAGA_CPPFLAGS=""
+	SAGA_FILE=""
+	SAGA_ENABLED=""
+else
+	if test -z "$WXCFG" ; then
+	   WXCFG="$(which wx-config)"
+	fi
+	if test "`$WXCFG --list | grep unicode`" == "" ; then
+	   AC_MSG_ERROR(SAGA requires a unicode build of wxGTK)
+	fi
+	WX_ISSUE="-D_WX_WXCRTVARARG_H_"
+	SAGA_DEFS="-D_SAGA_LINUX -D_TYPEDEF_BYTE -D_TYPEDEF_WORD -DMODULE_LIBRARY_PATH=\\\"$SAGAPATH/lib/saga\\\""
+	SAGA_CPPFLAGS="-DSAGA_VERSION=${SAGAVERS} -fPIC -I$SAGAPATH/include/saga/saga_core/saga_api/ `$WXCFG --unicode=yes --static=no --cxxflags` -D_SAGA_UNICODE $SAGA_DEFS $WX_ISSUE"
+	SAGA_LDFLAGS="-fPIC `$WXCFG --unicode=yes --static=no --libs` -lsaga_api"
+	SAGA_ENABLED="-DUSE_SAGA"
+	SAGA_FILE="service_internal_saga.o"
+	
+	AC_LANG_PUSH([C++])
+	# Check headers file
+	CPPFLAGS_SAVE="$CPPFLAGS"
+	CPPFLAGS="$SAGA_CPPFLAGS"
+	LIBS_SAVE="$LIBS"
+	LIBS="$SAGA_LDFLAGS"
+        if test "$SAGAVERS" == "2"; then
+        AC_CHECK_HEADERS([module_library.h],
+                        [], [AC_MSG_ERROR([could not find header file $i related to SAGA-GIS])])
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "module_library.h"],[SG_Get_Module_Library_Manager();]])],
+                [AC_MSG_RESULT([checking for SG_Get_Module_Library_Manager... yes])],[AC_MSG_ERROR([checking for SG_Get_Module_Library_Manager... failed])])
+        else
+        AC_CHECK_HEADERS([tool_library.h],
+                        [], [AC_MSG_ERROR([could not find header file $i related to SAGA-GIS])])
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "tool_library.h"],[SG_Get_Tool_Library_Manager();]])],
+                [AC_MSG_RESULT([checking for SG_Get_Tool_Library_Manager... yes])],[AC_MSG_ERROR([checking for SG_Get_Tool_Library_Manager... failed])])
+        fi
+	
+	LIBS="$LIBS_SAVE"
+	AC_LANG_POP([C++])
+fi
+AC_SUBST([SAGA_CPPFLAGS])
+AC_SUBST([SAGA_LDFLAGS])
+AC_SUBST([SAGA_FILE])
+AC_SUBST([SAGA_ENABLED])
+
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([ZOOMakefile.opts])
+AC_CONFIG_FILES([main.cfg])
+AC_OUTPUT
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/doc/index.dox
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/doc/index.dox	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/doc/index.dox	(revision 942)
@@ -0,0 +1,20 @@
+#ifndef DOXYGEN_SKIP                                                            
+/* $Id$ */               
+#endif /* DOXYGEN_SKIP */                                                       
+
+/*! \mainpage ZOO-Project C-API Documentation
+
+
+<a href="http://zoo-project.org/">ZOO-Project</a> is an open source WPS platform
+that is released under an <a href="http://zoo-project.org/trac/browser/trunk/zoo-project/LICENSE">X/MIT</a> style 
+<a href="http://www.opensource.org/"> Open Source</a> license. ZOO-Project software is incubating at the <a href="http://www.osgeo.org/">Open Source
+Geospatial Foundation</a>. 
+
+Home: http://www.zoo-project.org<br>
+Download: 
+ <a href="http://zoo-project.org/Code/Download">http at zoo-project.org</a>,
+ <a href="http://svn.zoo-project.org/svn/">svn at zoo-project.org</a>
+
+This documentation describes the ZOO-Project C-API. You can start your visit by the Data Structures link above which details all available structures in ZOO-Project. The Files link presents all source files used to generate this documentation.
+
+*/
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/de.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/de.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/de.po	(revision 942)
@@ -0,0 +1,332 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Daniel Kastl, 2015,2017
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel Internationalization\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: 2017-09-22 11:18+0000\n"
+"Last-Translator: Daniel Kastl\n"
+"Language-Team: German (http://www.transifex.com/zoo-project/zoo-kernel-internationalization/language/de/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: de\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "Speicher kann nicht zugewiesen werden."
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "Die Datei kann nicht heruntergeladen werden."
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "Die maximal zulässigen Vorkommen für <%s> (%i) wurden überschritten."
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "Der ZOO-Kernel konnte Ihre Daten für %s Position %s nicht laden."
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "Die maximal zulässige Anzahl für <%s> ist eins."
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "Es konnte kein gültiges Protokoll gefunden werden, um die Datei %s herunterzuladen"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "Es kann keine Anforderung zur Warteschlange hinzugefügt werden."
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "Die Karte kann nicht zur Karte hinzugefügt werde."
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "Mehrfache <Output> Elemente im der WPS Execute Anfrage"
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr "Der Parameter <%s> hat eine Größenbeschränkung (%s MB), die in der Konfigurationsdatei ZOO ServicesProvider definiert ist, aber die angegebene Referenz überschreitet diese Grenze (%f MB)."
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr "Das Argument <%s> wurde in DataInputs nicht angegeben, ist aber nach der Konfigurationsdatei ZOO ServicesProvider erforderlich."
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined"
+" in the ZOO Configuration File)."
+msgstr "Das als %s-Bezeichner angegebene <%s> -Argument wurde nicht erkannt (nicht in der ZOO-Konfigurationsdatei definiert)."
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "Der erforderliche Parameter <%s> wurde nicht angegeben."
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "Der Wert <%s> wurde nicht erkannt, %s %s der einzige akzeptable Wert."
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "ist"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "sind"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "Der Dienst \"%s\" wurde erfolgreich ausgeführt."
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr "Der ZOO-Dienst \"%s\" läuft derzeit. Bitte laden Sie dieses Dokument neu, um den aktuellen Status des Dienstes zu erhalten."
+
+#: response_print.c:1644
+#, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr "Der Dienst \"%s\" wurde vom ZOO-Kernel akzeptiert und läuft als Hintergrundaufgabe. Bitte rufen Sie die URL im StatusLocation-Attribut auf, das in diesem Dokument enthalten ist, um den aktuellen Status und die aktuellen Ergebnisse zu erhalten."
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "Keine weiteren Informationen verfügbar"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "Fehlercode nicht bekannt: %i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "Sperre fehlgeschlagen."
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "Die Datei \"%s\" zum Speichern der ExecuteResponse kann nicht erstellt werden."
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "Kein Debug Meldung vorhanden"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "Die Datei \"%s\" zum Speichern der Session Maps kann nicht erstellt werden."
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr "Der Dienst kann nicht ausgeführt werden. Die Nachricht, die durch den Service zurückgegeben wurde, war folgende:"
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr "Der Dienst kann nicht ausgeführt werden. Die Nachricht, die durch den Service zurückgegeben wurde, war folgende: %s"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr "Der Dienst kann nicht ausgeführt werden. Keine weiteren Informationen wurden vom Service zurückgegeben."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "Die Datei \"%s\" kann nicht erstellt werden, um das %s-Endergebnis zu speichern."
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr "Falscher RawDataOutput-Parameter: Kann kein Ergebnis für den angegebenen Parameternamen abrufen: \"%s\"."
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr "Die JobID aus der Anfrage stimmt nicht mit einem der Aufträge überein, die auf diesem Server ausgeführt werden"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "Das Ergebnis für die angeforderte JobID wurde noch nicht generiert."
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "Der Job kann nicht entfernt werden, eine Datei kann nicht entfernt werden"
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr "Das Registrierungsverzeichnis konnte nicht geöffnet werden."
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "Speicher kann nicht zugewiesen werden."
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "Die ZCFG-Datei kann nicht gelesen werden: %s (%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "Die ZCFG-Datei kann nicht gelesen werden: %s."
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "Es konnte keine mapserverAddress gefunden werden, die in der main.cfg-Datei definiert ist"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "Die PHP-Datei %s kann nicht geladen werden"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "Python-Modul %s kann nicht geladen werden. Nachricht: %s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following messages : %s"
+msgstr "%s\nIhr Python-Prozess kann nicht korrekt ausgeführt werden. Bitte überprüfen Sie die folgenden Meldungen: %s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further information."
+msgstr "%s\nIhr Python-Prozess kann nicht korrekt ausgeführt werden. Weitere Informationen sind nicht möglich."
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOO Kernel konnte Ihre Anfrage nicht verarbeiten und empfängt das Signal %d = %s"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "Beim Ausführen der %s-Funktion ist ein Fehler aufgetreten: %s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "C Library %s kann nicht geladen werden"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO"
+" Kernel.\n"
+msgstr "Die in der ZCFG-Datei eingestellte Programmiersprache (%s) wird derzeit nicht von ZOO-Kernel unterstützt.\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "Der HTTP POST Execute Aufruf kann nicht gecached werden."
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "Die Datei main.cfg kann nicht geladen werden."
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr "%s Die folgende Datei: %s kann nicht gefunden werden."
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "Der Wert %s wird für den <language>-Parameter nicht unterstützt"
+
+#: zoo_service_loader.c:1238
+msgid "The specified path does not exist."
+msgstr "Der angegebene Pfad existiert nicht."
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr "Die ZCFG-Datei kann für den folgenden ZOO-Service nicht bestimmt werden: %s.\nMeldung: %s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "Die ZCFG-Datei kann für den folgenden ZOO-Service nicht bestimmt werden: %s."
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "Kann nicht mit der GET HTTP-Methode ausgeführt werden"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the"
+" processes in the list returned by a GetCapabilities request."
+msgstr "Der Wert für <identifier> scheint falsch zu sein (%s). Bitte geben Sie einen der Prozesse in der Liste an, die von einer GetCapabilities-Anfrage zurückgegeben wird."
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to"
+" false. Please modify your request parameters."
+msgstr "Der Status-Parameter kann nicht auf true gesetzt werden, wenn storeExecuteResponse auf false gesetzt ist. Bitte ändern Sie Ihre Anfrageparameter."
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "Der Prozess erlaubt den gewünschten Ausführungsmodus nicht."
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "Keine Meldung bereitgestellt"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "Initialisierung"
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "Der untergeordneten Prozess kann nicht ordnungsgemäß ausgeführt werden"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/en_US.utf8.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/en_US.utf8.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/en_US.utf8.po	(revision 942)
@@ -0,0 +1,171 @@
+# English translations for ZOO Kernel package.
+# Copyright (C) 2010 THE ZOO Kernel'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the ZOO Kernel package.
+# root <gerald.fenoy@geolabs.fr>, 2010.
+#
+#: service_internal.c:1672 zoo_service_loader.c:158 zoo_service_loader.c:160
+#: zoo_service_loader.c:220 zoo_service_loader.c:267 zoo_service_loader.c:341
+#: zoo_service_loader.c:1135 zoo_service_loader.c:1277
+#: zoo_service_loader.c:1364
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO Kernel 0.0.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-28 00:38+0200\n"
+"PO-Revision-Date: 2010-09-28 00:39+0200\n"
+"Last-Translator: root <gerald.fenoy@geolabs.fr>\n"
+"Language-Team: English\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: service_internal.c:1056
+#, c-format
+msgid ""
+"ZOO Service \"%s\" is currently running. Please, reload this document to get "
+"the up-to-date status of the Service."
+msgstr ""
+"ZOO Service \"%s\" is currently running. Please, reload this document to get "
+"the up-to-date status of the Service."
+
+#: service_internal.c:1062
+#, c-format
+msgid ""
+"Service \"%s\" was accepted by the ZOO Kernel and it run as a background "
+"task. Please consult the statusLocation attribtue providen in this document "
+"to get the up-to-date document."
+msgstr ""
+"Service \"%s\" was accepted by the ZOO Kernel and it run as a background "
+"task. Please consult the statusLocation attribtue providen in this document "
+"to get the up-to-date document."
+
+#: service_internal.c:1079
+msgid "No more information available"
+msgstr "No more information available"
+
+#: service_internal.c:1432 service_internal.c:1485
+msgid "No debug message available"
+msgstr "No debug message available"
+
+#: service_internal.c:1546
+msgid "Unable to fetch any result"
+msgstr "Unable to fetch any result"
+
+#: service_internal.c:1587
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following : %s"
+msgstr ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following : %s"
+
+#: service_internal.c:1589
+#, c-format
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+
+#: zoo_service_loader.c:119
+#, c-format
+msgid "ZOO Kernel failed to process your request receiving signal %d = %s"
+msgstr "ZOO Kernel failed to process your request receiving signal %d = %s"
+
+#: zoo_service_loader.c:147 zoo_service_loader.c:280 zoo_service_loader.c:367
+#: zoo_service_loader.c:420 zoo_service_loader.c:547 zoo_service_loader.c:623
+#: zoo_service_loader.c:637 zoo_service_loader.c:664 zoo_service_loader.c:705
+#: zoo_service_loader.c:788 zoo_service_loader.c:806 zoo_service_loader.c:864
+#: zoo_service_loader.c:905 zoo_service_loader.c:952 zoo_service_loader.c:987
+#: zoo_service_loader.c:1005 zoo_service_loader.c:1146
+#: zoo_service_loader.c:1218 zoo_service_loader.c:1238
+#: zoo_service_loader.c:1298 zoo_service_loader.c:1324
+msgid "Unable to allocate memory."
+msgstr "Unable to allocate memory."
+
+#: zoo_service_loader.c:181
+msgid "Parameter <request> was not specified"
+msgstr "Parameter <request> was not specified"
+
+#: zoo_service_loader.c:191 zoo_service_loader.c:402
+msgid ""
+"Unenderstood <request> value. Please check that it was set to "
+"GetCapabilities, DescribeProcess or Execute."
+msgstr ""
+"Unenderstood <request> value. Please check that it was set to "
+"GetCapabilities, DescribeProcess or Execute."
+
+#: zoo_service_loader.c:201
+msgid "Parameter <service> was not specified"
+msgstr "Parameter <service> was not specified"
+
+#: zoo_service_loader.c:210
+msgid "Parameter <version> was not specified"
+msgstr "Parameter <version> was not specified"
+
+#: zoo_service_loader.c:257
+msgid "The specified path doesn't exist."
+msgstr "The specified path doesn't exist."
+
+#: zoo_service_loader.c:311
+msgid "Mandatory <identifier> was not specified"
+msgstr "Mandatory <identifier> was not specified"
+
+#: zoo_service_loader.c:322
+msgid "The specified path path doesn't exist."
+msgstr "The specified path path doesn't exist."
+
+#: zoo_service_loader.c:404
+#, c-format
+msgid "No request found %s"
+msgstr "No request found %s"
+
+#: zoo_service_loader.c:441
+#, c-format
+msgid ""
+"The value for <indetifier> seems to be wrong (%s). Please, ensure that the "
+"process exist using the GetCapabilities request."
+msgstr ""
+"The value for <indetifier> seems to be wrong (%s). Please, ensure that the "
+"process exist using the GetCapabilities request."
+
+#: zoo_service_loader.c:519 zoo_service_loader.c:530
+msgid "Unable to allocate memory"
+msgstr "Unable to allocate memory"
+
+#: zoo_service_loader.c:606
+msgid "Parameter <DataInputs> was not specified"
+msgstr "Parameter <DataInputs> was not specified"
+
+#: service_internal.c:1048
+#, c-format
+msgid "Service \"%s\" run successfully."
+msgstr "Service \"%s\" run successfully."
+
+#: zoo_service_loader.c:1366
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but defined as requested "
+"in ZOO ServicesProvider configuration file, please correct your query or the "
+"ZOO Configuration file."
+msgstr ""
+"The <%s> argument was not specified in DataInputs but defined as requested "
+"in ZOO ServicesProvider configuration file, please correct your query or the "
+"ZOO Configuration file."
+
+#: zoo_service_loader.c:1651 zoo_service_loader.c:1871
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO "
+"Kernel.\n"
+msgstr ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO "
+"Kernel.\n"
+
+
+#: zoo_service_loader.c:1700
+msgid "Unable to run the child process properly"
+msgstr "Unable to run the child process properly"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/es.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/es.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/es.po	(revision 942)
@@ -0,0 +1,332 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Carlos Nelson Jimenez <carlos.nelson.jimenez@googlemail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel Internationalization\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: 2017-09-23 14:40+0000\n"
+"Last-Translator: Carlos Nelson Jimenez <carlos.nelson.jimenez@googlemail.com>\n"
+"Language-Team: Spanish (http://www.transifex.com/zoo-project/zoo-kernel-internationalization/language/es/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: es\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "No se puede descargar el archivo."
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "No se puede descargar el archivo."
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "Se superaron las instancias máximas permitidas para <%s> (%i)."
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "ZOO-Kernel no pudo cargar sus datos para %s en la posición %s."
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "La instancia máxima permitida para <%s> es única."
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "No se puede encontrar un protocolo válido para descargar el archivo remoto %s"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "No se puede agregar una solicitud en cola."
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "No se pueden agregar mapas a los mapas."
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "Elementos <Output> duplicados en la solicitud WPS Execute"
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr "El parámetro <%s> tiene un tamaño límite de (%s MB) definido en el archivo de configuración ZOO ServicesProvider, pero la referencia que ha proporcionado excede ese límite (%f MB)."
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr "No se especificó el argumento <%s> en DataInputs, pero se requiere de acuerdo con el archivo de configuración ZOO ServicesProvider."
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined"
+" in the ZOO Configuration File)."
+msgstr "El argumento <%s> especificado como identificador %s  no fue reconocido (no se encuentra definido en el archivo ZOO Configuration)."
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "No se especificó el parámetro obligatorio <%s>"
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "El se reconoció el valor <%s>, %s %s es el único valor aceptable."
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "es/está"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "son/están"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "Se ha ejecutado correctamente el servicio \"%s\"."
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr "El servicio ZOO \"%s\" ya está en ejecución. Vuelva a cargar este documento para obtener el estado actualizado del servicio."
+
+#: response_print.c:1644
+#, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr "ZOO-Kernel aceptó el servicio \"%s\" y se está ejecutando como una tarea de fondo. Acceda a la URL en el atributo statusLocation que se proporciona en este documento para obtener el estado y los resultados actualizados."
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "No hay más información disponible"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "código de error desconocido: %i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "Falló el bloqueo."
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "No se puede crear el archivo \"%s\" para almacenar ExecuteResponse."
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "No hay mensaje de depuración disponible"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "No se puede crear el archivo \"%s\" para almacenar los mapas de sesión."
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr "No se puede ejecutar el servicio. El mensaje devuelto fue el siguiente:"
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr "No se puede ejecutar el servicio. El mensaje devuelto fue el siguiente: %s"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr "No se puede ejecutar el servicio. No hay más información devuelta por el mismo."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "No se puede crear el archivo \"%s\" para guardar el resultado final %s."
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr "Parámetro RawDataOutput incorrecto: no se puede obtener ningún resultado para el nombre del parámetro dado: \"%s\"."
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr "El JobID de la solicitud no coincide con ninguno de los trabajos que se ejecutan en este servidor"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "El resultado para el JobID solicitado aún no se ha generado."
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "No se puede eliminar el trabajo, no se puede eliminar un archivo"
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr "No se puede abrir el directorio de registro."
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "No se puede asignar memoria."
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "No se puede analizar el archivo ZCFG: %s (%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "No se puede analizar el archivo ZCFG: %s."
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "No se puede encontrar ningún mapserverAddress definido en el archivo main.cfg"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "No se puede cargar el archivo PHP %s"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "No se puede cargar el módulo Python %s. Mensaje: %s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following messages : %s"
+msgstr "%s\nNo se puede ejecutar correctamente su proceso python. Compruebe los siguientes mensajes: %s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further information."
+msgstr "%s\nNo se puede ejecutar correctamente su proceso python. No hay más información que se pueda proporcionar."
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOO Kernel ha fallado en procesar su solicitud al recibir la señal %d = %s"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "Se produjo un error al ejecutar la función %s: %s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "No se puede cargar la biblioteca C %s"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO"
+" Kernel.\n"
+msgstr "El lenguaje de programación (%s) establecido en el archivo ZCFG no está soportado por ZOO Kernel.\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "No se puede almacenar en caché la solicitud HTTP POST Execute."
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "No se puede cargar el archivo main.cfg."
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr "%s No se puede encontrar el archivo: %s."
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "El valor %s no es compatible con el parámetro <language>"
+
+#: zoo_service_loader.c:1238
+msgid "The specified path does not exist."
+msgstr "La ruta especificada no existe."
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr "No se puede analizar el archivo ZCFG para el siguiente servicio ZOO: %s. Mensaje: %s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "No se puede analizar el archivo ZCFG para el siguiente servicio ZOO: %s."
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "No se puede ejecutar la solicitud Execute mediante el método GET HTTP"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the"
+" processes in the list returned by a GetCapabilities request."
+msgstr "El valor de <identifier> parece estar equivocado (%s). Por favor, especifique uno de los procesos de la lista devuelta por una solicitud GetCapabilities."
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to"
+" false. Please modify your request parameters."
+msgstr "El parámetro de estado no se puede establecer en true si storeExecuteResponse se establece en false. Por favor, modifique los parámetros de su solicitud."
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "El proceso no permite el modo de ejecución deseado."
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "No se proporcionó ningún mensaje"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "Inicializando"
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "No se puede ejecutar correctamente el proceso secundario"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/es_AR.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/es_AR.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/es_AR.po	(revision 942)
@@ -0,0 +1,332 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Carlos Nelson Jimenez <carlos.nelson.jimenez@googlemail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel Internationalization\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: 2017-09-23 14:40+0000\n"
+"Last-Translator: Carlos Nelson Jimenez <carlos.nelson.jimenez@googlemail.com>\n"
+"Language-Team: Spanish (Argentina) (http://www.transifex.com/zoo-project/zoo-kernel-internationalization/language/es_AR/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: es_AR\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "No se puede asignar memoria"
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "No se puede descargar el archivo."
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "Se superaron las instancias máximas permitidas para <%s> (%i)."
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "ZOO-Kernel no pudo cargar sus datos para %s en la posición %s."
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "La instancia máxima permitida para <%s> es única."
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "No se puede encontrar un protocolo válido para descargar el archivo remoto %s"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "No se puede agregar una solicitud en cola."
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "No se pueden agregar mapas a los mapas."
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "Elementos <Output> duplicados en la solicitud WPS Execute"
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr "El parámetro <%s> tiene un tamaño límite de (%s MB) definido en el archivo de configuración ZOO ServicesProvider, pero la referencia que ha proporcionado excede ese límite (%f MB)."
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr "No se especificó el argumento <%s> en DataInputs, pero se requiere de acuerdo con el archivo de configuración ZOO ServicesProvider."
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined"
+" in the ZOO Configuration File)."
+msgstr "El argumento <%s> especificado como identificador %s  no fue reconocido (no se encuentra definido en el archivo ZOO Configuration)."
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "No se especificó el parámetro obligatorio <%s>"
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "El se reconoció el valor <%s>, %s %s es el único valor aceptable."
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "es/está"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "son/están"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "Se ha ejecutado correctamente el servicio \"%s\"."
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr "El servicio ZOO \"%s\" ya está en ejecución. Vuelva a cargar este documento para obtener el estado actualizado del servicio."
+
+#: response_print.c:1644
+#, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr "ZOO-Kernel aceptó el servicio \"%s\" y se está ejecutando como una tarea de fondo. Acceda a la URL en el atributo statusLocation que se proporciona en este documento para obtener el estado y los resultados actualizados."
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "No hay más información disponible"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "código de error desconocido: %i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "Falló el bloqueo."
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "No se puede crear el archivo \"%s\" para almacenar ExecuteResponse."
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "No hay mensaje de depuración disponible"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "No se puede crear el archivo \"%s\" para almacenar los mapas de sesión."
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr "No se puede ejecutar el servicio. El mensaje devuelto fue el siguiente:"
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr "No se puede ejecutar el servicio. El mensaje devuelto fue el siguiente: %s"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr "No se puede ejecutar el servicio. No hay más información devuelta por el mismo."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "No se puede crear el archivo \"%s\" para guardar el resultado final %s."
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr "Parámetro RawDataOutput incorrecto: no se puede obtener ningún resultado para el nombre del parámetro dado: \"%s\"."
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr "El JobID de la solicitud no coincide con ninguno de los trabajos que se ejecutan en este servidor"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "El resultado para el JobID solicitado aún no se ha generado"
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "No se puede eliminar el trabajo, no se puede eliminar un archivo"
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr "No se puede abrir el directorio de registro."
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "No se puede asignar memoria."
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "No se puede analizar el archivo ZCFG: %s (%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "No se puede analizar el archivo ZCFG: %s."
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "No se puede encontrar ningún mapserverAddress definido en el archivo main.cfg"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "No se puede cargar el archivo PHP %s"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "No se puede cargar el módulo Python %s. Mensaje: %s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following messages : %s"
+msgstr "%s\nNo se puede ejecutar correctamente su proceso python. Compruebe los siguientes mensajes: %s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further information."
+msgstr "%s\nNo se puede ejecutar correctamente su proceso python. No hay más información que se pueda proporcionar."
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOO Kernel ha fallado en procesar su solicitud al recibir la señal %d = %s"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "Se produjo un error al ejecutar la función %s: %s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "No se puede cargar la biblioteca C %s"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO"
+" Kernel.\n"
+msgstr "El lenguaje de programación (%s) establecido en el archivo ZCFG no está soportado por ZOO Kernel.\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "No se puede almacenar en caché la solicitud HTTP POST Execute."
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "No se puede cargar el archivo main.cfg."
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr "%s No se puede encontrar el archivo: %s."
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "El valor %s no es compatible con el parámetro <language>"
+
+#: zoo_service_loader.c:1238
+msgid "The specified path does not exist."
+msgstr "La ruta especificada no existe."
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr "No se puede analizar el archivo ZCFG para el siguiente servicio ZOO: %s. Mensaje: %s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "No se puede analizar el archivo ZCFG para el siguiente servicio ZOO: %s."
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "No se puede ejecutar la solicitud Execute mediante el método GET HTTP"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the"
+" processes in the list returned by a GetCapabilities request."
+msgstr "El valor de <identifier> parece estar equivocado (%s). Por favor, especifique uno de los procesos de la lista devuelta por una solicitud GetCapabilities."
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to"
+" false. Please modify your request parameters."
+msgstr "El parámetro de estado no se puede establecer en true si storeExecuteResponse se establece en false. Por favor, modifique los parámetros de su solicitud."
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "El proceso no permite el modo de ejecución deseado."
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "No se proporcionó ningún mensaje"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "Inicializando"
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "No se puede ejecutar correctamente el proceso secundario"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/fr_FR.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/fr_FR.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/fr_FR.po	(revision 942)
@@ -0,0 +1,333 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Gérald FENOY <gerald.fenoy@geolabs.fr>, 2015-2016
+# Nicolas Bozon <nicolas.bozon@gmail.com>, 2015
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel Internationalization\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: 2017-09-22 11:15+0000\n"
+"Last-Translator: Gérald FENOY <gerald.fenoy@geolabs.fr>\n"
+"Language-Team: French (France) (http://www.transifex.com/zoo-project/zoo-kernel-internationalization/language/fr_FR/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: fr_FR\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "Impossible d'allouer la mémoire"
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "Impossible de télécharger le fichier."
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "Le maximum d'occurrences autorisées pour <%s> (%i) a été atteint"
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "ZOO-Kernel n'a pas pu charger vos données pour %s position %s."
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "Le nombre maximum d'occurence pour <%s> est un."
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "Impossible de trouver un protocole valable pour télécharger le fichier %s"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "Impossible d'ajouter la requête dans la file d'attente."
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "Impossible d'ajouter la maps à la maps."
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "Eléments <Output> dupliqués dans la requête WPS Execute"
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr "Le paramètre <%s> possède une limite de taille (%s MB) définie dans le fichier de configuration du ServicesProvider ZOO, mais la référence fournie excède cette limite (%f MB)."
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr "L'argument <%s> n'a pas été spécifié en entrée, ce qui est requis selon le fichier de configuration du ServicesProvider ZOO."
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined"
+" in the ZOO Configuration File)."
+msgstr "L'argument <%s> spécifié pour l'identifiant %s n'a pas été reconnu (non défini dans le fichier de configuration du ZOO)."
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "Le paramètre obligatoire <%s> n'as pas été spécifié"
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "La valeur <%s> n'a pas été reconnue, %s %s est la seule valeur acceptée. "
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "est"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "sont"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "Le service \"%s\" s'est exécuté avec succès."
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr "Le ZOO-Service \"%s\" est actuellement en cours d'exécution. Merci de recharger ce document afin d'obtenir le status mis à jour du service."
+
+#: response_print.c:1644
+#, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr "Le service \"%s\" a été accepté par le ZOO-Kernel et est en cours d'exécution en tâche de fond. Merci d'utiliser le lien URL fournis dans l'attribut statusLocation de la racine de ce document pour obtenir des informations sur l'état d'éxcution du service."
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "Pas plus d'infomation disponible"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "Code d'erreur inconnu : %i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "Impossible de vérouiller."
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "Impossible de créer le fichier \"%s\" pour stocker le fichier ExecuteResponse."
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "Pas de message de débugage disponible"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "Impossible de créer le fichier \"%s\" pour stocker la maps de session."
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr "Impossible d'exécuter le service. Le message retourné par le service est : "
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr "Impossible d'exécuter le service. Le message retourné par le service est : %s"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr "Impossible d'exécuter le service. Aucune information n'a été retournée par le service."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "Impossible de créer le fichier \"%s\" pour stocker le résultat final : %s."
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr "Paramètre RawDataOutput erroné: Impossible de récupérer un résultat pour le nom de paramètre fourni: \"%s\"."
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr "Le paramètre JobID de la requête ne correspond à aucun process en cours sur le serveur"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "Le résultat pour le JobID demandé n'as pas encore été généré."
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "Le processus ne peut pas être supprimé, un fichier ne peut être supprimé."
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr "Impossible d'accéder au répertoire du registre."
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "Impossible d'allouer la mémoire."
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "Impossible d'analyser le fichier ZCFG: %s (%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "Impossible d'analyser le fichier ZCFG: %s."
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "Aucun paramètre mapserverAddress trouvé dans le fichier main.cfg"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "Impossible de charger le fichier PHP %s"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "Le module python %s ne peut être chargé. Message: %s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following messages : %s"
+msgstr "%s\nImpossible de charger votre service python correctement. Veuillez vous réferer aux messages suivants : %s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further information."
+msgstr "%s\nImpossible d'exécuter votre servce Python correctement. Impossible de fournir plus d'informations."
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOO-Kernel n'as pas pu traiter votre requête, recevant un signal %d = %s"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "Une erreur s'est produite lors de l'exécution de la fonction %s : %s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "Impossible de charger la librairie C %s"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO"
+" Kernel.\n"
+msgstr "Le langage de programmation (%s) spécifié dans le fichier ZCFG n'est actuellement pas supporté par ZOO-Kernel.\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "Impossible de mettre la requête Execute HTTP POST en cache."
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "Impossible de charger le fichier main.cfg."
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr "%s Le fichier : %s ne peut pas être trouvé."
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "La valeur %s n'est pas supportée pour le paramètre <language>"
+
+#: zoo_service_loader.c:1238
+msgid "The specified path does not exist."
+msgstr "Le chemin spécifié n'existe pas."
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr "Impossible de lire correctement le fichier ZCFG pour le ZOO-Service : %s. Message : %s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "Impossible de lire correctement le fichier ZCFG pour le ZOO-Service : %s."
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "Impossible de lancer la requête Execute en utilisant la méthode GET"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the"
+" processes in the list returned by a GetCapabilities request."
+msgstr "La valeur d' <identifier> à l'air erronée (%s). Spécifiez s'il vous plait un des services retournés par la requête GetCapabilities."
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to"
+" false. Please modify your request parameters."
+msgstr "Le paramètre de status ne peut être définit à vrai si storeExecuteResponse est défini à faux. Veuillez s'il vous plaît modifier les paramètres de la requête."
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "Le service ne supporte pas ce mode d'exécution."
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "Pas de message fourni"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "Initialisation"
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "Impossible de lancer le processus fils"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/fr_FR.utf8.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/fr_FR.utf8.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/fr_FR.utf8.po	(revision 942)
@@ -0,0 +1,174 @@
+# French translations for ZOO Kernel package.
+# Copyright (C) 2010 THE ZOO Kernel'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the ZOO Kernel package.
+# root <gerald.fenoy@geolabs.fr>, 2010.
+#
+#: service_internal.c:1672 zoo_service_loader.c:158 zoo_service_loader.c:160
+#: zoo_service_loader.c:220 zoo_service_loader.c:267 zoo_service_loader.c:341
+#: zoo_service_loader.c:1135 zoo_service_loader.c:1277
+#: zoo_service_loader.c:1364
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO Kernel 0.0.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-28 00:38+0200\n"
+"PO-Revision-Date: 2010-09-28 00:39+0200\n"
+"Last-Translator: root <gerald.fenoy@geolabs.fr>\n"
+"Language-Team: French\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: service_internal.c:34
+msgid "0123456789abcdef"
+msgstr ""
+
+#: service_internal.c:1056
+#, c-format
+msgid ""
+"ZOO Service \"%s\" is currently running. Please, reload this document to get "
+"the up-to-date status of the Service."
+msgstr ""
+"Le Service ZOO \"%s\" est en cous d'exécution. Merci de recharger document pour"
+" obtenir une version à jour du status du Service."
+
+#: service_internal.c:1062
+#, c-format
+msgid ""
+"Service \"%s\" was accepted by the ZOO Kernel and it run as a background "
+"task. Please consult the statusLocation attribtue providen in this document "
+"to get the up-to-date document."
+msgstr ""
+"Le Service \"%s\" a été accepté par le Noyau ZOO et tourne en tâche de fond. "
+"Merci de consulter le lien fourni dans ce document afin d'obtenir le status actuel du "
+"Service."
+
+#: service_internal.c:1079
+msgid "No more information available"
+msgstr "Pas plus d'information disponible"
+
+#: service_internal.c:1432 service_internal.c:1485
+msgid "No debug message available"
+msgstr "Pas de message de débuguage disponible"
+
+#: service_internal.c:1546
+msgid "Unable to fetch any result"
+msgstr "Impossible de récupérer un résultat"
+
+#: service_internal.c:1587
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following : %s"
+msgstr ""
+"Impossible d'exécuter le Service. Le message retourné par le Service est le suivant : %s"
+
+#: service_internal.c:1589
+#, c-format
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr ""
+"Impossible d'exécuter le Service. Pas plus d'information disponible."
+
+#: zoo_service_loader.c:119
+#, c-format
+msgid "ZOO Kernel failed to process your request receiving signal %d = %s"
+msgstr ""
+"Le Noyau ZOO a rencontré un problème lors de l'exécution de votre resquête et a "
+"reçu le signal %d : %s "
+
+#: zoo_service_loader.c:147 zoo_service_loader.c:280 zoo_service_loader.c:367
+#: zoo_service_loader.c:420 zoo_service_loader.c:547 zoo_service_loader.c:623
+#: zoo_service_loader.c:637 zoo_service_loader.c:664 zoo_service_loader.c:705
+#: zoo_service_loader.c:788 zoo_service_loader.c:806 zoo_service_loader.c:864
+#: zoo_service_loader.c:905 zoo_service_loader.c:952 zoo_service_loader.c:987
+#: zoo_service_loader.c:1005 zoo_service_loader.c:1146
+#: zoo_service_loader.c:1218 zoo_service_loader.c:1238
+#: zoo_service_loader.c:1298 zoo_service_loader.c:1324
+msgid "Unable to allocate memory."
+msgstr "Impossible d'allouer de la mémoire."
+
+#: zoo_service_loader.c:181
+msgid "Parameter <request> was not specified"
+msgstr "Le paramètre <request> n'a pas été spécifié"
+
+#: zoo_service_loader.c:191 zoo_service_loader.c:402
+msgid ""
+"Unenderstood <request> value. Please check that it was set to "
+"GetCapabilities, DescribeProcess or Execute."
+msgstr ""
+"La valeur de <request> est incompréhensible. Merci d'utiliser l'une des valeurs "
+"suivantes : GetCapabilities, DescribeProcess ou Execute."
+
+#: zoo_service_loader.c:201
+msgid "Parameter <service> was not specified"
+msgstr "La paramètre <service> n'a pas été spécifié"
+
+#: zoo_service_loader.c:210
+msgid "Parameter <version> was not specified"
+msgstr "Le paramètre <version> n'a pas été spécifié"
+
+#: zoo_service_loader.c:257
+msgid "The specified path doesn't exist."
+msgstr "Le chemin spécifié n'existe pas"
+
+#: zoo_service_loader.c:311
+msgid "Mandatory <identifier> was not specified"
+msgstr "Le paramètre obligatoire <identifier> n'a pas été précisé"
+
+#: zoo_service_loader.c:322
+msgid "The specified path path doesn't exist."
+msgstr "Le chemin fourni n'existe pas."
+
+#: zoo_service_loader.c:404
+#, c-format
+msgid "No request found %s"
+msgstr "Aucune requête trouvée %s"
+
+#: zoo_service_loader.c:441
+#, c-format
+msgid ""
+"The value for <indetifier> seems to be wrong (%s). Please, ensure that the "
+"process exist using the GetCapabilities request."
+msgstr ""
+"La valeur pour le paramètre <identifier> semble éronné (%s). Merci de vous assurer que"
+" le service existe en utilisant une requête GetCapabilities."
+
+#: zoo_service_loader.c:519 zoo_service_loader.c:530
+msgid "Unable to allocate memory"
+msgstr "Impossible d'allouer de la mémoire"
+
+#: zoo_service_loader.c:606
+msgid "Parameter <DataInputs> was not specified"
+msgstr "Paramètre <DataInputs> n'a pas été précisé"
+
+#: service_internal.c:1048
+#, c-format
+msgid "Service \"%s\" run successfully."
+msgstr "Le Service \"%s\" a été exécuté avec succès."
+
+#: zoo_service_loader.c:1366
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but defined as requested "
+"in ZOO ServicesProvider configuration file, please correct your query or the "
+"ZOO Configuration file."
+msgstr ""
+"L'argument <%s> n'a pas été précisé dans les données en entrée (DataInputs) mais "
+"est défini comme obligatoire dans le fichier de méta-données du Service ZOO (zcfg). "
+"Merci de corriger votre requête ou le fichier de méta-données."
+
+#: zoo_service_loader.c:1651 zoo_service_loader.c:1871
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO "
+"Kernel.\n"
+msgstr ""
+"Le langage de programmation (%s) utilisé dans le fichier ZCFG n'est actuellement pas "
+"supporté par votre installation du noyau ZOO.\n"
+
+#: zoo_service_loader.c:1700
+msgid "Unable to run the child process properly"
+msgstr "Impossible d'exécuter le processus en tâche de fond"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/it_IT.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/it_IT.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/it_IT.po	(revision 942)
@@ -0,0 +1,332 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Luca Delucchi <lucadeluge@gmail.com>, 2015,2017
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel Internationalization\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: 2017-09-22 11:15+0000\n"
+"Last-Translator: Luca Delucchi <lucadeluge@gmail.com>\n"
+"Language-Team: Italian (Italy) (http://www.transifex.com/zoo-project/zoo-kernel-internationalization/language/it_IT/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: it_IT\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "Impossibile assegnare la memoria"
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "Impossibile scaricare il file."
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "Le occorrenze massime consentite per <%s> (%i) sono state superate"
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "ZOO-Kernel non è stato in grado di caricare i dati per %s posizione %s."
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "Le occorrenze massime consentite per <%s> è uno"
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "Impossibile trovare un protocollo valido per scaricare il file remoto %s"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "Impossibile aggiungere una richiesta nella coda"
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "Impossibile aggiungere mappe alle mappe"
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "Elementi <Output> duplicati nella richiesta WPS Execute"
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr "Il parametro <%s> ha un limite (%s MB) definito nel file di configurazione del ServicesProvider di ZOO, ma la fonte che è stato fornito eccede questo limite (%f MB)"
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr "L'argomento <%s> non è stato specificato nel DataInputs ma è richiesto secondo il file di configurazione del ServicesProvider di ZOO."
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined"
+" in the ZOO Configuration File)."
+msgstr "L'argomento <%s> specificato come l'identificatore %s non è stato riconosciuto (non definito nel File di Configurazione di ZOO)"
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "Il parametro obbligatorio <%s> non è stato specificato"
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "Il valore <%s> non è stato riconosciuto, %s %s è l'unico valore ammissibile"
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "è"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "sono"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "Il servizio \"%s\" è stato eseguito correttamente."
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr "Il servizio di ZOO \"%s\" è in esecuzione. Ricaricare questo documento per ottenere lo stato aggiornato del servizio"
+
+#: response_print.c:1644
+#, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr "Il servizio \"%s\" è stato accettato dal ZOO Kernel e sta andando avanti come processo di background. Accedere al URL nell'attributo statusLocation fornito in questo documento per ottenere lo stato aggiornato e risultati."
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "Nessuna ulteriore informazione disponibile"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "Codice dell'errore non conosciuto : %i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "Blocco non riuscito."
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "Impossibile creare il file \"%s\" per immagazzinare la ExecuteResponse."
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "Nessun messaggio di debug disponibile"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "Impossibile creare il file \"%s\" per immagazzinare la mappe della sessione."
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr "Impossibile eseguire il Servizio. Il messaggio restituito dal Servizio è il seguente:"
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr "Impossibile eseguire il Servizio. Il messaggio restituito dal Servizio è il seguente: %s"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr "Impossibile eseguire il Servizio. Nessun ulteriore informazione è stata restituita dal Servizio."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "Impossibile creare il file \"%s\" per immagazzinare il risultato finale %s."
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr "Parametro RawDataOutput errato: impossibile riportare qualsiasi risultato per il parametro name fornito: \"%s\"."
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr "Il JobID dalla richiesta non corrisponde con nessuno di processi eseguiti su questo server"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "Il risultato per il JobID richiesto non è stato ancora generato."
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "Il processo non può essere rimosso, un file non può essere rimosso"
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr "Impossibile aprire la directory del registro"
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "Impossibile assegnare la memoria."
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "Impossibile analizzare il file ZCFG: %s (%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "Impossibile analizzare il file ZCFG: %s."
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "Impossibile trovare nessun mapserverAddress definito nel file main.cfg"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "Impossibile caricare il file PHP %s"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "Il modulo Python %s non può essere caricato. Message: %s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following messages : %s"
+msgstr "%s\nImpossibile eseguire il processo di Python correttamente. Controllare il seguente messaggio: %s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further information."
+msgstr "%s\nImpossibile eseguire il processo python correttamente. Impossible fornire nessun'altra informazione"
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOO Kernel è fallito processando la richiesta, ricevendo il segnale %d = %s"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "Errore accaduto durante l'esecuzione della funzione %s: %s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "Impossibile caricare la Libreria C %s"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO"
+" Kernel.\n"
+msgstr "Il linguaggio di programmazione (%s) impostato nel file ZCFG non è attualmente supportato dal ZOO Kernel.\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "Impossibile salvare nella cache la richieste HTTP POST Execute."
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "Impossibile caricare il file main.cfg"
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr "%s il senguente file: %s non può essere trovato"
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "Il valore %s non è supportato per il parametro <language>"
+
+#: zoo_service_loader.c:1238
+msgid "The specified path does not exist."
+msgstr "Il percorso specificato non esiste"
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr "Imposibile analizzare  il file ZCFG per il seguente Servizio di ZOO: %s. Messaggio: %s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "Imposibile analizzare  il file ZCFG per il seguente Servizio di ZOO: %s."
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "Impossibile eseguire la richiesta Execute usando il metodo GET HTTP"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the"
+" processes in the list returned by a GetCapabilities request."
+msgstr "Il valore per <identifier> sembra essere sbagliato (%s). Specificare uno dei processi nella lista ottenuta dalla richiesta GetCapabilities"
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to"
+" false. Please modify your request parameters."
+msgstr "Il parametro status non può essere settato a true se storeExecuteResponse è impostato su false. Modificare i parametri della richiesta."
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "Il processo non permette il metodo di esecuzione desiderato"
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "Nessun messaggio fornito"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "Inizializzando"
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "Impossibile eseguire il processo figlio correttamente"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/ja_JP.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/ja_JP.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/ja_JP.po	(revision 942)
@@ -0,0 +1,334 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Nicolas Bozon <nicolas.bozon@gmail.com>, 2015
+# 林博文 <pica.hayashi@gmail.com>, 2015
+# 林博文 <pica.hayashi@gmail.com>, 2016
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel Internationalization\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: 2017-09-22 11:15+0000\n"
+"Last-Translator: Gérald FENOY <gerald.fenoy@geolabs.fr>\n"
+"Language-Team: Japanese (Japan) (http://www.transifex.com/zoo-project/zoo-kernel-internationalization/language/ja_JP/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: ja_JP\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "メモリを割り当てられません."
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "ファイルをダウンロードできません。"
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "<%s> (%i) の発生最大数を超えました。"
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "ZOO-Kernel は %s の %sの位置のデータをロードできませんでした。"
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "<%s> の最大発生数は 1 です。"
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "リモートファイル %s をダウントードするための適切なプロトコルが見つかりません。"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "キューにリクエストを追加できません。"
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "マップにマップを追加できません。"
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "WPS実行リクエストの <Output> 重複 "
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr "<%s> 変数の上限サイズはZOOサービスプロバイダ設定ファイルで (%s MB) に定義されています。与えられた参照はこの上限を超えています (%f MB) 。"
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr "ZOOサービスプロバイダ設定ファイルに対して必要とされる <%s> 引数が Datainputs に記述されていませんでした。"
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined"
+" in the ZOO Configuration File)."
+msgstr "記述された <%s> は識別子 %s としては受け入れられません(ZOO設定ファイルに定義されていません)。"
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "必須変数 <%s> が記述されていません。"
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "値 <%s> は受け入れられません。%s %s のみが受け入れ可能な値です。"
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "あります"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "あります"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "%s サービスが動作しました."
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr "現在，ZOOサービス \"%s\" が動作しています. このサービスのステータスを最新のものにするためにこのドキュメントを再読込してください."
+
+#: response_print.c:1644
+#, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr "サービス %s はZOO-Kernelに受け入れられ、バックグラウンドタスクとして実行中です。最新の状態および結果を得るためにはこのドキュメントで提供されるstatusLocationの属性のURLにアクセスしてください。"
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "情報はありません．"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "エラーコードが見つかりません : %i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "ロックに失敗しました。"
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "実行レスポンスとして格納される \"%s\" ファイルのが生成できませんでした。"
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "デバッグメッセージはありません．"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "セッションマップとして格納される \"%s\" ファイルのが生成できませんでした。"
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr "サービスを実行できません。サービスから返されたメッセージは次の通り :"
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr "サービスを開始することができませんでした．このサービスによって返されたメッセージは  %s　です。"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr "サービスを開始できませんでした．このサービスによって返された情報はありません ."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "最終結果 %s として格納される \"%s\" ファイルのが生成できませんでした。"
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr "誤った RawDataOutput 変数  : 与えられた引数名のどの結果からも取り出せません: \"%s\""
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr "リクエストされた JobID はサーバで実行中のどのJobとも一致しません。"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "リクエストされた JobID の結果はまだ生成されていませんでした。"
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "ジョブが削除されません、ファイルが削除されません。"
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr "レジストリディレクトリをオープンできません。"
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "メモリを割り当てられません."
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "ZCFG ファイルをパースできません : %s (%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "ZCFG ファイルをパースできません : %s 。"
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "main.cfg ファイルに定義されたどの mapserverAddress も見つかりません。"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "PHPファイル %s をロードできません"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "Python モジュール %s がロードされません。メッセージ : %s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following messages : %s"
+msgstr "%s\nユーザーPythonプロセスを正しく実行できません。次のメッセージをチェックしてください : %s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further information."
+msgstr "%s\nユーザーPythonプロセスを正しく実行できません。より詳しい情報は提供されていません。"
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOOカーネルはリクエストを処理することができませんでした．受け取ったシグナルは %d : %s です．"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "%s ファンクションを実行中にエラーが発生しました : %s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "C Library %s をロードできません"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO"
+" Kernel.\n"
+msgstr "ZCFG ファイルで設定されたプログラミング言語 (%s) は現在 ZOOカーネルでサポートされていません。\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "HTTP POST 実行リクエストをキャッシュできません。"
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "main.cfg ファイルをロードできません。"
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr ""
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "値 %s は <language>変数としてサポートされていません"
+
+#: zoo_service_loader.c:1238
+msgid "The specified path does not exist."
+msgstr "記述されたパスが存在しません。"
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr "次のZOO-Service :%s のZCFG ファイルをパースできません。メッセージ: %s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "次のZOO-Service :%s のZCFG ファイルをパースできません。"
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "GET HTTP メソッドを使用した実行リクエストを実行できません"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the"
+" processes in the list returned by a GetCapabilities request."
+msgstr "<identifier> についての値が不正です(%s). GetCapabilitiesによりそのプロセスが存在しているか確認してください."
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to"
+" false. Please modify your request parameters."
+msgstr "storeExecuteResponse が false に設定されている場合 status 変数を true に設定できません。リクエスト変数を変更してください。"
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "プロセスは要求された実行モードは許可されません。"
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "メッセージは提供されません"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "初期化中"
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "子プロセスを開始することができません．"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/ja_JP.utf8.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/ja_JP.utf8.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/ja_JP.utf8.po	(revision 942)
@@ -0,0 +1,174 @@
+# Japanese translations for ZOO Kernel package.
+# Copyright (C) 2010 THE ZOO Kernel'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the ZOO Kernel package.
+# Daisuke YOSHIDA <yoshida@la.tezuka-gu.ac.jp>, 2010.
+#
+#: service_internal.c:1672 zoo_service_loader.c:158 zoo_service_loader.c:160
+#: zoo_service_loader.c:220 zoo_service_loader.c:267 zoo_service_loader.c:341
+#: zoo_service_loader.c:1135 zoo_service_loader.c:1277
+#: zoo_service_loader.c:1364
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO Kernel 0.0.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-28 00:38+0200\n"
+"PO-Revision-Date: 2010-09-28 00:39+0200\n"
+"Last-Translator: Daisuke YOSHIDA <yoshida@la.tezuka-gu.ac.jp>\n"
+"Language-Team: Japanese\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: service_internal.c:34
+msgid "0123456789abcdef"
+msgstr ""
+
+#: service_internal.c:1056
+#, c-format
+msgid ""
+"ZOO Service \"%s\" is currently running. Please, reload this document to get "
+"the up-to-date status of the Service."
+msgstr ""
+"現在，ZOOサービス \"%s\" が動作しています. このサービスのステータスを最新のものにするために，"
+"このドキュメントを再読込してください."
+
+#: service_internal.c:1062
+#, c-format
+msgid ""
+"Service \"%s\" was accepted by the ZOO Kernel and it run as a background "
+"task. Please consult the statusLocation attribtue providen in this document "
+"to get the up-to-date document."
+msgstr ""
+"ZOOカーネルが \"%s\" サービスをアクセプトし，バックグラウンドタスクとして動作しています．"
+"ドキュメントを最新の状態に保つために，ドキュメントで提供されている"
+"statusLocation属性を確認してください．"
+
+#: service_internal.c:1079
+msgid "No more information available"
+msgstr "情報はありません．"
+
+#: service_internal.c:1432 service_internal.c:1485
+msgid "No debug message available"
+msgstr "デバッグメッセージはありません．"
+
+#: service_internal.c:1546
+msgid "Unable to fetch any result"
+msgstr "結果が取得できませんでした．"
+
+#: service_internal.c:1587
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following : %s"
+msgstr ""
+"サービスを開始することができませんでした．このサービスによって返されたメッセージは  %s　です。"
+
+#: service_internal.c:1589
+#, c-format
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr ""
+"サービスを開始できませんでした．このサービスによって返された情報はありません ."
+
+#: zoo_service_loader.c:119
+#, c-format
+msgid "ZOO Kernel failed to process your request receiving signal %d = %s"
+msgstr ""
+"ZOOカーネルはリクエストを処理することができませんでした．受け取ったシグナルは"
+"%d : %s です．"
+
+#: zoo_service_loader.c:147 zoo_service_loader.c:280 zoo_service_loader.c:367
+#: zoo_service_loader.c:420 zoo_service_loader.c:547 zoo_service_loader.c:623
+#: zoo_service_loader.c:637 zoo_service_loader.c:664 zoo_service_loader.c:705
+#: zoo_service_loader.c:788 zoo_service_loader.c:806 zoo_service_loader.c:864
+#: zoo_service_loader.c:905 zoo_service_loader.c:952 zoo_service_loader.c:987
+#: zoo_service_loader.c:1005 zoo_service_loader.c:1146
+#: zoo_service_loader.c:1218 zoo_service_loader.c:1238
+#: zoo_service_loader.c:1298 zoo_service_loader.c:1324
+msgid "Unable to allocate memory."
+msgstr "Impossible d'allouer de la mémoire."
+
+#: zoo_service_loader.c:181
+msgid "Parameter <request> was not specified"
+msgstr "パラメーターが指定されていません．"
+
+#: zoo_service_loader.c:191 zoo_service_loader.c:402
+msgid ""
+"Unenderstood <request> value. Please check that it was set to "
+"GetCapabilities, DescribeProcess or Execute."
+msgstr ""
+"<request>値を認識しました. 値が下記のリクエストを指定されているか確認してください．"
+"GetCapabilities, DescribeProcess, Execute."
+
+#: zoo_service_loader.c:201
+msgid "Parameter <service> was not specified"
+msgstr "<service> パラメーターが指定されていません．"
+
+#: zoo_service_loader.c:210
+msgid "Parameter <version> was not specified"
+msgstr "<version>パラメーターが指定されていません．"
+
+#: zoo_service_loader.c:257
+msgid "The specified path doesn't exist."
+msgstr "指定されたパスが存在しません．"
+
+#: zoo_service_loader.c:311
+msgid "Mandatory <identifier> was not specified"
+msgstr "<identifier>値（要指定）が指定されていません．"
+
+#: zoo_service_loader.c:322
+msgid "The specified path path doesn't exist."
+msgstr "指定されたパスが存在しません．"
+
+#: zoo_service_loader.c:404
+#, c-format
+msgid "No request found %s"
+msgstr "%sのリクエストが見つかりません．"
+
+#: zoo_service_loader.c:441
+#, c-format
+msgid ""
+"The value for <indetifier> seems to be wrong (%s). Please, ensure that the "
+"process exist using the GetCapabilities request."
+msgstr ""
+"<identifier>についての値が不正です(%s). GetCapabilitiesにより"
+"そのプロセスが存在しているか確認してください."
+
+#: zoo_service_loader.c:519 zoo_service_loader.c:530
+msgid "Unable to allocate memory"
+msgstr "メモリを割り当てられません．"
+
+#: zoo_service_loader.c:606
+msgid "Parameter <DataInputs> was not specified"
+msgstr "<DataInputs> パラメーターが指定されていません．"
+
+#: service_internal.c:1048
+#, c-format
+msgid "Service \"%s\" run successfully."
+msgstr " \"%s\"サービスが動作しました."
+
+#: zoo_service_loader.c:1366
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but defined as requested "
+"in ZOO ServicesProvider configuration file, please correct your query or the "
+"ZOO Configuration file."
+msgstr ""
+"DataInputsの中の引数 <%s>が指定されていませんでしたが，"
+"ZOO ServicesProviderの設定ファイル(zcfg)の中で定義されています．"
+"クエリー，もしくはZOO設定ファイルを修正してください．"
+
+#: zoo_service_loader.c:1651 zoo_service_loader.c:1871
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO "
+"Kernel.\n"
+msgstr ""
+"ZCFGファイルの中で設定されているプログラム言語 (%s) は "
+"現在のZOOカーネルではサポートしていません.\n"
+
+#: zoo_service_loader.c:1700
+msgid "Unable to run the child process properly"
+msgstr "子プロセスを開始することができません．"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/messages.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/messages.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/messages.po	(revision 942)
@@ -0,0 +1,368 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# Gerald Fenoy <gerald.fenoy@geolabs.fr>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel 1.5.0\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "Unable to allocate memory"
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "Unable to download the file."
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "The maximum allowed occurrences for <%s> (%i) was exceeded."
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "ZOO-Kernel was unable to load your data for %s position %s."
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "The maximum allowed occurrences for <%s> is one."
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "Unable to find a valid protocol to download the remote file %s"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "Unable to add a request in the queue."
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "Unable to append maps to maps."
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "Duplicate <Output> elements in WPS Execute request"
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined "
+"in the ZOO Configuration File)."
+msgstr ""
+"The <%s> argument specified as %s identifier was not recognized (not defined "
+"in the ZOO Configuration File)."
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "Mandatory parameter <%s> was not specified"
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "The value <%s> was not recognized, %s %s the only acceptable value."
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "is"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "are"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "The service \"%s\" ran successfully."
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+
+#: response_print.c:1644
+#, fuzzy, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr ""
+"The service \"%s\" was accepted by the ZOO kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "No more information available"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "error code not know : %i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "Lock failed."
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "Unable to create the file \"%s\" for storing the ExecuteResponse."
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "No debug message available"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "Unable to create the file \"%s\" for storing the session maps."
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "Unable to create the file \"%s\" for storing the %s final result."
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "The result for the requested JobID has not yet been generated. "
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "The job cannot be removed, a file cannot be removed"
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr ""
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "Unable to allocate memory."
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "Unable to parse the ZCFG file: %s (%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "Unable to parse the ZCFG file: %s."
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "Unable to find any mapserverAddress defined in the main.cfg file"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "Unable to load the PHP file %s"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "Python module %s cannot be loaded. Message: %s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following "
+"messages : %s"
+msgstr ""
+"%s\n"
+"Unable to run your python process properly. Please check the following "
+"messages : %s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further "
+"information."
+msgstr ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further "
+"information."
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOO Kernel failed to process your request, receiving signal %d = %s"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "Error occurred while running the %s function: %s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "Unable to load C Library %s"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO "
+"Kernel.\n"
+msgstr ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO "
+"Kernel.\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "Unable to cache HTTP POST Execute request."
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "Unable to load the main.cfg file."
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr "%s The following file: %s cannot be found."
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "The value %s is not supported for the <language> parameter"
+
+#: zoo_service_loader.c:1238
+#, fuzzy
+msgid "The specified path does not exist."
+msgstr "The specified path path does not exist."
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "Unable to run Execute request using the GET HTTP method"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the "
+"processes in the list returned by a GetCapabilities request."
+msgstr ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the "
+"processes in the list returned by a GetCapabilities request."
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to "
+"false. Please modify your request parameters."
+msgstr ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to "
+"false. Please modify your request parameters."
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "The process does not permit the desired execution mode."
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "No message provided"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "Initializing"
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "Unable to run the child process properly"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/zh_CN.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/zh_CN.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/locale/po/zh_CN.po	(revision 942)
@@ -0,0 +1,333 @@
+# ZOO-Kernel Internationalization.
+# Copyright (C) 2015 GeoLabs SARL
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# 许秋熹 <xqx930807@gmail.com>, 2017
+# 许秋熹 <xqx930807@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: ZOO-Kernel Internationalization\n"
+"Report-Msgid-Bugs-To: zoo-discuss@lists.osgeo.org\n"
+"POT-Creation-Date: 2015-07-02 18:06+0200\n"
+"PO-Revision-Date: 2017-09-23 15:01+0000\n"
+"Last-Translator: 许秋熹 <xqx930807@gmail.com>\n"
+"Language-Team: Chinese (China) (http://www.transifex.com/zoo-project/zoo-kernel-internationalization/language/zh_CN/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: zh_CN\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: caching.c:217 caching.c:235 caching.c:356 request_parser.c:214
+#: request_parser.c:225 request_parser.c:262 request_parser.c:403
+#: request_parser.c:414 request_parser.c:441 request_parser.c:537
+#: request_parser.c:562 request_parser.c:665 request_parser.c:782
+#: request_parser.c:1112 request_parser.c:1204 zcfg2yaml.c:38
+#: zoo_service_loader.c:259 zoo_service_loader.c:880 zoo_service_loader.c:1363
+#: zoo_service_loader.c:1559
+msgid "Unable to allocate memory"
+msgstr "无法分配内存"
+
+#: caching.c:344
+msgid "Unable to download the file."
+msgstr "无法下载文件."
+
+#: request_parser.c:92
+#, c-format
+msgid "The maximum allowed occurrences for <%s> (%i) was exceeded."
+msgstr "<%s>所允许的最大事件(%i)溢出了"
+
+#: request_parser.c:113
+#, c-format
+msgid "ZOO-Kernel was unable to load your data for %s position %s."
+msgstr "ZOO核心无法从%s的位置上为%s载入您的数据。"
+
+#: request_parser.c:124
+#, c-format
+msgid "The maximum allowed occurrences for <%s> is one."
+msgstr "<%s>所允许的最大事件只有一个."
+
+#: request_parser.c:315
+#, c-format
+msgid "Unable to find a valid protocol to download the remote file %s"
+msgstr "无法找到有效的协议用于下载远程文件%s"
+
+#: request_parser.c:613
+msgid "Unable to add a request in the queue."
+msgstr "无法在队列中加入请求。"
+
+#: request_parser.c:1021
+msgid "Unable to append maps to maps."
+msgstr "无法将追加键值."
+
+#: request_parser.c:1291
+msgid "Duplicate <Output> elements in WPS Execute request"
+msgstr "元素<Output>的副本在WPS Execute请求中"
+
+#: request_parser.c:1487
+#, c-format
+msgid ""
+"The <%s> parameter has a size limit (%s MB) defined in the ZOO "
+"ServicesProvider configuration file, but the reference you provided exceeds "
+"this limit (%f MB)."
+msgstr "参数<%s>在 ZOO服务提供者的配置文件中定义了大小限制%s(MB)，您提供的参考超过了该限制(%fMB)."
+
+#: request_parser.c:1519
+#, c-format
+msgid ""
+"The <%s> argument was not specified in DataInputs but is required according "
+"to the ZOO ServicesProvider configuration file."
+msgstr "参数<%s>在输入数据中未定义，但是根据ZOO服务提供者配置文件中要求提供。"
+
+#: request_parser.c:1545
+#, c-format
+msgid ""
+"The <%s> argument specified as %s identifier was not recognized (not defined"
+" in the ZOO Configuration File)."
+msgstr "被定义为标识符%s的参数<%s>未被识别(在ZOO服务提供者配置文件中未定义)。"
+
+#: request_parser.c:1663
+#, c-format
+msgid "Mandatory parameter <%s> was not specified"
+msgstr "强制参数<%s>未定义"
+
+#: request_parser.c:1712
+#, c-format
+msgid "The value <%s> was not recognized, %s %s the only acceptable value."
+msgstr "值<%s>未被识别，%s%s仅有的可接受值。"
+
+#: request_parser.c:1715
+msgid "is"
+msgstr "是"
+
+#: request_parser.c:1727
+msgid "are"
+msgstr "是"
+
+#: response_print.c:1630
+#, c-format
+msgid "The service \"%s\" ran successfully."
+msgstr "“%s”服务成功运行"
+
+#: response_print.c:1638
+#, c-format
+msgid ""
+"The ZOO service \"%s\" is currently running. Please reload this document to "
+"get the up-to-date status of the service."
+msgstr "ZOO服务“%s”正在运行。请重新载入页面以获取服务的最新状态。"
+
+#: response_print.c:1644
+#, c-format
+msgid ""
+"The service \"%s\" was accepted by the ZOO-Kernel and is running as a "
+"background task. Please access the URL in the statusLocation attribute "
+"provided in this document to get the up-to-date status and results."
+msgstr "服务\"%s\"已经被ZOO核心接受并在后台任务运行。请打开该网页中状态位置属性里的URL以获得最新状态和结果。"
+
+#: response_print.c:1661
+msgid "No more information available"
+msgstr "没有更多可获得的信息"
+
+#: response_print.c:1668
+#, c-format
+msgid "error code not know : %i\n"
+msgstr "未知错误状态码:%i\n"
+
+#: response_print.c:1760
+msgid "Lock failed."
+msgstr "加锁失败。"
+
+#: response_print.c:1773
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the ExecuteResponse."
+msgstr "无法创建文件\"%s\"以存储执行响应。"
+
+#: response_print.c:2290
+msgid "No debug message available"
+msgstr "没有可获得的调试信息"
+
+#: response_print.c:2378
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the session maps."
+msgstr "无法创建文件\"%s\"以存储会话映射。"
+
+#: response_print.c:2394
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: "
+msgstr "无法运行服务.服务返回的信息如下:"
+
+#: response_print.c:2395
+#, c-format
+msgid ""
+"Unable to run the Service. The message returned back by the Service was the "
+"following: %s"
+msgstr "无法运行服务.服务返回的信息如下:%s"
+
+#: response_print.c:2398 response_print.c:2399
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr "无法运行服务.服务没有返回更多信息."
+
+#: response_print.c:2486
+#, c-format
+msgid "Unable to create the file \"%s\" for storing the %s final result."
+msgstr "无法创建文件\"%s\"以存储%s最后结果。"
+
+#: response_print.c:2572
+#, c-format
+msgid ""
+"Wrong RawDataOutput parameter: unable to fetch any result for the given "
+"parameter name: \"%s\"."
+msgstr "错误的元数据输出参数：对于输入参数“%s”无法获取任何结果。"
+
+#: server_internal.c:869 server_internal.c:946
+msgid ""
+"The JobID from the request does not match any of the Jobs running on this "
+"server"
+msgstr "请求的JobID和该服务器上运行的任务不匹配"
+
+#: server_internal.c:875 server_internal.c:907
+msgid "The result for the requested JobID has not yet been generated. "
+msgstr "请求的JobID的几个还未生成."
+
+#: server_internal.c:988
+msgid "The job cannot be removed, a file cannot be removed"
+msgstr "任务不能移除，文件不能移除"
+
+#: server_internal.c:1063
+msgid "Unable to open the registry directory."
+msgstr "无法打开注册目录。"
+
+#: server_internal.c:1082
+msgid "Unable to allocate memory."
+msgstr "无法分配内存。"
+
+#: server_internal.c:1093 zoo_service_loader.c:276 zoo_service_loader.c:1384
+#: zoo_service_loader.c:1427
+#, c-format
+msgid "Unable to parse the ZCFG file: %s (%s)"
+msgstr "无法解析ZCFG文件:%s(%s)"
+
+#: server_internal.c:1096 zoo_service_loader.c:279 zoo_service_loader.c:1389
+#: zoo_service_loader.c:1431
+#, c-format
+msgid "Unable to parse the ZCFG file: %s."
+msgstr "无法解析ZCFG文件:%s."
+
+#: service_internal_ms.c:136
+msgid "Unable to find any mapserverAddress defined in the main.cfg file"
+msgstr "无法找到main.cfg文件中定义的mapserver地址"
+
+#: service_internal_php.c:227
+#, c-format
+msgid "Unable to load the PHP file %s"
+msgstr "无法载入PHP文件%s"
+
+#: service_internal_python.c:316
+#, c-format
+msgid "Python module %s cannot be loaded. Message: %s\n"
+msgstr "Python模块%s无法载入。信息如下：%s\n"
+
+#: service_internal_python.c:355
+#, c-format
+msgid ""
+"%s\n"
+"Unable to run your python process properly. Please check the following messages : %s"
+msgstr "%s\n无法正确运行您的python进程。请检查下面的信息：%s"
+
+#: service_internal_python.c:361
+#, c-format
+msgid ""
+"%s \n"
+" Unable to run your python process properly. Unable to provide any further information."
+msgstr "%s\n无法正确运行您的python进程。无法提供更多信息。"
+
+#: zoo_service_loader.c:352
+#, c-format
+msgid "ZOO Kernel failed to process your request, receiving signal %d = %s"
+msgstr "ZOO核心无法处理您的请求，收到信号%d=%s"
+
+#: zoo_service_loader.c:527
+#, c-format
+msgid "Error occurred while running the %s function: %s"
+msgstr "运行%s函数时发生错误：%s"
+
+#: zoo_service_loader.c:578
+#, c-format
+msgid "Unable to load C Library %s"
+msgstr "无法载入C程序库%s"
+
+#: zoo_service_loader.c:672
+#, c-format
+msgid ""
+"Programming Language (%s) set in ZCFG file is not currently supported by ZOO"
+" Kernel.\n"
+msgstr "ZCFG文件中设置的编程语言(%s)尚未被ZOO核心支持。\n"
+
+#: zoo_service_loader.c:737
+msgid "Unable to cache HTTP POST Execute request."
+msgstr "无法缓存HTTP POST执行请求。"
+
+#: zoo_service_loader.c:895
+msgid "Unable to load the main.cfg file."
+msgstr "无法载入main.cfg文件。"
+
+#: zoo_service_loader.c:895
+msgid "%s The following file: %s cannot be found."
+msgstr "%s下面的文件：%s找不到"
+
+#: zoo_service_loader.c:940
+#, c-format
+msgid "The value %s is not supported for the <language> parameter"
+msgstr "参数<language>不支持值%s"
+
+#: zoo_service_loader.c:1238
+msgid "The specified path does not exist."
+msgstr "指定的路径不存在。"
+
+#: zoo_service_loader.c:1303
+#, c-format
+msgid ""
+"Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"
+msgstr "无法解析下列ZOO服务：%s的ZCFG文件。信息：%s"
+
+#: zoo_service_loader.c:1308
+#, c-format
+msgid "Unable to parse the ZCFG file for the following ZOO-Service: %s."
+msgstr "无法解析下列ZOO服务：%s的ZCFG文件。"
+
+#: zoo_service_loader.c:1534
+msgid "Unable to run Execute request using the GET HTTP method"
+msgstr "无法使用HTTP GET方法执行请求"
+
+#: zoo_service_loader.c:1606
+#, c-format
+msgid ""
+"The value for <identifier> seems to be wrong (%s). Please specify one of the"
+" processes in the list returned by a GetCapabilities request."
+msgstr "<identifier>的值看起来不对(%s)。请定义一个在GetCapabilities请求返回列表中的处理进程。"
+
+#: zoo_service_loader.c:1733
+msgid ""
+"The status parameter cannot be set to true if storeExecuteResponse is set to"
+" false. Please modify your request parameters."
+msgstr "如果storeExecuteResponse被设置为false,状态参数不能被设置为true.请调整您的请求参数."
+
+#: zoo_service_loader.c:1761
+msgid "The process does not permit the desired execution mode."
+msgstr "该进程不允许期望的执行模式."
+
+#: zoo_service_loader.c:1837
+msgid "No message provided"
+msgstr "没有可以提供的信息"
+
+#: zoo_service_loader.c:1995
+msgid "Initializing"
+msgstr "初始化中..."
+
+#: zoo_service_loader.c:2142
+msgid "Unable to run the child process properly"
+msgstr "无法正确执行子进程"
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/main.cfg.in
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/main.cfg.in	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/main.cfg.in	(revision 942)
@@ -0,0 +1,33 @@
+[main]
+encoding = utf-8
+version = 1.0.0
+serverAddress = http://www.zoo-project.org/zoo/
+language = en-US
+lang = fr-FR,en-CA,en-US
+tmpPath=/tmp/
+tmpUrl = ../tmpPathRelativeToServerAdress/
+dataPath = @sharedstatedir@/zoo-project
+cacheDir = /tmp/
+
+[identification]
+title = The ZOO-Project OGC WPS Development Server
+abstract = Development version of ZOO-Project OGC WPS. See http://www.zoo-project.org
+fees = None
+accessConstraints = none
+keywords = WPS,GIS,buffer
+
+[provider]
+providerName=ZOO-Project
+providerSite=http://www.zoo-project.org
+individualName=Gerald FENOY
+positionName=Developer
+role=Dev
+addressDeliveryPoint=1280, avenue des Platanes
+addressCity=Lattes
+addressAdministrativeArea=False
+addressPostalCode=34970
+addressCountry=fr
+addressElectronicMailAddress=gerald.fenoy@geolabs.fr
+phoneVoice=False
+phoneFacsimile=False
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/main_conf_read.l
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/main_conf_read.l	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/main_conf_read.l	(revision 942)
@@ -0,0 +1,65 @@
+/*
+ * Zoo main configuration file parser
+ *
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 209-2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+%option yylineno
+
+%{
+
+#include <string.h>
+#include "main_conf_read.tab.h"
+static int affichetrace = 0 ;
+
+%}
+
+attname	[a-zA-Z0-9_\-:.]+
+
+attvalue1	[%\*,;@a-zA-Z0-9_\-.:" "\"\'/\\\(\)\+\x41-\xff?&=\!$]+
+
+whitesp                      [ ]
+newline                 [\r\n]|[\n]
+
+%x DANSBALISE HORSBALISE PAIRSTART
+
+%%
+
+"\n" {if (affichetrace==1) printf ("\n\nNEWLINE\n") ; return NEWLINE;}
+
+{newline}+{whitesp}*			{if (affichetrace==1) printf ("\n\nNEWLINE 1\n") ; return NEWLINE;}
+
+<INITIAL,HORSBALISE>"["{attname}"]"             {if (affichetrace==1) printf ("\n\nANID:%s\n",yytext); crlval.chaine=yytext;crlval.chaine[strlen(crlval.chaine)-1]=0;crlval.chaine+=1;return ANID; }
+
+<INITIAL,HORSBALISE>{attname}             {if (affichetrace==1) printf ("\n\nATT_NAME:%s\n",yytext); crlval.chaine=yytext; return SPAIR; }
+
+<PAIRSTART,HORSBALISE>{attvalue1}             {if (affichetrace==1) printf ("\n\nATT_VALUE:%s\n",yytext);crlval.chaine=yytext;BEGIN(INITIAL);return EPAIR;}
+
+<PAIRSTART,INITIAL,HORSBALISE>{whitesp}*"="{whitesp}*             {BEGIN(PAIRSTART);}
+
+<PAIRSTART,INITIAL,HORSBALISE,DANSBALISE>{newline}+{whitesp}*			{if (affichetrace==1) printf ("\n\nNEWLINE 2\n") ; BEGIN(INITIAL); return NEWLINE;}
+
+%%
+
+
+int crwrap()
+{return 1;}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/main_conf_read.y
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/main_conf_read.y	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/main_conf_read.y	(revision 942)
@@ -0,0 +1,176 @@
+/*
+ * Zoo main configuration file parser
+ *
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 209-2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+%{
+#include <service.h>
+
+static maps* my_maps=NULL;
+static maps* current_maps=NULL;
+static map* current_content=NULL;
+static char* curr_key;
+static int debug=0;
+
+extern void crerror(const char *s);
+
+void usage(void) ;
+
+extern int crdebug;
+
+extern char crtext[];
+
+extern int crlineno;
+
+extern FILE* crin;
+
+extern int crlex(void);
+extern int crlex_destroy(void);
+
+%}
+
+%union { char* s;char* chaine; char* key;char* val;}
+
+%token <s> ID
+%token <s> CHAINE
+
+%token PAIR SPAIR EPAIR EPAIRS ANID
+%type <chaine> PAIR
+%type <chaine> EPAIRS
+%type <chaine> EPAIR
+%type <chaine> SPAIR
+
+%token WHITESPACE NEWLINE
+
+%type <s> ANID
+
+%%
+
+document
+ : miscetoile miscetoile {}
+ | contentetoile processid contentetoile document {}
+ ;
+
+miscetoile
+ : {}
+ ;
+
+Attributeetoile
+ : Attributeetoile  {}
+ | 	                          {/* Epsilon */}
+ ;
+
+contentetoile
+: contentetoile NEWLINE {}
+ | contentetoile pair {}
+ | {/* Epsilon */}
+ ;
+
+pair: PAIR {if(curr_key!=NULL) free(curr_key);curr_key=zStrdup($1);}
+| EPAIR {
+  if(current_content==NULL) 
+    current_content=createMap(curr_key,$1);
+  else{ 
+    addToMap(current_content,curr_key,$1);
+  }
+  if(debug){ 
+    printf("EPAIR FOUND !! \n"); 
+    printf("[%s=>%s]\n",curr_key,$1);
+  }
+  free(curr_key);
+  curr_key=NULL;
+  }
+| SPAIR  {if(curr_key!=NULL) free(curr_key);curr_key=zStrdup($1);if(debug) printf("SPAIR FOUND !!\n"); }
+ ;
+
+
+processid
+: ANID  {
+   if(current_maps->name!=NULL){
+     addMapToMap(&current_maps->content,current_content);
+     freeMap(&current_content);
+     free(current_content);
+     current_maps->next=NULL;
+     current_maps->next=createMaps($1);
+     current_maps=current_maps->next;
+     current_content=current_maps->content;
+   }
+   else{
+     current_maps->name=(char*)malloc((strlen($1)+1)*sizeof(char));
+     snprintf(current_maps->name,(strlen($1)+1),"%s",$1);
+     current_maps->content=NULL;
+     current_maps->next=NULL;
+     current_content=NULL;
+   }
+ }
+ ;
+
+%%
+
+/**
+ * Print on stderr the message and the line number of the error which occurred.
+ *
+ * @param s the error message
+ */
+void crerror(const char *s)
+{
+  if(debug)
+    printf("\nligne %d : %s\n",crlineno,s);
+}
+
+/**
+ * Parse the main.cfg file and fill the maps structure.
+ *
+ * @param file the filename to parse
+ * @param my_map the maps structure to fill
+ */
+int conf_read(const char* file,maps* my_map){
+  
+  crin = fopen(file,"r");
+  if (crin==NULL){
+    return 2 ;
+  }
+
+  my_maps=my_map;
+  my_maps->name=NULL;
+  current_maps=my_maps;
+  
+  int resultatYYParse = crparse() ;
+  if(current_content!=NULL){
+    addMapToMap(&current_maps->content,current_content);
+    current_maps->next=NULL;
+    freeMap(&current_content);
+    free(current_content);
+  }
+  if(curr_key!=NULL){
+    free(curr_key);
+  }
+
+  fclose(crin);
+#ifndef WIN32
+  crlex_destroy();
+#endif
+
+  return resultatYYParse;
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/makefile.vc	(revision 942)
@@ -0,0 +1,116 @@
+# WIN32 Makefile tested using VC-9.0
+# Don't forget to set your PATH using the following command :
+# c:\Progam Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat
+# set PATH=%PATH%;$(TOOLS)
+# using value for TOOLS relative to your local installation
+#
+
+!INCLUDE nmake.opt
+
+all:  $(PROGRAMNAME) zcfg2yaml
+
+version.h:
+	echo #define LOCALEDIR "c:/" > version.h
+	echo #define ZOO_VERSION "1.7.0" >> version.h
+
+main_conf_read.tab.c: main_conf_read.y service.h
+	bison -p cr -d main_conf_read.y
+
+main_conf_read.tab.obj: main_conf_read.tab.c service.h
+	$(CPP) /EHsc $(CFLAGS) main_conf_read.tab.c /c
+
+lex.cr.c: main_conf_read.y main_conf_read.l main_conf_read.tab.c service.h
+	flex -Pcr main_conf_read.l
+
+lex.cr.obj: lex.cr.c service.h
+	$(CPP) $(CFLAGS) /c lex.cr.c
+
+service_conf.tab.c: service_conf.y service.h
+	bison -p sr -d service_conf.y
+
+service_conf.tab.obj: service_conf.tab.c service.h
+	$(CPP) $(CFLAGS) service_conf.tab.c /c
+
+lex.sr.c: service_conf.y service_conf.l service_conf.tab.c service.h
+	flex -Psr service_conf.l
+
+lex.sr.obj: lex.sr.c service.h
+	$(CPP) $(CFLAGS) /c lex.sr.c
+
+zcfg2yaml.obj: zcfg2yaml.c
+	$(CPP) $(CFLAGS) /c zcfg2yaml.c
+
+service_internal.obj: service_internal.c service_internal.h
+	$(CPP) $(CFLAGS) /c service_internal.c
+
+server_internal.obj: server_internal.c server_internal.h
+	$(CPP) $(CFLAGS) /c server_internal.c
+
+caching.obj: caching.c caching.h
+	$(CPP) $(CFLAGS) /c caching.c
+
+service_json.obj: service_json.c service_json.h
+	$(CPP) $(CFLAGS) /c service_json.c
+
+request_parser.obj: request_parser.c request_parser.h
+	$(CPP) $(CFLAGS) /c request_parser.c
+
+response_print.obj: response_print.c response_print.h
+	$(CPP) $(CFLAGS) /c response_print.c
+
+service.obj: service.c service.h
+	$(CPP) $(CFLAGS) /c service.c
+
+sqlapi.obj: sqlapi.c sqlapi.h
+	$(CPP) $(CFLAGS) /c sqlapi.c
+
+service_internal_js.obj: service_internal_js.c service.h
+	$(CPP) /c $(CFLAGS) service_internal_js.c
+
+service_internal_java.obj: service_internal_java.c service.h
+	$(CPP) /c $(CFLAGS) service_internal_java.c
+
+service_internal_ruby.obj: service_internal_ruby.c service_internal_ruby.h service.h
+	$(CPP) /c $(CFLAGS) service_internal_ruby.c
+
+service_internal_mono.obj: service_internal_mono.c service_internal_mono.h service.h
+        $(CPP) /c $(MONO_CLAGS) $(CFLAGS) service_internal_mono.c
+
+service_internal_python.obj: service_internal_python.c service.h
+	$(CPP) /c $(CFLAGS) service_internal_python.c
+
+service_internal_ms.obj: service_internal_ms.c service.h
+	$(CPP) /c $(CFLAGS) service_internal_ms.c
+
+service_loader.obj: service_loader.c service.h
+	$(CPP) /c $(CFLAGS)  service_loader.c
+
+zoo_service_loader.obj: zoo_service_loader.c service.h
+	$(CPP) /c $(CFLAGS)  zoo_service_loader.c
+
+zoo_loader.obj: zoo_loader.c service.h
+	$(CPP) /EHsc /c $(CFLAGS) zoo_loader.c
+
+service_internal_php.obj: service_internal_php.c service_internal_php.h service.h
+	$(CPP) /c $(CFLAGS) $(PHP_CFLAGS) service_internal_php.c
+    
+service_callback.obj: service_callback.c service_callback.h service.h
+	$(CPP) /c $(CFLAGS) service_callback.c
+    
+service_internal_php7.obj: service_internal_php7.c service_internal_php.h service.h
+	$(CPP) /c $(CFLAGS) $(PHP_CFLAGS) service_internal_php7.c    
+
+$(LIBZOO_SERVICE): service_internal.obj service.obj sqlapi.obj
+	link /dll /out:$(LIBZOO_SERVICE) ./service.obj ./service_internal.obj ./sqlapi.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+$(PROGRAMNAME): version.h $(LIBZOO_SERVICE) zoo_loader.obj zoo_service_loader.obj service_internal.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj lex.cr.obj lex.sr.obj service_conf.tab.obj main_conf_read.tab.obj request_parser.obj response_print.obj server_internal.obj caching.obj service_json.obj service_callback.obj
+	link zoo_loader.obj request_parser.obj response_print.obj server_internal.obj caching.obj service_json.obj service_callback.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj main_conf_read.tab.obj lex.cr.obj service_conf.tab.obj lex.sr.obj  zoo_service_loader.obj ./libzoo_service.lib /out:$(PROGRAMNAME) $(LDFLAGS) $(LDFLAGSCGI) $(JSONC_LIB) $(PTHREADS_LIB) $(XSLT_LIB)
+
+zcfg2yaml: version.h zcfg2yaml.obj zoo_service_loader.obj service_internal.obj caching.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) ulinet.obj lex.cr.obj lex.sr.obj service_conf.tab.obj main_conf_read.tab.obj
+	link zcfg2yaml.obj server_internal.obj caching.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) $(MONO_FILE) $(RUBY_FILE) $(PHP_FILE) ulinet.obj response_print.obj main_conf_read.tab.obj lex.cr.obj service_conf.tab.obj lex.sr.obj ./libzoo_service.lib /out:zcfg2yaml.exe $(LDFLAGS) $(LDFLAGSCGI)
+
+clean:
+	erase -f *.cgi *.obj *.tab.c* *.tab.h *.sr.c* lex.* *.lreg *.sibling *.lib *.dll
+
+embed-manifest: zoo_loader.cgi
+	mt.exe -manifest zoo_loader.cgi.manifest -outputresource:zoo_loader.cgi;
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/meta_sql.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/meta_sql.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/meta_sql.c	(revision 942)
@@ -0,0 +1,482 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ * Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef META_DB
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+
+#include "meta_sql.h"
+#include "sqlapi.h"
+#include "response_print.h"
+#ifdef USE_HPC
+#include "service_internal_hpc.h"
+#endif
+#define META_SERVICES_LIST_ALL \
+  "select id,identifier,title,abstract,service_type,service_provider,conf_id"\
+  " from ows_process"
+#define META_SERVICES_LIST_ALL_LENGTH strlen(META_SERVICES_LIST_ALL)
+
+#define META_SERVICES_KEYWORDS_FROM_PROCESS \
+  "SELECT keyword FROM CollectionDB.ows_Keywords where id in"\
+  " (SELECT keywords_id FROM CollectionDB.DescriptionsKeywordsAssignment"\
+  " where descriptions_id=%s) "
+#define META_SERVICES_KEYWORDS_FROM_PROCESS_LENGTH strlen(META_SERVICES_KEYWORDS_FROM_PROCESS)
+
+#define META_SERVICES_META_FROM_ANYTHING \
+  "SELECT title,role,href FROM CollectionDB.ows_Metadata where id in"\
+  " (SELECT metadata_id FROM CollectionDB.DescriptionsMetadataAssignment"\
+  " where descriptions_id=%s) "
+#define META_SERVICES_META_FROM_ANYTHING_LENGTH strlen(META_SERVICES_META_FROM_ANYTHING)
+
+#define META_SERVICES_AP_FROM_ANYTHING \
+  "SELECT id,title,role,href FROM CollectionDB.ows_AdditionalParameters where id in"\
+  " (SELECT additional_parameters_id FROM CollectionDB.DescriptionsAdditionalParametersAssignment"\
+  " where descriptions_id=%s) "
+#define META_SERVICES_AP_FROM_ANYTHING_LENGTH strlen(META_SERVICES_AP_FROM_ANYTHING)
+
+#define META_SERVICES_AP_FROM_AP \
+  "SELECT key,value FROM CollectionDB.ows_AdditionalParameter where additional_parameters_id =$q$%s$q$"
+#define META_SERVICES_AP_FROM_AP_LENGTH strlen(META_SERVICES_AP_FROM_AP)
+
+#define META_SERVICES_LIST_INPUTS_FROM_PROCESS				\
+  "select id, identifier,title,abstract,min_occurs,max_occurs from CollectionDB.ows_Input where id in (SELECT input_id from CollectionDB.ProcessInputAssignment where process_id=%s) order by id"
+#define META_SERVICES_LIST_INPUTS_FROM_PROCESS_LENGTH strlen(META_SERVICES_LIST_INPUTS_FROM_PROCESS)
+
+#define META_SERVICES_LIST_INPUTS_FROM_INPUT				\
+  "select id, identifier,title,abstract,min_occurs,max_occurs from CollectionDB.ows_Input where id in (SELECT child_input from CollectionDB.InputInputAssignment where parent_input=%s) order by id"
+#define META_SERVICES_LIST_INPUTS_FROM_INPUT_LENGTH strlen(META_SERVICES_LIST_INPUTS_FROM_INPUT)
+
+#define META_SERVICES_LIST_OUTPUTS_FROM_PROCESS \
+  "select id, identifier,title,abstract from CollectionDB.ows_Output where id in (SELECT output_id from CollectionDB.ProcessOutputAssignment where process_id=%s) order by id"
+#define META_SERVICES_LIST_OUTPUTS_FROM_PROCESS_LENGTH strlen(META_SERVICES_LIST_OUTPUTS_FROM_PROCESS)
+
+#define META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT \
+  "select id, identifier,title,abstract from CollectionDB.ows_Output where id in (SELECT child_output from CollectionDB.OutputOutputAssignment where parent_output=%s) order by id"
+#define META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT_LENGTH strlen(META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT)
+
+#define META_SERVICES_LIST_LITERAL_FROM_IO \
+  "select (SELECT name as type FROM CollectionDB.PrimitiveDatatypes where CollectionDB.PrimitiveDatatypes.id=data_type_id),default_value,(SELECT uom from CollectionDB.PrimitiveUOM where id=CollectionDB.LiteralDataDomain.uom),translate(translate(ARRAY((SELECT allowed_Value from CollectionDB.AllowedValues where id in (SELECT allowed_value_id from CollectionDB.AllowedValuesAssignment where literal_data_domain_id=CollectionDB.LiteralDataDomain.id)))::varchar,'{',''),'}',''),def as allowedvalues from CollectionDB.LiteralDataDomain where id in (SELECT data_description_id from CollectionDB.%sDataDescriptionAssignment where %s_id = %s);"
+#define META_SERVICES_LIST_LITERAL_FROM_IO_LENGTH strlen(META_SERVICES_LIST_LITERAL_FROM_IO)
+
+#define META_SERVICES_LIST_FORMATS_FROM_IO \
+  "select mime_type,encoding,schema,maximum_megabytes,CASE WHEN use_mapserver THEN 'true' ELSE 'false' END, ms_styles, def from CollectionDB.ows_Format,CollectionDB.PrimitiveFormats where CollectionDB.ows_Format.primitive_format_id=CollectionDB.PrimitiveFormats.id and CollectionDB.ows_Format.id in (SELECT format_id from collectiondb.ows_datadescription where id in ( SELECT data_description_id from CollectionDB.%sDataDescriptionAssignment where %s_id = %s))"
+#define META_SERVICES_LIST_FORMATS_FROM_IO_LENGTH strlen(META_SERVICES_LIST_FORMATS_FROM_IO)
+
+/**
+ * Create a new iotype pointer using field names from an OGRFeature
+ *
+ * @param f the OGRFeature 
+ * @param fields the fields names
+ * @return the iotype
+ */
+iotype* getIoType(OGRFeature* f,const char** fields){
+  iotype* io=(iotype*)malloc(IOTYPE_SIZE);
+  io->content=NULL;
+  io->next=NULL;
+  for(int i=0;i<6;i++){
+    if(fields[i]==NULL)
+      return io;
+    const char* tmpS=f->GetFieldAsString( i );
+    if(strlen(tmpS)>0){
+      if(io->content==NULL)
+	io->content=createMap(fields[i],tmpS);
+      else
+	addToMap(io->content,fields[i],tmpS);
+    }
+  }
+  return io;
+}
+
+/**
+ * Fill the AdditionalParameters map with the data extracted from metadb
+ *
+ * @param conf the main configuration maps
+ * @param ap the map to fill
+ * @param dref the description identifier
+ * @return the number of metadata field found
+ */
+int fillAdditionalParameters(maps* conf,map** ap,const char* dref){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_AP_FROM_ANYTHING_LENGTH+strlen(dref)+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_AP_FROM_ANYTHING,dref);
+  OGRFeature  *meta = NULL;
+  OGRLayer *metas=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int cnt=0;
+  char fields[3][255]={
+    "title",
+    "role",
+    "href"
+  };
+  while( (meta = metas->GetNextFeature()) != NULL ){
+    int i=0;
+    for(i=0;i<3;i++){      
+      const char *tmp=meta->GetFieldAsString(i+1);
+      if(strlen(tmp)>0)
+	if(*ap==NULL){
+	  (*ap)=createMap(fields[i],tmp);
+	  addToMap(*ap,"fromDb","true");
+	}
+	else
+	  setMapArray(*ap,fields[i],res,tmp);
+    }
+    char* apQuery=(char*)malloc((META_SERVICES_AP_FROM_AP_LENGTH+strlen(dref)+1)*sizeof(char));
+    sprintf(apQuery,META_SERVICES_AP_FROM_AP,meta->GetFieldAsString(0));
+    OGRFeature  *adp = NULL;
+    OGRLayer *adps=fetchSql(conf,0,apQuery);
+    free(apQuery);
+    while( (adp = adps->GetNextFeature()) != NULL ){
+      addToMap(*ap,adp->GetFieldAsString(0),adp->GetFieldAsString(1));
+      OGRFeature::DestroyFeature( adp );
+    }
+    cleanFetchSql(conf,0,adps);
+    res++;
+    OGRFeature::DestroyFeature( meta );
+  }
+  cleanFetchSql(conf,0,metas);
+  return res;
+}
+
+/**
+ * Fill the metadata map with the data extracted from metadb
+ *
+ * @param conf the main configuration maps
+ * @param metadata the map to fill
+ * @param dref the description identifier
+ * @return the number of metadata field found
+ */
+int fillMetadata(maps* conf,map** metadata,const char* dref){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_META_FROM_ANYTHING_LENGTH+strlen(dref)+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_META_FROM_ANYTHING,dref);
+  OGRFeature  *meta = NULL;
+  OGRLayer *metas=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int cnt=0;
+  char fields[3][255]={
+    "title",
+    "role",
+    "href"
+  };
+  while( (meta = metas->GetNextFeature()) != NULL ){
+    int i=0;
+    for(i=0;i<3;i++){
+      const char *tmp=meta->GetFieldAsString(i);
+      if(strlen(tmp)>0)
+	if(*metadata==NULL)
+	  *metadata=createMap(fields[i],tmp);
+	else
+	  addToMap(*metadata,fields[i],tmp);
+    }
+    res++;
+    OGRFeature::DestroyFeature( meta );
+  }
+  cleanFetchSql(conf,0,metas);
+  return res;
+}
+
+/**
+ * Try to fill the default/supported map for the LiteralData with the data
+ * extracted from metadb.
+ *
+ * @param conf the main configuration maps
+ * @param in the element to fill default/supported
+ * @param input the OGRFeature corresponding to the input/output
+ * @param ltype the element type ("Input" or "Output")
+ * @return the number of default/supported definition found
+ */
+int fillLiteralData(maps* conf,elements* in,OGRFeature  *input,const char* ltype){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_LIST_LITERAL_FROM_IO_LENGTH+(strlen(ltype)*2)+strlen(input->GetFieldAsString( 0 ))+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_LIST_LITERAL_FROM_IO,ltype,ltype,input->GetFieldAsString( 0 ));
+  OGRFeature  *io = NULL;
+  OGRLayer *ios=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int ioCnt=0;
+  const char* fields[5]={"dataType","value","uom","AllowedValues",NULL};
+  while( (io = ios->GetNextFeature()) != NULL ){
+    iotype* currentIoType;
+    if(strncmp(io->GetFieldAsString( 4 ),"1",1)==0){
+      in->defaults=getIoType(io,fields);
+    }else{
+      if(in->supported==NULL)
+	in->supported=getIoType(io,fields);
+      else{
+	iotype* p=in->supported;
+	while(p->next!=NULL){
+	  p=p->next;
+	}
+	p->next=getIoType(io,fields);
+      }
+    }
+    in->format=strdup("LiteralData");
+    res++;
+    OGRFeature::DestroyFeature( io );
+  }
+  cleanFetchSql(conf,0,ios);
+  return res;
+}
+
+/**
+ * Try to fill the default/supported map for the ComplexData with the data
+ * extracted from metadb.
+ *
+ * @param conf the main configuration maps
+ * @param in the element to fill default/supported
+ * @param input the OGRFeature corresponding to the input/output
+ * @param ltype the element type ("Input" or "Output")
+ * @return the number of default/supported definition found
+ */
+int fillComplexData(maps* conf,elements* in,OGRFeature  *input,const char* ltype){
+  int res=0;
+  char* ioQuery=(char*)malloc((META_SERVICES_LIST_FORMATS_FROM_IO_LENGTH+(strlen(ltype)*2)+strlen(input->GetFieldAsString( 0 ))+1)*sizeof(char));
+  sprintf(ioQuery,META_SERVICES_LIST_FORMATS_FROM_IO,ltype,ltype,input->GetFieldAsString( 0 ));
+  OGRFeature  *io = NULL;
+  OGRLayer *ios=fetchSql(conf,0,ioQuery);
+  free(ioQuery);
+  int ioCnt=0;
+  const char* fields[6]={"mimeType","ecoding","schema","maximumMegabytes","useMapserver","msStyle"};
+  while( (io = ios->GetNextFeature()) != NULL ){
+    iotype* currentIoType;
+    if(strncmp(io->GetFieldAsString( 6 ),"1",1)==0){
+      in->defaults=getIoType(io,fields);
+    }else{
+      if(in->supported==NULL)
+	in->supported=getIoType(io,fields);
+      else{
+	iotype* p=in->supported;
+	while(p->next!=NULL){
+	  p=p->next;
+	}
+	p->next=getIoType(io,fields);
+      }
+    }
+    in->format=strdup("ComplexData");
+    res++;
+    OGRFeature::DestroyFeature( io );
+  }
+  cleanFetchSql(conf,0,ios);
+  return res;
+}
+
+/**
+ * Extract input definition from metadb
+ *
+ * @param conf the main configuration maps
+ * @param input the OGRFeature pointing to an input
+ * @return a new elements* corresponding to the current input
+ */
+elements* extractInput(maps* conf,OGRFeature *input){
+  elements* res=createElements(input->GetFieldAsString( 1 ));
+  res->content=createMap("title",input->GetFieldAsString( 2 ));
+  addToMap(res->content,"abstract",input->GetFieldAsString( 3 ));
+  addToMap(res->content,"minOccurs",input->GetFieldAsString( 4 ));
+  addToMap(res->content,"maxOccurs",input->GetFieldAsString( 5 ));
+  // Extract metadata
+  fillMetadata(conf,&res->metadata,input->GetFieldAsString( 0 ));
+  res->additional_parameters=NULL;
+  fillAdditionalParameters(conf,&res->additional_parameters,input->GetFieldAsString( 0 ));
+  res->defaults=NULL;
+  res->supported=NULL;
+  res->child=NULL;
+  res->next=NULL;
+  // Extract iotypes
+  int ioCnt=fillLiteralData(conf,res,input,"Input");
+  if(ioCnt==0){
+    ioCnt=fillComplexData(conf,res,input,"Input");
+  }
+  if(ioCnt==0){
+    char* nestedInputsQuery=(char*)malloc((META_SERVICES_LIST_INPUTS_FROM_INPUT_LENGTH+strlen(input->GetFieldAsString( 0 ))+1)*sizeof(char));
+    sprintf(nestedInputsQuery,META_SERVICES_LIST_INPUTS_FROM_INPUT,input->GetFieldAsString( 0 ));
+    OGRFeature  *ninput = NULL;
+    OGRLayer *ninputs=fetchSql(conf,0,nestedInputsQuery);
+    free(nestedInputsQuery);
+    while( (ninput = ninputs->GetNextFeature()) != NULL ){
+      elements* nin=extractInput(conf,ninput);
+      addToElements(&res->child,nin);
+      freeElements(&nin);
+      free(nin);
+      OGRFeature::DestroyFeature( ninput );
+    }
+    cleanFetchSql(conf,0,ninputs);
+  }
+  return res;
+}
+
+/**
+ * Extract output definition from metadb
+ *
+ * @param conf the main configuration maps
+ * @param output the OGRFeature pointing to an output
+ * @return a new elements* corresponding to the current output
+ */
+elements* extractOutput(maps* conf,OGRFeature *output){
+  elements* res=createElements(output->GetFieldAsString( 1 ));
+  res->content=createMap("title",output->GetFieldAsString( 2 ));
+  addToMap(res->content,"abstract",output->GetFieldAsString( 3 ));
+  fillMetadata(conf,&res->metadata,output->GetFieldAsString( 0 ));
+  fillAdditionalParameters(conf,&res->additional_parameters,output->GetFieldAsString( 0 ));
+  int ioCnt=fillLiteralData(conf,res,output,"Output");
+  if(ioCnt==0)
+    ioCnt=fillComplexData(conf,res,output,"Output");
+  char* nestedOutputsQuery=(char*)malloc((META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT_LENGTH+strlen(output->GetFieldAsString( 0 ))+1)*sizeof(char));
+  sprintf(nestedOutputsQuery,META_SERVICES_LIST_OUTPUTS_FROM_OUTPUT,output->GetFieldAsString( 0 ));
+  OGRFeature  *noutput = NULL;
+  OGRLayer *noutputs=fetchSql(conf,0,nestedOutputsQuery);
+  free(nestedOutputsQuery);
+  while( (noutput = noutputs->GetNextFeature()) != NULL ){
+    elements* nout=extractOutput(conf,noutput);
+    addToElements(&res->child,nout);
+    freeElements(&nout);
+    free(nout);
+    OGRFeature::DestroyFeature( noutput );
+  }
+  cleanFetchSql(conf,0,noutputs);
+  return res;
+}
+
+/**
+ * Extract service from metadb
+ *
+ * @param conf the main configuration maps
+ * @param serviceName the service name
+ * @param minimal 1 for minimal metadata extraction (GetCapabilities), 0 in other cases.
+ * @return a new service* corresponding to the service
+ */
+service* extractServiceFromDb(maps* conf,const char* serviceName,int minimal){
+  OGRFeature  *poFeature = NULL;
+  char* tmpQuery=(char*)malloc((META_SERVICES_LIST_ALL_LENGTH+strlen(serviceName)+21)*sizeof(char));
+  sprintf(tmpQuery,"%s WHERE identifier='%s'",META_SERVICES_LIST_ALL,serviceName);  
+  OGRLayer *res=fetchSql(conf,0,tmpQuery);
+  free(tmpQuery);
+  if(res!=NULL){
+    while( (poFeature = res->GetNextFeature()) != NULL ){
+      service* s = (service*) malloc(SERVICE_SIZE);
+      s->name = strdup(poFeature->GetFieldAsString( 1 ));
+      s->content = createMap("title",poFeature->GetFieldAsString( 2 ));
+      addToMap(s->content,"abstract",poFeature->GetFieldAsString( 3 ));
+      addToMap(s->content,"serviceType",poFeature->GetFieldAsString( 4 ));
+      addToMap(s->content,"serviceProvider",poFeature->GetFieldAsString( 5 ));
+      addToMap(s->content,"confId",poFeature->GetFieldAsString( 6 ));
+      addToMap(s->content,"fromDb","true");
+      s->metadata=NULL;
+      fillMetadata(conf,&s->metadata,poFeature->GetFieldAsString( 0 ));
+      s->additional_parameters=NULL;
+      fillAdditionalParameters(conf,&s->additional_parameters,poFeature->GetFieldAsString( 0 ));
+      s->inputs=NULL;
+      s->outputs=NULL;
+      if(minimal==1){
+	OGRFeature::DestroyFeature( poFeature );
+	cleanFetchSql(conf,0,res);
+	return s;
+      }
+      char* inputsQuery=(char*)malloc((META_SERVICES_LIST_INPUTS_FROM_PROCESS_LENGTH+strlen(poFeature->GetFieldAsString( 0 ))+1)*sizeof(char));
+      sprintf(inputsQuery,META_SERVICES_LIST_INPUTS_FROM_PROCESS,poFeature->GetFieldAsString( 0 ));
+      OGRFeature  *input = NULL;
+      OGRLayer *inputs=fetchSql(conf,0,inputsQuery);
+      free(inputsQuery);
+      while( (input = inputs->GetNextFeature()) != NULL ){
+	elements* in=extractInput(conf,input);
+	if(in!=NULL){
+	  addToElements(&s->inputs,in);
+	  freeElements(&in);
+	  free(in);
+	}
+	OGRFeature::DestroyFeature( input );
+      }
+      cleanFetchSql(conf,0,inputs);
+      char* outputsQuery=(char*)malloc((META_SERVICES_LIST_OUTPUTS_FROM_PROCESS_LENGTH+strlen(poFeature->GetFieldAsString( 0 ))+1)*sizeof(char));
+      sprintf(outputsQuery,META_SERVICES_LIST_OUTPUTS_FROM_PROCESS,poFeature->GetFieldAsString( 0 ));
+      OGRFeature  *output = NULL;
+      OGRLayer *outputs=fetchSql(conf,0,outputsQuery);
+      free(outputsQuery);
+      s->outputs=NULL;
+      while( (output = outputs->GetNextFeature()) != NULL ){
+	elements* in=extractOutput(conf,output);
+	if(in!=NULL){
+	  addToElements(&s->outputs,in);
+	  freeElements(&in);
+	  free(in);
+	}
+	OGRFeature::DestroyFeature( output );
+      }
+      cleanFetchSql(conf,0,outputs);
+      OGRFeature::DestroyFeature( poFeature );
+      cleanFetchSql(conf,0,res);
+      return s;
+    }
+  }
+  cleanFetchSql(conf,0,res);
+  return NULL;
+}
+
+/**
+ * Extract every service definitions from metadb
+ *
+ * @param reg the registry
+ * @param conf the main configuration maps
+ * @param n the node where to add the services found
+ * @param func the C function to call for each service found
+ * @param minimal 1 for minimal metadata extraction (GetCapabilities), 0 in other cases.
+ * @return the number of services found, -1 in case of failure
+ */
+int fetchServicesFromDb(registry* reg,maps* conf, xmlDocPtr doc, xmlNodePtr n,
+			void (func) (registry *, maps *, xmlDocPtr, xmlNodePtr,
+				     service *), int minimal ){
+  int result=0;
+  result=_init_sql(conf,"metadb");
+  if(getMapFromMaps(conf,"lenv","dbIssue")!=NULL || result < 0)
+    return -1;
+  // Fetch every services
+  OGRLayer *res=fetchSql(conf,0,META_SERVICES_LIST_ALL);
+  if(res!=NULL){
+    OGRFeature  *poFeature = NULL;
+    const char *tmp1;
+    poFeature = res->GetNextFeature();
+    while( poFeature != NULL ){
+      service* s=extractServiceFromDb(conf,poFeature->GetFieldAsString( 1 ),minimal);
+#ifdef USE_HPC
+      addNestedOutputs(&s);
+#endif
+      func(reg,conf,doc,n,s);
+      freeService(&s);
+      free(s);
+      OGRFeature::DestroyFeature( poFeature );
+      poFeature = res->GetNextFeature();
+      result++;
+    }
+    cleanFetchSql(conf,0,res);
+  }
+  return result;
+}
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/meta_sql.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/meta_sql.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/meta_sql.h	(revision 942)
@@ -0,0 +1,53 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_META_SQL_H
+#define ZOO_META_SQL_H 1
+#ifdef META_DB
+
+#include "service.h"
+#include "service_internal.h"
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  ZOO_DLL_EXPORT int fetchServicesFromDb(registry*,maps*, xmlDocPtr, xmlNodePtr,
+					 void (func) (registry *, maps *, xmlDocPtr,
+						      xmlNodePtr,service *),int);
+  ZOO_DLL_EXPORT service* extractServiceFromDb(maps*,const char*,int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/mimetypes.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/mimetypes.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/mimetypes.h	(revision 942)
@@ -0,0 +1,865 @@
+#include "service.h"
+ 
+typedef enum MimeTypes {
+	 M_Type,
+	 M_Extension
+} mimetype;
+
+#define NUM_MIME_TYPES 767
+
+/*
+ * This array has been constructed based on the
+ * Apache web server's mime.types file
+ */
+const char* const MIME[NUM_MIME_TYPES][2] = {
+	{ "application/andrew-inset", "ez" },
+	{ "application/applixware", "aw" },
+	{ "application/atom+xml", "atom" },
+	{ "application/atomcat+xml", "atomcat" },
+	{ "application/atomsvc+xml", "atomsvc" },
+	{ "application/ccxml+xml", "ccxml" },
+	{ "application/cdmi-capability", "cdmia" },
+	{ "application/cdmi-container", "cdmic" },
+	{ "application/cdmi-domain", "cdmid" },
+	{ "application/cdmi-object", "cdmio" },
+	{ "application/cdmi-queue", "cdmiq" },
+	{ "application/cu-seeme", "cu" },
+	{ "application/davmount+xml", "davmount" },
+	{ "application/docbook+xml", "dbk" },
+	{ "application/dssc+der", "dssc" },
+	{ "application/dssc+xml", "xdssc" },
+	{ "application/ecmascript", "ecma" },
+	{ "application/emma+xml", "emma" },
+	{ "application/epub+zip", "epub" },
+	{ "application/exi", "exi" },
+	{ "application/font-tdpfr", "pfr" },
+	{ "application/gml+xml", "gml" },
+	{ "application/gpx+xml", "gpx" },
+	{ "application/gxf", "gxf" },
+	{ "application/hyperstudio", "stk" },
+	{ "application/inkml+xml", "ink" },
+	{ "application/ipfix", "ipfix" },
+	{ "application/java-archive", "jar" },
+	{ "application/java-serialized-object", "ser" },
+	{ "application/java-vm", "class" },
+	{ "application/javascript", "js" },
+	{ "application/json", "json" },
+	{ "application/jsonml+json", "jsonml" },
+	{ "application/lost+xml", "lostxml" },
+	{ "application/mac-binhex40", "hqx" },
+	{ "application/mac-compactpro", "cpt" },
+	{ "application/mads+xml", "mads" },
+	{ "application/marc", "mrc" },
+	{ "application/marcxml+xml", "mrcx" },
+	{ "application/mathematica", "ma" },
+	{ "application/mathml+xml", "mathml" },
+	{ "application/mbox", "mbox" },
+	{ "application/mediaservercontrol+xml", "mscml" },
+	{ "application/metalink+xml", "metalink" },
+	{ "application/metalink4+xml", "meta4" },
+	{ "application/mets+xml", "mets" },
+	{ "application/mods+xml", "mods" },
+	{ "application/mp21", "m21" },
+	{ "application/mp4", "mp4s" },
+	{ "application/msword", "doc" },
+	{ "application/mxf", "mxf" },
+	{ "application/octet-stream", "bin" },
+	{ "application/oda", "oda" },
+	{ "application/oebps-package+xml", "opf" },
+	{ "application/ogg", "ogx" },
+	{ "application/omdoc+xml", "omdoc" },
+	{ "application/onenote", "onetoc" },
+	{ "application/oxps", "oxps" },
+	{ "application/patch-ops-error+xml", "xer" },
+	{ "application/pdf", "pdf" },
+	{ "application/pgp-encrypted", "pgp" },
+	{ "application/pgp-signature", "asc" },
+	{ "application/pics-rules", "prf" },
+	{ "application/pkcs10", "p10" },
+	{ "application/pkcs7-mime", "p7m" },
+	{ "application/pkcs7-signature", "p7s" },
+	{ "application/pkcs8", "p8" },
+	{ "application/pkix-attr-cert", "ac" },
+	{ "application/pkix-cert", "cer" },
+	{ "application/pkix-crl", "crl" },
+	{ "application/pkix-pkipath", "pkipath" },
+	{ "application/pkixcmp", "pki" },
+	{ "application/pls+xml", "pls" },
+	{ "application/postscript", "ps" },
+	{ "application/prs.cww", "cww" },
+	{ "application/pskc+xml", "pskcxml" },
+	{ "application/rdf+xml", "rdf" },
+	{ "application/reginfo+xml", "rif" },
+	{ "application/relax-ng-compact-syntax", "rnc" },
+	{ "application/resource-lists+xml", "rl" },
+	{ "application/resource-lists-diff+xml", "rld" },
+	{ "application/rls-services+xml", "rs" },
+	{ "application/rpki-ghostbusters", "gbr" },
+	{ "application/rpki-manifest", "mft" },
+	{ "application/rpki-roa", "roa" },
+	{ "application/rsd+xml", "rsd" },
+	{ "application/rss+xml", "rss" },
+	{ "application/rtf", "rtf" },
+	{ "application/sbml+xml", "sbml" },
+	{ "application/scvp-cv-request", "scq" },
+	{ "application/scvp-cv-response", "scs" },
+	{ "application/scvp-vp-request", "spq" },
+	{ "application/scvp-vp-response", "spp" },
+	{ "application/sdp", "sdp" },
+	{ "application/set-payment-initiation", "setpay" },
+	{ "application/set-registration-initiation", "setreg" },
+	{ "application/shf+xml", "shf" },
+	{ "application/smil+xml", "smi" },
+	{ "application/sparql-query", "rq" },
+	{ "application/sparql-results+xml", "srx" },
+	{ "application/srgs", "gram" },
+	{ "application/srgs+xml", "grxml" },
+	{ "application/sru+xml", "sru" },
+	{ "application/ssdl+xml", "ssdl" },
+	{ "application/ssml+xml", "ssml" },
+	{ "application/tei+xml", "tei" },
+	{ "application/thraud+xml", "tfi" },
+	{ "application/timestamped-data", "tsd" },
+	{ "application/vnd.3gpp.pic-bw-large", "plb" },
+	{ "application/vnd.3gpp.pic-bw-small", "psb" },
+	{ "application/vnd.3gpp.pic-bw-var", "pvb" },
+	{ "application/vnd.3gpp2.tcap", "tcap" },
+	{ "application/vnd.3m.post-it-notes", "pwn" },
+	{ "application/vnd.accpac.simply.aso", "aso" },
+	{ "application/vnd.accpac.simply.imp", "imp" },
+	{ "application/vnd.acucobol", "acu" },
+	{ "application/vnd.acucorp", "atc" },
+	{ "application/vnd.adobe.air-application-installer-package+zip", "air" },
+	{ "application/vnd.adobe.formscentral.fcdt", "fcdt" },
+	{ "application/vnd.adobe.fxp", "fxp" },
+	{ "application/vnd.adobe.xdp+xml", "xdp" },
+	{ "application/vnd.adobe.xfdf", "xfdf" },
+	{ "application/vnd.ahead.space", "ahead" },
+	{ "application/vnd.airzip.filesecure.azf", "azf" },
+	{ "application/vnd.airzip.filesecure.azs", "azs" },
+	{ "application/vnd.amazon.ebook", "azw" },
+	{ "application/vnd.americandynamics.acc", "acc" },
+	{ "application/vnd.amiga.ami", "ami" },
+	{ "application/vnd.android.package-archive", "apk" },
+	{ "application/vnd.anser-web-certificate-issue-initiation", "cii" },
+	{ "application/vnd.anser-web-funds-transfer-initiation", "fti" },
+	{ "application/vnd.antix.game-component", "atx" },
+	{ "application/vnd.apple.installer+xml", "mpkg" },
+	{ "application/vnd.apple.mpegurl", "m3u8" },
+	{ "application/vnd.aristanetworks.swi", "swi" },
+	{ "application/vnd.astraea-software.iota", "iota" },
+	{ "application/vnd.audiograph", "aep" },
+	{ "application/vnd.blueice.multipass", "mpm" },
+	{ "application/vnd.bmi", "bmi" },
+	{ "application/vnd.businessobjects", "rep" },
+	{ "application/vnd.chemdraw+xml", "cdxml" },
+	{ "application/vnd.chipnuts.karaoke-mmd", "mmd" },
+	{ "application/vnd.cinderella", "cdy" },
+	{ "application/vnd.claymore", "cla" },
+	{ "application/vnd.cloanto.rp9", "rp9" },
+	{ "application/vnd.clonk.c4group", "c4g" },
+	{ "application/vnd.cluetrust.cartomobile-config", "c11amc" },
+	{ "application/vnd.cluetrust.cartomobile-config-pkg", "c11amz" },
+	{ "application/vnd.commonspace", "csp" },
+	{ "application/vnd.contact.cmsg", "cdbcmsg" },
+	{ "application/vnd.cosmocaller", "cmc" },
+	{ "application/vnd.crick.clicker", "clkx" },
+	{ "application/vnd.crick.clicker.keyboard", "clkk" },
+	{ "application/vnd.crick.clicker.palette", "clkp" },
+	{ "application/vnd.crick.clicker.template", "clkt" },
+	{ "application/vnd.crick.clicker.wordbank", "clkw" },
+	{ "application/vnd.criticaltools.wbs+xml", "wbs" },
+	{ "application/vnd.ctc-posml", "pml" },
+	{ "application/vnd.cups-ppd", "ppd" },
+	{ "application/vnd.curl.car", "car" },
+	{ "application/vnd.curl.pcurl", "pcurl" },
+	{ "application/vnd.dart", "dart" },
+	{ "application/vnd.data-vision.rdz", "rdz" },
+	{ "application/vnd.dece.data", "uvf" },
+	{ "application/vnd.dece.ttml+xml", "uvt" },
+	{ "application/vnd.dece.unspecified", "uvx" },
+	{ "application/vnd.dece.zip", "uvz" },
+	{ "application/vnd.denovo.fcselayout-link", "fe_launch" },	
+	{ "application/vnd.dna", "dna" },
+	{ "application/vnd.dolby.mlp", "mlp" },
+	{ "application/vnd.dpgraph", "dpg" },
+	{ "application/vnd.dreamfactory", "dfac" },
+	{ "application/vnd.ds-keypoint", "kpxx" },
+	{ "application/vnd.dvb.ait", "ait" },
+	{ "application/vnd.dvb.service", "svc" },
+	{ "application/vnd.dynageo", "geo" },
+	{ "application/vnd.ecowin.chart", "mag" },
+	{ "application/vnd.enliven", "nml" },
+	{ "application/vnd.epson.esf", "esf" },
+	{ "application/vnd.epson.msf", "msf" },
+	{ "application/vnd.epson.quickanime", "qam" },
+	{ "application/vnd.epson.salt", "slt" },
+	{ "application/vnd.epson.ssf", "ssf" },
+	{ "application/vnd.eszigno3+xml", "es3" },
+	{ "application/vnd.ezpix-album", "ez2" },
+	{ "application/vnd.ezpix-package", "ez3" },
+	{ "application/vnd.fdf", "fdf" },
+	{ "application/vnd.fdsn.mseed", "mseed" },
+	{ "application/vnd.fdsn.seed", "seed" },
+	{ "application/vnd.flographit", "gph" },
+	{ "application/vnd.fluxtime.clip", "ftc" },
+	{ "application/vnd.framemaker", "fm" },
+	{ "application/vnd.frogans.fnc", "fnc" },
+	{ "application/vnd.frogans.ltf", "ltf" },
+	{ "application/vnd.fsc.weblaunch", "fsc" },
+	{ "application/vnd.fujitsu.oasys", "oas" },
+	{ "application/vnd.fujitsu.oasys2", "oa2" },
+	{ "application/vnd.fujitsu.oasys3", "oa3" },
+	{ "application/vnd.fujitsu.oasysgp", "fg5" },
+	{ "application/vnd.fujitsu.oasysprs", "bh2" },
+	{ "application/vnd.fujixerox.ddd", "ddd" },
+	{ "application/vnd.fujixerox.docuworks", "xdw" },
+	{ "application/vnd.fujixerox.docuworks.binder", "xbd" },
+	{ "application/vnd.fuzzysheet", "fzs" },
+	{ "application/vnd.genomatix.tuxedo", "txd" },
+	{ "application/vnd.geogebra.file", "ggb" },
+	{ "application/vnd.geogebra.tool", "ggt" },
+	{ "application/vnd.geometry-explorer", "gex" },
+	{ "application/vnd.geonext", "gxt" },
+	{ "application/vnd.geoplan", "g2w" },
+	{ "application/vnd.geospace", "g3w" },
+	{ "application/vnd.gmx", "gmx" },
+	{ "application/vnd.google-earth.kml+xml", "kml" },
+	{ "application/vnd.google-earth.kmz", "kmz" },
+	{ "application/vnd.grafeq", "gqf" },
+	{ "application/vnd.groove-account", "gac" },
+	{ "application/vnd.groove-help", "ghf" },
+	{ "application/vnd.groove-identity-message", "gim" },
+	{ "application/vnd.groove-injector", "grv" },
+	{ "application/vnd.groove-tool-message", "gtm" },
+	{ "application/vnd.groove-tool-template", "tpl" },
+	{ "application/vnd.groove-vcard", "vcg" },
+	{ "application/vnd.hal+xml", "hal" },
+	{ "application/vnd.handheld-entertainment+xml", "zmm" },
+	{ "application/vnd.hbci", "hbci" },
+	{ "application/vnd.hhe.lesson-player", "les" },
+	{ "application/vnd.hp-hpgl", "hpgl" },
+	{ "application/vnd.hp-hpid", "hpid" },
+	{ "application/vnd.hp-hps", "hps" },
+	{ "application/vnd.hp-jlyt", "jlt" },
+	{ "application/vnd.hp-pcl", "pcl" },
+	{ "application/vnd.hp-pclxl", "pclxl" },
+	{ "application/vnd.hydrostatix.sof-data", "sfd-hdstx" },
+	{ "application/vnd.ibm.minipay", "mpy" },
+	{ "application/vnd.ibm.modcap", "afp" },
+	{ "application/vnd.ibm.rights-management", "irm" },
+	{ "application/vnd.ibm.secure-container", "sc" },
+	{ "application/vnd.iccprofile", "icc" },
+	{ "application/vnd.igloader", "igl" },
+	{ "application/vnd.immervision-ivp", "ivp" },
+	{ "application/vnd.immervision-ivu", "ivu" },
+	{ "application/vnd.insors.igm", "igm" },
+	{ "application/vnd.intercon.formnet", "xpw" },
+	{ "application/vnd.intergeo", "i2g" },
+	{ "application/vnd.intu.qbo", "qbo" },
+	{ "application/vnd.intu.qfx", "qfx" },
+	{ "application/vnd.ipunplugged.rcprofile", "rcprofile" },
+	{ "application/vnd.irepository.package+xml", "irp" },
+	{ "application/vnd.is-xpr", "xpr" },
+	{ "application/vnd.isac.fcs", "fcs" },
+	{ "application/vnd.jam", "jam" },
+	{ "application/vnd.jcp.javame.midlet-rms", "rms" },
+	{ "application/vnd.jisp", "jisp" },
+	{ "application/vnd.joost.joda-archive", "joda" },
+	{ "application/vnd.kahootz", "ktz" },
+	{ "application/vnd.kde.karbon", "karbon" },
+	{ "application/vnd.kde.kchart", "chrt" },
+	{ "application/vnd.kde.kformula", "kfo" },
+	{ "application/vnd.kde.kivio", "flw" },
+	{ "application/vnd.kde.kontour", "kon" },
+	{ "application/vnd.kde.kpresenter", "kpr" },
+	{ "application/vnd.kde.kspread", "ksp" },
+	{ "application/vnd.kde.kword", "kwd" },
+	{ "application/vnd.kenameaapp", "htke" },
+	{ "application/vnd.kidspiration", "kia" },
+	{ "application/vnd.kinar", "kne" },
+	{ "application/vnd.koan", "skp" },
+	{ "application/vnd.kodak-descriptor", "sse" },
+	{ "application/vnd.las.las+xml", "lasxml" },
+	{ "application/vnd.llamagraphics.life-balance.desktop", "lbd" },
+	{ "application/vnd.llamagraphics.life-balance.exchange+xml", "lbe" },
+	{ "application/vnd.lotus-1-2-3", "123" },
+	{ "application/vnd.lotus-approach", "apr" },
+	{ "application/vnd.lotus-freelance", "pre" },
+	{ "application/vnd.lotus-notes", "nsf" },
+	{ "application/vnd.lotus-organizer", "org" },
+	{ "application/vnd.lotus-screencam", "scm" },
+	{ "application/vnd.lotus-wordpro", "lwp" },
+	{ "application/vnd.macports.portpkg", "portpkg" },
+	{ "application/vnd.mcd", "mcd" },
+	{ "application/vnd.medcalcdata", "mc1" },
+	{ "application/vnd.mediastation.cdkey", "cdkey" },
+	{ "application/vnd.mfer", "mwf" },
+	{ "application/vnd.mfmp", "mfm" },
+	{ "application/vnd.micrografx.flo", "flo" },
+	{ "application/vnd.micrografx.igx", "igx" },
+	{ "application/vnd.mif", "mif" },
+	{ "application/vnd.mobius.daf", "daf" },
+	{ "application/vnd.mobius.dis", "dis" },
+	{ "application/vnd.mobius.mbk", "mbk" },
+	{ "application/vnd.mobius.mqy", "mqy" },
+	{ "application/vnd.mobius.msl", "msl" },
+	{ "application/vnd.mobius.plc", "plc" },
+	{ "application/vnd.mobius.txf", "txf" },
+	{ "application/vnd.mophun.application", "mpn" },
+	{ "application/vnd.mophun.certificate", "mpc" },
+	{ "application/vnd.mozilla.xul+xml", "xul" },
+	{ "application/vnd.ms-artgalry", "cil" },
+	{ "application/vnd.ms-cab-compressed", "cab" },
+	{ "application/vnd.ms-excel", "xls" },
+	{ "application/vnd.ms-excel.addin.macroenabled.12", "xlam" },
+	{ "application/vnd.ms-excel.sheet.binary.macroenabled.12", "xlsb" },
+	{ "application/vnd.ms-excel.sheet.macroenabled.12", "xlsm" },
+	{ "application/vnd.ms-excel.template.macroenabled.12", "xltm" },
+	{ "application/vnd.ms-fontobject", "eot" },
+	{ "application/vnd.ms-htmlhelp", "chm" },
+	{ "application/vnd.ms-ims", "ims" },
+	{ "application/vnd.ms-lrm", "lrm" },
+	{ "application/vnd.ms-officetheme", "thmx" },
+	{ "application/vnd.ms-pki.seccat", "cat" },
+	{ "application/vnd.ms-pki.stl", "stl" },
+	{ "application/vnd.ms-powerpoint", "ppt" },
+	{ "application/vnd.ms-powerpoint.addin.macroenabled.12", "ppam" },
+	{ "application/vnd.ms-powerpoint.presentation.macroenabled.12", "pptm" },
+	{ "application/vnd.ms-powerpoint.slide.macroenabled.12", "sldm" },
+	{ "application/vnd.ms-powerpoint.slideshow.macroenabled.12", "ppsm" },
+	{ "application/vnd.ms-powerpoint.template.macroenabled.12", "potm" },
+	{ "application/vnd.ms-project", "mpp" },
+	{ "application/vnd.ms-word.document.macroenabled.12", "docm" },
+	{ "application/vnd.ms-word.template.macroenabled.12", "dotm" },
+	{ "application/vnd.ms-works", "wps" },
+	{ "application/vnd.ms-wpl", "wpl" },
+	{ "application/vnd.ms-xpsdocument", "xps" },
+	{ "application/vnd.mseq", "mseq" },
+	{ "application/vnd.musician", "mus" },
+	{ "application/vnd.muvee.style", "msty" },
+	{ "application/vnd.mynfc", "taglet" },
+	{ "application/vnd.neurolanguage.nlu", "nlu" },
+	{ "application/vnd.nitf", "ntf" },
+	{ "application/vnd.noblenet-directory", "nnd" },
+	{ "application/vnd.noblenet-sealer", "nns" },
+	{ "application/vnd.noblenet-web", "nnw" },
+	{ "application/vnd.nokia.n-gage.data", "ngdat" },
+	{ "application/vnd.nokia.n-gage.symbian.install", "n-gage" },
+	{ "application/vnd.nokia.radio-preset", "rpst" },
+	{ "application/vnd.nokia.radio-presets", "rpss" },
+	{ "application/vnd.novadigm.edm", "edm" },
+	{ "application/vnd.novadigm.edx", "edx" },
+	{ "application/vnd.novadigm.ext", "ext" },
+	{ "application/vnd.oasis.opendocument.chart", "odc" },
+	{ "application/vnd.oasis.opendocument.chart-template", "otc" },
+	{ "application/vnd.oasis.opendocument.database", "odb" },
+	{ "application/vnd.oasis.opendocument.formula", "odf" },
+	{ "application/vnd.oasis.opendocument.formula-template", "odft" },
+	{ "application/vnd.oasis.opendocument.graphics", "odg" },
+	{ "application/vnd.oasis.opendocument.graphics-template", "otg" },
+	{ "application/vnd.oasis.opendocument.image", "odi" },
+	{ "application/vnd.oasis.opendocument.image-template", "oti" },
+	{ "application/vnd.oasis.opendocument.presentation", "odp" },
+	{ "application/vnd.oasis.opendocument.presentation-template", "otp" },
+	{ "application/vnd.oasis.opendocument.spreadsheet", "ods" },
+	{ "application/vnd.oasis.opendocument.spreadsheet-template", "ots" },
+	{ "application/vnd.oasis.opendocument.text", "odt" },
+	{ "application/vnd.oasis.opendocument.text-master", "odm" },
+	{ "application/vnd.oasis.opendocument.text-template", "ott" },
+	{ "application/vnd.oasis.opendocument.text-web", "oth" },
+	{ "application/vnd.olpc-sugar", "xo" },
+	{ "application/vnd.oma.dd2+xml", "dd2" },
+	{ "application/vnd.openofficeorg.extension", "oxt" },
+	{ "application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx" },
+	{ "application/vnd.openxmlformats-officedocument.presentationml.slide", "sldx" },
+	{ "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "ppsx" },
+	{ "application/vnd.openxmlformats-officedocument.presentationml.template", "potx" },
+	{ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx" },
+	{ "application/vnd.openxmlformats-officedocument.spreadsheetml.template", "xltx" },
+	{ "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx" },
+	{ "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "dotx" },
+	{ "application/vnd.osgeo.mapguide.package", "mgp" },
+	{ "application/vnd.osgi.dp", "dp" },
+	{ "application/vnd.osgi.subsystem", "esa" },
+	{ "application/vnd.palm", "pdb" },
+	{ "application/vnd.pawaafile", "paw" },
+	{ "application/vnd.pg.format", "str" },
+	{ "application/vnd.pg.osasli", "ei6" },
+	{ "application/vnd.picsel", "efif" },
+	{ "application/vnd.pmi.widget", "wg" },
+	{ "application/vnd.pocketlearn", "plf" },
+	{ "application/vnd.powerbuilder6", "pbd" },
+	{ "application/vnd.previewsystems.box", "box" },
+	{ "application/vnd.proteus.magazine", "mgz" },
+	{ "application/vnd.publishare-delta-tree", "qps" },
+	{ "application/vnd.pvi.ptid1", "ptid" },
+	{ "application/vnd.quark.quarkxpress", "qxd" },
+	{ "application/vnd.realvnc.bed", "bed" },
+	{ "application/vnd.recordare.musicxml", "mxl" },
+	{ "application/vnd.recordare.musicxml+xml", "musicxml" },
+	{ "application/vnd.rig.cryptonote", "cryptonote" },
+	{ "application/vnd.rim.cod", "cod" },
+	{ "application/vnd.rn-realmedia", "rm" },
+	{ "application/vnd.rn-realmedia-vbr", "rmvb" },
+	{ "application/vnd.route66.link66+xml", "link66" },
+	{ "application/vnd.sailingtracker.track", "st" },
+	{ "application/vnd.seemail", "see" },
+	{ "application/vnd.sema", "sema" },
+	{ "application/vnd.semd", "semd" },
+	{ "application/vnd.semf", "semf" },
+	{ "application/vnd.shana.informed.formdata", "ifm" },
+	{ "application/vnd.shana.informed.formtemplate", "itp" },
+	{ "application/vnd.shana.informed.interchange", "iif" },
+	{ "application/vnd.shana.informed.package", "ipk" },
+	{ "application/vnd.simtech-mindmapper", "twd" },
+	{ "application/vnd.smaf", "mmf" },
+	{ "application/vnd.smart.teacher", "teacher" },
+	{ "application/vnd.solent.sdkm+xml", "sdkm" },
+	{ "application/vnd.spotfire.dxp", "dxp" },
+	{ "application/vnd.spotfire.sfs", "sfs" },
+	{ "application/vnd.stardivision.calc", "sdc" },
+	{ "application/vnd.stardivision.draw", "sda" },
+	{ "application/vnd.stardivision.impress", "sdd" },
+	{ "application/vnd.stardivision.math", "smf" },
+	{ "application/vnd.stardivision.writer", "sdw" },
+	{ "application/vnd.stardivision.writer-global", "sgl" },
+	{ "application/vnd.stepmania.package", "smzip" },
+	{ "application/vnd.stepmania.stepchart", "sm" },
+	{ "application/vnd.sun.xml.calc", "sxc" },
+	{ "application/vnd.sun.xml.calc.template", "stc" },
+	{ "application/vnd.sun.xml.draw", "sxd" },
+	{ "application/vnd.sun.xml.draw.template", "std" },
+	{ "application/vnd.sun.xml.impress", "sxi" },
+	{ "application/vnd.sun.xml.impress.template", "sti" },
+	{ "application/vnd.sun.xml.math", "sxm" },
+	{ "application/vnd.sun.xml.writer", "sxw" },
+	{ "application/vnd.sun.xml.writer.global", "sxg" },
+	{ "application/vnd.sun.xml.writer.template", "stw" },
+	{ "application/vnd.sus-calendar", "sus" },
+	{ "application/vnd.svd", "svd" },
+	{ "application/vnd.symbian.install", "sis" },
+	{ "application/vnd.syncml+xml", "xsm" },
+	{ "application/vnd.syncml.dm+wbxml", "bdm" },
+	{ "application/vnd.syncml.dm+xml", "xdm" },
+	{ "application/vnd.tao.intent-module-archive", "tao" },
+	{ "application/vnd.tcpdump.pcap", "pcap" },
+	{ "application/vnd.tmobile-livetv", "tmo" },
+	{ "application/vnd.trid.tpt", "tpt" },
+	{ "application/vnd.triscape.mxs", "mxs" },
+	{ "application/vnd.trueapp", "tra" },
+	{ "application/vnd.ufdl", "ufd" },
+	{ "application/vnd.uiq.theme", "utz" },
+	{ "application/vnd.umajin", "umj" },
+	{ "application/vnd.unity", "unityweb" },
+	{ "application/vnd.uoml+xml", "uoml" },
+	{ "application/vnd.vcx", "vcx" },
+	{ "application/vnd.visio", "vsd" },
+	{ "application/vnd.visionary", "vis" },
+	{ "application/vnd.vsf", "vsf" },
+	{ "application/vnd.wap.wbxml", "wbxml" },
+	{ "application/vnd.wap.wmlc", "wmlc" },
+	{ "application/vnd.wap.wmlscriptc", "wmlsc" },
+	{ "application/vnd.webturbo", "wtb" },
+	{ "application/vnd.wolfram.player", "nbp" },
+	{ "application/vnd.wordperfect", "wpd" },
+	{ "application/vnd.wqd", "wqd" },
+	{ "application/vnd.wt.stf", "stf" },
+	{ "application/vnd.xara", "xar" },
+	{ "application/vnd.xfdl", "xfdl" },
+	{ "application/vnd.yamaha.hv-dic", "hvd" },
+	{ "application/vnd.yamaha.hv-script", "hvs" },
+	{ "application/vnd.yamaha.hv-voice", "hvp" },
+	{ "application/vnd.yamaha.openscoreformat", "osf" },
+	{ "application/vnd.yamaha.openscoreformat.osfpvg+xml", "osfpvg" },
+	{ "application/vnd.yamaha.smaf-audio", "saf" },
+	{ "application/vnd.yamaha.smaf-phrase", "spf" },
+	{ "application/vnd.yellowriver-custom-menu", "cmp" },
+	{ "application/vnd.zul", "zir" },
+	{ "application/vnd.zzazz.deck+xml", "zaz" },
+	{ "application/voicexml+xml", "vxml" },
+	{ "application/widget", "wgt" },
+	{ "application/winhlp", "hlp" },
+	{ "application/wsdl+xml", "wsdl" },
+	{ "application/wspolicy+xml", "wspolicy" },
+	{ "application/x-7z-compressed", "7z" },
+	{ "application/x-abiword", "abw" },
+	{ "application/x-ace-compressed", "ace" },
+	{ "application/x-apple-diskimage", "dmg" },
+	{ "application/x-authorware-bin", "aab" },
+	{ "application/x-authorware-map", "aam" },
+	{ "application/x-authorware-seg", "aas" },
+	{ "application/x-bcpio", "bcpio" },
+	{ "application/x-bittorrent", "torrent" },
+	{ "application/x-blorb", "blb" },
+	{ "application/x-bzip", "bz" },
+	{ "application/x-bzip2", "bz2" },
+	{ "application/x-cbr", "cbr" },
+	{ "application/x-cdlink", "vcd" },
+	{ "application/x-cfs-compressed", "cfs" },
+	{ "application/x-chat", "chat" },
+	{ "application/x-chess-pgn", "pgn" },
+	{ "application/x-conference", "nsc" },
+	{ "application/x-cpio", "cpio" },
+	{ "application/x-csh", "csh" },
+	{ "application/x-debian-package", "deb" },
+	{ "application/x-dgc-compressed", "dgc" },
+	{ "application/x-director", "dir" },
+	{ "application/x-doom", "wad" },
+	{ "application/x-dtbncx+xml", "ncx" },
+	{ "application/x-dtbook+xml", "dtb" },
+	{ "application/x-dtbresource+xml", "res" },
+	{ "application/x-dvi", "dvi" },
+	{ "application/x-envoy", "evy" },
+	{ "application/x-eva", "eva" },
+	{ "application/x-font-bdf", "bdf" },
+	{ "application/x-font-ghostscript", "gsf" },
+	{ "application/x-font-linux-psf", "psf" },
+	{ "application/x-font-otf", "otf" },
+	{ "application/x-font-pcf", "pcf" },
+	{ "application/x-font-snf", "snf" },
+	{ "application/x-font-ttf", "ttf" },
+	{ "application/x-font-type1", "pfa" },
+	{ "application/font-woff", "woff" },
+	{ "application/x-freearc", "arc" },
+	{ "application/x-futuresplash", "spl" },
+	{ "application/x-gca-compressed", "gca" },
+	{ "application/x-glulx", "ulx" },
+	{ "application/x-gnumeric", "gnumeric" },
+	{ "application/x-gramps-xml", "gramps" },
+	{ "application/x-gtar", "gtar" },
+	{ "application/x-hdf", "hdf" },
+	{ "application/x-install-instructions", "install" },
+	{ "application/x-iso9660-image", "iso" },
+	{ "application/x-java-jnlp-file", "jnlp" },
+	{ "application/x-latex", "latex" },
+	{ "application/x-lzh-compressed", "lzh" },
+	{ "application/x-mie", "mie" },
+	{ "application/x-mobipocket-ebook", "prc" },
+	{ "application/x-ms-application", "application" },
+	{ "application/x-ms-shortcut", "lnk" },
+	{ "application/x-ms-wmd", "wmd" },
+	{ "application/x-ms-wmz", "wmz" },
+	{ "application/x-ms-xbap", "xbap" },
+	{ "application/x-msaccess", "mdb" },
+	{ "application/x-msbinder", "obd" },
+	{ "application/x-mscardfile", "crd" },
+	{ "application/x-msclip", "clp" },
+	{ "application/x-msdownload", "exe" },
+	{ "application/x-msmediaview", "mvb" },
+	{ "application/x-msmetafile", "wmf" },
+	{ "application/x-msmoney", "mny" },
+	{ "application/x-mspublisher", "pub" },
+	{ "application/x-msschedule", "scd" },
+	{ "application/x-msterminal", "trm" },
+	{ "application/x-mswrite", "wri" },
+	{ "application/x-netcdf", "nc" },
+	{ "application/x-nzb", "nzb" },
+	{ "application/x-pkcs12", "p12" },
+	{ "application/x-pkcs7-certificates", "p7b" },
+	{ "application/x-pkcs7-certreqresp", "p7r" },
+	{ "application/x-rar-compressed", "rar" },
+	{ "application/x-research-info-systems", "ris" },
+	{ "application/x-sh", "sh" },
+	{ "application/x-shar", "shar" },
+	{ "application/x-shockwave-flash", "swf" },
+	{ "application/x-silverlight-app", "xap" },
+	{ "application/x-sql", "sql" },
+	{ "application/x-stuffit", "sit" },
+	{ "application/x-stuffitx", "sitx" },
+	{ "application/x-subrip", "srt" },
+	{ "application/x-sv4cpio", "sv4cpio" },
+	{ "application/x-sv4crc", "sv4crc" },
+	{ "application/x-t3vm-image", "t3" },
+	{ "application/x-tads", "gam" },
+	{ "application/x-tar", "tar" },
+	{ "application/x-tcl", "tcl" },
+	{ "application/x-tex", "tex" },
+	{ "application/x-tex-tfm", "tfm" },
+	{ "application/x-texinfo", "texinfo" },
+	{ "application/x-tgif", "obj" },
+	{ "application/x-ustar", "ustar" },
+	{ "application/x-wais-source", "src" },
+	{ "application/x-x509-ca-cert", "der" },
+	{ "application/x-xfig", "fig" },
+	{ "application/x-xliff+xml", "xlf" },
+	{ "application/x-xpinstall", "xpi" },
+	{ "application/x-xz", "xz" },
+	{ "application/x-zmachine", "z1" },
+	{ "application/xaml+xml", "xaml" },
+	{ "application/xcap-diff+xml", "xdf" },
+	{ "application/xenc+xml", "xenc" },
+	{ "application/xhtml+xml", "xhtml" },
+	{ "application/xml", "xml" },
+	{ "application/xml-dtd", "dtd" },
+	{ "application/xop+xml", "xop" },
+	{ "application/xproc+xml", "xpl" },
+	{ "application/xslt+xml", "xslt" },
+	{ "application/xspf+xml", "xspf" },
+	{ "application/xv+xml", "mxml" },
+	{ "application/yang", "yang" },
+	{ "application/yin+xml", "yin" },
+	{ "application/zip", "zip" },
+	{ "audio/adpcm", "adp" },
+	{ "audio/basic", "au" },
+	{ "audio/midi", "mid" },
+	{ "audio/mp4", "mp4a" },
+	{ "audio/mpeg", "mpga" },
+	{ "audio/ogg", "oga" },
+	{ "audio/s3m", "s3m" },
+	{ "audio/silk", "sil" },
+	{ "audio/vnd.dece.audio", "uva" },
+	{ "audio/vnd.digital-winds", "eol" },
+	{ "audio/vnd.dra", "dra" },
+	{ "audio/vnd.dts", "dts" },
+	{ "audio/vnd.dts.hd", "dtshd" },
+	{ "audio/vnd.lucent.voice", "lvp" },
+	{ "audio/vnd.ms-playready.media.pya", "pya" },
+	{ "audio/vnd.nuera.ecelp4800", "ecelp4800" },
+	{ "audio/vnd.nuera.ecelp7470", "ecelp7470" },
+	{ "audio/vnd.nuera.ecelp9600", "ecelp9600" },
+	{ "audio/vnd.rip", "rip" },
+	{ "audio/webm", "weba" },
+	{ "audio/x-aac", "aac" },
+	{ "audio/x-aiff", "aif" },
+	{ "audio/x-caf", "caf" },
+	{ "audio/x-flac", "flac" },
+	{ "audio/x-matroska", "mka" },
+	{ "audio/x-mpegurl", "m3u" },
+	{ "audio/x-ms-wax", "wax" },
+	{ "audio/x-ms-wma", "wma" },
+	{ "audio/x-pn-realaudio", "ram" },
+	{ "audio/x-pn-realaudio-plugin", "rmp" },
+	{ "audio/x-wav", "wav" },
+	{ "audio/xm", "xm" },
+	{ "chemical/x-cdx", "cdx" },
+	{ "chemical/x-cif", "cif" },
+	{ "chemical/x-cmdf", "cmdf" },
+	{ "chemical/x-cml", "cml" },
+	{ "chemical/x-csml", "csml" },
+	{ "chemical/x-xyz", "xyz" },
+	{ "image/bmp", "bmp" },
+	{ "image/cgm", "cgm" },
+	{ "image/g3fax", "g3" },
+	{ "image/gif", "gif" },
+	{ "image/ief", "ief" },
+	{ "image/jpg", "jpg" },
+	{ "image/jpeg", "jpeg" },
+	{ "image/ktx", "ktx" },
+	{ "image/png", "png" },
+	{ "image/prs.btif", "btif" },
+	{ "image/sgi", "sgi" },
+	{ "image/svg+xml", "svg" },
+	{ "image/tiff", "tiff" },
+	{ "image/vnd.adobe.photoshop", "psd" },
+	{ "image/vnd.dece.graphic", "uvi" },
+	{ "image/vnd.dvb.subtitle", "sub" },
+	{ "image/vnd.djvu", "djvu" },
+	{ "image/vnd.dwg", "dwg" },
+	{ "image/vnd.dxf", "dxf" },
+	{ "image/vnd.fastbidsheet", "fbs" },
+	{ "image/vnd.fpx", "fpx" },
+	{ "image/vnd.fst", "fst" },
+	{ "image/vnd.fujixerox.edmics-mmr", "mmr" },
+	{ "image/vnd.fujixerox.edmics-rlc", "rlc" },
+	{ "image/vnd.ms-modi", "mdi" },
+	{ "image/vnd.ms-photo", "wdp" },
+	{ "image/vnd.net-fpx", "npx" },
+	{ "image/vnd.wap.wbmp", "wbmp" },
+	{ "image/vnd.xiff", "xif" },
+	{ "image/webp", "webp" },
+	{ "image/x-3ds", "3ds" },
+	{ "image/x-cmu-raster", "ras" },
+	{ "image/x-cmx", "cmx" },
+	{ "image/x-freehand", "fh" },
+	{ "image/x-icon", "ico" },
+	{ "image/x-mrsid-image", "sid" },
+	{ "image/x-pcx", "pcx" },
+	{ "image/x-pict", "pic" },
+	{ "image/x-portable-anymap", "pnm" },
+	{ "image/x-portable-bitmap", "pbm" },
+	{ "image/x-portable-graymap", "pgm" },
+	{ "image/x-portable-pixmap", "ppm" },
+	{ "image/x-rgb", "rgb" },
+	{ "image/x-tga", "tga" },
+	{ "image/x-xbitmap", "xbm" },
+	{ "image/x-xpixmap", "xpm" },
+	{ "image/x-xwindowdump", "xwd" },
+	{ "message/rfc822", "eml" },
+	{ "model/iges", "igs" },
+	{ "model/mesh", "msh" },
+	{ "model/vnd.collada+xml", "dae" },
+	{ "model/vnd.dwf", "dwf" },
+	{ "model/vnd.gdl", "gdl" },
+	{ "model/vnd.gtw", "gtw" },
+	{ "model/vnd.mts", "mts" },
+	{ "model/vnd.vtu", "vtu" },
+	{ "model/vrml", "wrl" },
+	{ "model/x3d+binary", "x3db" },
+	{ "model/x3d+vrml", "x3dv" },
+	{ "model/x3d+xml", "x3d" },
+	{ "text/cache-manifest", "appcache" },
+	{ "text/calendar", "ics" },
+	{ "text/css", "css" },
+	{ "text/csv", "csv" },
+	{ "text/html", "html" },
+	{ "text/n3", "n3" },
+	{ "text/plain", "txt" },
+	{ "text/prs.lines.tag", "dsc" },
+	{ "text/richtext", "rtx" },
+	{ "text/sgml", "sgml" },
+	{ "text/tab-separated-values", "tsv" },
+	{ "text/troff", "t" },
+	{ "text/turtle", "ttl" },
+	{ "text/uri-list", "uri" },
+	{ "text/vcard", "vcard" },
+	{ "text/vnd.curl", "curl" },
+	{ "text/vnd.curl.dcurl", "dcurl" },
+	{ "text/vnd.curl.scurl", "scurl" },
+	{ "text/vnd.curl.mcurl", "mcurl" },
+	{ "text/vnd.dvb.subtitle", "sub" },
+	{ "text/vnd.fly", "fly" },
+	{ "text/vnd.fmi.flexstor", "flx" },
+	{ "text/vnd.graphviz", "gv" },
+	{ "text/vnd.in3d.3dml", "3dml" },
+	{ "text/vnd.in3d.spot", "spot" },
+	{ "text/vnd.sun.j2me.app-descriptor", "jad" },
+	{ "text/vnd.wap.wml", "wml" },
+	{ "text/vnd.wap.wmlscript", "wmls" },
+	{ "text/x-asm", "s" },
+	{ "text/x-c", "c" },
+	{ "text/x-fortran", "f" },
+	{ "text/x-java-source", "java" },
+	{ "text/x-opml", "opml" },
+	{ "text/x-pascal", "p" },
+	{ "text/x-nfo", "nfo" },
+	{ "text/x-setext", "etx" },
+	{ "text/x-sfv", "sfv" },
+	{ "text/x-uuencode", "uu" },
+	{ "text/x-vcalendar", "vcs" },
+	{ "text/x-vcard", "vcf" },
+	{ "text/xml", "xml" },
+	{ "video/3gpp", "3gp" },
+	{ "video/3gpp2", "3g2" },
+	{ "video/h261", "h261" },
+	{ "video/h263", "h263" },
+	{ "video/h264", "h264" },
+	{ "video/jpeg", "jpgv" },
+	{ "video/jpm", "jpm" },
+	{ "video/mj2", "mj2" },
+	{ "video/mp4", "mp4" },
+	{ "video/mpeg", "mpeg" },
+	{ "video/ogg", "ogv" },
+	{ "video/quicktime", "qt" },
+	{ "video/vnd.dece.hd", "uvh" },
+	{ "video/vnd.dece.mobile", "uvm" },
+	{ "video/vnd.dece.pd", "uvp" },
+	{ "video/vnd.dece.sd", "uvs" },
+	{ "video/vnd.dece.video", "uvv" },
+	{ "video/vnd.dvb.file", "dvb" },
+	{ "video/vnd.fvt", "fvt" },
+	{ "video/vnd.mpegurl", "mxu" },
+	{ "video/vnd.ms-playready.media.pyv", "pyv" },
+	{ "video/vnd.uvvu.mp4", "uvu" },
+	{ "video/vnd.vivo", "viv" },
+	{ "video/webm", "webm" },
+	{ "video/x-f4v", "f4v" },
+	{ "video/x-fli", "fli" },
+	{ "video/x-flv", "flv" },
+	{ "video/x-m4v", "m4v" },
+	{ "video/x-matroska", "mkv" },
+	{ "video/x-mng", "mng" },
+	{ "video/x-ms-asf", "asf" },
+	{ "video/x-ms-vob", "vob" },
+	{ "video/x-ms-wm", "wm" },
+	{ "video/x-ms-wmv", "wmv" },
+	{ "video/x-ms-wmx", "wmx" },
+	{ "video/x-ms-wvx", "wvx" },
+	{ "video/x-msvideo", "avi" },
+	{ "video/x-sgi-movie", "movie" },
+	{ "video/x-smv", "smv" },
+	{ "x-conference/x-cooltalk", "ice" }
+};
+
+/**
+* Obtain default file extension for a give MIME type
+*
+* @param mimeType a MIME type (lowercase string), e.g. "image/png"
+* @param extension a buffer in which to store the file extension; the default value is "txt" if no extension is found
+* @param length the size of the buffer extension
+* @return true if a file extension is found for the given MIME type, otherwise false
+*/
+static bool getFileExtension(const char* mimeType, char* extension, size_t length) {
+
+	bool hasExt = false;
+	strncpy(extension, "txt", length);
+	
+	if (mimeType != NULL) { 	
+		for (int i = 0; i < NUM_MIME_TYPES; i++) {					
+			if 	(strncmp(mimeType, MIME[i][M_Type], strlen(MIME[i][M_Type])) == 0) {
+				strncpy(extension, MIME[i][M_Extension], length);
+				hasExt = true;
+				break;				
+			}		
+		}
+		if (hasExt == false && strncmp(mimeType, "image/", 6) == 0) {
+			strncpy(extension, strstr(mimeType, "/") + 1, length);
+		}	
+	}	
+	return hasExt;
+}
+
+/**
+* Obtain default file extension for a give MIME type
+*
+* @param mimeType a MIME type (lowercase string), e.g. "image/png"
+* @param hasExt the value of this pointer is set to true if a default file extension is found, otherwise false
+* @return a map with name "extension" and value set to file extension, e.g. "png"; if not found the default value is "txt" 
+*/
+static map* getFileExtensionMap(const char* mimeType, bool* hasExt) {
+  map* ext = createMap("extension", "txt");
+  *hasExt = false;
+	
+  if (mimeType != NULL) { 	
+    for (int i = 0; i < NUM_MIME_TYPES; i++) {			
+      if(strncmp(mimeType, MIME[i][M_Type], strlen(MIME[i][M_Type])) == 0) {
+	free(ext->value);
+	ext->value = zStrdup(MIME[i][M_Extension]);
+	*hasExt = true;
+	break;				
+      }	
+    }
+    if (*hasExt == false && strncmp(mimeType, "image/", 6) == 0) {
+      free(ext->value);
+      ext->value = zStrdup(strstr(mimeType, "/") + 1);
+    }
+  }	
+  return ext;
+}
+
+static int isGeographic(const char* mimeType){
+  const char* imageMimeType[4]={
+    "image/tiff",
+    "image/png",
+    "image/jpeg",
+    "application/vnd.google-earth.kmz"
+  };
+  const char* vectorMimeType[5]={
+    "text/xml",
+    "application/json",
+    "application/gml+xml",
+    "application/zip",
+    "application/vnd.google-earth.kml+xml"
+  };
+  int i=0;
+  for(;i<4;i++){
+    if(strncmp(imageMimeType[i],mimeType,strlen(imageMimeType[i]))==0)
+      return 1;
+  }
+  i=0;
+  for(;i<5;i++){
+    if(strncmp(vectorMimeType[i],mimeType,strlen(vectorMimeType[i]))==0)
+      return 2;
+  }
+  return -1;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/nmake.opt
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/nmake.opt	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/nmake.opt	(revision 942)
@@ -0,0 +1,115 @@
+PROGRAMNAME=zoo_loader.cgi
+LIBZOO_SERVICE=libzoo_service.dll
+
+CC=cl $(CFLAGS)
+CPP=cl /TP $(CFLAGS)
+
+#PY_DIR=C:/"Program Files (x86)"/Python3.3
+#PY_LIB=$(PY_DIR)/libs/python33.lib
+
+#PHP_DIR=C:\php-sdk\phpdev\vc12\x86\php-5.5.10-src
+#PHP_LIB=$(PHP_DIR)\Release_TS\php5embed.lib
+#PHP7_DIR=C:\php-sdk\phpdev\vc14\x64\php-7.0.9-src
+
+#!IF DEFINED(MS_DIR)
+#MS_BASE=$(MS_DIR)
+#!INCLUDE $(MS_DIR)\nmake.opt
+#!ENDIF
+
+!IFDEF JS_DIR
+JS_CFLAGS=-DXP_WIN -DUSE_JS -I$(JS_DIR) -I$(JS_DIR)/dist/include
+JS_LDFLAGS=$(JS_DIR)/mozjs185-1.0.lib
+JS_FILE=service_internal_js.obj
+!ENDIF
+
+!IFDEF JS_CFG
+#!INCLUDE $(JS_CFG)
+#JS_CFLAGS=-DXP_WIN -DUSE_JS $(JS_CONFIG_CFLAGS)
+#JS_LDFLAGS=$(JS_CONFIG_LDFLAGS)
+JS_CFLAGS=-DXP_WIN -DUSE_JS -include c:/mozilla-build/msys/local/include/mozjs-24/js/RequiredDefines.h -Ic:/mozilla-build/msys/local/include/mozjs-24 -IC:/mozilla-build/msys/local/include
+JS_LDFLAGS=c:/mozilla-build/msys/local/lib/mozjs-24.lib  kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib psapi.lib 
+JS_FILE=service_internal_js.obj
+!ENDIF
+
+!IFDEF MS_DIR
+MS_CFLAGS=-DUSE_MS -DHAVE_STRCASECMP -DHAVE_STRNCASECMP -I$(MS_DIR)/include
+MS_LDFLAGS=$(MS_DIR)/lib/mapserver_i.lib
+MS_FILE=service_internal_ms.obj
+!ENDIF
+
+!IFDEF JDK_DIR
+JAVA_CFLAGS=-DJAVA7 -DUSE_JAVA -I"$(JDK_DIR)\include" -I"$(JDK_DIR)\include\win32"
+JAVA_LDFLAGS="$(JDK_DIR)/lib/jvm.lib"
+JAVA_FILE=service_internal_java.obj
+!ENDIF
+
+!IFDEF PY_DIR
+PY_CFLAGS=-DUSE_PYTHON -I$(PY_DIR)\Include -I$(PY_DIR)\PC
+PY_LDFLAGS=$(PY_LIBRARY) 
+PY_FILE=service_internal_python.obj
+!ENDIF
+
+!IFDEF PHP_DIR
+PHP_LIB=$(PHP_DIR)\Release_TS\php5embed.lib
+PHP_CURL_LIB=$(PHP_DIR)\Release_TS\php_curl.lib
+PHP_SRC=$(PHP_DIR)
+PHP_LDFLAGS=$(PHP_LIB) $(PHP_CURL_LIB)
+PHP_FILE=service_internal_php.obj
+PHP_CFLAGS=-I$(PHP_SRC) -I$(PHP_SRC)\Zend -I$(PHP_SRC)\TSRM /DPHP_WIN32 /DZEND_WIN32 /DWIN32 /D_USE_32BIT_TIME_T /DZTS /DUSE_PHP
+!ELSE IFDEF PHP7_DIR
+PHP_LIB=$(PHP7_DIR)\x64\Release_TS\php7embed.lib
+PHP_CURL_LIB=
+PHP_LDFLAGS=$(PHP_LIB) $(PHP_CURL_LIB)
+PHP_FILE=service_internal_php7.obj
+PHP_CFLAGS=-I$(PHP7_DIR) -I$(PHP7_DIR)\Zend -I$(PHP7_DIR)\TSRM /DPHP_WIN32 /DZEND_WIN32 /DWIN32 /DZTS /DUSE_PHP # /D_USE_32BIT_TIME_T
+!ENDIF
+
+!IFDEF RUBY_DIR
+#################################################################
+#RUBY 1.8.7
+ZRUBY_VERSION=1
+RUBY_CFLAGS=-DZRUBY_VERSION=1 -DUSE_RUBY -I$(RUBY_DIR) 
+RUBY_LDFLAGS="$(RUBY_DIR)/msvcr100-ruby18.lib"
+#################################################################
+#RUBY 1.9.3
+#ZRUBY_VERSION=2
+#RUBY_CFLAGS=-DZRUBY_VERSION=2 -DUSE_RUBY -I$(RUBY_DIR)/include/ruby-1.9.1/ -I$(RUBY_DIR)/include/ruby-1.9.1/i386-mswin32_100
+#RUBY_LDFLAGS="$(RUBY_DIR)/lib/msvcr100-ruby191.lib"
+#RUBY 2.1.0
+#ZRUBY_VERSION=2
+#RUBY_CFLAGS=-DZRUBY_VERSION=2 -DUSE_RUBY -I$(RUBY_DIR)/include/ruby-2.1.0/ -I$(RUBY_DIR)/include/ruby-2.1.0/i386-mswin32_100
+#RUBY_LDFLAGS="$(RUBY_DIR)/lib/msvcr100-ruby210.lib"
+#################################################################
+RUBY_FILE=service_internal_ruby.obj
+!IFDEF MS_DIR
+RUBY_CFLAGS=$(RUBY_CFLAGS) -DHAVE_ROUND
+!ENDIF
+!ENDIF
+
+!IFDEF MONO_DIR
+MONO_CFLAGS=-DUSE_MONO -I"$(MONO_DIR)"\msvc -I"$(MONO_DIR)"\msvc\include -I"$(MONO_DIR)"
+MONO_LDFLAGS=/LIBPATH:"$(MONO_DIR)/msvc/build/sgen/x64/lib/Release" mono-2.0-sgen.lib
+MONO_FILE=service_internal_mono.obj
+!ENDIF
+
+!IFNDEF ZOOK_DIR
+ZOOK_DIR=.
+!ENDIF
+
+TROOT=$(ZOOK_DIR)
+TPATH=$(ZOOK_DIR)\..\..\..\tools
+LIBINTL_CPATH=$(ZOOK_DIR)\..\..\..\
+PYTHON_CPATH=$(PY_DIR)
+
+!IFDEF DB
+DB_FLAGS=-DRELY_ON_DB
+!ENDIF
+
+!IFDEF WIN32_DEBUG
+WIN32_DBG=-DWIN32_DEBUG
+!ENDIF
+
+CFLAGS=$(MONO_CFLAGS) $(WIN32_DBG) $(DB_FLAGS) $(MS_DEFS) $(INCLUDES) $(CFLAGS1) /nologo /MD /W3 /EHsc /Ox /D_CRT_SECURE_NO_WARNINGS /DWIN32 /DPROGRAMNAME=\"$(PROGRAMNAME)\" $(CJFLAGS) -I$(ZOOK_DIR) $(RUBY_CFLAGS) -I./ $(JAVA_CFLAGS) $(MS_CFLAGS) -I$(TROOT)\..\..\thirds\dirent-win32 -I$(INTL_DIR) -I$(CURL_DIR)\include -I$(XML2_DIR)\include -I$(GDAL_DIR)\port $(JS_CFLAGS) -I$(GDAL_DIR)\ogr -I$(GDAL_DIR)\gcore -I$(GD_DIR) -I$(ICONV_DIR) -I$(TROOT)\..\..\thirds\include -I$(TROOT)\..\..\thirds\cgic206 -I$(PYTHON_CPATH)\include -I$(SSL_DIR)/inc32 -I$(FCGI_DIR)\include $(PY_CFLAGS) $(PHP_CFLAGS) -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
+
+LDFLAGSCGI=$(TROOT)/../../thirds/cgic206/libcgic.lib 
+LDFLAGS=$(MONO_LDFLAGS) $(FCGI_DIR)/libfcgi/Release/libfcgi.lib $(CURL_LIBRARY) $(PY_LDFLAGS) $(XML2_LIBRARY) $(SSL_DIR)/out32dll/libeay32.lib $(JAVA_LDFLAGS) $(SSL_DIR)/out32dll/ssleay32.lib $(MS_LDFLAGS) $(INTL_DIR)/intl.lib $(XML2_DIR)/win32/bin.msvc/libxml2.lib $(GDAL_DIR)/gdal_i.lib $(CURL_DIR)/lib/libcurl.lib $(JS_LDFLAGS) $(RUBY_LDFLAGS) $(PHP_LDFLAGS) /machine:i386
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/otbZooWatcher.cxx
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/otbZooWatcher.cxx	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/otbZooWatcher.cxx	(revision 942)
@@ -0,0 +1,75 @@
+/*=========================================================================
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+  Some parts of this code are derived from ITK. See ITKCopyright.txt
+  for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+  See Ref: http://hg.orfeo-toolbox.org/OTB/ Copyright
+
+=========================================================================*/
+#include "otbZooWatcher.h"
+#include "otbConfigure.h"
+#include "service_internal.h"
+
+ZooWatcher
+::ZooWatcher()
+{
+}
+
+ZooWatcher
+::ZooWatcher(itk::ProcessObject* process,
+	     const char *comment)
+  : otb::FilterWatcherBase(process, comment)
+{
+}
+
+ZooWatcher
+::ZooWatcher(itk::ProcessObject* process,
+	     const std::string& comment)
+  : otb::FilterWatcherBase(process, comment.c_str())
+{
+}
+
+void
+ZooWatcher
+::ShowProgress()
+{
+  if (m_Process)
+    {
+      int progressPercent = static_cast<int>(m_Process->GetProgress() * 100);
+      updateStatus(m_Conf,progressPercent,m_Comment.c_str());
+    }
+}
+
+void
+ZooWatcher
+::StartFilter()
+{
+#if OTB_VERSION_MAJOR < 6 
+  m_TimeProbe.Start();
+#endif
+}
+
+void
+ZooWatcher
+::EndFilter()
+{
+#if OTB_VERSION_MAJOR < 6 
+  m_TimeProbe.Stop();
+  std::ostringstream elapsedTime;
+  elapsedTime.precision(1);
+  elapsedTime << m_TimeProbe.GetMean();
+
+  std::cerr << " (OTB Execution: "
+            << elapsedTime.str()
+            << " seconds)"
+            << std::endl;
+#endif
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/otbZooWatcher.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/otbZooWatcher.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/otbZooWatcher.h	(revision 942)
@@ -0,0 +1,91 @@
+/*=========================================================================
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+  Some parts of this code are derived from ITK. See ITKCopyright.txt
+  for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+  See Ref: http://hg.orfeo-toolbox.org/OTB/ Copyright
+
+=========================================================================*/
+#ifndef __zooOtbWatcher_h
+#define __zooOtbWatcher_h
+
+#include "otbFilterWatcherBase.h"
+#include "service.h"
+
+/**
+ * Observer used to access the ongoing status of a running OTB Application
+ */
+class /*ITK_EXPORT*/ ZooWatcher : public otb::FilterWatcherBase
+{
+public:
+
+  /**
+   * Constructor
+   * @param process the itk::ProcessObject to monitor
+   * @param comment comment string that is prepended to each event message
+   */
+  ZooWatcher(itk::ProcessObject* process,
+                        const char *comment = "");
+
+  /**
+   * Constructor
+   * @param process the itk::ProcessObject to monitor
+   * @param comment comment string that is prepended to each event message
+   */
+  ZooWatcher(itk::ProcessObject* process,
+                        const std::string& comment = "");
+
+  /** Default constructor */
+  ZooWatcher();
+
+  /** 
+   * Copy the original conf in the m_Conf property
+   *
+   * @param conf the maps pointer to copy
+   */
+  void SetConf(maps **conf)
+  {
+    m_Conf=dupMaps(conf);
+  }
+  /**  
+   * Get Configuration maps (m_Conf)
+   * @return the m_Conf property
+   */
+  const maps& GetConf() const
+  {
+    return *m_Conf;
+  }
+  /**  
+   * Free Configuration maps (m_Conf)
+   */
+  void FreeConf(){
+    freeMaps(&m_Conf);
+    free(m_Conf);
+  }
+protected:
+
+  /** Callback method to show the ProgressEvent */
+  virtual void ShowProgress();
+
+  /** Callback method to show the StartEvent */
+  virtual void StartFilter();
+
+  /** Callback method to show the EndEvent */
+  virtual void EndFilter();
+
+private:
+
+  /** Main conf maps */
+  maps* m_Conf;
+
+};
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/request_parser.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/request_parser.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/request_parser.c	(revision 942)
@@ -0,0 +1,2011 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "request_parser.h"
+#include "service_internal.h"
+#include "server_internal.h"
+#include "response_print.h"
+#include "caching.h"
+#include "cgic.h"
+
+/**
+ * Apply XPath Expression on XML document.
+ *
+ * @param doc the XML Document
+ * @param search the XPath expression
+ * @return xmlXPathObjectPtr containing the resulting nodes set
+ */
+xmlXPathObjectPtr
+extractFromDoc (xmlDocPtr doc, const char *search)
+{
+  xmlXPathContextPtr xpathCtx;
+  xmlXPathObjectPtr xpathObj;
+  xpathCtx = xmlXPathNewContext (doc);
+  xpathObj = xmlXPathEvalExpression (BAD_CAST search, xpathCtx);
+  xmlXPathFreeContext (xpathCtx);
+  return xpathObj;
+}
+
+/**
+ * Create (or append to) an array valued maps value = "["",""]"
+ *
+ * @param m the conf maps containing the main.cfg settings
+ * @param mo the map to update
+ * @param mi the map to append
+ * @param elem the elements containing default definitions
+ * @return 0 on success, -1 on failure
+ */
+int appendMapsToMaps (maps * m, maps * mo, maps * mi, elements * elem){
+  maps *tmpMaps = getMaps (mo, mi->name);
+  map *tmap = getMapType (tmpMaps->content);
+  elements *el = getElements (elem, mi->name);
+  elements *cursor = elem;
+  while(cursor!=NULL && el==NULL){
+    if(cursor->child!=NULL)
+      el = getElements (cursor->child, mi->name);
+    cursor=cursor->next;
+  }
+  int hasEl = 1;
+  if (el == NULL)
+    hasEl = -1;
+
+  if (tmap == NULL)
+    {
+      if (hasEl > 0)
+	tmap = getMapType (el->defaults->content);
+    }
+  
+  map *testMap = NULL;
+  if (hasEl > 0)
+    {
+      testMap = getMap (el->content, "maxOccurs");
+    }
+  else
+    {
+      testMap = createMap ("maxOccurs", "unbounded");
+    }
+    
+  if (testMap != NULL)
+    {
+      if (strncasecmp (testMap->value, "unbounded", 9) != 0
+	  && atoi (testMap->value) > 1)
+	{
+	  addMapsArrayToMaps (&mo, mi, tmap->name);
+	  map* nb=getMapFromMaps(mo,mi->name,"length");
+	  if (nb!=NULL && atoi(nb->value)>atoi(testMap->value))
+	    {
+	      char emsg[1024];
+	      sprintf (emsg,
+		       _("The maximum allowed occurrences for <%s> (%i) was exceeded."),
+		       mi->name, atoi (testMap->value));
+	      errorException (m, emsg, "InternalError", NULL);
+	      return -1;
+	    }
+	}
+      else
+	{
+	  if (strncasecmp (testMap->value, "unbounded", 9) == 0)
+	    {
+	      if (hasEl < 0)
+		{
+		  freeMap (&testMap);
+		  free (testMap);
+		}
+	      if (addMapsArrayToMaps (&mo, mi, tmap->name) < 0)
+		{
+		  char emsg[1024];
+		  map *tmpMap = getMap (mi->content, "length");
+		  sprintf (emsg,
+			   _
+			   ("ZOO-Kernel was unable to load your data for %s position %s."),
+			   mi->name, tmpMap->value);
+		  errorException (m, emsg, "InternalError", NULL);
+		  return -1;
+		}
+	    }
+	  else
+	    {
+	      char emsg[1024];
+	      sprintf (emsg,
+		       _
+		       ("The maximum allowed occurrences for <%s> is one."),
+		       mi->name);
+	      errorException (m, emsg, "InternalError", NULL);
+	      return -1;
+	    }
+	}
+    }
+  return 0;
+}
+
+/**
+ * Make sure that each value encoded in base64 in a maps is decoded.
+ *
+ * @param in the maps containing the values
+ * @see readBase64
+ */
+void ensureDecodedBase64(maps **in){
+  maps* cursor=*in;
+  while(cursor!=NULL){
+    map *tmp=getMap(cursor->content,"encoding");
+    if(tmp!=NULL && strncasecmp(tmp->value,"base64",6)==0){
+      tmp=getMap(cursor->content,"value");
+      readBase64(&tmp);
+      addToMap(cursor->content,"base64_value",tmp->value);
+      int size=0;
+      char *s=zStrdup(tmp->value);
+      free(tmp->value);
+      tmp->value=base64d(s,strlen(s),&size);
+      free(s);
+      char sizes[1024];
+      sprintf(sizes,"%d",size);
+      addToMap(cursor->content,"size",sizes);
+    }
+    map* length=getMap(cursor->content,"length");
+    if(length!=NULL){
+      int len=atoi(length->value);
+      for(int i=1;i<len;i++){
+	tmp=getMapArray(cursor->content,"encoding",i);
+	if(tmp!=NULL && strncasecmp(tmp->value,"base64",6)==0){
+	  char key[17];
+	  sprintf(key,"base64_value_%d",i);
+	  tmp=getMapArray(cursor->content,"value",i);
+	  readBase64(&tmp);
+	  addToMap(cursor->content,key,tmp->value);
+	  int size=0;
+	  char *s=zStrdup(tmp->value);
+	  free(tmp->value);
+	  tmp->value=base64d(s,strlen(s),&size);
+	  free(s);
+	  char sizes[1024];
+	  sprintf(sizes,"%d",size);
+	  sprintf(key,"size_%d",i);
+	  addToMap(cursor->content,key,sizes);
+	}
+      }
+    }
+    if(cursor->child!=NULL)
+      ensureDecodedBase64(&cursor->child);
+    cursor=cursor->next;
+  }
+}
+
+/**
+ * Parse inputs provided as KVP and store them in a maps.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param s the service
+ * @param request_inputs the map storing KVP raw value 
+ * @param request_output the maps to store the KVP pairs 
+ * @param hInternet the HINTERNET queue to add potential requests
+ * @return 0 on success, -1 on failure
+ */
+int kvpParseInputs(maps** main_conf,service* s,map *request_inputs,maps** request_output,HINTERNET* hInternet){
+  // Parsing inputs provided as KVP
+  maps *tmpmaps = *request_output;
+  map* r_inputs = getMap (request_inputs, "DataInputs");
+  char* cursor_input;
+  if (r_inputs != NULL){
+    //snprintf (cursor_input, 40960, "%s", r_inputs->value);
+    if(strstr(r_inputs->value,"=")==NULL)
+      cursor_input = url_decode (r_inputs->value);
+    else
+      cursor_input = zStrdup (r_inputs->value);
+    int j = 0;
+
+    // Put each DataInputs into the inputs_as_text array
+    char *pToken;
+    pToken = strtok (cursor_input, ";");
+    char **inputs_as_text = (char **) malloc (100 * sizeof (char *));
+    if (inputs_as_text == NULL)
+      {
+	free(cursor_input);
+	return errorException (*main_conf, _("Unable to allocate memory"),
+			       "InternalError", NULL);
+      }
+    int i = 0;
+    while (pToken != NULL)
+      {
+	inputs_as_text[i] =
+	  (char *) malloc ((strlen (pToken) + 1) * sizeof (char));
+	if (inputs_as_text[i] == NULL)
+	  {
+	    free(cursor_input);
+	    return errorException (*main_conf, _("Unable to allocate memory"),
+				   "InternalError", NULL);
+	  }
+	snprintf (inputs_as_text[i], strlen (pToken) + 1, "%s", pToken);
+	pToken = strtok (NULL, ";");
+	i++;
+      }
+	
+    for (j = 0; j < i; j++)
+      {
+	char *tmp = zStrdup (inputs_as_text[j]);
+	free (inputs_as_text[j]);
+	char *tmpc;
+	tmpc = strtok (tmp, "@");
+	while (tmpc != NULL)
+	  {
+	    char *tmpv = strstr (tmpc, "=");
+	    char tmpn[256];
+	    memset (tmpn, 0, 256);
+	    if (tmpv != NULL)
+	      {
+		strncpy (tmpn, tmpc,
+			 (strlen (tmpc) - strlen (tmpv)) * sizeof (char));
+		tmpn[strlen (tmpc) - strlen (tmpv)] = 0;
+	      }
+	    else
+	      {
+		strncpy (tmpn, tmpc, strlen (tmpc) * sizeof (char));
+		tmpn[strlen (tmpc)] = 0;
+	      }
+	    if (tmpmaps == NULL)
+	      {
+		tmpmaps = createMaps(tmpn);
+		if (tmpmaps == NULL)
+		  {
+		    free(cursor_input);
+		    return errorException (*main_conf,
+					   _("Unable to allocate memory"),
+					   "InternalError", NULL);
+		  }
+		if (tmpv != NULL)
+		  {
+		    char *tmpvf = url_decode (tmpv + 1);
+		    tmpmaps->content = createMap ("value", tmpvf);
+		    free (tmpvf);
+		  }
+		else
+		  tmpmaps->content = createMap ("value", "Reference");
+		tmpmaps->next = NULL;
+	      }
+	    tmpc = strtok (NULL, "@");
+	    while (tmpc != NULL)
+	      {
+		char *tmpv1 = strstr (tmpc, "=");
+		char tmpn1[1024];
+		memset (tmpn1, 0, 1024);
+		if (tmpv1 != NULL)
+		  {
+		    strncpy (tmpn1, tmpc, strlen (tmpc) - strlen (tmpv1));
+		    tmpn1[strlen (tmpc) - strlen (tmpv1)] = 0;
+		    addToMap (tmpmaps->content, tmpn1, tmpv1 + 1);
+		  }
+		else
+		  {
+		    strncpy (tmpn1, tmpc, strlen (tmpc));
+		    tmpn1[strlen (tmpc)] = 0;
+		    map *lmap = getLastMap (tmpmaps->content);
+		    char *tmpValue =
+		      (char *) malloc ((strlen (tmpv) + strlen (tmpc) + 1) *
+				       sizeof (char));
+		    sprintf (tmpValue, "%s@%s", tmpv + 1, tmpc);
+		    free (lmap->value);
+		    lmap->value = zStrdup (tmpValue);
+		    free (tmpValue);
+		    tmpc = strtok (NULL, "@");
+		    continue;
+		  }
+		if (strcmp (tmpn1, "xlink:href") != 0)
+		  addToMap (tmpmaps->content, tmpn1, tmpv1 + 1);
+		else if (tmpv1 != NULL)
+		  {
+		    char *tmpx2 = url_decode (tmpv1 + 1);
+		    if (strncasecmp (tmpx2, "http://", 7) != 0 &&
+			strncasecmp (tmpx2, "ftp://", 6) != 0 &&
+			strncasecmp (tmpx2, "https://", 8) != 0)
+		      {
+			char emsg[1024];
+			sprintf (emsg,
+				 _
+				 ("Unable to find a valid protocol to download the remote file %s"),
+				 tmpv1 + 1);
+			free(cursor_input);
+			return errorException (*main_conf, emsg, "InternalError", NULL);
+		      }
+		    addToMap (tmpmaps->content, tmpn1, tmpx2);
+		    {
+		      if (loadRemoteFile
+			  (&*main_conf, &tmpmaps->content, hInternet, tmpx2) < 0)
+			{
+			  free(cursor_input);
+			  return errorException (*main_conf, "Unable to fetch any resource", "InternalError", NULL);
+			}
+		      }
+		    free (tmpx2);
+		    addIntToMap (tmpmaps->content, "Order", hInternet->nb);
+		    addToMap (tmpmaps->content, "Reference", tmpv1 + 1);
+		  }
+		tmpc = strtok (NULL, "@");
+	      }
+	    if (*request_output == NULL)
+	      *request_output = dupMaps (&tmpmaps);
+	    else
+	      {
+		maps *testPresence =
+		  getMaps (*request_output, tmpmaps->name);
+		if (testPresence != NULL)
+		  {
+		    elements *elem =
+		      getElements (s->inputs, tmpmaps->name);
+		    if (elem != NULL)
+		      {
+			if (appendMapsToMaps
+			    (*main_conf, *request_output, tmpmaps,
+			     elem) < 0)
+			  {
+			    free(cursor_input);
+			    return errorException (*main_conf, "Unable to append maps", "InternalError", NULL);
+			  }
+		      }
+		  }
+		else
+		  addMapsToMaps (request_output, tmpmaps);
+	      }
+	    freeMaps (&tmpmaps);
+	    free (tmpmaps);
+	    tmpmaps = NULL;
+	    free (tmp);
+	  }
+      }
+    free (inputs_as_text);
+    free(cursor_input);
+  }
+  return 1;
+}
+
+/**
+ * Parse outputs provided as KVP and store them in a maps.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request_inputs the map storing KVP raw value 
+ * @param request_output the maps to store the KVP pairs 
+ * @return 0 on success, -1 on failure
+ */
+int kvpParseOutputs(maps** main_conf,map *request_inputs,maps** request_output){
+  /**
+   * Parsing outputs provided as KVP
+   */
+  map *r_inputs = NULL;
+  r_inputs = getMap (request_inputs, "ResponseDocument");
+  if (r_inputs == NULL)
+    r_inputs = getMap (request_inputs, "RawDataOutput");
+
+  if (r_inputs != NULL)
+    {
+      char *cursor_output = zStrdup (r_inputs->value);
+      int j = 0;
+
+      /**
+       * Put each Output into the outputs_as_text array
+       */
+      char *pToken;
+      maps *tmp_output = NULL;
+      pToken = strtok (cursor_output, ";");
+      char **outputs_as_text = (char **) malloc (128 * sizeof (char *));
+      if (outputs_as_text == NULL)
+	{
+	  free(cursor_output);
+	  return errorException (*main_conf, _("Unable to allocate memory"),
+				 "InternalError", NULL);
+	}
+      int i = 0;
+      while (pToken != NULL)
+	{
+	  outputs_as_text[i] =
+	    (char *) malloc ((strlen (pToken) + 1) * sizeof (char));
+	  if (outputs_as_text[i] == NULL)
+	    {
+	      free(cursor_output);
+	      return errorException (*main_conf, _("Unable to allocate memory"),
+				     "InternalError", NULL);
+	    }
+	  snprintf (outputs_as_text[i], strlen (pToken) + 1, "%s",
+		    pToken);
+	  pToken = strtok (NULL, ";");
+	  i++;
+	}
+      for (j = 0; j < i; j++)
+	{
+	  char *tmp = zStrdup (outputs_as_text[j]);
+	  free (outputs_as_text[j]);
+	  char *tmpc;
+	  tmpc = strtok (tmp, "@");
+	  int k = 0;
+	  while (tmpc != NULL)
+	    {
+	      if (k == 0)
+		{
+		  if (tmp_output == NULL)
+		    {
+		      tmp_output = createMaps(tmpc);
+		      if (tmp_output == NULL)
+			{
+			  free(cursor_output);
+			  return errorException (*main_conf,
+						 _
+						 ("Unable to allocate memory"),
+						 "InternalError", NULL);
+			}
+		    }
+		}
+	      else
+		{
+		  char *tmpv = strstr (tmpc, "=");
+		  char tmpn[256];
+		  memset (tmpn, 0, 256);
+		  strncpy (tmpn, tmpc,
+			   (strlen (tmpc) -
+			    strlen (tmpv)) * sizeof (char));
+		  tmpn[strlen (tmpc) - strlen (tmpv)] = 0;
+		  if (tmp_output->content == NULL)
+		    {
+		      tmp_output->content = createMap (tmpn, tmpv + 1);
+		      tmp_output->content->next = NULL;
+		    }
+		  else
+		    addToMap (tmp_output->content, tmpn, tmpv + 1);
+		}
+	      k++;
+	      tmpc = strtok (NULL, "@");
+	    }
+	  if (*request_output == NULL)
+	    *request_output = dupMaps (&tmp_output);
+	  else
+	    addMapsToMaps (request_output, tmp_output);
+	  freeMaps (&tmp_output);
+	  free (tmp_output);
+	  tmp_output = NULL;
+	  free (tmp);
+	}
+      free (outputs_as_text);
+      free(cursor_output);
+    }
+  return 1;
+}
+
+/**
+ * Create a "missingIdentifier" maps in case it is NULL.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param mymaps the maps to update
+ * @return 0 on success, 4 on failure
+ */
+int defineMissingIdentifier(maps** main_conf,maps** mymaps){
+  if (*mymaps == NULL){
+    *mymaps = createMaps("missingIndetifier");
+    if (*mymaps == NULL){
+      return errorException (*main_conf,
+			     _("Unable to allocate memory"),
+			     "InternalError", NULL);
+    }
+  }
+  return 0;
+}
+
+/**
+ * Parse inputs from XML nodes and store them in a maps.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param s the service
+ * @param request_output the maps to store the KVP pairs 
+ * @param doc the xmlDocPtr containing the original request
+ * @param nodes the input nodes array
+ * @param hInternet the HINTERNET queue to add potential requests
+ * @return 0 on success, -1 on failure
+ */
+int xmlParseInputs(maps** main_conf,service* s,maps** request_output,xmlDocPtr doc,xmlNodeSet* nodes,HINTERNET* hInternet){
+  int k = 0;
+  int l = 0;
+  map* version=getMapFromMaps(*main_conf,"main","rversion");
+  map* memory=getMapFromMaps(*main_conf,"main","memory");
+  int vid=getVersionId(version->value);
+  for (k=0; k < nodes->nodeNr; k++)
+    {
+      maps *tmpmaps = NULL;
+      xmlNodePtr cur = nodes->nodeTab[k];
+
+      if (nodes->nodeTab[k]->type == XML_ELEMENT_NODE)
+	{
+	  // A specific Input node.
+	  if(vid==1){
+	    xmlChar *val = xmlGetProp (cur, BAD_CAST "id");
+	    tmpmaps = createMaps((char *) val);
+	    xmlFree(val);
+	  }
+
+	  xmlNodePtr cur2 = cur->children;
+	  while (cur2 != NULL)
+	    {
+	      while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE)
+		cur2 = cur2->next;
+	      if (cur2 == NULL)
+		break;
+	      // Indentifier
+	      if (xmlStrncasecmp
+		  (cur2->name, BAD_CAST "Identifier",
+		   xmlStrlen (cur2->name)) == 0)
+		{
+		  xmlChar *val =
+		    xmlNodeListGetString (doc, cur2->xmlChildrenNode, 1);
+		  if (tmpmaps == NULL && val!=NULL)
+		    {
+		      tmpmaps = createMaps((char*)val);
+		      if (tmpmaps == NULL)
+			{
+			  return errorException (*main_conf,
+						 _
+						 ("Unable to allocate memory"),
+						 "InternalError", NULL);
+			}
+		      xmlFree (val);
+		    }
+		}
+	      // Title, Asbtract
+	      if (xmlStrncasecmp
+		  (cur2->name, BAD_CAST "Title",
+		   xmlStrlen (cur2->name)) == 0
+		  || xmlStrncasecmp (cur2->name, BAD_CAST "Abstract",
+				     xmlStrlen (cur2->name)) == 0)
+		{
+		  xmlChar *val =
+		    xmlNodeListGetString (doc, cur2->xmlChildrenNode, 1);
+		  defineMissingIdentifier(main_conf,&tmpmaps);
+		  if(val!=NULL){
+		    if (tmpmaps->content != NULL)
+		      addToMap (tmpmaps->content,
+				(char *) cur2->name, (char *) val);
+		    else
+		      tmpmaps->content =
+			createMap ((char *) cur2->name, (char *) val);
+		    xmlFree (val);
+		  }
+		}
+	      // InputDataFormChoice (Reference or Data ?) / 2.0.0 DataInputType / Input 
+	      if (xmlStrcasecmp (cur2->name, BAD_CAST "Input") == 0)
+		{
+		  char *xpathExpr=(char*)malloc(61+strlen(tmpmaps->name));
+		  sprintf(xpathExpr,"/*/*[local-name()='Input' and @id='%s']/*[local-name()='Input']",tmpmaps->name);
+		  xmlXPathObjectPtr tmpsptr = extractFromDoc (doc, xpathExpr);
+		  xmlNodeSet *tmps = tmpsptr->nodesetval;
+		  if(tmps!=NULL){
+		    maps* request_output1=NULL;
+		    if(xmlParseInputs(main_conf,s,&request_output1,doc,tmps,hInternet)<0)
+		      return -1;
+		    if(tmpmaps->child==NULL)
+		      tmpmaps->child=dupMaps(&request_output1);
+		    else
+		      addMapsToMaps(&tmpmaps->child,request_output1);
+		    freeMaps(&request_output1);
+		    free(request_output1);
+		  }
+		  while(cur2->next!=NULL)
+		    cur2=cur2->next;
+		}
+	      else if (xmlStrcasecmp (cur2->name, BAD_CAST "Reference") == 0)
+		{
+		  defineMissingIdentifier(main_conf,&tmpmaps);
+		  // Get every attribute from a Reference node
+		  // mimeType, encoding, schema, href, method
+		  // Header and Body gesture should be added here
+		  const char *refs[5] =
+		    { "mimeType", "encoding", "schema", "method",
+		      "href"
+		    };
+		  for (l = 0; l < 5; l++)
+		    {
+		      xmlChar *val = xmlGetProp (cur2, BAD_CAST refs[l]);
+		      if (val != NULL && xmlStrlen (val) > 0)
+			{
+			  if (tmpmaps->content != NULL)
+			    addToMap (tmpmaps->content, refs[l],
+				      (char *) val);
+			  else
+			    tmpmaps->content =
+			      createMap (refs[l], (char *) val);
+			  map *ltmp = getMap (tmpmaps->content, "method");
+			  if (l == 4 )
+			    {
+			      if ((ltmp==NULL || strncmp (ltmp->value, "POST",4) != 0))
+				{
+				  if (loadRemoteFile
+				      (main_conf, &tmpmaps->content, hInternet,
+				       (char *) val) != 0)
+				    {
+				      return errorException (*main_conf,
+							     _("Unable to add a request in the queue."),
+							     "InternalError",
+							     NULL);
+				    }
+				  addIntToMap (tmpmaps->content, "Order", hInternet->nb);
+				}
+			      addToMap (tmpmaps->content, "Reference", (char*) val);
+			    }
+			}
+		      xmlFree (val);
+		    }
+		  // Parse Header and Body from Reference
+		  xmlNodePtr cur3 = cur2->children;
+		  while (cur3 != NULL)
+		    {
+		      while (cur3 != NULL
+			     && cur3->type != XML_ELEMENT_NODE)
+			cur3 = cur3->next;
+		      if (cur3 == NULL)
+			break;
+		      if (xmlStrcasecmp (cur3->name, BAD_CAST "Header") ==
+			  0)
+			{
+			  const char *ha[2];
+			  ha[0] = "key";
+			  ha[1] = "value";
+			  int hai;
+			  char *has=NULL;
+			  char *key;
+			  for (hai = 0; hai < 2; hai++)
+			    {
+			      xmlChar *val =
+				xmlGetProp (cur3, BAD_CAST ha[hai]);
+#ifdef POST_DEBUG
+			      fprintf (stderr, "%s = %s\n", ha[hai],
+				       (char *) val);
+#endif
+			      if (hai == 0)
+				{
+				  key = zStrdup ((char *) val);
+				}
+			      else
+				{
+				  has =
+				    (char *)
+				    malloc ((4 + xmlStrlen (val) +
+					     strlen (key)) *
+					    sizeof (char));
+				  if (has == NULL)
+				    {
+				      return errorException (*main_conf,
+							     _
+							     ("Unable to allocate memory"),
+							     "InternalError",
+							     NULL);
+				    }
+				  snprintf (has,
+					    (3 + xmlStrlen (val) +
+					     strlen (key)), "%s: %s", key,
+					    (char *) val);
+				  free (key);
+				}
+			      xmlFree (val);
+			    }
+			  if (has != NULL){
+			    hInternet->ihandle[hInternet->nb].header = NULL;
+			    hInternet->ihandle[hInternet->nb].header =
+			      curl_slist_append (hInternet->ihandle
+						 [hInternet->nb].header,
+						 has);
+			    free (has);
+			  }
+			}
+		      else
+			{
+#ifdef POST_DEBUG
+			  fprintf (stderr,
+				   "Try to fetch the body part of the request ...\n");
+#endif
+			  if (xmlStrcasecmp (cur3->name, BAD_CAST "Body")
+			      == 0)
+			    {
+#ifdef POST_DEBUG
+			      fprintf (stderr, "Body part found (%s) !!!\n",
+				       (char *) cur3->content);
+#endif
+			      char *tmp = NULL;
+			      xmlNodePtr cur4 = cur3->children;
+			      while (cur4 != NULL)
+				{
+				  while (cur4 && cur4 != NULL && cur4->type && cur4->type != XML_ELEMENT_NODE){
+				    if(cur4->next)
+				      cur4 = cur4->next;
+				    else
+				      cur4 = NULL;
+				  }
+				  if(cur4 != NULL) {
+				    xmlDocPtr bdoc =
+				      xmlNewDoc (BAD_CAST "1.0");
+				    bdoc->encoding =
+				      xmlCharStrdup ("UTF-8");
+				    xmlDocSetRootElement (bdoc, cur4);
+				    xmlChar *btmps;
+				    int bsize;
+				    // TODO : check for encoding defined in the input
+				    xmlDocDumpFormatMemoryEnc(bdoc, &btmps, &bsize, "UTF-8", 0);
+				    if (btmps != NULL){
+				      tmp = (char *) malloc ((bsize + 1) * sizeof (char));
+
+				      sprintf (tmp, "%s", (char*) btmps);
+
+				      //xmlFreeDoc (bdoc);
+					  
+				      map *btmp =
+					getMap (tmpmaps->content, "Reference");
+				      addToMap (tmpmaps->content, "Body", tmp);
+				      if (btmp != NULL)
+					{
+					  addRequestToQueue(main_conf,hInternet,(char *) btmp->value,false);
+					  InternetOpenUrl (hInternet,
+							   btmp->value,
+							   tmp,
+							   xmlStrlen(btmps),
+							   INTERNET_FLAG_NO_CACHE_WRITE,
+							   0,
+							   *main_conf);
+					  addIntToMap (tmpmaps->content, "Order", hInternet->nb);
+					}
+				      xmlFree (btmps);
+				      free (tmp);
+				      break;
+				    }
+				  }
+				  cur4 = cur4->next;
+				}
+			    }
+			  else
+			    if (xmlStrcasecmp
+				(cur3->name,
+				 BAD_CAST "BodyReference") == 0)
+			      {
+				xmlChar *val =
+				  xmlGetProp (cur3, BAD_CAST "href");
+				HINTERNET bInternet, res1, res;
+				maps *tmpConf=createMaps("main");
+				tmpConf->content=createMap("memory","load");
+				bInternet = InternetOpen (
+#ifndef WIN32
+							  (LPCTSTR)
+#endif
+							  "ZooWPSClient\0",
+							  INTERNET_OPEN_TYPE_PRECONFIG,
+							  NULL, NULL, 0);
+#ifndef WIN32
+				if (!CHECK_INET_HANDLE (bInternet))
+				  fprintf (stderr,
+					   "WARNING : bInternet handle failed to initialize");
+#endif
+				bInternet.waitingRequests[0] =
+				  zStrdup ((char *) val);
+				res1 =
+				  InternetOpenUrl (&bInternet,
+						   bInternet.waitingRequests
+						   [0], NULL, 0,
+						   INTERNET_FLAG_NO_CACHE_WRITE,
+						   0,
+						   tmpConf);
+				processDownloads (&bInternet);
+				freeMaps(&tmpConf);
+				free(tmpConf);
+				char *tmp =
+				  (char *)
+				  malloc ((bInternet.ihandle[0].nDataLen +
+					   1) * sizeof (char));
+				if (tmp == NULL)
+				  {
+				    return errorException (*main_conf,
+							   _
+							   ("Unable to allocate memory"),
+							   "InternalError",
+							   NULL);
+				  }
+				size_t bRead;
+				InternetReadFile (bInternet.ihandle[0],
+						  (LPVOID) tmp,
+						  bInternet.
+						  ihandle[0].nDataLen,
+						  &bRead);
+				tmp[bInternet.ihandle[0].nDataLen] = 0;
+				InternetCloseHandle(&bInternet);
+				addToMap (tmpmaps->content, "Body", tmp);
+				map *btmp =
+				  getMap (tmpmaps->content, "href");
+				if (btmp != NULL)
+				  {
+				    addRequestToQueue(main_conf,hInternet,(char *) btmp->value,false);
+
+				    res =
+				      InternetOpenUrl (hInternet,
+						       btmp->value,
+						       tmp,
+						       strlen(tmp),
+						       INTERNET_FLAG_NO_CACHE_WRITE,
+						       0,
+						       *main_conf);
+				    addIntToMap (tmpmaps->content, "Order", hInternet->nb);
+				  }
+				free (tmp);
+				xmlFree (val);
+			      }
+			}
+		      cur3 = cur3->next;
+		    }
+		}
+	      else if (xmlStrcasecmp (cur2->name, BAD_CAST "Data") == 0)
+		{
+		  defineMissingIdentifier(main_conf,&tmpmaps);
+		  xmlNodePtr cur4 = cur2->children;
+		  if(vid==1){
+		    // Get every dataEncodingAttributes from a Data node:
+		    // mimeType, encoding, schema
+		    const char *coms[3] =
+		      { "mimeType", "encoding", "schema" };
+		    for (l = 0; l < 3; l++){
+		      xmlChar *val =
+			  xmlGetProp (cur4, BAD_CAST coms[l]);
+			if (val != NULL && strlen ((char *) val) > 0){
+			  if (tmpmaps->content != NULL)
+			    addToMap (tmpmaps->content,coms[l],(char *) val);
+			  else
+			    tmpmaps->content =
+			      createMap (coms[l],(char *) val);
+			}
+			xmlFree (val);
+		    }
+		    while (cur4 != NULL){
+		      while(cur4 != NULL && 
+			    cur4->type != XML_CDATA_SECTION_NODE &&
+			    cur4->type != XML_TEXT_NODE &&
+			    cur4->type != XML_ELEMENT_NODE)
+			cur4=cur4->next;
+		      if(cur4!=NULL){
+			if (cur4->type == XML_ELEMENT_NODE)
+			  {
+			    xmlChar *mv;
+			    int buffersize;
+			    xmlDocPtr doc1 = xmlNewDoc (BAD_CAST "1.0");
+			    xmlDocSetRootElement (doc1, cur4);
+			    xmlDocDumpFormatMemoryEnc (doc1, &mv,
+						       &buffersize,
+						       "utf-8", 0);
+			    if (tmpmaps->content != NULL)
+			      addToMap (tmpmaps->content, "value",
+					(char *) mv);
+			    else
+			      tmpmaps->content =
+				createMap ("value", (char *) mv);
+			    free(mv);
+			  }
+			else{
+			  if (tmpmaps->content != NULL)
+			    addToMap (tmpmaps->content, "value",
+				      (char *) cur4->content);
+			  else
+			    tmpmaps->content =
+			      createMap ("value", (char *) cur4->content);
+			}
+			cur4=cur4->next;
+		      }
+		    }
+		  }
+
+		  while (cur4 != NULL)
+		    {
+		      while (cur4 != NULL
+			     && cur4->type != XML_ELEMENT_NODE)
+			cur4 = cur4->next;
+		      if (cur4 == NULL)
+			break;
+		      if (xmlStrcasecmp
+			  (cur4->name, BAD_CAST "LiteralData") == 0)
+			{
+			  // Get every attribute from a LiteralData node
+			  // dataType , uom
+			  char *list[2];
+			  list[0] = zStrdup ("dataType");
+			  list[1] = zStrdup ("uom");
+			  for (l = 0; l < 2; l++)
+			    {
+			      xmlChar *val =
+				xmlGetProp (cur4, BAD_CAST list[l]);
+			      if (val != NULL
+				  && strlen ((char *) val) > 0)
+				{
+				  if (tmpmaps->content != NULL)
+				    addToMap (tmpmaps->content, list[l],
+					      (char *) val);
+				  else
+				    tmpmaps->content =
+				      createMap (list[l], (char *) val);
+				  xmlFree (val);
+				}
+			      else{
+				if(l==0){
+				  if (tmpmaps->content != NULL)
+				    addToMap (tmpmaps->content, list[l],
+					      "string");
+				  else
+				    tmpmaps->content =
+				      createMap (list[l],"string");
+				}
+			      }
+			      free (list[l]);
+			    }
+			}
+		      else
+			if (xmlStrcasecmp
+			    (cur4->name, BAD_CAST "ComplexData") == 0)
+			  {
+			    // Get every attribute from a Reference node
+			    // mimeType, encoding, schema
+			    const char *coms[3] =
+			      { "mimeType", "encoding", "schema" };
+			    for (l = 0; l < 3; l++)
+			      {
+				xmlChar *val =
+				  xmlGetProp (cur4, BAD_CAST coms[l]);
+				if (val != NULL
+				    && strlen ((char *) val) > 0)
+				  {
+				    if (tmpmaps->content != NULL)
+				      addToMap (tmpmaps->content, coms[l],
+						(char *) val);
+				    else
+				      tmpmaps->content =
+					createMap (coms[l], (char *) val);
+				    xmlFree (val);
+				  }
+			      }
+			  }
+
+		      map *test = getMap (tmpmaps->content, "encoding");
+		      if (test == NULL)
+			{
+			  if (tmpmaps->content != NULL)
+			    addToMap (tmpmaps->content, "encoding",
+				      "utf-8");
+			  else
+			    tmpmaps->content =
+			      createMap ("encoding", "utf-8");
+			  test = getMap (tmpmaps->content, "encoding");
+			}
+
+		      if (getMap(tmpmaps->content,"dataType")==NULL && test!=NULL && strcasecmp (test->value, "base64") != 0)
+			{
+			  xmlChar *mv = NULL;
+			  /*if(cur4!=NULL && cur4->xmlChildrenNode!=NULL)
+			    xmlChar *mv = xmlNodeListGetString (doc,
+								cur4->xmlChildrenNode,
+								1);*/
+			  map *ltmp =
+			    getMap (tmpmaps->content, "mimeType");
+			  if (/*mv == NULL
+			      ||*/
+			      (xmlStrcasecmp
+			       (cur4->name, BAD_CAST "ComplexData") == 0
+			       && (ltmp == NULL
+				   || strncasecmp (ltmp->value,
+						   "text/xml", 8) == 0)))
+			    {
+			      xmlDocPtr doc1 = xmlNewDoc (BAD_CAST "1.0");
+			      int buffersize;
+			      xmlNodePtr cur5 = cur4->children;
+			      while (cur5 != NULL
+				     && cur5->type != XML_ELEMENT_NODE
+				     && cur5->type != XML_CDATA_SECTION_NODE)
+				cur5 = cur5->next;
+			      if (cur5 != NULL
+				  && cur5->type != XML_CDATA_SECTION_NODE)
+				{
+				  xmlDocSetRootElement (doc1, cur5);
+				  xmlDocDumpFormatMemoryEnc (doc1, &mv,
+							     &buffersize,
+							     "utf-8", 0);
+				  xmlFreeDoc (doc1);
+				}
+			      else
+				{
+				  if (cur5 != NULL
+				      && cur5->type == XML_CDATA_SECTION_NODE){
+				    xmlDocPtr doc2 = xmlReadMemory((const char*)cur5->content,xmlStrlen(cur5->content),
+								   "input_content.xml", NULL, XML_PARSE_RECOVER);
+				    xmlDocDumpFormatMemoryEnc (doc2, &mv,
+							       &buffersize,
+							       "utf-8", 0);
+				    xmlFreeDoc (doc2);
+				  }
+				}
+			      addIntToMap (tmpmaps->content, "size",
+					   buffersize);
+			    }else{
+
+			    if(xmlStrcasecmp
+			       (cur4->name, BAD_CAST "BoundingBoxData") == 0){
+			      xmlDocPtr doc1 = xmlNewDoc(BAD_CAST "1.0");
+			      int buffersize;
+			      xmlDocSetRootElement(doc1,cur4);
+			      xmlDocDumpFormatMemoryEnc(doc1,&mv,
+							&buffersize,
+							"utf-8",0);
+			      addIntToMap (tmpmaps->content, "size",
+					   buffersize);
+			      xmlParseBoundingBox(main_conf,&tmpmaps->content,doc1);
+			    }else{
+			      xmlNodePtr cur5 = cur4->children;
+			      while (cur5 != NULL
+				     && cur5->type != XML_ELEMENT_NODE
+				     && cur5->type != XML_TEXT_NODE
+				     && cur5->type != XML_CDATA_SECTION_NODE)
+				cur5 = cur5->next;
+			      if (cur5 != NULL
+				  && cur5->type != XML_CDATA_SECTION_NODE
+				  && cur5->type != XML_TEXT_NODE)
+				{
+				  xmlDocPtr doc1 = xmlNewDoc (BAD_CAST "1.0");
+				  int buffersize;
+				  xmlDocSetRootElement (doc1, cur5);
+				  xmlDocDumpFormatMemoryEnc (doc1, &mv,
+							     &buffersize,
+							     "utf-8", 0);
+				  addIntToMap (tmpmaps->content, "size",
+					       buffersize);
+				}
+			      else if (cur5 != NULL){
+				if(ltmp!= NULL && strstr(ltmp->value,"text/")!=NULL){
+				  xmlChar *tmp = xmlNodeListGetRawString (doc,
+									  cur4->xmlChildrenNode,
+									  0);
+				  addToMap (tmpmaps->content, "value",
+					    (char *) tmp);
+				  xmlFree (tmp);
+				}else{
+				  while(cur5!=NULL && cur5->type != XML_CDATA_SECTION_NODE)
+				    cur5=cur5->next;
+				  xmlFree(mv);
+				  if(cur5!=NULL && cur5->content!=NULL){
+				    mv=xmlStrdup(cur5->content);
+				  }
+			 	}
+			      }
+			    }
+			  }
+			  if (mv != NULL)
+			    {
+			      addToMap (tmpmaps->content, "value",
+					(char*) mv);
+			      xmlFree (mv);
+			    }
+			}
+		      else
+			{
+			  xmlNodePtr cur5 = cur4->children;
+			  while (cur5 != NULL
+				 && cur5->type != XML_CDATA_SECTION_NODE)
+			    cur5 = cur5->next;
+			  if (cur5 != NULL
+			      && cur5->type == XML_CDATA_SECTION_NODE)
+			    {
+			      addToMap (tmpmaps->content,
+					"value",
+					(char *) cur5->content);
+			    }
+			  else{
+			    if(cur4->xmlChildrenNode!=NULL){
+			      xmlChar *tmp = xmlNodeListGetRawString (doc,
+								      cur4->xmlChildrenNode,
+								      0);
+			      addToMap (tmpmaps->content, "value",
+					(char *) tmp);
+			      xmlFree (tmp);
+			    }
+			  }
+			}
+
+		      cur4 = cur4->next;
+		    }
+		}
+	      cur2 = cur2->next;
+	      while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE){
+		cur2 = cur2->next;
+	      }
+	    }
+	  if(memory!=NULL && strncasecmp(memory->value,"load",4)!=0)
+	    if(getMap(tmpmaps->content,"to_load")==NULL){
+	      addToMap(tmpmaps->content,"to_load","false");
+	    }
+	  {
+	    map* test=getMap(tmpmaps->content,"value");
+	    if(test==NULL && tmpmaps->child==NULL)
+	      addToMap(tmpmaps->content,"value","");
+	    maps *testPresence = getMaps (*request_output, tmpmaps->name);
+	    maps *cursor=*request_output;
+	    while(testPresence == NULL && cursor!=NULL){
+	      if(cursor->child!=NULL){
+		testPresence = getMaps (cursor->child, tmpmaps->name);
+	      }
+	      cursor=cursor->next;
+	    }
+	    if (testPresence != NULL)
+	      {
+		elements *elem = getElements (s->inputs, tmpmaps->name);
+		elements *cursor=s->inputs;
+		while(elem == NULL && cursor!=NULL){
+		  if(cursor->child!=NULL){
+		    elem = getElements (cursor->child, tmpmaps->name);
+		  }
+		  cursor=cursor->next;
+		}
+		if (elem != NULL)
+		  {
+		    if (appendMapsToMaps
+			(*main_conf, testPresence, tmpmaps, elem) < 0)
+		      {
+			return errorException (*main_conf,
+					       _("Unable to append maps to maps."),
+					       "InternalError",
+					       NULL);
+		      }
+		  }
+	      }
+	    else{
+	      addMapsToMaps (request_output, tmpmaps);
+	    }
+	  }
+	  freeMaps (&tmpmaps);
+	  free (tmpmaps);
+	  tmpmaps = NULL;
+	}
+    }
+  return 1;
+}
+
+/**
+ * Parse a BoundingBoxData node
+ *
+ * http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd: BoundingBoxType
+ * 
+ * A map to store boundingbox information will contain:
+ *  - LowerCorner : double double (minimum within this bounding box)
+ *  - UpperCorner : double double (maximum within this bounding box)
+ *  - crs : URI (Reference to definition of the CRS)
+ *  - dimensions : int 
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request_inputs the map storing KVP raw value 
+ * @param doc the xmlDocPtr containing the BoudingoxData node
+ * @return a map containing all the bounding box keys
+ */
+int xmlParseBoundingBox(maps** main_conf,map** current_input,xmlDocPtr doc){
+  xmlNode *root_element = xmlDocGetRootElement(doc);
+  for(xmlAttrPtr attr = root_element->properties; NULL != attr; attr = attr->next){
+    xmlChar *val = xmlGetProp (root_element, BAD_CAST attr->name);
+    addToMap(*current_input,(char*)attr->name,(char*)val);
+    xmlFree(val);
+    xmlNodePtr cur = root_element->children;
+    while(cur!=NULL && cur->type != XML_ELEMENT_NODE)
+      cur=cur->next;
+    while(cur!=NULL && cur->type==XML_ELEMENT_NODE){
+      xmlChar *val =
+	xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
+      addToMap(*current_input,(char*)cur->name,(char*)val);
+      cur=cur->next;
+      xmlFree(val);
+      while(cur!=NULL && cur->type != XML_ELEMENT_NODE)
+	cur=cur->next;
+    }
+  }
+  return 0;
+}
+
+/**
+ * Parse outputs from XML nodes and store them in a maps (WPS version 2.0.0).
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request_inputs the map storing KVP raw value 
+ * @param request_output the maps to store the KVP pairs 
+ * @param doc the xmlDocPtr containing the original request
+ * @param cur the xmlNodePtr corresponding to the ResponseDocument or RawDataOutput XML node
+ * @param raw true if the node is RawDataOutput, false in case of ResponseDocument
+ * @return 0 on success, -1 on failure
+ */
+int xmlParseOutputs2(maps** main_conf,map** request_inputs,maps** request_output,xmlDocPtr doc,xmlNodeSet* nodes){
+  int k = 0;
+  int l = 0;
+  for (k=0; k < nodes->nodeNr; k++){
+    maps *tmpmaps = NULL;
+    xmlNodePtr cur = nodes->nodeTab[k];
+    if (cur->type == XML_ELEMENT_NODE){
+      maps *tmpmaps = NULL;
+      xmlChar *val = xmlGetProp (cur, BAD_CAST "id");
+      if(val!=NULL)
+	tmpmaps = createMaps((char *)val);
+      else
+	tmpmaps = createMaps("unknownIdentifier");
+      const char ress[4][13] =
+	{ "mimeType", "encoding", "schema", "transmission" };
+      xmlFree (val);
+      for (l = 0; l < 4; l++){
+	val = xmlGetProp (cur, BAD_CAST ress[l]);
+	if (val != NULL && strlen ((char *) val) > 0)
+	  {
+	    if (tmpmaps->content != NULL)
+	      addToMap (tmpmaps->content, ress[l],
+			(char *) val);
+	    else
+	      tmpmaps->content =
+		createMap (ress[l], (char *) val);
+	    if(l==3 && strncasecmp((char*)val,"reference",xmlStrlen(val))==0)
+	      addToMap (tmpmaps->content,"asReference","true");
+	  }
+	xmlFree (val);
+      }
+      if(cur->children!=NULL){
+	xmlNodePtr ccur = cur->children;
+	while (ccur != NULL){
+	  if(ccur->type == XML_ELEMENT_NODE){
+	    char *xpathExpr=(char*)malloc(66+strlen(tmpmaps->name));
+	    sprintf(xpathExpr,"/*/*[local-name()='Output' and @id='%s']/*[local-name()='Output']",tmpmaps->name);	    
+	    xmlXPathObjectPtr tmpsptr = extractFromDoc (doc, xpathExpr);
+	    xmlNodeSet* cnodes = tmpsptr->nodesetval;
+	    xmlParseOutputs2(main_conf,request_inputs,&tmpmaps->child,doc,cnodes);
+	    xmlXPathFreeObject (tmpsptr);
+	    free(xpathExpr);
+	    break;
+	  }
+	  ccur = ccur->next;
+	}
+      }
+      if (*request_output == NULL){
+	*request_output = dupMaps(&tmpmaps);
+      }
+      else{
+	addMapsToMaps(request_output,tmpmaps);
+      }
+      freeMaps(&tmpmaps);
+      free(tmpmaps);
+    }
+  }
+  return 0;
+}
+
+/**
+ * Parse outputs from XML nodes and store them in a maps.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request_inputs the map storing KVP raw value 
+ * @param request_output the maps to store the KVP pairs 
+ * @param doc the xmlDocPtr containing the original request
+ * @param cur the xmlNodePtr corresponding to the ResponseDocument or RawDataOutput XML node
+ * @param raw true if the node is RawDataOutput, false in case of ResponseDocument
+ * @return 0 on success, -1 on failure
+ */
+int xmlParseOutputs(maps** main_conf,map** request_inputs,maps** request_output,xmlDocPtr doc,xmlNodePtr cur,bool raw){
+  int l=0;
+  if( raw == true)
+    {
+      addToMap (*request_inputs, "RawDataOutput", "");
+      if (cur->type == XML_ELEMENT_NODE)
+	{
+
+	  maps *tmpmaps = createMaps("unknownIdentifier");
+	  if (tmpmaps == NULL)
+	    {
+	      return errorException (*main_conf, _("Unable to allocate memory"),
+				     "InternalError", NULL);
+	    }
+
+	  // Get every attribute from a RawDataOutput node
+	  // mimeType, encoding, schema, uom
+	  const char *outs[4] =
+	    { "mimeType", "encoding", "schema", "uom" };
+	  for (l = 0; l < 4; l++)
+	    {
+	      xmlChar *val = xmlGetProp (cur, BAD_CAST outs[l]);
+	      if (val != NULL)
+		{
+		  if (strlen ((char *) val) > 0)
+		    {
+		      if (tmpmaps->content != NULL)
+			addToMap (tmpmaps->content, outs[l],
+				  (char *) val);
+		      else
+			tmpmaps->content =
+			  createMap (outs[l], (char *) val);
+		    }
+		  xmlFree (val);
+		}
+	    }
+	  xmlNodePtr cur2 = cur->children;
+	  while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE)
+	    cur2 = cur2->next;
+	  while (cur2 != NULL)
+	    {
+	      if (xmlStrncasecmp
+		  (cur2->name, BAD_CAST "Identifier",
+		   xmlStrlen (cur2->name)) == 0)
+		{
+		  xmlChar *val =
+		    xmlNodeListGetString (NULL, cur2->xmlChildrenNode, 1);
+		  free (tmpmaps->name);
+		  tmpmaps->name = zStrdup ((char *) val);
+		  xmlFree (val);
+		}
+	      cur2 = cur2->next;
+	      while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE)
+		cur2 = cur2->next;
+	    }
+	  if (*request_output == NULL)
+	    *request_output = dupMaps (&tmpmaps);
+	  else
+	    addMapsToMaps (request_output, tmpmaps);
+	  if (tmpmaps != NULL)
+	    {
+	      freeMaps (&tmpmaps);
+	      free (tmpmaps);
+	      tmpmaps = NULL;
+	    }
+	}
+    }
+  else
+    {
+      addToMap (*request_inputs, "ResponseDocument", "");
+
+      if (cur->type == XML_ELEMENT_NODE) {
+	// Get every attribute: storeExecuteResponse, lineage, status
+	const char *ress[3] =
+	  { "storeExecuteResponse", "lineage", "status" };
+	xmlChar *val;
+	for (l = 0; l < 3; l++)
+	  {
+	    val = xmlGetProp (cur, BAD_CAST ress[l]);
+	    if (val != NULL && strlen ((char *) val) > 0)
+	      {
+		addToMap (*request_inputs, ress[l], (char *) val);
+	      }
+	    xmlFree (val);
+	  }
+			
+	xmlNodePtr cur1 = cur->children;		
+	while (cur1 != NULL) // iterate over Output nodes
+	  {
+	    if (cur1->type != XML_ELEMENT_NODE || 
+		xmlStrncasecmp(cur1->name, BAD_CAST "Output", 
+			       xmlStrlen (cur1->name)) != 0) {
+	      cur1 = cur1->next;
+	      continue;
+	    }
+				
+	    maps *tmpmaps = createMaps("unknownIdentifier"); // one per Output node
+	    if (tmpmaps == NULL) {
+	      return errorException (*main_conf,
+				     _
+				     ("Unable to allocate memory"),
+				     "InternalError", NULL);
+	    }
+				
+	    xmlNodePtr elems = cur1->children;
+				
+	    while (elems != NULL) {
+
+	      // Identifier
+	      if (xmlStrncasecmp
+		  (elems->name, BAD_CAST "Identifier",
+		   xmlStrlen (elems->name)) == 0)
+		{
+		  xmlChar *val =
+		    xmlNodeListGetString (doc, elems->xmlChildrenNode, 1);
+		
+		  free(tmpmaps->name);
+		  tmpmaps->name = zStrdup ((char *) val);
+		  if (tmpmaps->content == NULL) {
+		    tmpmaps->content = createMap("Identifier", zStrdup ((char *) val));
+		  }
+		  else {
+		    addToMap(tmpmaps->content, "Identifier", zStrdup ((char *) val));
+		  }
+
+		  map* tt = getMap (*request_inputs, "ResponseDocument");
+		  if (strlen(tt->value) == 0) {
+		    addToMap (*request_inputs, "ResponseDocument",
+			      (char *) val);
+		  }
+		  else {
+		    char* tmp = (char*) malloc((strlen(tt->value) + 1 
+						+ strlen((char*) val) + 1) * sizeof(char));
+		    sprintf (tmp, "%s;%s", tt->value, (char *) val);
+		    free(tt->value);
+		    tt->value = tmp;
+		  }
+		  xmlFree (val);
+		}
+	      
+	      // Title, Abstract
+	      else if (xmlStrncasecmp(elems->name, BAD_CAST "Title",
+				      xmlStrlen (elems->name)) == 0
+		       || xmlStrncasecmp(elems->name, BAD_CAST "Abstract",
+					 xmlStrlen (elems->name)) == 0)
+		{
+		  xmlChar *val =
+		    xmlNodeListGetString (doc, elems->xmlChildrenNode, 1);
+							
+		  if (tmpmaps->content == NULL) {
+		    tmpmaps->content = createMap((char*) elems->name, zStrdup ((char *) val));
+		  }
+		  else {
+		    addToMap(tmpmaps->content, (char*) elems->name, zStrdup ((char *) val));
+		  }
+		  xmlFree (val);
+		}
+	      elems = elems->next;
+	    }
+				
+	    // Get every attribute from an Output node:
+	    // mimeType, encoding, schema, uom, asReference
+	    const char *outs[5] =
+	      { "mimeType", "encoding", "schema", "uom", "asReference" };
+					  
+	    for (l = 0; l < 5; l++) {
+	      xmlChar *val = xmlGetProp (cur1, BAD_CAST outs[l]);				
+	      if (val != NULL && xmlStrlen(val) > 0) {
+		if (tmpmaps->content != NULL) {
+		  addToMap (tmpmaps->content, outs[l], (char *) val);
+		}			  
+		else {
+		  tmpmaps->content = createMap (outs[l], (char *) val);
+		}	
+	      }
+	      xmlFree (val);
+	    }
+				
+	    if (*request_output == NULL) {
+	      *request_output = tmpmaps;
+	    }	
+	    else if (getMaps(*request_output, tmpmaps->name) != NULL) {
+	      return errorException (*main_conf,
+				     _
+				     ("Duplicate <Output> elements in WPS Execute request"),
+				     "InternalError", NULL);
+	    }
+	    else {
+	      maps* mptr = *request_output;
+	      while (mptr->next != NULL) {
+		mptr = mptr->next;
+	      }
+	      mptr->next = tmpmaps;	
+	    }					
+	    cur1 = cur1->next;
+	  }			 
+      }
+    }
+  return 1;
+}
+
+/**
+ * Parse XML request and store information in maps.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param post the string containing the XML request
+ * @param request_inputs the map storing KVP raw value 
+ * @param s the service
+ * @param inputs the maps to store the KVP pairs 
+ * @param outputs the maps to store the KVP pairs 
+ * @param hInternet the HINTERNET queue to add potential requests
+ * @return 0 on success, -1 on failure
+ */
+int xmlParseRequest(maps** main_conf,const char* post,map** request_inputs,service* s,maps** inputs,maps** outputs,HINTERNET* hInternet){
+
+  map* version=getMapFromMaps(*main_conf,"main","rversion");
+  int vid=getVersionId(version->value);
+
+  xmlInitParser ();
+  xmlDocPtr doc = xmlReadMemory (post, cgiContentLength, "input_request.xml", NULL, XML_PARSE_RECOVER);
+
+  /**
+   * Extract Input nodes from the XML Request.
+   */
+  xmlXPathObjectPtr tmpsptr =
+    extractFromDoc (doc, (vid==0?"/*/*/*[local-name()='Input']":"/*/*[local-name()='Input']"));
+  xmlNodeSet *tmps = tmpsptr->nodesetval;
+  if(tmps==NULL || xmlParseInputs(main_conf,s,inputs,doc,tmps,hInternet)<0){
+    xmlXPathFreeObject (tmpsptr);
+    xmlFreeDoc (doc);
+    xmlCleanupParser ();
+    return -1;
+  }
+  xmlXPathFreeObject (tmpsptr);
+
+  if(vid==1){
+    tmpsptr =
+      extractFromDoc (doc, "/*[local-name()='Execute']");
+    bool asRaw = false;
+    tmps = tmpsptr->nodesetval;
+    if(tmps->nodeNr > 0){
+      int k = 0;
+      for (k=0; k < tmps->nodeNr; k++){
+	maps *tmpmaps = NULL;
+	xmlNodePtr cur = tmps->nodeTab[k];
+	if (cur->type == XML_ELEMENT_NODE){
+	  xmlChar *val = xmlGetProp (cur, BAD_CAST "mode");
+	  if(val!=NULL)
+	    addToMap(*request_inputs,"mode",(char*)val);
+	  else
+	    addToMap(*request_inputs,"mode","auto");
+	  xmlFree(val);
+	  val = xmlGetProp (cur, BAD_CAST "response");
+	  if(val!=NULL){
+	    addToMap(*request_inputs,"response",(char*)val);
+	    if(strncasecmp((char*)val,"raw",xmlStrlen(val))==0)
+	      addToMap(*request_inputs,"RawDataOutput","");
+	    else
+	      addToMap(*request_inputs,"ResponseDocument","");
+	  }
+	  else{
+	    addToMap(*request_inputs,"response","document");
+	    addToMap(*request_inputs,"ResponseDocument","");
+	  }
+	  xmlFree(val);
+	}
+      }
+    }
+    xmlXPathFreeObject (tmpsptr);
+    tmpsptr =
+      extractFromDoc (doc, "/*/*[local-name()='Output']");
+    tmps = tmpsptr->nodesetval;
+    if(tmps->nodeNr > 0){
+      if(xmlParseOutputs2(main_conf,request_inputs,outputs,doc,tmps)<0){
+	xmlXPathFreeObject (tmpsptr);
+	xmlFreeDoc (doc);
+	xmlCleanupParser ();
+	return -1;
+      }
+    }
+  }
+  else{
+    // Extract ResponseDocument / RawDataOutput from the XML Request 
+    tmpsptr =
+      extractFromDoc (doc, "/*/*/*[local-name()='ResponseDocument']");
+    bool asRaw = false;
+    tmps = tmpsptr->nodesetval;
+    if (tmps->nodeNr == 0)
+      {
+	xmlXPathFreeObject (tmpsptr);
+	tmpsptr =
+	  extractFromDoc (doc, "/*/*/*[local-name()='RawDataOutput']");
+	tmps = tmpsptr->nodesetval;
+	asRaw = true;
+      }
+    if(tmps->nodeNr != 0){
+      if(xmlParseOutputs(main_conf,request_inputs,outputs,doc,tmps->nodeTab[0],asRaw)<0){
+	xmlXPathFreeObject (tmpsptr);
+	xmlFreeDoc (doc);
+	xmlCleanupParser ();
+	return -1;
+      }
+    }
+  }
+  xmlXPathFreeObject (tmpsptr);
+  xmlFreeDoc (doc);
+  xmlCleanupParser ();
+  return 1;
+}
+
+/**
+ * Parse request and store information in maps.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param post the string containing the XML request
+ * @param request_inputs the map storing KVP raw value 
+ * @param s the service
+ * @param inputs the maps to store the KVP pairs 
+ * @param outputs the maps to store the KVP pairs 
+ * @param hInternet the HINTERNET queue to add potential requests
+ * @return 0 on success, -1 on failure
+ * @see kvpParseOutputs,kvpParseInputs,xmlParseRequest
+ */
+int parseRequest(maps** main_conf,map** request_inputs,service* s,maps** inputs,maps** outputs,HINTERNET* hInternet){
+  map *postRequest = NULL;
+  postRequest = getMap (*request_inputs, "xrequest");
+  if (postRequest == NULLMAP)
+    {
+      if(kvpParseOutputs(main_conf,*request_inputs,outputs)<0){
+	return -1;
+      }
+      if(kvpParseInputs(main_conf,s,*request_inputs,inputs,hInternet)<0){
+	return -1;
+      }
+    }
+  else
+    {
+      //Parse XML request
+      if(xmlParseRequest(main_conf,postRequest->value,request_inputs,s,inputs,outputs,hInternet)<0){
+	return -1;
+      }
+    }
+  return 1;
+}
+
+/**
+ * Ensure that each requested arguments are present in the request
+ * DataInputs and ResponseDocument / RawDataOutput. Potentially run
+ * http requests from the queue in parallel.
+ * For optional inputs add default values defined in the ZCFG file.
+ * 
+ * @param main_conf
+ * @param s 
+ * @param original_request
+ * @param request_inputs
+ * @param request_outputs
+ * @param hInternet 
+ * 
+ * @see runHttpRequests
+ */
+int validateRequest(maps** main_conf,service* s,map* original_request, maps** request_inputs,maps** request_outputs,HINTERNET* hInternet){
+
+  map* errI0=NULL;
+  runHttpRequests (main_conf, request_inputs, hInternet,&errI0);
+  if(errI0!=NULL){
+    printExceptionReportResponse (*main_conf, errI0);
+    InternetCloseHandle (hInternet);
+    return -1;
+  }
+  InternetCloseHandle (hInternet);
+
+
+  map* errI=NULL;
+  char *dfv = addDefaultValues (request_inputs, s->inputs, *main_conf, 0,&errI);
+
+  maps *ptr = *request_inputs;
+  while (ptr != NULL)
+    {
+      map *tmp0 = getMap (ptr->content, "size");
+      map *tmp1 = getMap (ptr->content, "maximumMegabytes");
+      if (tmp1 != NULL && tmp0 != NULL)
+        {
+          float i = atof (tmp0->value) / 1048576.0;
+          if (i >= atoi (tmp1->value))
+            {
+              char tmps[1024];
+              map *tmpe = createMap ("code", "FileSizeExceeded");
+              snprintf (tmps, 1024,
+                        _
+                        ("The <%s> parameter has a size limit (%s MB) defined in the ZOO ServicesProvider configuration file, but the reference you provided exceeds this limit (%f MB)."),
+                        ptr->name, tmp1->value, i);
+              addToMap (tmpe, "locator", ptr->name);
+              addToMap (tmpe, "text", tmps);
+              printExceptionReportResponse (*main_conf, tmpe);
+              freeMap (&tmpe);
+              free (tmpe);
+	      return -1;
+            }
+        }
+      ptr = ptr->next;
+    }
+
+  map* errO=NULL;
+  char *dfv1 =
+    addDefaultValues (request_outputs, s->outputs, *main_conf, 1,&errO);
+
+  if (strcmp (dfv1, "") != 0 || strcmp (dfv, "") != 0)
+    {
+      char tmps[1024];
+      map *tmpe = NULL;
+      if (strcmp (dfv, "") != 0)
+        {
+	  tmpe = createMap ("code", "MissingParameterValue");
+	  int nb=0;
+	  int length=1;
+	  map* len=getMap(errI,"length");
+	  if(len!=NULL)
+	    length=atoi(len->value);
+	  for(nb=0;nb<length;nb++){
+	    map* errp=getMapArray(errI,"value",nb);
+	    snprintf (tmps, 1024,
+		      _
+		      ("The <%s> argument was not specified in DataInputs but is required according to the ZOO ServicesProvider configuration file."),
+		      errp->value);
+	    setMapArray (tmpe, "locator", nb , errp->value);
+	    setMapArray (tmpe, "text", nb , tmps);
+	    setMapArray (tmpe, "code", nb , "MissingParameterValue");
+	  }
+	}
+      if (strcmp (dfv1, "") != 0)
+        {
+	  int ilength=0;
+	  if(tmpe==NULL)
+	    tmpe = createMap ("code", "InvalidParameterValue");
+	  else{
+	    map* len=getMap(tmpe,"length");
+	    if(len!=NULL)
+	      ilength=atoi(len->value);
+	  }
+	  int nb=0;
+	  int length=1;
+	  map* len=getMap(errO,"length");
+	  if(len!=NULL)
+	    length=atoi(len->value);
+	  for(nb=0;nb<length;nb++){
+	    map* errp=getMapArray(errO,"value",nb);
+	    snprintf (tmps, 1024,
+		      _
+		      ("The <%s> argument specified as %s identifier was not recognized (not defined in the ZOO Configuration File)."),
+		      errp->value,
+		      ((getMap(original_request,"RawDataOutput")!=NULL)?"RawDataOutput":"ResponseDocument"));
+	    setMapArray (tmpe, "locator", nb+ilength , errp->value);
+	    setMapArray (tmpe, "text", nb+ilength , tmps);
+	    setMapArray (tmpe, "code", nb+ilength , "InvalidParameterValue");
+	  }
+	}
+      printExceptionReportResponse (*main_conf, tmpe);
+      if(errI!=NULL){
+	freeMap(&errI);
+	free(errI);
+      }
+      if(errO!=NULL){
+	freeMap(&errO);
+	free(errO);
+      }
+      freeMap (&tmpe);
+      free (tmpe);
+      return -1;
+    }
+  maps *tmpReqI = *request_inputs;
+  while (tmpReqI != NULL)
+    {
+      char name[1024];
+      if (getMap (tmpReqI->content, "isFile") != NULL)
+        {
+          if (cgiFormFileName (tmpReqI->name, name, sizeof (name)) ==
+              cgiFormSuccess)
+            {
+              int BufferLen = 1024;
+              cgiFilePtr file;
+              int targetFile;
+              char *storageNameOnServer;
+              char *fileNameOnServer;
+              char contentType[1024];
+              char buffer[1024];
+              char *tmpStr = NULL;
+              int size;
+              int got, t;
+              map *path = getMapFromMaps (*main_conf, "main", "tmpPath");
+              cgiFormFileSize (tmpReqI->name, &size);
+              cgiFormFileContentType (tmpReqI->name, contentType,
+                                      sizeof (contentType));
+              if (cgiFormFileOpen (tmpReqI->name, &file) == cgiFormSuccess)
+                {
+                  t = -1;
+                  while (1)
+                    {
+                      tmpStr = strstr (name + t + 1, "\\");
+                      if (NULL == tmpStr)
+                        tmpStr = strstr (name + t + 1, "/");
+                      if (NULL != tmpStr)
+                        t = (int) (tmpStr - name);
+                      else
+                        break;
+                    }
+		  fileNameOnServer=(char*)malloc((strlen(name) - t - 1 )*sizeof(char));
+                  strcpy (fileNameOnServer, name + t + 1);
+
+		  storageNameOnServer=(char*)malloc((strlen(path->value) + strlen(fileNameOnServer) + 2)*sizeof(char));
+                  sprintf (storageNameOnServer, "%s/%s", path->value,
+                           fileNameOnServer);
+#ifdef DEBUG
+                  fprintf (stderr, "Name on server %s\n",
+                           storageNameOnServer);
+                  fprintf (stderr, "fileNameOnServer: %s\n",
+                           fileNameOnServer);
+#endif
+                  targetFile =
+                    zOpen (storageNameOnServer, O_RDWR | O_CREAT | O_TRUNC,
+                          S_IRWXU | S_IRGRP | S_IROTH);
+                  if (targetFile < 0)
+                    {
+#ifdef DEBUG
+                      fprintf (stderr, "could not create the new file,%s\n",
+                               fileNameOnServer);
+#endif
+                    }
+                  else
+                    {
+                      while (cgiFormFileRead (file, buffer, BufferLen, &got)
+                             == cgiFormSuccess)
+                        {
+                          if (got > 0)
+                            write (targetFile, buffer, got);
+                        }
+                    }
+                  addToMap (tmpReqI->content, "lref", storageNameOnServer);
+                  cgiFormFileClose (file);
+                  zClose (targetFile);
+		  free(fileNameOnServer);
+		  free(storageNameOnServer);
+#ifdef DEBUG
+                  fprintf (stderr, "File \"%s\" has been uploaded",
+                           fileNameOnServer);
+#endif
+                }
+            }
+        }
+      tmpReqI = tmpReqI->next;
+    }
+
+  ensureDecodedBase64 (request_inputs);
+  return 1;
+}
+
+
+/**
+ * Verify if a parameter value is valid.
+ * 
+ * @param request the request map
+ * @param res the error map potentially generated
+ * @param toCheck the parameter to use
+ * @param avalues the acceptable values (or null if testing only for presence)
+ * @param mandatory verify the presence of the parameter if mandatory > 0 
+ */
+void checkValidValue(map* request,map** res,const char* toCheck,const char** avalues,int mandatory){
+  map* lres=*res;
+  map* r_inputs = getMap (request,toCheck);
+  if (r_inputs == NULL){
+    if(mandatory>0){
+      const char *replace=_("Mandatory parameter <%s> was not specified");
+      char *message=(char*)malloc((strlen(replace)+strlen(toCheck)+1)*sizeof(char));
+      sprintf(message,replace,toCheck);
+      if(lres==NULL){
+	lres=createMap("code","MissingParameterValue");
+	addToMap(lres,"text",message);
+	addToMap(lres,"locator",toCheck);       
+      }else{
+	int length=1;
+	map* len=getMap(lres,"length");
+	if(len!=NULL){
+	  length=atoi(len->value);
+	}
+	setMapArray(lres,"text",length,message);
+	setMapArray(lres,"locator",length,toCheck);
+	setMapArray(lres,"code",length,"MissingParameterValue");
+      }
+      free(message);
+    }
+  }else{
+    if(avalues==NULL)
+      return;
+    int nb=0;
+    int hasValidValue=-1;
+    if(strncasecmp(toCheck,"Accept",6)==0){
+      char *tmp=zStrdup(r_inputs->value);
+      char *pToken,*saveptr;
+      pToken=strtok_r(tmp,",",&saveptr);
+      while(pToken!=NULL){
+	while(avalues[nb]!=NULL){
+	  if(strcasecmp(avalues[nb],pToken)==0){
+	    hasValidValue=1;
+	    break;
+	  }
+	  nb++;
+	}
+	pToken=strtok_r(NULL,",",&saveptr);
+      }
+      free(tmp);
+    }else{
+      while(avalues[nb]!=NULL){
+	if(strcasecmp(avalues[nb],r_inputs->value)==0){
+	  hasValidValue=1;
+	  break;
+	}
+	nb++;
+      }
+    }
+    if(hasValidValue<0){
+      const char *replace=_("The value <%s> was not recognized, %s %s the only acceptable value.");
+      nb=0;
+      char *vvalues=NULL;
+      const char* num=_("is");
+      while(avalues[nb]!=NULL){
+	char *tvalues;
+	if(vvalues==NULL){
+	  vvalues=(char*)malloc((strlen(avalues[nb])+3)*sizeof(char));
+	  sprintf(vvalues,"%s",avalues[nb]);
+	}
+	else{
+	  tvalues=zStrdup(vvalues);
+	  vvalues=(char*)realloc(vvalues,(strlen(tvalues)+strlen(avalues[nb])+3)*sizeof(char));
+	  sprintf(vvalues,"%s, %s",tvalues,avalues[nb]);
+	  free(tvalues);
+	  num=_("are");
+	}
+	nb++;
+      }
+      char *message=(char*)malloc((strlen(replace)+strlen(num)+strlen(vvalues)+strlen(toCheck)+1)*sizeof(char));
+      sprintf(message,replace,toCheck,vvalues,num);
+      const char *code="VersionNegotiationFailed";
+      code="InvalidParameterValue";
+      const char *locator=toCheck;
+      if( strncasecmp(toCheck,"version",7)==0 ||
+	  strncasecmp(toCheck,"AcceptVersions",14)==0 )
+	code="VersionNegotiationFailed";
+      if( strncasecmp(toCheck,"request",7)==0){
+	code="OperationNotSupported";
+	locator=r_inputs->value;
+      }
+      if(lres==NULL){
+	lres=createMap("code",code);
+	addToMap(lres,"text",message);
+	addToMap(lres,"locator",locator);       
+      }else{
+	int length=1;
+	map* len=getMap(lres,"length");
+	if(len!=NULL){
+	  length=atoi(len->value);
+	}
+	setMapArray(lres,"text",length,message);
+	setMapArray(lres,"locator",length,locator);
+	setMapArray(lres,"code",length,code);
+      }
+    }
+  }
+  if(lres!=NULL){
+    *res=lres;
+  }
+}
+
+/**
+ * Parse cookie contained in request headers.
+ *
+ * @param conf the conf maps containinfg the main.cfg
+ * @param cookie the 
+ */
+void parseCookie(maps** conf,const char* cookie){
+  char* tcook=zStrdup(cookie);
+  char *token, *saveptr;
+  token = strtok_r (tcook, "; ", &saveptr);
+  maps* res=createMaps("cookies");
+  while (token != NULL){
+    char *token1, *saveptr1, *name;
+    int i=0;
+    token1 = strtok_r (token, "=", &saveptr1);
+    while (token1 != NULL){
+      if(i==0){
+	name=zStrdup(token1);
+	i++;
+      }
+      else{
+	if(res->content==NULL)
+	  res->content=createMap(name,token1);
+	else
+	  addToMap(res->content,name,token1);
+	free(name);
+	name=NULL;
+	i=0;
+      }
+      token1 = strtok_r (NULL, "=", &saveptr1);
+    }
+    if(name!=NULL)
+      free(name);
+    token = strtok_r (NULL, "; ", &saveptr);
+  }
+  addMapsToMaps(conf,res);
+  freeMaps(&res);
+  free(res);
+  free(tcook);
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/request_parser.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/request_parser.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/request_parser.h	(revision 942)
@@ -0,0 +1,59 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_REQUEST_PARSER_H
+#define ZOO_REQUEST_PARSER_H 1
+
+#pragma once 
+
+#include "service.h"
+#include "ulinet.h"
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  xmlXPathObjectPtr extractFromDoc (xmlDocPtr, const char *);
+  int appendMapsToMaps (maps*, maps*, maps*, elements*);
+  void ensureDecodedBase64(maps**);
+  int kvpParseInputs(maps**,service*,map*,maps**,HINTERNET*);
+  int xmlParseBoundingBox(maps**,map**,xmlDocPtr);
+  int kvpParseOutputs(maps**,map *,maps**);
+  int xmlParseInputs(maps**,service*,maps**,xmlDocPtr,xmlNodeSet*,HINTERNET*);
+  int xmlParseBoundingBox(maps** main_conf,map** current_input,xmlDocPtr doc);
+  int xmlParseOutputs(maps**,map**,maps**,xmlDocPtr,xmlNodePtr,bool);
+  int xmlParseRequest(maps**,const char*,map**,service*,maps**,maps**,HINTERNET*);
+  int parseRequest(maps**,map**,service*,maps**,maps**,HINTERNET*);
+  void checkValidValue(map*,map**,const char*,const char**,int);
+  int validateRequest(maps**,service*,map*,maps**,maps**,HINTERNET*);
+  void parseCookie(maps**,const char*);
+  
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/response_print.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/response_print.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/response_print.c	(revision 942)
@@ -0,0 +1,3215 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef USE_MS
+#include "service_internal_ms.h"
+#else
+#include "cpl_vsi.h"
+#endif
+#ifdef USE_CALLBACK
+#include "service_callback.h"
+#endif
+#include "service.h"
+#include "service_internal.h"
+#include "server_internal.h"
+#include "response_print.h"
+
+#ifndef WIN32
+#include <dlfcn.h>
+#endif
+
+#include "mimetypes.h"
+
+/**
+ * Add prefix to the service name.
+ * 
+ * @param conf the conf maps containing the main.cfg settings
+ * @param level the map containing the level information
+ * @param serv the service structure created from the zcfg file
+ */
+void addPrefix(maps* conf,map* level,service* serv){
+  if(level!=NULL){
+    char key[25];
+    char* prefix=NULL;
+    int clevel=atoi(level->value);
+    int cl=0;
+    for(cl=0;cl<clevel;cl++){
+      sprintf(key,"sprefix_%d",cl);
+      map* tmp2=getMapFromMaps(conf,"lenv",key);
+      if(tmp2!=NULL){
+	if(prefix==NULL)
+	  prefix=zStrdup(tmp2->value);
+	else{
+	  int plen=strlen(prefix);
+	  prefix=(char*)realloc(prefix,(plen+strlen(tmp2->value)+2)*sizeof(char));
+	  memcpy(prefix+plen,tmp2->value,strlen(tmp2->value)*sizeof(char));
+	  prefix[plen+strlen(tmp2->value)]=0;
+	}
+      }
+    }
+    if(prefix!=NULL){
+      char* tmp0=zStrdup(serv->name);
+      free(serv->name);
+      serv->name=(char*)malloc((strlen(prefix)+strlen(tmp0)+1)*sizeof(char));
+      sprintf(serv->name,"%s%s",prefix,tmp0);
+      free(tmp0);
+      free(prefix);
+      prefix=NULL;
+    }
+  }
+}
+
+/**
+ * Print the HTTP headers based on a map.
+ * 
+ * @param m the map containing the headers information
+ */
+void printHeaders(maps* m){
+  maps *_tmp=getMaps(m,"headers");
+  if(_tmp!=NULL){
+    map* _tmp1=_tmp->content;
+    while(_tmp1!=NULL){
+      printf("%s: %s\r\n",_tmp1->name,_tmp1->value);
+      _tmp1=_tmp1->next;
+    }
+  }
+}
+
+/**
+ * Add a land attribute to a XML node
+ *
+ * @param n the XML node to add the attribute
+ * @param m the map containing the language key to add as xml:lang
+ */
+void addLangAttr(xmlNodePtr n,maps *m){
+  map *tmpLmap=getMapFromMaps(m,"main","language");
+  if(tmpLmap!=NULL)
+    xmlNewProp(n,BAD_CAST "xml:lang",BAD_CAST tmpLmap->value);
+  else
+    xmlNewProp(n,BAD_CAST "xml:lang",BAD_CAST "en-US");
+}
+
+/**
+ * Replace the first letter by its upper case version in a new char array
+ *
+ * @param tmp the char*
+ * @return a new char* with first letter in upper case
+ * @warning be sure to free() the returned string after use
+ */
+char *zCapitalize1(char *tmp){
+  char *res=zStrdup(tmp);
+  if(res[0]>=97 && res[0]<=122)
+    res[0]-=32;
+  return res;
+}
+
+/**
+ * Replace all letters by their upper case version in a new char array
+ *
+ * @param tmp the char*
+ * @return a new char* with first letter in upper case
+ * @warning be sure to free() the returned string after use
+ */
+char *zCapitalize(char *tmp){
+  int i=0;
+  char *res=zStrdup(tmp);
+  for(i=0;i<strlen(res);i++)
+    if(res[i]>=97 && res[i]<=122)
+      res[i]-=32;
+  return res;
+}
+
+/**
+ * Search for an existing XML namespace in usedNS.
+ * 
+ * @param name the name of the XML namespace to search
+ * @return the index of the XML namespace found or -1 if not found.
+ */
+int zooXmlSearchForNs(const char* name){
+  int i;
+  int res=-1;
+  for(i=0;i<nbNs;i++)
+    if(strncasecmp(name,nsName[i],strlen(nsName[i]))==0){
+      res=i;
+      break;
+    }
+  return res;
+}
+
+/**
+ * Add an XML namespace to the usedNS if it was not already used.
+ * 
+ * @param nr the xmlNodePtr to attach the XML namspace (can be NULL)
+ * @param url the url of the XML namespace to add
+ * @param name the name of the XML namespace to add
+ * @return the index of the XML namespace added.
+ */
+int zooXmlAddNs(xmlNodePtr nr,const char* url,const char* name){
+#ifdef DEBUG
+  fprintf(stderr,"zooXmlAddNs %d %s \n",nbNs,name);
+#endif
+  int currId=-1;
+  if(nbNs==0){
+    nbNs++;
+    currId=0;
+    nsName[currId]=zStrdup(name);
+    usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
+  }else{
+    currId=zooXmlSearchForNs(name);
+    if(currId<0){
+      nbNs++;
+      currId=nbNs-1;
+      nsName[currId]=zStrdup(name);
+      usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
+    }
+  }
+  return currId;
+}
+
+/**
+ * Free allocated memory to store used XML namespace.
+ */
+void zooXmlCleanupNs(){
+  int j;
+#ifdef DEBUG
+  fprintf(stderr,"zooXmlCleanup %d\n",nbNs);
+#endif
+  for(j=nbNs-1;j>=0;j--){
+#ifdef DEBUG
+    fprintf(stderr,"zooXmlCleanup %d\n",j);
+#endif
+    if(j==0)
+      xmlFreeNs(usedNs[j]);
+    free(nsName[j]);
+    nbNs--;
+  }
+  nbNs=0;
+}
+
+/**
+ * Add a XML document to the iDocs.
+ * 
+ * @param value the string containing the XML document
+ * @return the index of the XML document added.
+ */
+int zooXmlAddDoc(const char* value){
+  int currId=0;
+  nbDocs++;
+  currId=nbDocs-1;
+  iDocs[currId]=xmlParseMemory(value,strlen(value));
+  return currId;
+}
+
+/**
+ * Free allocated memort to store XML documents
+ */
+void zooXmlCleanupDocs(){
+  int j;
+  for(j=nbDocs-1;j>=0;j--){
+    xmlFreeDoc(iDocs[j]);
+  }
+  nbDocs=0;
+}
+
+/**
+ * Generate a SOAP Envelope node when required (if the isSoap key of the [main]
+ * section is set to true).
+ * 
+ * @param conf the conf maps containing the main.cfg settings
+ * @param n the node used as children of the generated soap:Envelope
+ * @return the generated soap:Envelope (if isSoap=true) or the input node n 
+ *  (when isSoap=false)
+ */
+xmlNodePtr soapEnvelope(maps* conf,xmlNodePtr n){
+  map* soap=getMapFromMaps(conf,"main","isSoap");
+  if(soap!=NULL && strcasecmp(soap->value,"true")==0){
+    int lNbNs=nbNs;
+    nsName[lNbNs]=zStrdup("soap");
+    usedNs[lNbNs]=xmlNewNs(NULL,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
+    nbNs++;
+    xmlNodePtr nr = xmlNewNode(usedNs[lNbNs], BAD_CAST "Envelope");
+    nsName[nbNs]=zStrdup("soap");
+    usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
+    nbNs++;
+    nsName[nbNs]=zStrdup("xsi");
+    usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2001/XMLSchema-instance",BAD_CAST "xsi");
+    nbNs++;
+    xmlNsPtr ns_xsi=usedNs[nbNs-1];
+    xmlNewNsProp(nr,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.w3.org/2003/05/soap-envelope http://www.w3.org/2003/05/soap-envelope");
+    xmlNodePtr nr1 = xmlNewNode(usedNs[lNbNs], BAD_CAST "Body");
+    xmlAddChild(nr1,n);
+    xmlAddChild(nr,nr1);
+    return nr;
+  }else
+    return n;
+}
+
+/**
+ * Generate a WPS header.
+ * 
+ * @param doc the document to add the header
+ * @param m the conf maps containing the main.cfg settings
+ * @param req the request type (GetCapabilities,DescribeProcess,Execute)
+ * @param rname the root node name
+ * @return the generated wps:rname xmlNodePtr (can be wps: Capabilities, 
+ *  wps:ProcessDescriptions,wps:ExecuteResponse)
+ */
+xmlNodePtr printWPSHeader(xmlDocPtr doc,maps* m,const char* req,const char* rname,const char* version,int reqId){
+
+  xmlNsPtr ns,ns_xsi;
+  xmlNodePtr n;
+
+  int vid=getVersionId(version);
+
+  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
+  ns=usedNs[wpsId];
+  n = xmlNewNode(ns, BAD_CAST rname);
+  zooXmlAddNs(n,schemas[vid][1],"ows");
+  xmlNewNs(n,BAD_CAST schemas[vid][2],BAD_CAST "wps");
+  zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
+  int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
+  ns_xsi=usedNs[xsiId];
+  char *tmp=(char*) malloc((86+strlen(req)+1)*sizeof(char));
+  sprintf(tmp,schemas[vid][4],schemas[vid][2],schemas[vid][3],req);
+  xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST tmp);
+  free(tmp);
+  if(vid==0 || reqId==0){
+    xmlNewProp(n,BAD_CAST "service",BAD_CAST "WPS");
+    xmlNewProp(n,BAD_CAST "version",BAD_CAST schemas[vid][0]);
+  }
+  if(vid==0)
+    addLangAttr(n,m);
+  xmlNodePtr fn=soapEnvelope(m,n);
+  xmlDocSetRootElement(doc, fn);
+  return n;
+}
+
+void addLanguageNodes(maps* conf,xmlNodePtr n,xmlNsPtr ns,xmlNsPtr ns_ows){
+  xmlNodePtr nc1,nc2,nc3,nc4;
+  map* version=getMapFromMaps(conf,"main","rversion");
+  int vid=getVersionId(version->value);
+  if(vid==1)
+    nc1 = xmlNewNode(ns_ows, BAD_CAST "Languages");
+  else{
+    nc1 = xmlNewNode(ns, BAD_CAST "Languages");
+    nc2 = xmlNewNode(ns, BAD_CAST "Default");
+    nc3 = xmlNewNode(ns, BAD_CAST "Supported");
+  }
+
+  maps* tmp=getMaps(conf,"main");
+  if(tmp!=NULL){
+    map* tmp1=getMap(tmp->content,"lang");
+    char *toto=tmp1->value;
+    char buff[256];
+    int i=0;
+    int j=0;
+    int dcount=0;
+    while(toto[i]){
+      if(toto[i]!=',' && toto[i]!=0){
+	buff[j]=toto[i];
+	buff[j+1]=0;
+	j++;
+      }
+      else{
+	if(dcount==0){
+	  if(vid==0){
+	    nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
+	    xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
+	    xmlAddChild(nc2,nc4);
+	    xmlAddChild(nc1,nc2);
+	  }
+	  dcount++;
+	}
+	nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
+	xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
+	if(vid==0)
+	  xmlAddChild(nc3,nc4);
+	else
+	  xmlAddChild(nc1,nc4);
+	j=0;
+	buff[j]=0;
+      }
+      i++;
+    }
+    if(strlen(buff)>0){
+      nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
+      xmlAddChild(nc4,xmlNewText(BAD_CAST buff));	      
+      if(vid==0)
+	xmlAddChild(nc3,nc4);
+      else
+	xmlAddChild(nc1,nc4);
+    }
+  }
+  if(vid==0)
+    xmlAddChild(nc1,nc3);
+  xmlAddChild(n,nc1);
+}
+
+/**
+ * Generate a Capabilities header.
+ * 
+ * @param doc the document to add the header
+ * @param m the conf maps containing the main.cfg settings
+ * @return the generated wps:ProcessOfferings xmlNodePtr 
+ */
+xmlNodePtr printGetCapabilitiesHeader(xmlDocPtr doc,maps* m,const char* version="1.0.0"){
+
+  xmlNsPtr ns,ns_ows,ns_xlink;
+  xmlNodePtr n,nc,nc1,nc2,nc3,nc4,nc5,nc6;
+  n = printWPSHeader(doc,m,"GetCapabilities","Capabilities",version,0);
+  maps* toto1=getMaps(m,"main");
+  char tmp[256];
+  map* v=getMapFromMaps(m,"main","rversion");
+  int vid=getVersionId(v->value);
+
+  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
+  ns=usedNs[wpsId];
+  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
+  ns_ows=usedNs[owsId];
+
+  nc = xmlNewNode(ns_ows, BAD_CAST "ServiceIdentification");
+  maps* tmp4=getMaps(m,"identification");
+  if(tmp4!=NULL){
+    map* tmp2=tmp4->content;
+    const char *orderedFields[5];
+    orderedFields[0]="Title";
+    orderedFields[1]="Abstract";
+    orderedFields[2]="Keywords";
+    orderedFields[3]="Fees";
+    orderedFields[4]="AccessConstraints";
+    int oI=0;
+    for(oI=0;oI<5;oI++)
+      if((tmp2=getMap(tmp4->content,orderedFields[oI]))!=NULL){
+	if(strcasecmp(tmp2->name,"abstract")==0 ||
+	   strcasecmp(tmp2->name,"title")==0 ||
+	   strcasecmp(tmp2->name,"accessConstraints")==0 ||
+	   strcasecmp(tmp2->name,"fees")==0){
+	  tmp2->name[0]=toupper(tmp2->name[0]);
+	  nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
+	  xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
+	  xmlAddChild(nc,nc1);
+	}
+	else
+	  if(strcmp(tmp2->name,"keywords")==0){
+	    nc1 = xmlNewNode(ns_ows, BAD_CAST "Keywords");
+	    char *toto=tmp2->value;
+	    char buff[256];
+	    int i=0;
+	    int j=0;
+	    while(toto[i]){
+	      if(toto[i]!=',' && toto[i]!=0){
+		buff[j]=toto[i];
+		buff[j+1]=0;
+		j++;
+	      }
+	      else{
+		nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
+		xmlAddChild(nc2,xmlNewText(BAD_CAST buff));	      
+		xmlAddChild(nc1,nc2);
+		j=0;
+	      }
+	      i++;
+	    }
+	    if(strlen(buff)>0){
+	      nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
+	      xmlAddChild(nc2,xmlNewText(BAD_CAST buff));	      
+	      xmlAddChild(nc1,nc2);
+	    }
+	    xmlAddChild(nc,nc1);
+	    nc2 = xmlNewNode(ns_ows, BAD_CAST "ServiceType");
+	    xmlAddChild(nc2,xmlNewText(BAD_CAST "WPS"));
+	    xmlAddChild(nc,nc2);
+	    nc2 = xmlNewNode(ns_ows, BAD_CAST "ServiceTypeVersion");
+	    map* tmpv=getMapFromMaps(m,"main","rversion");
+	    xmlAddChild(nc2,xmlNewText(BAD_CAST tmpv->value));
+	    xmlAddChild(nc,nc2);
+	  }
+	tmp2=tmp2->next;
+      }
+  }
+  else{
+    fprintf(stderr,"TMP4 NOT FOUND !!");
+    return NULL;
+  }
+  xmlAddChild(n,nc);
+
+  nc = xmlNewNode(ns_ows, BAD_CAST "ServiceProvider");
+  nc3 = xmlNewNode(ns_ows, BAD_CAST "ServiceContact");
+  nc4 = xmlNewNode(ns_ows, BAD_CAST "ContactInfo");
+  nc5 = xmlNewNode(ns_ows, BAD_CAST "Phone");
+  nc6 = xmlNewNode(ns_ows, BAD_CAST "Address");
+  tmp4=getMaps(m,"provider");
+  if(tmp4!=NULL){
+    map* tmp2=tmp4->content;
+    const char *tmpAddress[6];
+    tmpAddress[0]="addressDeliveryPoint";
+    tmpAddress[1]="addressCity";
+    tmpAddress[2]="addressAdministrativeArea";
+    tmpAddress[3]="addressPostalCode";
+    tmpAddress[4]="addressCountry";
+    tmpAddress[5]="addressElectronicMailAddress";
+    const char *tmpPhone[2];
+    tmpPhone[0]="phoneVoice";
+    tmpPhone[1]="phoneFacsimile";
+    const char *orderedFields[12];
+    orderedFields[0]="providerName";
+    orderedFields[1]="providerSite";
+    orderedFields[2]="individualName";
+    orderedFields[3]="positionName";
+    orderedFields[4]=tmpPhone[0];
+    orderedFields[5]=tmpPhone[1];
+    orderedFields[6]=tmpAddress[0];
+    orderedFields[7]=tmpAddress[1];
+    orderedFields[8]=tmpAddress[2];
+    orderedFields[9]=tmpAddress[3];
+    orderedFields[10]=tmpAddress[4];
+    orderedFields[11]=tmpAddress[5];
+    int oI=0;
+    for(oI=0;oI<12;oI++)
+      if((tmp2=getMap(tmp4->content,orderedFields[oI]))!=NULL){
+	if(strcmp(tmp2->name,"keywords")!=0 &&
+	   strcmp(tmp2->name,"serverAddress")!=0 &&
+	   strcmp(tmp2->name,"lang")!=0){
+	  tmp2->name[0]=toupper(tmp2->name[0]);
+	  if(strcmp(tmp2->name,"ProviderName")==0){
+	    nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
+	    xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
+	    xmlAddChild(nc,nc1);
+	  }
+	  else{
+	    if(strcmp(tmp2->name,"ProviderSite")==0){
+	      nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
+	      xmlNewNsProp(nc1,ns_xlink,BAD_CAST "href",BAD_CAST tmp2->value);
+	      xmlAddChild(nc,nc1);
+	    } 
+	    else  
+	      if(strcmp(tmp2->name,"IndividualName")==0 || 
+		 strcmp(tmp2->name,"PositionName")==0){
+		nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
+		xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
+		xmlAddChild(nc3,nc1);
+	      } 
+	      else 
+		if(strncmp(tmp2->name,"Phone",5)==0){
+		  int j;
+		  for(j=0;j<2;j++)
+		    if(strcasecmp(tmp2->name,tmpPhone[j])==0){
+		      char *tmp4=tmp2->name;
+		      nc1 = xmlNewNode(ns_ows, BAD_CAST tmp4+5);
+		      xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
+		      xmlAddChild(nc5,nc1);
+		    }
+		}
+		else 
+		  if(strncmp(tmp2->name,"Address",7)==0){
+		    int j;
+		    for(j=0;j<6;j++)
+		      if(strcasecmp(tmp2->name,tmpAddress[j])==0){
+			char *tmp4=tmp2->name;
+			nc1 = xmlNewNode(ns_ows, BAD_CAST tmp4+7);
+			xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
+			xmlAddChild(nc6,nc1);
+		      }
+		  }
+	  }
+	}
+	else
+	  if(strcmp(tmp2->name,"keywords")==0){
+	    nc1 = xmlNewNode(ns_ows, BAD_CAST "Keywords");
+	    char *toto=tmp2->value;
+	    char buff[256];
+	    int i=0;
+	    int j=0;
+	    while(toto[i]){
+	      if(toto[i]!=',' && toto[i]!=0){
+		buff[j]=toto[i];
+		buff[j+1]=0;
+		j++;
+	      }
+	      else{
+		nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
+		xmlAddChild(nc2,xmlNewText(BAD_CAST buff));	      
+		xmlAddChild(nc1,nc2);
+		j=0;
+	      }
+	      i++;
+	    }
+	    if(strlen(buff)>0){
+	      nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
+	      xmlAddChild(nc2,xmlNewText(BAD_CAST buff));	      
+	      xmlAddChild(nc1,nc2);
+	    }
+	    xmlAddChild(nc,nc1);
+	  }
+	tmp2=tmp2->next;
+      }
+  }
+  else{
+    fprintf(stderr,"TMP4 NOT FOUND !!");
+  }
+  xmlAddChild(nc4,nc5);
+  xmlAddChild(nc4,nc6);
+  xmlAddChild(nc3,nc4);
+  xmlAddChild(nc,nc3);
+  xmlAddChild(n,nc);
+
+
+  nc = xmlNewNode(ns_ows, BAD_CAST "OperationsMetadata");
+
+  int j=0;
+
+  if(toto1!=NULL){
+    map* tmp=getMap(toto1->content,"serverAddress");
+    if(tmp!=NULL){
+      SERVICE_URL = zStrdup(tmp->value);
+    }
+    else
+      SERVICE_URL = zStrdup("not_defined");
+  }
+  else
+    SERVICE_URL = zStrdup("not_defined");
+
+  for(j=0;j<nbSupportedRequests;j++){
+    if(requests[vid][j]==NULL)
+      break;
+    else{
+      nc1 = xmlNewNode(ns_ows, BAD_CAST "Operation");
+      xmlNewProp(nc1,BAD_CAST "name",BAD_CAST requests[vid][j]);
+      nc2 = xmlNewNode(ns_ows, BAD_CAST "DCP");
+      nc3 = xmlNewNode(ns_ows, BAD_CAST "HTTP");
+      if(vid!=1 || j!=2){
+	nc4 = xmlNewNode(ns_ows, BAD_CAST "Get");
+	xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST SERVICE_URL);
+	xmlAddChild(nc3,nc4);
+      }
+      nc4 = xmlNewNode(ns_ows, BAD_CAST "Post");
+      xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST SERVICE_URL);
+      xmlAddChild(nc3,nc4);
+      xmlAddChild(nc2,nc3);
+      xmlAddChild(nc1,nc2);
+      xmlAddChild(nc,nc1);
+    }
+  }
+  xmlAddChild(n,nc);
+
+  if(vid==1)
+    addLanguageNodes(m,n,ns,ns_ows);
+  free(SERVICE_URL);
+
+  nc = xmlNewNode(ns, BAD_CAST root_nodes[vid][0]);
+  xmlAddChild(n,nc);
+
+  if(vid==0)
+    addLanguageNodes(m,n,ns,ns_ows);
+
+  return nc;
+}
+
+/**
+ * Generate a wps:Process node for a servie and add it to a given node.
+ * 
+ * @param reg the profiles registry
+ * @param m the conf maps containing the main.cfg settings
+ * @param registry the profile registry if any
+ * @param nc the XML node to add the Process node
+ * @param serv the service structure created from the zcfg file
+ * @return the generated wps:ProcessOfferings xmlNodePtr 
+ */
+void printGetCapabilitiesForProcess(registry *reg, maps* m,xmlDocPtr doc,xmlNodePtr nc,service* serv){
+  xmlNsPtr ns,ns_ows,ns_xml,ns_xlink;
+  xmlNodePtr n=NULL,nc1,nc2,nc3;
+  map* version=getMapFromMaps(m,"main","rversion");
+  int vid=getVersionId(version->value);
+  // Initialize or get existing namespaces
+  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
+  ns=usedNs[wpsId];
+  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
+  ns_ows=usedNs[owsId];
+  int xmlId=zooXmlAddNs(NULL,"http://www.w3.org/XML/1998/namespace","xml");
+  ns_xml=usedNs[xmlId];
+  int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+  map* tmp1;
+  if(serv->content!=NULL){
+    nc1 = xmlNewNode(ns, BAD_CAST capabilities[vid][0]);
+    int i=1;
+    int limit=3;
+    if(vid==1){
+      ns=NULL;
+      limit=7;
+    }
+    nc3=NULL;
+    map* sType=getMap(serv->content,"serviceType");
+    for(;i<limit;i+=2){
+      if(capabilities[vid][i]==NULL)
+	break;
+      else{
+	tmp1=getMap(serv->content,capabilities[vid][i]);
+	if(tmp1!=NULL){
+	  if(vid==1 && i==1 && strlen(tmp1->value)<5){
+	    char *val=(char*)malloc((strlen(tmp1->value)+5)*sizeof(char));
+	    sprintf(val,"%s.0.0",tmp1->value);
+	    xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST val);
+	    free(val);
+	  }
+	  else
+	    xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST tmp1->value);
+	}
+	else{
+	  if(i==3 && vid==1 && sType!=NULL && strstr(sType->value,"HPC")!=NULL)
+	    xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST "async-execute dismiss");
+	  else
+	    xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+	}
+      }
+    }
+    map* tmp3=getMapFromMaps(m,"lenv","level");
+    addPrefix(m,tmp3,serv);
+    printDescription(nc1,ns_ows,serv->name,serv->content,vid);
+    tmp1=serv->metadata;
+
+    addMetadata(tmp1,doc,nc1,ns_ows,ns_xlink,vid);
+    tmp1=serv->additional_parameters;
+    int fromDb=-1;
+    map* test=getMap(serv->content,"fromDb");
+    if(test!=NULL && strncasecmp(test->value,"true",4)==0)
+      fromDb=1;
+    addAdditionalParameters(tmp1,doc,nc1,ns_ows,ns_xlink,fromDb);
+
+    if(nc3!=NULL)
+      xmlAddChild(nc1,nc3);
+    xmlAddChild(nc,nc1);
+  }
+
+}
+
+/**
+ * Attach attributes to a ProcessDescription or a ProcessOffering node.
+ * 
+ * @param n the XML node to attach the attributes to
+ * @param ns the XML namespace to create the attributes
+ * @param content the servive main content created from the zcfg file
+ * @param vid the version identifier (0 for 1.0.0 and 1 for 2.0.0)
+ * @param serviceType string containing the current service type
+ */
+void attachAttributes(xmlNodePtr n,xmlNsPtr ns,map* content,int vid,map* serviceType){
+  int limit=7;
+  for(int i=1;i<limit;i+=2){
+    map* tmp1=getMap(content,capabilities[vid][i]);
+    if(tmp1!=NULL){
+      if(vid==1 && i==1 && strlen(tmp1->value)<5){
+	char *val=(char*)malloc((strlen(tmp1->value)+5)*sizeof(char));
+	sprintf(val,"%s.0.0",tmp1->value);
+	xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST val);
+	free(val);
+      }
+      else{
+	if(vid==0 && i>=2)
+	  xmlNewProp(n,BAD_CAST capabilities[vid][i],BAD_CAST tmp1->value);
+	else
+	  xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST tmp1->value);
+      }
+    }
+    else{
+      if(i==3 && vid==1 && serviceType!=NULL && strstr(serviceType->value,"HPC")!=NULL)
+	xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST "async-execute dismiss");
+      else
+	if(vid==0 && i>=2)
+	  xmlNewProp(n,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+	else
+	  xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
+    }
+  }
+}
+
+/**
+ * Add a Metadata node to any existing node.
+ * @param meta the map defining the additional parameters
+ * @param doc the XML document used
+ * @param nb the node to add the additional parameters
+ * @param ns_ows the OWS namespace
+ * @param ns_xlink the xlink namespace
+ * @param vid the version of WPS to use (0 for 1.0.0 and 1 for 2.0)
+ */
+void addMetadata(map* meta,xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,int vid){
+  int hasTitle=-1;
+  int hasValue=-1;
+  xmlNodePtr nc1;
+  map* oMeta=meta;
+  int isAdditionalParameters=-1;
+  int level=0;
+  map* test=getMap(meta,"title");
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"href");
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"role");
+  if(test!=NULL)
+    level+=1;
+  if(count(oMeta)>level+1)
+    isAdditionalParameters=1;
+  char *ctitle=NULL;
+  while(meta!=NULL){
+    if(hasTitle<0)
+      if(isAdditionalParameters<0)
+	nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
+      else
+	if(hasValue<0)
+	  nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+    if(strncasecmp(meta->name,"title",5)==0 ||
+       strcasecmp(meta->name,"href")==0 ||
+       strcasecmp(meta->name,"role")==0 ){
+      int index=5;
+      if(strncasecmp(meta->name,"title",5)==0){
+	index=6;
+	hasTitle=1;
+	if(ctitle!=NULL && strcasecmp(meta->value,ctitle)!=0){
+	  xmlAddChild(nc,nc1);
+	  nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+	  free(ctitle);
+	  ctitle=NULL;
+	}
+	if(ctitle==NULL){
+	  char *tmp=(char*)malloc((strlen(meta->name)+1)*sizeof(char));
+	  snprintf(tmp,index,"%s",meta->name);
+	  xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp,BAD_CAST meta->value);
+	  free(tmp);
+	}	  
+	if(ctitle!=NULL)
+	  free(ctitle);
+	ctitle=zStrdup(meta->value);
+      }
+    }else{
+      xmlNodePtr nc2 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameter");
+      xmlNodePtr nc3 = xmlNewNode(ns_ows, BAD_CAST "Name");
+      xmlAddChild(nc3,xmlNewText(BAD_CAST meta->name));
+      xmlNodePtr nc4 = xmlNewNode(ns_ows, BAD_CAST "Value");
+      xmlAddChild(nc4,xmlNewText(BAD_CAST meta->value));
+      xmlAddChild(nc2,nc3);
+      xmlAddChild(nc2,nc4);
+      xmlAddChild(nc1,nc2);
+      hasTitle=-1;
+    }
+    meta=meta->next;
+    if(hasTitle<0){
+      hasValue=1;
+      if(isAdditionalParameters){
+	if(vid==0){
+	  meta=NULL;
+	  break;
+	}else
+	  xmlAddChild(nc,nc1);
+      }
+    }
+  }
+  if(oMeta!=NULL && hasValue<0 && nc1!=NULL){
+    xmlAddChild(nc,nc1);
+  }
+}
+
+/**
+ * Add AdditionalParameters nodes to any existing node.
+ * @param meta the map defining the additional parameters
+ * @param doc the XML document used
+ * @param nb the node to add the additional parameters
+ * @param ns_ows the OWS namespace
+ * @param ns_xlink the xlink namespace
+ * @param fromDb 1 if the metadata has been extracted from the metadb, 
+ * 0 otherwise
+ */
+void addAdditionalParameters(map* meta,xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,int fromDb){
+  int hasTitle=-1;
+  int hasValue=-1;
+  int toAddAtEnd=-1;
+  int cnt=0;
+  xmlNodePtr* ncr=NULL;
+  xmlNodePtr nc1;
+  map* oMeta=meta;
+  int isAdditionalParameters=-1;
+  int level=0;
+  map* test=getMap(meta,"title");
+  map* otitle=getMap(meta,"title");
+  map* length=getMap(meta,"length");
+  int len=0;
+  char *ctitle=NULL;
+    
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"href");
+  if(test!=NULL)
+    level+=1;
+  test=getMap(meta,"role");
+  if(test!=NULL)
+    level+=1;
+  if(count(oMeta)>level+1)
+    isAdditionalParameters=1;
+
+  while(meta!=NULL){
+    if(hasTitle<0 && hasValue<0){
+      nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+    }
+    if(strncasecmp(meta->name,"title",5)==0 ||
+       strcasecmp(meta->name,"href")==0 ||
+       strcasecmp(meta->name,"role")==0 ){
+      int index=5;
+      if(strncasecmp(meta->name,"title",5)==0){
+	index=6;
+	hasTitle=1;
+	if(ctitle!=NULL && strcasecmp(meta->value,ctitle)!=0){
+	  xmlNodePtr ncTmp = xmlDocCopyNodeList(doc,nc1);
+	  xmlAddChild(nc,ncTmp);
+	  xmlFreeNode(nc1);
+	  toAddAtEnd=1;
+	  cnt++;
+	  nc1 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameters");
+	  free(ctitle);
+	  ctitle=NULL;
+	}
+	if(ctitle==NULL){
+	  char *tmp=(char*)malloc((strlen(meta->name)+1)*sizeof(char));
+	  snprintf(tmp,index,"%s",meta->name);
+	  xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp,BAD_CAST meta->value);
+	  free(tmp);
+	}	  
+	if(ctitle!=NULL)
+	  free(ctitle);
+	ctitle=zStrdup(meta->value);
+      }else{
+	xmlNewNsProp(nc1,ns_xlink,BAD_CAST meta->name,BAD_CAST meta->value);
+      }
+    }else{
+      if(strncasecmp(meta->name,"length",6)!=0 && strncasecmp(meta->name,"fromDb",6)!=0){
+	xmlNodePtr nc2 = xmlNewNode(ns_ows, BAD_CAST "AdditionalParameter");
+	xmlNodePtr nc3 = xmlNewNode(ns_ows, BAD_CAST "Name");
+	xmlAddChild(nc3,xmlNewText(BAD_CAST meta->name));
+	xmlAddChild(nc2,nc3);
+	if(fromDb<0){
+	  char *mptr;
+	  char* meta_values=strtok_r(meta->value,",",&mptr);
+	  while(meta_values!=NULL){
+	    xmlNodePtr nc4 = xmlNewNode(ns_ows, BAD_CAST "Value");
+	    xmlAddChild(nc4,xmlNewText(BAD_CAST meta_values));
+	    xmlAddChild(nc2,nc4);
+	    meta_values=strtok_r(NULL,",",&mptr);
+	  }
+	}else{
+	  xmlNodePtr nc4 = xmlNewNode(ns_ows, BAD_CAST "Value");
+	  xmlAddChild(nc4,xmlNewCDataBlock(doc,BAD_CAST meta->value,strlen(meta->value)));
+	  xmlAddChild(nc2,nc4);
+	}
+	xmlAddChild(nc1,nc2);
+      }
+      hasTitle=-1;
+    }
+    meta=meta->next;
+    if(hasTitle<0){
+      //xmlAddChild(nc,nc1);
+      hasValue=1;
+    }/*else
+       if(ctitle!=NULL)
+       free(ctitle);*/
+  }
+  if(length!=NULL)
+    len=atoi(length->value);
+  if(otitle!=NULL)
+    len=1;
+  if(cnt<len){
+    xmlAddChild(nc,nc1);
+    free(ctitle);
+  }
+}
+
+/**
+ * Add the ows:Metadata nodes relative to the profile registry
+ *
+ * @param n the XML node to add the ows:Metadata
+ * @param ns_ows the ows XML namespace
+ * @param ns_xlink the ows xlink namespace
+ * @param reg the profile registry
+ * @param main_conf the map containing the main configuration content
+ * @param serv the service 
+ */
+void addInheritedMetadata(xmlNodePtr n,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,registry* reg,maps* main_conf,service* serv){
+  int vid=1;
+  map* tmp1=getMap(serv->content,"extend");
+  if(tmp1==NULL)
+    tmp1=getMap(serv->content,"concept");
+  if(tmp1!=NULL){
+    map* level=getMap(serv->content,"level");
+    if(level!=NULL){
+      xmlNodePtr nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
+      char* ckey=level->value;
+      if(strncasecmp(level->value,"profile",7)==0)
+	ckey=(char*)"generic";
+      if(strncasecmp(level->value,"generic",7)==0)
+	ckey=(char*)"concept";
+      service* inherited=getServiceFromRegistry(reg,ckey,tmp1->value);
+      if(inherited!=NULL){
+	addInheritedMetadata(n,ns_ows,ns_xlink,reg,main_conf,inherited);
+      }
+      char cschema[71];
+      sprintf(cschema,"%s%s",schemas[vid][7],ckey);
+      map* regUrl=getMapFromMaps(main_conf,"main","registryUrl");
+      map* regExt=getMapFromMaps(main_conf,"main","registryExt");
+      char* registryUrl=(char*)malloc((strlen(regUrl->value)+strlen(ckey)+
+				       (regExt!=NULL?strlen(regExt->value)+1:0)+
+				       strlen(tmp1->value)+2)*sizeof(char));
+      if(regExt!=NULL)
+	sprintf(registryUrl,"%s%s/%s.%s",regUrl->value,ckey,tmp1->value,regExt->value);
+      else
+	sprintf(registryUrl,"%s%s/%s",regUrl->value,ckey,tmp1->value);
+      xmlNewNsProp(nc1,ns_xlink,BAD_CAST "role",BAD_CAST cschema);
+      xmlNewNsProp(nc1,ns_xlink,BAD_CAST "href",BAD_CAST registryUrl);
+      free(registryUrl);
+      xmlAddChild(n,nc1);
+    }
+  }
+}
+
+/**
+ * Generate a ProcessDescription node for a servie and add it to a given node.
+ * 
+ * @param reg the profile registry
+ * @param m the conf maps containing the main.cfg settings
+ * @param nc the XML node to add the Process node
+ * @param serv the servive structure created from the zcfg file
+ * @return the generated wps:ProcessOfferings xmlNodePtr 
+ */
+void printDescribeProcessForProcess(registry *reg, maps* m,xmlDocPtr doc,xmlNodePtr nc,service* serv){
+  xmlNsPtr ns,ns_ows,ns_xlink;
+  xmlNodePtr n,nc1;
+  xmlNodePtr nc2 = NULL;
+  map* version=getMapFromMaps(m,"main","rversion");
+  int vid=getVersionId(version->value);
+  int fromDb=-1;
+  map* serviceType=getMap(serv->content,"serviceType");
+  map* test=getMap(serv->content,"fromDb");
+  if(test!=NULL && strncasecmp(test->value,"true",4)==0)
+    fromDb=1;
+
+  n=nc;
+  int wpsId=zooXmlAddNs(NULL,schemas[vid][3],"wps");
+  ns=usedNs[wpsId];
+  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
+  ns_ows=usedNs[owsId];
+  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+  map* tmp1=NULL;
+
+  if(vid==0){
+    nc = xmlNewNode(NULL, BAD_CAST "ProcessDescription");
+    attachAttributes(nc,ns,serv->content,vid,NULL);
+  }
+  else{
+    nc2 = xmlNewNode(ns, BAD_CAST "ProcessOffering");
+    // In case mode was defined in the ZCFG file then restrict the 
+    // jobControlOptions value to this value. The dismiss is always 
+    // supported whatever you can set in the ZCFG file.
+    // cf. http://docs.opengeospatial.org/is/14-065/14-065.html#47 (Table 30)
+    map* mode=getMap(serv->content,"mode");
+    if(mode!=NULL){
+      if( strncasecmp(mode->value,"sync",strlen(mode->value))==0 ||
+	  strncasecmp(mode->value,"async",strlen(mode->value))==0 ){
+	char toReplace[22];
+	sprintf(toReplace,"%s-execute dismiss",mode->value);
+	addToMap(serv->content,capabilities[vid][3],toReplace);
+      }
+    }
+    attachAttributes(nc2,NULL,serv->content,vid,serviceType);
+    map* level=getMap(serv->content,"level");
+    if(level!=NULL && strcasecmp(level->value,"generic")==0)
+      nc = xmlNewNode(ns, BAD_CAST "GenericProcess");
+    else
+      nc = xmlNewNode(ns, BAD_CAST "Process");
+  }
+  
+  tmp1=getMapFromMaps(m,"lenv","level");
+  addPrefix(m,tmp1,serv);
+  printDescription(nc,ns_ows,serv->name,serv->content,vid);
+
+  if(vid==0){
+    tmp1=serv->metadata;
+    while(tmp1!=NULL){
+      addMetadata(tmp1,doc,nc,ns_ows,ns_xlink,vid);
+      tmp1=tmp1->next;
+    }
+    tmp1=getMap(serv->content,"Profile");
+    if(tmp1!=NULL && vid==0){
+      nc1 = xmlNewNode(ns, BAD_CAST "Profile");
+      xmlAddChild(nc1,xmlNewText(BAD_CAST tmp1->value));
+      xmlAddChild(nc,nc1);
+    }
+  }else{
+    tmp1=serv->metadata;
+    addMetadata(tmp1,doc,nc,ns_ows,ns_xlink,vid);
+    addInheritedMetadata(nc,ns_ows,ns_xlink,reg,m,serv);
+    tmp1=serv->additional_parameters;
+    if(vid!=0)
+      addAdditionalParameters(tmp1,doc,nc,ns_ows,ns_xlink,fromDb);
+  }
+
+  if(serv->inputs!=NULL){
+    elements* e=serv->inputs;
+    if(vid==0){
+      nc1 = xmlNewNode(NULL, BAD_CAST "DataInputs");
+      printFullDescription(doc,1,e,"Input",ns,ns_ows,nc1,vid,fromDb,NULL);
+      xmlAddChild(nc,nc1);
+    }
+    else{
+      printFullDescription(doc,1,e,"wps:Input",ns,ns_ows,nc,vid,fromDb,NULL);
+    }
+  }
+
+  elements* e=serv->outputs;
+  if(vid==0){
+    nc1 = xmlNewNode(NULL, BAD_CAST "ProcessOutputs");
+    printFullDescription(doc,0,e,"Output",ns,ns_ows,nc1,vid,fromDb,NULL);
+    xmlAddChild(nc,nc1);
+  }
+  else{
+    printFullDescription(doc,0,e,"wps:Output",ns,ns_ows,nc,vid,fromDb,serviceType);
+  }
+  if(vid==0)
+    xmlAddChild(n,nc);
+  else if (nc2 != NULL) {	  
+    xmlAddChild(nc2,nc);
+    xmlAddChild(n,nc2);
+  }
+
+}
+
+/**
+ * Generate the required XML tree for the detailled metadata information of 
+ * inputs or outputs
+ *
+ * @param in 1 in case of inputs, 0 for outputs
+ * @param elem the elements structure containing the metadata information
+ * @param type the name ("Input" or "Output") of the XML node to create
+ * @param ns_ows the ows XML namespace
+ * @param ns_ows the ows XML namespace
+ * @param nc1 the XML node to use to add the created tree
+ * @param vid the WPS version id (0 for 1.0.0, 1 for 2.0.0)
+ * @param fromDb 1 in case the metadata comes from the DB, -1 in other cases
+ * @param serviceType the serviceType found in the ZCFG file or the DB
+ */
+void printFullDescription(xmlDocPtr doc,int in,elements *elem,const char* type,xmlNsPtr ns,xmlNsPtr ns_ows,xmlNodePtr nc1,int vid,int fromDb,const map* serviceType){
+  xmlNsPtr ns1=NULL;
+  if(vid==1)
+    ns1=ns;
+
+  xmlNodePtr nc2,nc3,nc4,nc5,nc6,nc7,nc8,nc9,nc55=NULL,nc56;
+  elements* e=elem;
+  nc9=NULL;
+  map* tmp1=NULL;
+  while(e!=NULL){
+    int default1=0;
+    int isAnyValue=1;
+    nc2 = xmlNewNode(NULL, BAD_CAST type);
+    // Extract min/max Occurence information
+    if(strstr(type,"Input")!=NULL){
+      tmp1=getMap(e->content,"minOccurs");
+      if(tmp1!=NULL){
+	xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
+      }else
+	xmlNewProp(nc2,BAD_CAST "minOccurs",BAD_CAST "0");
+      tmp1=getMap(e->content,"maxOccurs");
+      if(tmp1!=NULL){
+	if(strcasecmp(tmp1->value,"unbounded")!=0)
+	  xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
+	else
+	  xmlNewProp(nc2,BAD_CAST "maxOccurs",BAD_CAST "1000");
+      }else
+	xmlNewProp(nc2,BAD_CAST "maxOccurs",BAD_CAST "1");
+      if((tmp1=getMap(e->content,"maximumMegabytes"))!=NULL){
+	xmlNewProp(nc2,BAD_CAST "maximumMegabytes",BAD_CAST tmp1->value);
+      }
+    }
+
+    printDescription(nc2,ns_ows,e->name,e->content,vid);
+
+    if(e->format!=NULL){
+#ifdef USE_HPC	    
+    DEFAULT_OUT:
+#endif
+      const char orderedFields[13][14]={
+	"mimeType",
+	"encoding",
+	"schema",
+	"dataType",
+	"uom",
+	"CRS",
+	"AllowedValues",
+	"range",
+	"rangeMin",
+	"rangeMax",
+	"rangeClosure",
+	"rangeSpace"
+      };
+
+      //Build the (Literal/Complex/BoundingBox)Data node
+      if(strncmp(type,"Output",6)==0){
+	if(strncasecmp(e->format,"LITERAL",7)==0)
+	  nc3 = xmlNewNode(ns1, BAD_CAST "LiteralOutput");
+	else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
+	  nc3 = xmlNewNode(ns1, BAD_CAST "ComplexOutput");
+	else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
+	  nc3 = xmlNewNode(ns1, BAD_CAST "BoundingBoxOutput");
+	else
+	  nc3 = xmlNewNode(ns1, BAD_CAST e->format);
+      }else{
+	if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0 ||
+	   strncasecmp(e->format,"LITERALOUTPUT",strlen(e->format))==0){
+	  nc3 = xmlNewNode(ns1, BAD_CAST "LiteralData");
+	}
+	else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
+	  nc3 = xmlNewNode(ns1, BAD_CAST "ComplexData");
+	else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
+	  nc3 = xmlNewNode(ns1, BAD_CAST "BoundingBoxData");
+	else
+	  nc3 = xmlNewNode(ns1, BAD_CAST e->format);
+      }
+
+      iotype* _tmp0=NULL;
+      iotype* _tmp=e->defaults;
+      int datatype=0;
+      bool hasUOM=false;
+      bool hasUOM1=false;
+      if(_tmp!=NULL){
+	if(strcmp(e->format,"LiteralOutput")==0 ||
+	   strcmp(e->format,"LiteralData")==0){
+	  datatype=1;
+	  if(vid==1){
+	    nc4 = xmlNewNode(ns1, BAD_CAST "Format");
+	    xmlNewProp(nc4,BAD_CAST "mimeType",BAD_CAST "text/plain");
+	    xmlNewProp(nc4,BAD_CAST "default",BAD_CAST "true");
+	    xmlAddChild(nc3,nc4);
+	    nc5 = xmlNewNode(NULL, BAD_CAST "LiteralDataDomain");
+	    nc55 = xmlNewNode(NULL, BAD_CAST "LiteralDataDomain");
+	    xmlNewProp(nc5,BAD_CAST "default",BAD_CAST "true");
+	  }
+	  else{
+	    nc4 = xmlNewNode(NULL, BAD_CAST "UOMs");
+	    nc5 = xmlNewNode(NULL, BAD_CAST "Default");
+	  }
+	}
+	else if(strcmp(e->format,"BoundingBoxOutput")==0 ||
+		strcmp(e->format,"BoundingBoxData")==0){
+	  datatype=2;
+	  if(vid==0)
+	    nc5 = xmlNewNode(NULL, BAD_CAST "Default");
+	  else{
+	    xmlNodePtr nc6 = xmlNewNode(ns1, BAD_CAST "Format");
+	    xmlNewProp(nc6,BAD_CAST "mimeType",BAD_CAST "text/xml");
+	    xmlNewProp(nc6,BAD_CAST "default",BAD_CAST "true");
+	    xmlAddChild(nc3,nc6);
+	    nc5 = xmlNewNode(NULL, BAD_CAST "SupportedCRS");
+	  }
+	}
+	else{
+	  if(vid==0)
+	    nc4 = xmlNewNode(NULL, BAD_CAST "Default");
+	  nc5 = xmlNewNode(ns1, BAD_CAST "Format");
+	  if(vid==1){
+	    xmlNewProp(nc5,BAD_CAST "default",BAD_CAST "true");
+	    int oI=0;
+	    for(oI=0;oI<3;oI++)
+	      if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
+		xmlNewProp(nc5,BAD_CAST orderedFields[oI],BAD_CAST tmp1->value);
+	      }
+	  }
+	}
+      
+	tmp1=_tmp->content;
+
+	if(vid==0)
+	  if((tmp1=getMap(_tmp->content,"DataType"))!=NULL){
+	    nc8 = xmlNewNode(ns_ows, BAD_CAST "DataType");
+	    xmlAddChild(nc8,xmlNewText(BAD_CAST tmp1->value));
+	    char tmp[1024];
+	    sprintf(tmp,"http://www.w3.org/TR/xmlschema-2/#%s",tmp1->value);
+	    xmlNewNsProp(nc8,ns_ows,BAD_CAST "reference",BAD_CAST tmp);
+	    if(vid==0)
+	      xmlAddChild(nc3,nc8);
+	    else
+	      xmlAddChild(nc5,nc8);
+	    datatype=1;
+	  }
+
+	bool isInput=false;
+	if(strncmp(type,"Input",5)==0 || strncmp(type,"wps:Input",9)==0){
+	  isInput=true;
+	  if((tmp1=getMap(_tmp->content,"AllowedValues"))!=NULL){
+	    nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
+	    char *token,*saveptr1;
+	    token=strtok_r(tmp1->value,",",&saveptr1);
+	    while(token!=NULL){
+	      nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
+	      char *tmps=zStrdup(token);
+	      tmps[strlen(tmps)]=0;
+	      nc8 = xmlNewText(BAD_CAST tmps);
+	      xmlAddChild(nc7,nc8);
+	      free(tmps);
+	      xmlAddChild(nc6,nc7);
+	      token=strtok_r(NULL,",",&saveptr1);
+	    }
+	    if(getMap(_tmp->content,"range")!=NULL ||
+	       getMap(_tmp->content,"rangeMin")!=NULL ||
+	       getMap(_tmp->content,"rangeMax")!=NULL ||
+	       getMap(_tmp->content,"rangeClosure")!=NULL )
+	      goto doRange;
+	    if(vid==0)
+	      xmlAddChild(nc3,nc6);
+	    else
+	      xmlAddChild(nc5,nc6);
+	    isAnyValue=-1;
+	  }
+
+	  tmp1=getMap(_tmp->content,"range");
+	  if(tmp1==NULL)
+	    tmp1=getMap(_tmp->content,"rangeMin");
+	  if(tmp1==NULL)
+	    tmp1=getMap(_tmp->content,"rangeMax");
+	
+	  if(tmp1!=NULL && isAnyValue==1){
+	    nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
+	  doRange:
+	  
+	    /**
+	     * Range: Table 46 OGC Web Services Common Standard
+	     */
+	    nc8 = xmlNewNode(ns_ows, BAD_CAST "Range");
+	  
+	    map* tmp0=getMap(tmp1,"range");
+	    if(tmp0!=NULL){
+	      char* pToken;
+	      char* orig=zStrdup(tmp0->value);
+	      /**
+	       * RangeClosure: Table 47 OGC Web Services Common Standard
+	       */
+	      const char *tmp="closed";
+	      if(orig[0]=='[' && orig[strlen(orig)-1]=='[')
+		tmp="closed-open";
+	      else
+		if(orig[0]==']' && orig[strlen(orig)-1]==']')
+		  tmp="open-closed";
+		else
+		  if(orig[0]==']' && orig[strlen(orig)-1]=='[')
+		    tmp="open";
+	      xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST tmp);
+	      pToken=strtok(orig,",");
+	      int nci0=0;
+	      while(pToken!=NULL){
+		char *tmpStr=(char*) malloc((strlen(pToken))*sizeof(char));
+		if(nci0==0){
+		  nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
+		  strncpy( tmpStr, pToken+1, strlen(pToken)-1 );
+		  tmpStr[strlen(pToken)-1] = '\0';
+		}else{
+		  nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
+		  const char* bkt;
+		  if ( ( bkt = strchr(pToken, '[') ) != NULL || ( bkt = strchr(pToken, ']') ) != NULL ){
+		    strncpy( tmpStr, pToken, bkt - pToken );
+		    tmpStr[bkt - pToken] = '\0';
+		  }
+		}
+		xmlAddChild(nc7,xmlNewText(BAD_CAST tmpStr));
+		free(tmpStr);
+		xmlAddChild(nc8,nc7);
+		nci0++;
+		pToken = strtok(NULL,",");
+	      }		    
+	      if(getMap(tmp1,"rangeSpacing")==NULL){
+		nc7 = xmlNewNode(ns_ows, BAD_CAST "Spacing");
+		xmlAddChild(nc7,xmlNewText(BAD_CAST "1"));
+		xmlAddChild(nc8,nc7);
+	      }
+	      free(orig);
+	    }else{
+	    
+	      tmp0=getMap(tmp1,"rangeMin");
+	      if(tmp0!=NULL){
+		nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
+		xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
+		xmlAddChild(nc8,nc7);
+	      }else{
+		nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
+		xmlAddChild(nc8,nc7);
+	      }
+	      tmp0=getMap(tmp1,"rangeMax");
+	      if(tmp0!=NULL){
+		nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
+		xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
+		xmlAddChild(nc8,nc7);
+	      }else{
+		nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
+		xmlAddChild(nc8,nc7);
+	      }
+	      tmp0=getMap(tmp1,"rangeSpacing");
+	      if(tmp0!=NULL){
+		nc7 = xmlNewNode(ns_ows, BAD_CAST "Spacing");
+		xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
+		xmlAddChild(nc8,nc7);
+	      }
+	      tmp0=getMap(tmp1,"rangeClosure");
+	      if(tmp0!=NULL){
+		const char *tmp="closed";
+		if(strcasecmp(tmp0->value,"co")==0)
+		  tmp="closed-open";
+		else
+		  if(strcasecmp(tmp0->value,"oc")==0)
+		    tmp="open-closed";
+		  else
+		    if(strcasecmp(tmp0->value,"o")==0)
+		      tmp="open";
+		xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST tmp);
+	      }else
+		xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST "closed");
+	    }
+	    if(_tmp0==NULL){
+	      xmlAddChild(nc6,nc8);
+	      _tmp0=e->supported;
+	      if(_tmp0!=NULL &&
+		 (getMap(_tmp0->content,"range")!=NULL ||
+		  getMap(_tmp0->content,"rangeMin")!=NULL ||
+		  getMap(_tmp0->content,"rangeMax")!=NULL ||
+		  getMap(_tmp0->content,"rangeClosure")!=NULL )){
+		tmp1=_tmp0->content;
+		goto doRange;
+	      }
+	    }else{
+	      _tmp0=_tmp0->next;
+	      if(_tmp0!=NULL){
+		xmlAddChild(nc6,nc8);
+		if(getMap(_tmp0->content,"range")!=NULL ||
+		   getMap(_tmp0->content,"rangeMin")!=NULL ||
+		   getMap(_tmp0->content,"rangeMax")!=NULL ||
+		   getMap(_tmp0->content,"rangeClosure")!=NULL ){
+		  tmp1=_tmp0->content;
+		  goto doRange;
+		}
+	      }
+	    }
+	    xmlAddChild(nc6,nc8);
+	    if(vid==0)
+	      xmlAddChild(nc3,nc6);
+	    else{
+	      xmlAddChild(nc5,nc6);
+	      xmlAddChild(nc55,nc6);
+	    }
+	    isAnyValue=-1;
+	  }
+	
+	}
+      
+	int oI=0;
+	/*if(vid==0)*/ {
+	  for(oI=0;oI<12;oI++)
+	    if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
+#ifdef DEBUG
+	      printf("DATATYPE DEFAULT ? %s\n",tmp1->name);
+#endif
+	      if(strcmp(tmp1->name,"asReference")!=0 &&
+		 strncasecmp(tmp1->name,"DataType",8)!=0 &&
+		 strcasecmp(tmp1->name,"extension")!=0 &&
+		 strcasecmp(tmp1->name,"value")!=0 &&
+		 strcasecmp(tmp1->name,"AllowedValues")!=0 &&
+		 strncasecmp(tmp1->name,"range",5)!=0){
+		if(datatype!=1){
+		  if(datatype==2 && vid==1){
+		    nc9 = xmlNewNode(ns, BAD_CAST "SupportedCRS");
+		    xmlNewProp(nc9,BAD_CAST "default",BAD_CAST "true");
+		  }
+		  else{
+		    char *tmp2=zCapitalize1(tmp1->name);
+		    nc9 = xmlNewNode(NULL, BAD_CAST tmp2);
+		    free(tmp2);
+		  }
+		}
+		else{
+		  char *tmp2=zCapitalize(tmp1->name);
+		  nc9 = xmlNewNode(ns_ows, BAD_CAST tmp2);
+		  free(tmp2);
+		}
+		xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
+		if(vid==0 || oI>=3){
+		  if(vid==0 || oI!=4){
+		    if(datatype==2 && vid==1)
+		      xmlAddChild(nc3,nc9);
+		    else
+		      xmlAddChild(nc5,nc9);
+		  }
+		}
+		else{
+		  xmlFreeNode(nc9);
+		}
+		if(strcasecmp(tmp1->name,"uom")==0)
+		  hasUOM1=true;
+		hasUOM=true;
+	      }
+	    }
+	}
+	if(datatype!=2){
+	  if(hasUOM==true){
+	    if(vid==0){
+	      xmlAddChild(nc4,nc5);
+	      xmlAddChild(nc3,nc4);
+	    }
+	    else{
+	      xmlAddChild(nc3,nc5);
+	    }
+	  }else{
+	    if(hasUOM1==false && vid==0){
+	      if(nc5!=NULL)
+		xmlFreeNode(nc5);
+	      if(datatype==1){
+		xmlFreeNode(nc4);
+	      }
+	    }
+	    else{
+	      xmlAddChild(nc3,nc5);
+	    }
+	  }
+	}else{
+	  if(vid==0)
+	    xmlAddChild(nc3,nc5);
+	  else
+	    xmlFreeNode(nc5);
+	}
+      
+	if(datatype==0 && default1<0){
+	  xmlFreeNode(nc5);
+	  if(datatype!=2){
+	    xmlFreeNode(nc4);
+	  }
+	}
+
+
+	if((isInput || vid==1) && datatype==1 &&
+	   getMap(_tmp->content,"AllowedValues")==NULL &&
+	   getMap(_tmp->content,"range")==NULL &&
+	   getMap(_tmp->content,"rangeMin")==NULL &&
+	   getMap(_tmp->content,"rangeMax")==NULL &&
+	   getMap(_tmp->content,"rangeClosure")==NULL ){
+	  tmp1=getMap(_tmp->content,"dataType");
+	  // We were tempted to define default value for boolean as {true,false}
+	  if(tmp1!=NULL && strcasecmp(tmp1->value,"boolean")==0){
+	    nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
+	    nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
+	    xmlAddChild(nc7,xmlNewText(BAD_CAST "true"));
+	    xmlAddChild(nc6,nc7);
+	    nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
+	    xmlAddChild(nc7,xmlNewText(BAD_CAST "false"));
+	    xmlAddChild(nc6,nc7);
+	    if(vid==0)
+	      xmlAddChild(nc3,nc6);
+	    else{
+	      xmlAddChild(nc5,nc6);
+	      xmlAddChild(nc55,nc6);
+	    }
+	  }
+	  else
+	    if(vid==0)
+	      xmlAddChild(nc3,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
+	    else{
+	      xmlAddChild(nc5,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
+	      xmlAddChild(nc55,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
+	    }
+	}
+
+	if(vid==1){
+	  if((tmp1=getMap(_tmp->content,"DataType"))!=NULL){
+	    nc8 = xmlNewNode(ns_ows, BAD_CAST "DataType");
+	    xmlAddChild(nc8,xmlNewText(BAD_CAST tmp1->value));
+	    char tmp[1024];
+	    sprintf(tmp,"http://www.w3.org/TR/xmlschema-2/#%s",tmp1->value);
+	    xmlNewNsProp(nc8,ns_ows,BAD_CAST "reference",BAD_CAST tmp);
+	    if(vid==0)
+	      xmlAddChild(nc3,nc8);
+	    else{
+	      xmlAddChild(nc5,nc8);
+	      xmlAddChild(nc55,nc8);
+	    }
+	    datatype=1;
+	  }
+	  if(hasUOM==true){
+	    tmp1=getMap(_tmp->content,"uom");
+	    if(tmp1!=NULL){
+	      xmlAddChild(nc5,nc9);
+	    }
+	  }
+	  if(e->defaults!=NULL && (tmp1=getMap(e->defaults->content,"value"))!=NULL){
+	    nc7 = xmlNewNode(ns_ows, BAD_CAST "DefaultValue");
+	    xmlAddChild(nc7,xmlNewText(BAD_CAST tmp1->value));
+	    xmlAddChild(nc5,nc7);
+	    xmlAddChild(nc55,nc7);
+	  }
+	}
+
+	map* metadata=e->metadata;
+	xmlNodePtr n=NULL;
+	int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
+	xmlNsPtr ns_xlink=usedNs[xlinkId];
+
+	addMetadata(metadata,doc,nc2,ns_ows,ns_xlink,vid);
+	if(vid!=0)
+	  addAdditionalParameters(e->additional_parameters,doc,nc2,ns_ows,ns_xlink,fromDb);
+
+      }
+
+      _tmp=e->supported;
+      if(_tmp==NULL && datatype==0)
+	_tmp=e->defaults;
+
+      int hasSupported=-1;
+
+      while(_tmp!=NULL){
+	
+	if(hasSupported<0){
+	  if(datatype==0){
+	    if(vid==0)
+	      nc4 = xmlNewNode(NULL, BAD_CAST "Supported");
+	    nc5 = xmlNewNode(ns1, BAD_CAST "Format");
+	    if(vid==1){
+	      int oI=0;
+	      for(oI=0;oI<3;oI++)
+		if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
+		  xmlNewProp(nc5,BAD_CAST orderedFields[oI],BAD_CAST tmp1->value);
+		}
+	    }
+	  }
+	  else
+	    if(vid==0)
+	      nc5 = xmlNewNode(NULL, BAD_CAST "Supported");
+	  hasSupported=0;
+	}else
+	  if(datatype==0){
+	    nc5 = xmlNewNode(ns1, BAD_CAST "Format");
+	    if(vid==1){
+	      int oI=0;
+	      for(oI=0;oI<3;oI++)
+		if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
+		  xmlNewProp(nc5,BAD_CAST orderedFields[oI],BAD_CAST tmp1->value);
+		}
+	    }
+	  }
+	tmp1=_tmp->content;
+	int oI=0;
+	for(oI=0;oI<6;oI++)
+	  if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
+#ifdef DEBUG
+	    printf("DATATYPE SUPPORTED ? %s\n",tmp1->name);
+#endif
+	    if(strcmp(tmp1->name,"asReference")!=0 && 
+	       strcmp(tmp1->name,"value")!=0 && 
+	       strcmp(tmp1->name,"DataType")!=0 &&
+	       strcasecmp(tmp1->name,"extension")!=0){
+	      if(datatype!=1){
+		if(datatype==2 && vid==1){
+		  nc6 = xmlNewNode(ns, BAD_CAST "SupportedCRS");
+		}
+		else{
+		  char *tmp2=zCapitalize1(tmp1->name);
+		  nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
+		  free(tmp2);
+		}
+	      }
+	      else{
+		char *tmp2=zCapitalize(tmp1->name);
+		nc6 = xmlNewNode(ns_ows, BAD_CAST tmp2);
+		free(tmp2);
+	      }
+	      if(datatype==2){
+		char *tmpv,*tmps;
+		tmps=strtok_r(tmp1->value,",",&tmpv);
+		while(tmps){
+		  xmlAddChild(nc6,xmlNewText(BAD_CAST tmps));
+		  tmps=strtok_r(NULL,",",&tmpv);
+		  if(tmps){
+		    char *tmp2=zCapitalize1(tmp1->name);
+		    nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
+		    free(tmp2);
+		  }
+		}
+	      }
+	      else{
+		xmlAddChild(nc6,xmlNewText(BAD_CAST tmp1->value));
+	      }
+	      if(vid==0 || oI>=3){
+		if(vid==0 || oI!=4){
+		  if(datatype==2 && vid==1)
+		    xmlAddChild(nc3,nc6);
+		  else
+		    xmlAddChild(nc5,nc6);
+		}
+		else{
+		  if(oI!=4)
+		    xmlFreeNode(nc6);
+		  else{
+		    nc56=xmlCopyNode(nc55,1);
+		    xmlReplaceNode(xmlGetLastChild(nc56),nc6);
+		    xmlAddChild(nc3,nc56);
+		  }
+		}
+	      }
+	      else{
+		xmlFreeNode(nc6);
+	      }
+	    }
+	    tmp1=tmp1->next;
+	  }
+	if(hasSupported<=0){
+	  if(datatype==0){
+	    if(vid==0){
+	      xmlAddChild(nc4,nc5);
+	      xmlAddChild(nc3,nc4);
+	    }
+	    else{
+	      xmlAddChild(nc3,nc5);
+	    }
+
+	  }else{
+	    if(datatype==2 && vid==0)
+	      xmlAddChild(nc3,nc5);
+	  }
+	  hasSupported=1;
+	}
+	else
+	  if(datatype==0){
+	    if(vid==0){
+	      xmlAddChild(nc4,nc5);
+	      xmlAddChild(nc3,nc4);
+	    }
+	    else{
+	      xmlAddChild(nc3,nc5);
+	    }
+	  }
+	  else
+	    if(datatype==0){
+	      xmlFreeNode(nc4);
+	      xmlAddChild(nc3,nc5);
+	    }
+
+	_tmp=_tmp->next;
+      }
+
+      if(hasSupported==0){
+	if(datatype==0 && vid!=0){
+	  xmlFreeNode(nc4);
+	}
+	xmlFreeNode(nc5);
+      }
+
+      _tmp=e->defaults;
+      if(datatype==1 && hasUOM1==true){
+	if(vid==0){
+	  xmlAddChild(nc4,nc5);
+	  xmlAddChild(nc3,nc4);
+	}
+	else{
+	  xmlAddChild(nc3,nc5);
+	}
+      }
+
+      if(vid==0 && _tmp!=NULL && (tmp1=getMap(_tmp->content,"value"))!=NULL){
+	nc7 = xmlNewNode(NULL, BAD_CAST "DefaultValue");
+	xmlAddChild(nc7,xmlNewText(BAD_CAST tmp1->value));
+	xmlAddChild(nc3,nc7);
+      }
+      xmlAddChild(nc2,nc3);
+    }else{
+      if(e->child!=NULL && vid!=0){
+	printFullDescription(doc,in,e->child,type,ns,ns_ows,nc2,vid,fromDb,NULL);
+      }
+    }
+    if(e->child!=NULL && vid==0){
+      elements* children=dupElements(e->child);
+      elements* cursor=children;
+      while(cursor!=NULL){
+	elements* ccursor=cursor;
+	char* tmp=zStrdup(ccursor->name);
+	free(ccursor->name);
+	ccursor->name=(char*)malloc((strlen(tmp)+strlen(e->name)+2)*sizeof(char));
+	sprintf(ccursor->name,"%s.%s",e->name,tmp);
+	cursor=cursor->next;
+      }
+      printFullDescription(doc,in,children,type,ns,ns_ows,nc1,vid,fromDb,serviceType);
+      freeElements(&children);
+      free(children);
+    }else{
+      if(nc2!=NULL){
+	xmlAddChild(nc1,nc2);
+      }
+    }
+    e=e->next;
+  }
+}
+
+/**
+ * Generate a wps:Execute XML document.
+ * 
+ * @param m the conf maps containing the main.cfg settings
+ * @param request the map representing the HTTP request
+ * @param pid the process identifier linked to a service
+ * @param serv the serv structure created from the zcfg file
+ * @param service the service name
+ * @param status the status returned by the service
+ * @param inputs the inputs provided
+ * @param outputs the outputs generated by the service
+ */
+void printProcessResponse(maps* m,map* request, int pid,service* serv,const char* service,int status,maps* inputs,maps* outputs){	
+  xmlNsPtr ns,ns_ows,ns_xlink;
+  xmlNodePtr nr,n,nc,nc1=NULL,nc3;
+  xmlDocPtr doc;
+  time_t time1;  
+  time(&time1);
+  nr=NULL;
+
+  doc = xmlNewDoc(BAD_CAST "1.0");
+  map* version=getMapFromMaps(m,"main","rversion");
+  int vid=getVersionId(version->value);
+  n = printWPSHeader(doc,m,"Execute",root_nodes[vid][2],(version!=NULL?version->value:"1.0.0"),2);
+  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
+  ns=usedNs[wpsId];
+  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
+  ns_ows=usedNs[owsId];
+  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+  bool hasStoredExecuteResponse=false;
+  char stored_path[1024];
+  memset(stored_path,0,1024);
+  
+  if(vid==0){
+    char tmp[256];
+    char url[1024];
+    memset(tmp,0,256);
+    memset(url,0,1024);
+    maps* tmp_maps=getMaps(m,"main");
+    if(tmp_maps!=NULL && tmp_maps->content!=NULL){
+      map* tmpm1=getMap(tmp_maps->content,"serverAddress");
+      /**
+       * Check if the ZOO Service GetStatus is available in the local directory.
+       * If yes, then it uses a reference to an URL which the client can access
+       * to get information on the status of a running Service (using the 
+       * percentCompleted attribute). 
+       * Else fallback to the initial method using the xml file to write in ...
+       */
+      map* cwdMap=getMapFromMaps(m,"main","servicePath");
+      struct stat myFileInfo;
+      int statRes;
+      char file_path[1024];
+      if(cwdMap!=NULL){
+	sprintf(file_path,"%s/GetStatus.zcfg",cwdMap->value);
+      }else{
+	char ntmp[1024];
+#ifndef WIN32
+	getcwd(ntmp,1024);
+#else
+	_getcwd(ntmp,1024);
+#endif
+	sprintf(file_path,"%s/GetStatus.zcfg",ntmp);
+      }
+      statRes=stat(file_path,&myFileInfo);
+      if(statRes==0){
+	char currentSid[128];
+	map* tmpm=getMap(tmp_maps->content,"rewriteUrl");
+	map *tmp_lenv=NULL;
+	tmp_lenv=getMapFromMaps(m,"lenv","usid");
+	if(tmp_lenv==NULL)
+	  sprintf(currentSid,"%i",pid);
+	else
+	  sprintf(currentSid,"%s",tmp_lenv->value);
+	if(tmpm==NULL || strcasecmp(tmpm->value,"false")==0){
+	  sprintf(url,"%s?request=Execute&service=WPS&version=1.0.0&Identifier=GetStatus&DataInputs=sid=%s&RawDataOutput=Result",tmpm1->value,currentSid);
+	}else{
+	  if(strlen(tmpm->value)>0)
+	    if(strcasecmp(tmpm->value,"true")!=0)
+	      sprintf(url,"%s/%s/GetStatus/%s",tmpm1->value,tmpm->value,currentSid);
+	    else
+	      sprintf(url,"%s/GetStatus/%s",tmpm1->value,currentSid);
+	  else
+	    sprintf(url,"%s/?request=Execute&service=WPS&version=1.0.0&Identifier=GetStatus&DataInputs=sid=%s&RawDataOutput=Result",tmpm1->value,currentSid);
+	}
+      }else{
+	int lpid;
+	map* tmpm2=getMapFromMaps(m,"lenv","usid");
+	map* tmpm3=getMap(tmp_maps->content,"tmpUrl");
+	if(tmpm1!=NULL && tmpm3!=NULL){
+	  if( strncasecmp( tmpm3->value, "http://", 7) == 0 ||
+	      strncasecmp( tmpm3->value, "https://", 8 ) == 0 ){
+	    sprintf(url,"%s/%s_%s.xml",tmpm3->value,service,tmpm2->value);
+	  }else
+	    sprintf(url,"%s/%s_%s.xml",tmpm1->value,service,tmpm2->value);
+	}
+      }
+      if(tmpm1!=NULL){
+	sprintf(tmp,"%s",tmpm1->value);
+      }
+      int lpid;
+      map* tmpm2=getMapFromMaps(m,"lenv","usid");
+      tmpm1=getMapFromMaps(m,"main","TmpPath");
+      sprintf(stored_path,"%s/%s_%s.xml",tmpm1->value,service,tmpm2->value);
+    }
+
+    xmlNewProp(n,BAD_CAST "serviceInstance",BAD_CAST tmp);
+    map* test=getMap(request,"storeExecuteResponse");
+    if(test!=NULL && strcasecmp(test->value,"true")==0){
+      xmlNewProp(n,BAD_CAST "statusLocation",BAD_CAST url);
+      hasStoredExecuteResponse=true;
+    }
+
+    nc = xmlNewNode(ns, BAD_CAST "Process");
+    map* tmp2=getMap(serv->content,"processVersion");
+    if(tmp2!=NULL)
+      xmlNewNsProp(nc,ns,BAD_CAST "processVersion",BAD_CAST tmp2->value);
+    else
+      xmlNewNsProp(nc,ns,BAD_CAST "processVersion",BAD_CAST "1");
+  
+    map* tmpI=getMapFromMaps(m,"lenv","oIdentifier");
+    printDescription(nc,ns_ows,tmpI->value,serv->content,0);
+
+    xmlAddChild(n,nc);
+
+    nc = xmlNewNode(ns, BAD_CAST "Status");
+    const struct tm *tm;
+    size_t len;
+    time_t now;
+    char *tmp1;
+    map *tmpStatus;
+  
+    now = time ( NULL );
+    tm = localtime ( &now );
+
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+
+    xmlNewProp(nc,BAD_CAST "creationTime",BAD_CAST tmp1);
+
+    char sMsg[2048];
+    switch(status){
+    case SERVICE_SUCCEEDED:
+      nc1 = xmlNewNode(ns, BAD_CAST "ProcessSucceeded");
+      sprintf(sMsg,_("The service \"%s\" ran successfully."),serv->name);
+      nc3=xmlNewText(BAD_CAST sMsg);
+      xmlAddChild(nc1,nc3);
+      break;
+    case SERVICE_STARTED:
+      nc1 = xmlNewNode(ns, BAD_CAST "ProcessStarted");
+      tmpStatus=getMapFromMaps(m,"lenv","status");
+      xmlNewProp(nc1,BAD_CAST "percentCompleted",BAD_CAST tmpStatus->value);
+      sprintf(sMsg,_("The ZOO service \"%s\" is currently running. Please reload this document to get the up-to-date status of the service."),serv->name);
+      nc3=xmlNewText(BAD_CAST sMsg);
+      xmlAddChild(nc1,nc3);
+      break;
+    case SERVICE_ACCEPTED:
+      nc1 = xmlNewNode(ns, BAD_CAST "ProcessAccepted");
+      sprintf(sMsg,_("The service \"%s\" was accepted by the ZOO-Kernel and is running as a background task. Please access the URL in the statusLocation attribute provided in this document to get the up-to-date status and results."),serv->name);
+      nc3=xmlNewText(BAD_CAST sMsg);
+      xmlAddChild(nc1,nc3);
+      break;
+    case SERVICE_FAILED:
+      nc1 = xmlNewNode(ns, BAD_CAST "ProcessFailed");
+      map *errorMap;
+      map *te;
+      te=getMapFromMaps(m,"lenv","code");
+      if(te!=NULL)
+	errorMap=createMap("code",te->value);
+      else
+	errorMap=createMap("code","NoApplicableCode");
+      te=getMapFromMaps(m,"lenv","message");
+      if(te!=NULL)
+	addToMap(errorMap,"text",_ss(te->value));
+      else
+	addToMap(errorMap,"text",_("No more information available"));
+      nc3=createExceptionReportNode(m,errorMap,0);
+      freeMap(&errorMap);
+      free(errorMap);
+      xmlAddChild(nc1,nc3);
+      break;
+    default :
+      printf(_("error code not know : %i\n"),status);
+      //exit(1);
+      break;
+    }
+    xmlAddChild(nc,nc1);
+    xmlAddChild(n,nc);
+    free(tmp1);
+
+#ifdef DEBUG
+    fprintf(stderr,"printProcessResponse %d\n",__LINE__);
+#endif
+
+    map* lineage=getMap(request,"lineage");
+    if(lineage!=NULL && strcasecmp(lineage->value,"true")==0){
+      nc = xmlNewNode(ns, BAD_CAST "DataInputs");
+      maps* mcursor=inputs;
+      elements* scursor=NULL;
+      while(mcursor!=NULL /*&& scursor!=NULL*/){
+	scursor=getElements(serv->inputs,mcursor->name);
+	printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Input",vid);
+	mcursor=mcursor->next;
+      }
+      xmlAddChild(n,nc);
+
+      nc = xmlNewNode(ns, BAD_CAST "OutputDefinitions");
+      mcursor=outputs;
+      scursor=NULL;
+      while(mcursor!=NULL){
+	scursor=getElements(serv->outputs,mcursor->name);
+	printOutputDefinitions(doc,nc,ns,ns_ows,scursor,mcursor,"Output");
+	mcursor=mcursor->next;
+      }
+      xmlAddChild(n,nc);
+    }
+  }
+  
+  /**
+   * Display the process output only when requested !
+   */
+  if(status==SERVICE_SUCCEEDED){
+    if(vid==0){
+      nc = xmlNewNode(ns, BAD_CAST "ProcessOutputs");
+    }
+    maps* mcursor=outputs;
+    elements* scursor=serv->outputs;
+    map* testResponse=getMap(request,"RawDataOutput");	
+    if(testResponse==NULL)
+      testResponse=getMap(request,"ResponseDocument");
+    while(mcursor!=NULL){		
+      map* tmp0=getMap(mcursor->content,"inRequest");
+      scursor=getElements(serv->outputs,mcursor->name);	  
+      if(scursor!=NULL){		  
+	if(testResponse==NULL || tmp0==NULL){		
+	  if(vid==0)
+	    printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
+	  else
+	    printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
+	}
+	else
+	  if(tmp0!=NULL && strncmp(tmp0->value,"true",4)==0){		  
+	    if(vid==0)
+	      printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
+	    else
+	      printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
+	  }	
+      }else
+	/**
+	 * In case there was no definition found in the ZCFG file but 
+	 * present in the service code
+	 */
+	if(vid==0)
+	  printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
+	else
+	  printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
+      mcursor=mcursor->next;
+    }	
+    if(vid==0)
+      xmlAddChild(n,nc);
+  }  
+  if(vid==0 && 
+     hasStoredExecuteResponse==true 
+     && status!=SERVICE_STARTED 
+#ifndef WIN32
+     && status!=SERVICE_ACCEPTED
+#endif
+     ){
+#ifndef RELY_ON_DB
+    semid lid=acquireLock(m);//,1);
+    if(lid<0){
+      /* If the lock failed */
+      errorException(m,_("Lock failed."),"InternalError",NULL);
+      xmlFreeDoc(doc);
+      xmlCleanupParser();
+      zooXmlCleanupNs();
+      return;
+    }
+    else{
+#endif
+      /* We need to write the ExecuteResponse Document somewhere */
+      FILE* output=fopen(stored_path,"w");
+      if(output==NULL){
+	/* If the file cannot be created return an ExceptionReport */
+	char tmpMsg[1024];
+	sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the ExecuteResponse."),stored_path);
+
+	errorException(m,tmpMsg,"InternalError",NULL);
+	xmlFreeDoc(doc);
+	xmlCleanupParser();
+	zooXmlCleanupNs();
+#ifndef RELY_ON_DB
+	unlockShm(lid);
+#endif
+	return;
+      }
+      xmlChar *xmlbuff;
+      int buffersize;
+      xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, "UTF-8", 1);
+      fwrite(xmlbuff,1,xmlStrlen(xmlbuff)*sizeof(char),output);
+      xmlFree(xmlbuff);
+      fclose(output);
+#ifndef RELY_ON_DB
+#ifdef DEBUG
+      fprintf(stderr,"UNLOCK %s %d !\n",__FILE__,__LINE__);
+#endif
+      unlockShm(lid);
+      map* v=getMapFromMaps(m,"lenv","sid");
+      // Remove the lock when running as a normal task
+      if(getpid()==atoi(v->value)){
+	removeShmLock (m, 1);
+      }
+    }
+#endif
+  }
+
+  printDocument(m,doc,pid);
+
+  xmlCleanupParser();
+  zooXmlCleanupNs();
+}
+
+/**
+ * Print a XML document.
+ * 
+ * @param m the conf maps containing the main.cfg settings
+ * @param doc the XML document
+ * @param pid the process identifier linked to a service
+ */
+void printDocument(maps* m, xmlDocPtr doc,int pid){
+  char *encoding=getEncoding(m);
+  if(pid==getpid()){
+    printHeaders(m);
+    printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
+  }
+  xmlChar *xmlbuff;
+  int buffersize;
+  /*
+   * Dump the document to a buffer and print it on stdout
+   * for demonstration purposes.
+   */
+  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
+  printf("%s",xmlbuff);
+  fflush(stdout);
+  /*
+   * Free associated memory.
+   */
+  xmlFree(xmlbuff);
+  xmlFreeDoc(doc);
+  xmlCleanupParser();
+  zooXmlCleanupNs();
+}
+
+/**
+ * Print a XML document.
+ * 
+ * @param doc the XML document (unused)
+ * @param nc the XML node to add the output definition
+ * @param ns_wps the wps XML namespace
+ * @param ns_ows the ows XML namespace
+ * @param e the output elements 
+ * @param m the conf maps containing the main.cfg settings
+ * @param type the type (unused)
+ */
+void printOutputDefinitions(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,elements* e,maps* m,const char* type){
+  xmlNodePtr nc1;
+  nc1=xmlNewNode(ns_wps, BAD_CAST type);
+  map *tmp=NULL;  
+  if(e!=NULL && e->defaults!=NULL)
+    tmp=e->defaults->content;
+  else{
+    /*
+      dumpElements(e);
+    */
+    return;
+  }
+  while(tmp!=NULL){
+    if(strncasecmp(tmp->name,"MIMETYPE",strlen(tmp->name))==0
+       || strncasecmp(tmp->name,"ENCODING",strlen(tmp->name))==0
+       || strncasecmp(tmp->name,"SCHEMA",strlen(tmp->name))==0
+       || strncasecmp(tmp->name,"UOM",strlen(tmp->name))==0)
+      xmlNewProp(nc1,BAD_CAST tmp->name,BAD_CAST tmp->value);
+    tmp=tmp->next;
+  }
+  tmp=getMap(e->defaults->content,"asReference");
+  if(tmp==NULL)
+    xmlNewProp(nc1,BAD_CAST "asReference",BAD_CAST "false");
+
+  tmp=e->content;
+
+  printDescription(nc1,ns_ows,m->name,e->content,0);
+
+  xmlAddChild(nc,nc1);
+
+}
+
+/**
+ * Generate XML nodes describing inputs or outputs metadata.
+ * 
+ * @param doc the XML document 
+ * @param nc the XML node to add the definition
+ * @param ns_wps the wps namespace
+ * @param ns_ows the ows namespace
+ * @param ns_xlink the xlink namespace
+ * @param e the output elements 
+ * @param m the conf maps containing the main.cfg settings
+ * @param type the type
+ */
+void printIOType(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,elements* e,maps* m,const char* type,int vid){	
+  xmlNodePtr nc1,nc2,nc3;
+  nc1=xmlNewNode(ns_wps, BAD_CAST type);
+  map *tmp=NULL;
+  if(e!=NULL)
+    tmp=e->content;
+  else
+    tmp=m->content;  
+  if(vid==0){
+    nc2=xmlNewNode(ns_ows, BAD_CAST "Identifier");
+    if(e!=NULL)
+      nc3=xmlNewText(BAD_CAST e->name);
+    else
+      nc3=xmlNewText(BAD_CAST m->name);
+    
+    xmlAddChild(nc2,nc3);
+    xmlAddChild(nc1,nc2);
+  
+    xmlAddChild(nc,nc1);
+
+    if(e!=NULL)
+      tmp=getMap(e->content,"Title");
+    else
+      tmp=getMap(m->content,"Title");
+    
+    if(tmp!=NULL){
+      nc2=xmlNewNode(ns_ows, BAD_CAST tmp->name);
+      nc3=xmlNewText(BAD_CAST _ss(tmp->value));
+      xmlAddChild(nc2,nc3);  
+      xmlAddChild(nc1,nc2);
+    }
+
+    if(e!=NULL)
+      tmp=getMap(e->content,"Abstract");
+    else
+      tmp=getMap(m->content,"Abstract");
+
+    if(tmp!=NULL){
+      nc2=xmlNewNode(ns_ows, BAD_CAST tmp->name);
+      nc3=xmlNewText(BAD_CAST _ss(tmp->value));
+      xmlAddChild(nc2,nc3);  
+      xmlAddChild(nc1,nc2);
+      xmlAddChild(nc,nc1);
+    }
+  }else{
+    xmlNewProp(nc1,BAD_CAST "id",BAD_CAST (e!=NULL?e->name:m->name));
+  }
+  
+  // IO type nested outputs
+  if(m->child!=NULL){	  
+    maps* curs=m->child;
+    elements* ecurs=getElements(e,(e!=NULL?e->name:m->name));
+    ecurs=ecurs->child;
+    while(curs!=NULL/* && ecurs!=NULL*/){
+      ecurs=getElements(ecurs,(curs->name));
+      map* inRequest=getMap(curs->content,"inRequest");
+      if(inRequest!=NULL && strncasecmp(inRequest->value,"true",4)==0)
+	printIOType(doc,nc1,ns_wps,ns_ows,ns_xlink,ecurs,curs,type,vid);
+      curs=curs->next;
+      ecurs=getElements(e,(e!=NULL?e->name:m->name));
+      ecurs=ecurs->child;
+    }
+  }
+  else{	  
+    map *tmpMap=getMap(m->content,"Reference");
+    if(tmpMap==NULL){		
+      nc2=xmlNewNode(ns_wps, BAD_CAST "Data");
+      if(e!=NULL && e->format!=NULL){		  
+		  if (strncasecmp(e->format, "LiteralOutput", strlen(e->format)) == 0)		  			  
+			  nc3 = xmlNewNode(ns_wps, BAD_CAST "LiteralData");		  
+	else
+	  if(strncasecmp(e->format,"ComplexOutput",strlen(e->format))==0)
+	    nc3=xmlNewNode(ns_wps, BAD_CAST "ComplexData");
+	  else if(strncasecmp(e->format,"BoundingBoxOutput",strlen(e->format))==0)
+	    nc3=xmlNewNode(ns_wps, BAD_CAST "BoundingBoxData");
+	  else
+	    nc3=xmlNewNode(ns_wps, BAD_CAST e->format);		  
+      }
+      else {		  
+	map* tmpV=getMapFromMaps(m,"format","value");	
+	if(tmpV!=NULL)
+	  nc3=xmlNewNode(ns_wps, BAD_CAST tmpV->value);
+	else
+	  nc3=xmlNewNode(ns_wps, BAD_CAST "LiteralData");
+      } 
+      tmp=m->content;	  
+
+      while(tmp!=NULL){
+	if(strcasecmp(tmp->name,"mimeType")==0 ||
+	   strcasecmp(tmp->name,"encoding")==0 ||
+	   strcasecmp(tmp->name,"schema")==0 ||
+	   strcasecmp(tmp->name,"datatype")==0 ||
+	   strcasecmp(tmp->name,"uom")==0) {	
+	  if(vid==0)
+	    xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
+	  else{
+	    if(strcasecmp(tmp->name,"datatype")==0)
+	      xmlNewProp(nc2,BAD_CAST "mimeType",BAD_CAST "text/plain");
+	    else
+	      if(strcasecmp(tmp->name,"uom")!=0)
+		xmlNewProp(nc2,BAD_CAST tmp->name,BAD_CAST tmp->value);
+	  }
+	}
+
+	if(vid==0)
+	  xmlAddChild(nc2,nc3);
+	tmp=tmp->next;	
+      }
+      if(e!=NULL && e->format!=NULL && strcasecmp(e->format,"BoundingBoxData")==0) {
+	map* bb=getMap(m->content,"value");
+	if(bb!=NULL) {
+	  map* tmpRes=parseBoundingBox(bb->value);
+	  printBoundingBox(ns_ows,nc3,tmpRes);
+	  freeMap(&tmpRes);
+	  free(tmpRes);
+	}
+      }
+      else {		  
+		  //if (e != NULL) {
+		  if (e != NULL && e->defaults != NULL) { // knut: add extra NULL pointer check in case user omits <Default> block in config file			  
+			  tmp = getMap(e->defaults->content, "mimeType");
+		  }
+	else
+	  tmp=NULL;	
+	map* tmp1=getMap(m->content,"encoding");
+	map* tmp2=getMap(m->content,"mimeType");
+	map* tmp3=getMap(m->content,"value");
+	int hasValue=1;
+	if(tmp3==NULL){
+	  tmp3=createMap("value","");
+	  hasValue=-1;
+	}
+	
+	if( ( tmp1 != NULL && strncmp(tmp1->value,"base64",6) == 0 )     // if encoding is base64
+	    || 	                                                       // or if 
+	    ( tmp2 != NULL && ( strstr(tmp2->value,"text") == NULL       //  mime type is not text 
+				&&                                       //  nor 
+				strstr(tmp2->value,"xml") == NULL        //  xml
+				&&                                       // nor
+				strstr(tmp2->value,"javascript") == NULL // javascript
+				&&
+				strstr(tmp2->value,"json") == NULL
+				&&
+				strstr(tmp2->value,"ecmascript") == NULL
+				&&
+				// include for backwards compatibility,
+				// although correct mime type is ...kml+xml:
+				strstr(tmp2->value,"google-earth.kml") == NULL							)
+	      )
+	    ) { 	                                                 // then	
+	  map* rs=getMap(m->content,"size");                       // obtain size
+	  bool isSized=true;
+	  if(rs==NULL){
+	    char tmp1[1024];
+	    sprintf(tmp1,"%ld",strlen(tmp3->value));
+	    rs=createMap("size",tmp1);
+	    isSized=false;
+	  }
+	  
+	  xmlAddChild((vid==0?nc3:nc2),xmlNewText(BAD_CAST base64(tmp3->value, atoi(rs->value))));  // base 64 encode in XML
+	  
+	  if(tmp1==NULL || (tmp1!=NULL && strncmp(tmp1->value,"base64",6)!=0)) {
+	    xmlAttrPtr ap = xmlHasProp((vid==0?nc3:nc2), BAD_CAST "encoding");
+	    if (ap != NULL) {
+	      xmlRemoveProp(ap);
+	    }			
+	    xmlNewProp((vid==0?nc3:nc2),BAD_CAST "encoding",BAD_CAST "base64");
+	  }
+	  
+	  if(!isSized){
+	    freeMap(&rs);
+	    free(rs);
+	  }
+	}
+	else if (tmp2!=NULL) {                                 // else (text-based format) 
+	  if(strstr(tmp2->value, "javascript") != NULL ||      //    if javascript put code in CDATA block 
+	     strstr(tmp2->value, "json") != NULL ||            //    (will not be parsed by XML reader) 
+	     strstr(tmp2->value, "ecmascript") != NULL
+	     ) {
+	    xmlAddChild((vid==0?nc3:nc2),xmlNewCDataBlock(doc,BAD_CAST tmp3->value,strlen(tmp3->value)));
+	  }   
+	  else {                                                     // else
+	    if (strstr(tmp2->value, "xml") != NULL ||                 // if XML-based format
+		// include for backwards compatibility,
+		// although correct mime type is ...kml+xml:		   
+		strstr(tmp2->value, "google-earth.kml") != NULL
+		) { 
+	      
+	      int li=zooXmlAddDoc(tmp3->value);
+	      xmlDocPtr doc = iDocs[li];
+	      xmlNodePtr ir = xmlDocGetRootElement(doc);
+	      xmlAddChild((vid==0?nc3:nc2),ir);
+	    }
+	    else                                                     // else	
+	      xmlAddChild((vid==0?nc3:nc2),xmlNewText(BAD_CAST tmp3->value));    //   add text node
+	  }
+	  xmlAddChild(nc2,nc3);
+	}
+	else {
+	  xmlAddChild((vid==0?nc3:nc2),xmlNewText(BAD_CAST tmp3->value));
+	}
+	
+	if(hasValue<0) {
+	  freeMap(&tmp3);
+	  free(tmp3);
+	}
+      }
+    }
+    else { // Reference
+      tmpMap=getMap(m->content,"Reference");
+      nc3=nc2=xmlNewNode(ns_wps, BAD_CAST "Reference");
+      /* Special case to avoid failing to validate against the WPS 2.0 schema */
+      if(strcasecmp(type,"Output")==0 && vid==0)
+	xmlNewProp(nc3,BAD_CAST "href",BAD_CAST tmpMap->value);
+      else
+	xmlNewNsProp(nc3,ns_xlink,BAD_CAST "href",BAD_CAST tmpMap->value);
+      
+      tmp=m->content;
+      while(tmp!=NULL) {
+	if(strcasecmp(tmp->name,"mimeType")==0 ||
+	   strcasecmp(tmp->name,"encoding")==0 ||
+	   strcasecmp(tmp->name,"schema")==0 ||
+	   strcasecmp(tmp->name,"datatype")==0 ||
+	   strcasecmp(tmp->name,"uom")==0){
+	  
+	  if(strcasecmp(tmp->name,"datatype")==0)
+	    xmlNewProp(nc3,BAD_CAST "mimeType",BAD_CAST "text/plain");
+	  else
+	    xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
+	}
+	tmp=tmp->next;
+	xmlAddChild(nc2,nc3);
+      }
+    }
+    xmlAddChild(nc1,nc2);
+  }
+  xmlAddChild(nc,nc1);
+}
+
+/**
+ * Create XML node with basic ows metadata information (Identifier,Title,Abstract)
+ *
+ * @param root the root XML node to add the description
+ * @param ns_ows the ows XML namespace
+ * @param identifier the identifier to use
+ * @param amap the map containing the ows metadata information 
+ */
+void printDescription(xmlNodePtr root,xmlNsPtr ns_ows,const char* identifier,map* amap,int vid=0){
+  xmlNodePtr nc2;
+  if(vid==0){
+    nc2 = xmlNewNode(ns_ows, BAD_CAST "Identifier");
+    xmlAddChild(nc2,xmlNewText(BAD_CAST identifier));
+    xmlAddChild(root,nc2);
+  }
+  map* tmp=amap;
+  const char *tmp2[2];
+  tmp2[0]="Title";
+  tmp2[1]="Abstract";
+  int j=0;
+  for(j=0;j<2;j++){
+    map* tmp1=getMap(tmp,tmp2[j]);
+    if(tmp1!=NULL){
+      nc2 = xmlNewNode(ns_ows, BAD_CAST tmp2[j]);
+      xmlAddChild(nc2,xmlNewText(BAD_CAST _ss(tmp1->value)));
+      xmlAddChild(root,nc2);
+    }
+  }
+  if(vid==1){
+    nc2 = xmlNewNode(ns_ows, BAD_CAST "Identifier");
+    xmlAddChild(nc2,xmlNewText(BAD_CAST identifier));
+    xmlAddChild(root,nc2);
+  }
+}
+
+/**
+ * Print an OWS ExceptionReport Document and HTTP headers (when required) 
+ * depending on the code.
+ * Set hasPrinted value to true in the [lenv] section.
+ * 
+ * @param m the maps containing the settings of the main.cfg file
+ * @param s the map containing the text,code,locator keys (or a map array of the same keys)
+ */
+void printExceptionReportResponse(maps* m,map* s){
+  if(getMapFromMaps(m,"lenv","hasPrinted")!=NULL)
+    return;
+  int buffersize;
+  xmlDocPtr doc;
+  xmlChar *xmlbuff;
+  xmlNodePtr n;
+
+  zooXmlCleanupNs();
+  doc = xmlNewDoc(BAD_CAST "1.0");
+  maps* tmpMap=getMaps(m,"main");
+  char *encoding=getEncoding(tmpMap);
+  const char *exceptionCode;
+  
+  map* tmp=getMap(s,"code");
+  if(tmp!=NULL){
+    if(strcmp(tmp->value,"OperationNotSupported")==0 ||
+       strcmp(tmp->value,"NoApplicableCode")==0)
+      exceptionCode="501 Not Implemented";
+    else
+      if(strcmp(tmp->value,"MissingParameterValue")==0 ||
+	 strcmp(tmp->value,"InvalidUpdateSequence")==0 ||
+	 strcmp(tmp->value,"OptionNotSupported")==0 ||
+	 strcmp(tmp->value,"VersionNegotiationFailed")==0 ||
+	 strcmp(tmp->value,"InvalidParameterValue")==0)
+	exceptionCode="400 Bad request";
+      else
+	exceptionCode="501 Internal Server Error";
+  }
+  else
+    exceptionCode="501 Internal Server Error";
+  tmp=getMapFromMaps(m,"lenv","status_code");
+  if(tmp!=NULL)
+    exceptionCode=tmp->value;
+  if(m!=NULL){
+    map *tmpSid=getMapFromMaps(m,"lenv","sid");
+    if(tmpSid!=NULL){
+      if( getpid()==atoi(tmpSid->value) ){
+	printHeaders(m);
+	printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
+      }
+    }
+    else{
+      printHeaders(m);
+      printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
+    }
+  }else{
+    printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
+  }
+  n=createExceptionReportNode(m,s,1);
+  xmlDocSetRootElement(doc, n);
+  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
+  printf("%s",xmlbuff);
+  fflush(stdout);
+  xmlFreeDoc(doc);
+  xmlFree(xmlbuff);
+  xmlCleanupParser();
+  zooXmlCleanupNs();
+  if(m!=NULL)
+    setMapInMaps(m,"lenv","hasPrinted","true");
+}
+
+/**
+ * Create an OWS ExceptionReport Node.
+ * 
+ * @param m the conf maps
+ * @param s the map containing the text,code,locator keys
+ * @param use_ns (0/1) choose if you want to generate an ExceptionReport or 
+ *  ows:ExceptionReport node respectively
+ * @return the ExceptionReport/ows:ExceptionReport node
+ */
+xmlNodePtr createExceptionReportNode(maps* m,map* s,int use_ns){
+  
+  xmlNsPtr ns,ns_xsi;
+  xmlNodePtr n,nc,nc1;
+
+  int nsid=zooXmlAddNs(NULL,"http://www.opengis.net/ows","ows");
+  ns=usedNs[nsid];
+  if(use_ns==0){
+    ns=NULL;
+  }
+  n = xmlNewNode(ns, BAD_CAST "ExceptionReport");
+  map* version=getMapFromMaps(m,"main","rversion");
+  int vid=-1;
+  if(version!=NULL)
+    vid=getVersionId(version->value);
+  if(vid<0)
+    vid=0;
+  if(use_ns==1){
+    xmlNewNs(n,BAD_CAST schemas[vid][1],BAD_CAST"ows");
+    int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
+    ns_xsi=usedNs[xsiId];
+    char tmp[1024];
+    sprintf(tmp,"%s %s",schemas[vid][1],schemas[vid][5]);
+    xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST tmp);
+  }
+
+
+  addLangAttr(n,m);
+  xmlNewProp(n,BAD_CAST "version",BAD_CAST schemas[vid][6]);
+  
+  int length=1;
+  int cnt=0;
+  map* len=getMap(s,"length");
+  if(len!=NULL)
+    length=atoi(len->value);
+  for(cnt=0;cnt<length;cnt++){
+    nc = xmlNewNode(ns, BAD_CAST "Exception");
+    
+    map* tmp=getMapArray(s,"code",cnt);
+    if(tmp==NULL)
+      tmp=getMap(s,"code");
+    if(tmp!=NULL)
+      xmlNewProp(nc,BAD_CAST "exceptionCode",BAD_CAST tmp->value);
+    else
+      xmlNewProp(nc,BAD_CAST "exceptionCode",BAD_CAST "NoApplicableCode");
+    
+    tmp=getMapArray(s,"locator",cnt);
+    if(tmp==NULL)
+      tmp=getMap(s,"locator");
+    if(tmp!=NULL && strcasecmp(tmp->value,"NULL")!=0)
+      xmlNewProp(nc,BAD_CAST "locator",BAD_CAST tmp->value);
+
+    tmp=getMapArray(s,"text",cnt);
+    if(tmp==NULL)
+      tmp=getMapArray(s,"message",cnt);
+    nc1 = xmlNewNode(ns, BAD_CAST "ExceptionText");
+    if(tmp!=NULL){
+      xmlNodePtr txt=xmlNewText(BAD_CAST tmp->value);
+      xmlAddChild(nc1,txt);
+      if(cnt==0)
+	setMapInMaps(m,"lenv","message",tmp->value);
+    }
+    else{
+      xmlNodeSetContent(nc1, BAD_CAST _("No debug message available"));
+    }
+    xmlAddChild(nc,nc1);
+    xmlAddChild(n,nc);
+  }
+  return n;
+}
+
+/**
+ * Print an OWS ExceptionReport.
+ * 
+ * @param m the conf maps
+ * @param message the error message 
+ * @param errorcode the error code
+ * @param locator the potential locator
+ */
+int errorException(maps *m, const char *message, const char *errorcode, const char *locator) 
+{
+  map* errormap = createMap("text", message);
+  addToMap(errormap,"code", errorcode);
+  if(locator!=NULL)
+    addToMap(errormap,"locator", locator);
+  else
+    addToMap(errormap,"locator", "NULL");
+  printExceptionReportResponse(m,errormap);
+  freeMap(&errormap);
+  free(errormap);
+  return -1;
+}
+
+/**
+ * Generate the output response (RawDataOutput or ResponseDocument)
+ *
+ * @param s the service structure containing the metadata information
+ * @param request_inputs the inputs provided to the service for execution
+ * @param request_outputs the outputs updated by the service execution
+ * @param request_inputs1 the map containing the HTTP request
+ * @param cpid the process identifier attached to a service execution
+ * @param m the conf maps containing the main.cfg settings
+ * @param res the value returned by the service execution
+ */
+void outputResponse(service* s,maps* request_inputs,maps* request_outputs,
+		    map* request_inputs1,int cpid,maps* m,int res){
+#ifdef DEBUG
+  dumpMaps(request_inputs);
+  dumpMaps(request_outputs);
+  fprintf(stderr,"printProcessResponse\n");
+#endif  
+  map* toto=getMap(request_inputs1,"RawDataOutput");
+  int asRaw=0;
+  if(toto!=NULL)
+    asRaw=1;
+  map* version=getMapFromMaps(m,"main","rversion");
+  int vid=getVersionId(version->value);
+  maps* tmpSess=getMaps(m,"senv");
+  if(tmpSess!=NULL){
+    map *_tmp=getMapFromMaps(m,"lenv","cookie");
+    maps *tmps=getMaps(m,"senv");
+    char* sessId=NULL;
+    if(_tmp!=NULL){
+      printf("Set-Cookie: %s; HttpOnly\r\n",_tmp->value);
+      map *_tmp1=getMapFromMaps(m,"senv","ecookie_length");
+      if(_tmp1!=NULL){
+	int len=atoi(_tmp1->value);
+	int cnt=0;
+	for(cnt=0;cnt<len;cnt++){
+	  map* _tmp2=getMapArray(tmps->content,"ecookie",cnt);
+	  if(_tmp2!=NULL)
+	    printf("Set-Cookie: %s; HttpOnly\r\n",_tmp2->value);
+	}
+      }
+      printf("P3P: CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"\r\n");
+      char session_file_path[100];
+      char *tmp1=strtok(_tmp->value,";");
+      if(tmp1!=NULL)
+	sprintf(session_file_path,"%s",strstr(tmp1,"=")+1);
+      else
+	sprintf(session_file_path,"%s",strstr(_tmp->value,"=")+1);
+      sessId=zStrdup(session_file_path);
+    }else{
+      maps* t=getMaps(m,"senv");
+      map*p=t->content;
+      while(p!=NULL){
+	if(strstr(p->name,"ID")!=NULL){
+	  sessId=zStrdup(p->value);
+	  break;
+	}
+	p=p->next;
+      }
+    }
+    char session_file_path[1024];
+    map *tmpPath=getMapFromMaps(m,"main","sessPath");
+    if(tmpPath==NULL)
+      tmpPath=getMapFromMaps(m,"main","tmpPath");
+    sprintf(session_file_path,"%s/sess_%s.cfg",tmpPath->value,sessId);
+    FILE* teste=fopen(session_file_path,"w");
+    if(teste==NULL){
+      char tmpMsg[1024];
+      sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the session maps."),session_file_path);
+      errorException(m,tmpMsg,"InternalError",NULL);
+      return;
+    }
+    else{
+      fclose(teste);
+      dumpMapsToFile(tmpSess,session_file_path,1);
+    }
+  }
+  if(res==SERVICE_FAILED){
+    map *lenv;
+    lenv=getMapFromMaps(m,"lenv","message");
+    char *tmp0;
+    if(lenv!=NULL){
+      tmp0=(char*)malloc((strlen(lenv->value)+strlen(_("Unable to run the Service. The message returned back by the Service was the following: "))+1)*sizeof(char));
+      sprintf(tmp0,_("Unable to run the Service. The message returned back by the Service was the following: %s"),lenv->value);
+    }
+    else{
+      tmp0=(char*)malloc((strlen(_("Unable to run the Service. No more information was returned back by the Service."))+1)*sizeof(char));
+      sprintf(tmp0,"%s",_("Unable to run the Service. No more information was returned back by the Service."));
+    }
+    errorException(m,tmp0,"InternalError",NULL);
+    free(tmp0);
+    return;
+  }
+
+  if(res==SERVICE_ACCEPTED && vid==1){
+    map* statusInfo=createMap("Status","Accepted");
+    map *usid=getMapFromMaps(m,"lenv","usid");
+    addToMap(statusInfo,"JobID",usid->value);
+    printStatusInfo(m,statusInfo,(char*)"Execute");
+    freeMap(&statusInfo);
+    free(statusInfo);
+    return;
+  }
+
+  if(res!=SERVICE_SUCCEEDED){	  
+    printProcessResponse(m,request_inputs1,cpid,
+                         s, s->name,res,  // replace serviceProvider with serviceName in stored response file name
+                         request_inputs,
+                         request_outputs);
+    return;
+  }
+      
+  map *tmp1=getMapFromMaps(m,"main","tmpPath");
+  if(asRaw==0){
+#ifdef DEBUG
+    fprintf(stderr,"REQUEST_OUTPUTS FINAL\n");
+    dumpMaps(request_outputs);
+#endif
+    maps* tmpI=request_outputs;
+    maps* stmpI=NULL;
+    map* usid=getMapFromMaps(m,"lenv","usid");
+    int itn=0;
+    int error=-1;
+  NESTED0:
+    while(tmpI!=NULL){
+      if(tmpI->child!=NULL){
+	stmpI=tmpI;
+	tmpI=tmpI->child;
+      }
+#ifdef USE_MS
+      map* testMap=getMap(tmpI->content,"useMapserver");	
+#endif
+      map *gfile=getMap(tmpI->content,"generated_file");
+      char *file_name=NULL;	  
+      if(gfile!=NULL){
+	gfile=getMap(tmpI->content,"expected_generated_file");
+	if(gfile==NULL){
+	  gfile=getMap(tmpI->content,"generated_file");
+	}
+	readGeneratedFile(m,tmpI->content,gfile->value);
+	file_name=zStrdup((gfile->value)+strlen(tmp1->value));
+      }	  
+      toto=getMap(tmpI->content,"asReference");
+#ifdef USE_MS
+      map* geodatatype=getMap(tmpI->content,"geodatatype");
+      if(toto!=NULL && strcasecmp(toto->value,"true")==0 &&
+	 (testMap==NULL ||
+	  strncasecmp(testMap->value,"true",4)!=0 ||
+	  (geodatatype!=NULL && strcasecmp(geodatatype->value,"other")==0) ) ) 
+#else
+	if(toto!=NULL && strcasecmp(toto->value,"true")==0)
+#endif
+	  {		
+	    elements* in=getElements(s->outputs,tmpI->name);
+	    if(in==NULL && s->outputs->child!=NULL){
+	      in=getElements(s->outputs->child,tmpI->name);
+	    }
+	    char *format=NULL;
+	    if(in!=NULL && in->format!=NULL){
+	      format=in->format;
+	    }else
+	      format=(char*)"LiteralData";
+	    if(format!=NULL && strcasecmp(format,"BoundingBoxData")==0){
+	      addToMap(tmpI->content,"extension","xml");
+	      addToMap(tmpI->content,"mimeType","text/xml");
+	      addToMap(tmpI->content,"encoding","UTF-8");
+	      addToMap(tmpI->content,"schema","http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd");
+	    }		
+	    char *file_path=NULL;
+	    if(gfile==NULL) {
+	      map *ext=getMap(tmpI->content,"extension");
+	      char file_ext[32];
+	    
+	      if( ext != NULL && ext->value != NULL) {
+		strncpy(file_ext, ext->value, 32);
+	      }
+	      else {
+		// Obtain default file extension (see mimetypes.h).	      
+		// If the MIME type is not recognized, txt is used as the default extension
+		map* mtype=getMap(tmpI->content,"mimeType");
+		getFileExtension(mtype != NULL ? mtype->value : NULL, file_ext, 32);
+	      }
+	      if(file_name!=NULL)
+		free(file_name);
+	      file_name=(char*)malloc((strlen(s->name)+strlen(usid->value)+strlen(file_ext)+strlen(tmpI->name)+45)*sizeof(char));
+	      sprintf(file_name,"ZOO_DATA_%s_%s_%s_%d.%s",s->name,tmpI->name,usid->value,itn,file_ext);
+	      itn++;
+	      file_path=(char*)malloc((strlen(tmp1->value)+strlen(file_name)+2)*sizeof(char));
+	      sprintf(file_path,"%s/%s",tmp1->value,file_name);
+
+	      FILE *ofile=fopen(file_path,"wb");
+	      if(ofile==NULL){
+		char tmpMsg[1024];
+		sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the %s final result."),file_name,tmpI->name);
+		errorException(m,tmpMsg,"InternalError",NULL);
+		free(file_name);
+		free(file_path);
+		return;
+	      }
+
+	      toto=getMap(tmpI->content,"value");
+	      if(toto==NULL){
+		char tmpMsg[1024];
+		sprintf(tmpMsg,_("No value found for the requested output %s."),tmpI->name);
+		errorException(m,tmpMsg,"InternalError",NULL);
+		fclose(ofile);
+		free(file_name);
+		free(file_path);
+		return;
+	      }
+	      if(strcasecmp(format,"BoundingBoxData")!=0){
+		map* size=getMap(tmpI->content,"size");
+		if(size!=NULL && toto!=NULL)
+		  fwrite(toto->value,1,(atoi(size->value))*sizeof(char),ofile);
+		else
+		  if(toto!=NULL && toto->value!=NULL)
+		    fwrite(toto->value,1,strlen(toto->value)*sizeof(char),ofile);
+	      }else{
+		printBoundingBoxDocument(m,tmpI,ofile);
+	      }
+	      fclose(ofile);
+	    }
+
+	    map *tmp2=getMapFromMaps(m,"main","tmpUrl");
+	    map *tmp3=getMapFromMaps(m,"main","serverAddress");
+	    char *file_url=NULL;
+	    if(strncasecmp(tmp2->value,"http://",7)==0 ||
+	       strncasecmp(tmp2->value,"https://",8)==0){
+	      file_url=(char*)malloc((strlen(tmp2->value)+strlen(file_name)+2)*sizeof(char));
+	      sprintf(file_url,"%s/%s",tmp2->value,file_name);
+	    }else{
+	      file_url=(char*)malloc((strlen(tmp3->value)+strlen(tmp2->value)+strlen(file_name)+3)*sizeof(char));
+	      sprintf(file_url,"%s/%s/%s",tmp3->value,tmp2->value,file_name);
+	    }
+	    addToMap(tmpI->content,"Reference",file_url);
+	    if(file_name!=NULL)
+	      free(file_name);
+	    if(file_url!=NULL)
+	      free(file_url);
+	    file_name=NULL;
+	  }
+#ifdef USE_MS
+	else{
+	  if(testMap!=NULL){
+	    map* nbFeatures;
+	    setMapInMaps(m,"lenv","state","out");
+	    setReferenceUrl(m,tmpI);
+	    nbFeatures=getMap(tmpI->content,"nb_features");
+	    geodatatype=getMap(tmpI->content,"geodatatype");
+	    if((nbFeatures!=NULL && atoi(nbFeatures->value)==0) ||
+	       (geodatatype!=NULL && strcasecmp(geodatatype->value,"other")==0)){
+	      error=1;
+	      res=SERVICE_FAILED;
+	    }
+	  }
+	}
+#endif	
+      if(file_name!=NULL){
+	free(file_name);
+	file_name=NULL;
+      }
+      tmpI=tmpI->next;
+    }
+    if(stmpI!=NULL){
+      tmpI=stmpI->next;
+      stmpI=NULL;
+      if(tmpI!=NULL)
+	goto NESTED0;
+    }    
+#ifdef DEBUG
+    fprintf(stderr,"SERVICE : %s\n",s->name);
+    dumpMaps(m);
+#endif	
+    if(error<0)
+      printProcessResponse(m,request_inputs1,cpid,
+			   s, s->name,res,  // replace serviceProvider with serviceName in stored response file name
+			   request_inputs,
+			   request_outputs);
+    else{
+      maps* tmpMaps=getMaps(m,"lenv");
+#ifdef USE_CALLBACK
+      invokeCallback(m,NULL,NULL,7,0);
+#endif
+      printExceptionReportResponse(m,tmpMaps->content);
+    }
+  }
+  else{
+    /**
+     * We get the requested output or fallback to the first one if the 
+     * requested one is not present in the resulting outputs maps.
+     */
+    maps* tmpI=NULL;
+    map* tmpIV=getMap(request_inputs1,"RawDataOutput");
+    if(tmpIV!=NULL){
+      tmpI=getMaps(request_outputs,tmpIV->value);	  
+    }
+    if(tmpI==NULL)
+      tmpI=request_outputs;
+
+    elements* e=getElements(s->outputs,tmpI->name);
+    if(e!=NULL && strcasecmp(e->format,"BoundingBoxData")==0){
+      printBoundingBoxDocument(m,tmpI,NULL);
+    }else{
+      map *gfile=getMap(tmpI->content,"generated_file");
+      if(gfile!=NULL){
+	gfile=getMap(tmpI->content,"expected_generated_file");	
+	if(gfile==NULL){
+	  gfile=getMap(tmpI->content,"generated_file");
+	}
+	readGeneratedFile(m,tmpI->content,gfile->value);
+      }
+      toto=getMap(tmpI->content,"value");	 
+      if(toto==NULL){
+	char tmpMsg[1024];
+	sprintf(tmpMsg,_("Wrong RawDataOutput parameter: unable to fetch any result for the given parameter name: \"%s\"."),tmpI->name);
+	errorException(m,tmpMsg,"InvalidParameterValue","RawDataOutput");
+	return;
+      }	  
+      map* fname=getMapFromMaps(tmpI,tmpI->name,"filename");	  	  
+      if(fname!=NULL)
+	printf("Content-Disposition: attachment; filename=\"%s\"\r\n",fname->value);
+      map* rs=getMapFromMaps(tmpI,tmpI->name,"size");
+      if(rs!=NULL)
+	printf("Content-Length: %s\r\n",rs->value);
+      printHeaders(m);
+      char mime[1024];
+      map* mi=getMap(tmpI->content,"mimeType");
+#ifdef DEBUG
+      fprintf(stderr,"SERVICE OUTPUTS\n");
+      dumpMaps(request_outputs);
+      fprintf(stderr,"SERVICE OUTPUTS\n");
+#endif
+      map* en=getMap(tmpI->content,"encoding");
+      if(mi!=NULL && en!=NULL)
+	sprintf(mime,
+		"Content-Type: %s; charset=%s\r\nStatus: 200 OK\r\n\r\n",
+		mi->value,en->value);
+      else
+	if(mi!=NULL)
+	  sprintf(mime,
+		  "Content-Type: %s; charset=UTF-8\r\nStatus: 200 OK\r\n\r\n",
+		  mi->value);
+	else
+	  sprintf(mime,"Content-Type: text/plain; charset=utf-8\r\nStatus: 200 OK\r\n\r\n");
+      printf("%s",mime);
+      if(rs!=NULL)
+	fwrite(toto->value,1,atoi(rs->value),stdout);
+      else
+	fwrite(toto->value,1,strlen(toto->value),stdout);
+#ifdef DEBUG
+      dumpMap(toto);
+#endif
+    }
+  }
+}
+
+/**
+ * Create required XML nodes for boundingbox and update the current XML node
+ *
+ * @param ns_ows the ows XML namespace
+ * @param n the XML node to update
+ * @param boundingbox the map containing the boundingbox definition
+ */
+void printBoundingBox(xmlNsPtr ns_ows,xmlNodePtr n,map* boundingbox){
+
+  xmlNodePtr lw=NULL,uc=NULL;
+
+  map* tmp=getMap(boundingbox,"value");
+
+  tmp=getMap(boundingbox,"lowerCorner");
+  if(tmp!=NULL){
+    lw=xmlNewNode(ns_ows,BAD_CAST "LowerCorner");
+    xmlAddChild(lw,xmlNewText(BAD_CAST tmp->value));
+  }
+
+  tmp=getMap(boundingbox,"upperCorner");
+  if(tmp!=NULL){
+    uc=xmlNewNode(ns_ows,BAD_CAST "UpperCorner");
+    xmlAddChild(uc,xmlNewText(BAD_CAST tmp->value));
+  }
+
+  tmp=getMap(boundingbox,"crs");
+  if(tmp!=NULL)
+    xmlNewProp(n,BAD_CAST "crs",BAD_CAST tmp->value);
+
+  tmp=getMap(boundingbox,"dimensions");
+  if(tmp!=NULL)
+    xmlNewProp(n,BAD_CAST "dimensions",BAD_CAST tmp->value);
+
+  xmlAddChild(n,lw);
+  xmlAddChild(n,uc);
+
+}
+
+/**
+ * Parse a BoundingBox string
+ *
+ * [OGC 06-121r3](http://portal.opengeospatial.org/files/?artifact_id=20040):
+ *  10.2 Bounding box
+ * 
+ *
+ * Value is provided as : lowerCorner,upperCorner,crs,dimension
+ * Exemple : 189000,834000,285000,962000,urn:ogc:def:crs:OGC:1.3:CRS84
+ *
+ * A map to store boundingbox information should contain:
+ *  - lowerCorner : double,double (minimum within this bounding box)
+ *  - upperCorner : double,double (maximum within this bounding box)
+ *  - crs : URI (Reference to definition of the CRS)
+ *  - dimensions : int 
+ * 
+ * Note : support only 2D bounding box.
+ *
+ * @param value the char* containing the KVP bouding box
+ * @return a map containing all the bounding box keys
+ */
+map* parseBoundingBox(const char* value){
+  map *res=NULL;
+  if(value!=NULL){
+    char *cv,*cvp;
+    cv=strtok_r((char*) value,",",&cvp);
+    int cnt=0;
+    int icnt=0;
+    char *currentValue=NULL;
+    while(cv){
+      if(cnt<2)
+	if(currentValue!=NULL){
+	  char *finalValue=(char*)malloc((strlen(currentValue)+strlen(cv)+1)*sizeof(char));
+	  sprintf(finalValue,"%s%s",currentValue,cv);
+	  switch(cnt){
+	  case 0:
+	    res=createMap("lowerCorner",finalValue);
+	    break;
+	  case 1:
+	    addToMap(res,"upperCorner",finalValue);
+	    icnt=-1;
+	    break;
+	  }
+	  cnt++;
+	  free(currentValue);
+	  currentValue=NULL;
+	  free(finalValue);
+	}
+	else{
+	  currentValue=(char*)malloc((strlen(cv)+2)*sizeof(char));
+	  sprintf(currentValue,"%s ",cv);
+	}
+      else
+	if(cnt==2){
+	  addToMap(res,"crs",cv);
+	  cnt++;
+	}
+	else
+	  addToMap(res,"dimensions",cv);
+      icnt++;
+      cv=strtok_r(NULL,",",&cvp);
+    }
+  }
+  return res;
+}
+
+/**
+ * Print an ows:BoundingBox XML document
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param boundingbox the maps containing the boundingbox definition
+ * @param file the file to print the BoundingBox (if NULL then print on stdout)
+ * @see parseBoundingBox, printBoundingBox
+ */
+void printBoundingBoxDocument(maps* m,maps* boundingbox,FILE* file){
+  if(file==NULL)
+    rewind(stdout);
+  xmlNodePtr n;
+  xmlDocPtr doc;
+  xmlNsPtr ns_ows,ns_xsi;
+  xmlChar *xmlbuff;
+  int buffersize;
+  char *encoding=getEncoding(m);
+  map *tmp;
+  if(file==NULL){
+    int pid=0;
+    tmp=getMapFromMaps(m,"lenv","sid");
+    if(tmp!=NULL)
+      pid=atoi(tmp->value);
+    if(pid==getpid()){
+      printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
+    }
+    fflush(stdout);
+  }
+
+  doc = xmlNewDoc(BAD_CAST "1.0");
+  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
+  ns_ows=usedNs[owsId];
+  n = xmlNewNode(ns_ows, BAD_CAST "BoundingBox");
+  xmlNewNs(n,BAD_CAST "http://www.opengis.net/ows/1.1",BAD_CAST "ows");
+  int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
+  ns_xsi=usedNs[xsiId];
+  xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd");
+  map *tmp1=getMap(boundingbox->content,"value");
+  tmp=parseBoundingBox(tmp1->value);
+  printBoundingBox(ns_ows,n,tmp);
+  xmlDocSetRootElement(doc, n);
+
+  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
+  if(file==NULL)
+    printf("%s",xmlbuff);
+  else{
+    fprintf(file,"%s",xmlbuff);
+  }
+
+  if(tmp!=NULL){
+    freeMap(&tmp);
+    free(tmp);
+  }
+  xmlFree(xmlbuff);
+  xmlFreeDoc(doc);
+  xmlCleanupParser();
+  zooXmlCleanupNs();
+  
+}
+
+/**
+ * Print a StatusInfo XML document.
+ * a statusInfo map should contain the following keys:
+ *  * JobID corresponding to usid key from the lenv section
+ *  * Status the current state (Succeeded,Failed,Accepted,Running)
+ *  * PercentCompleted (optional) the percent completed
+ *  * Message (optional) any messages the service may wish to share
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param statusInfo the map containing the statusInfo definition
+ * @param req the WPS requests (GetResult, GetStatus or Dismiss)
+ */
+void printStatusInfo(maps* conf,map* statusInfo,char* req){
+  rewind(stdout);
+  xmlNodePtr n,n1;
+  xmlDocPtr doc;
+  xmlNsPtr ns;
+  xmlChar *xmlbuff;
+  int buffersize;
+  char *encoding=getEncoding(conf);
+  map *tmp;
+  int pid=0;
+  printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
+
+  map* version=getMapFromMaps(conf,"main","rversion");
+  int vid=getVersionId(version->value);
+
+  doc = xmlNewDoc(BAD_CAST "1.0");
+  n1=printWPSHeader(doc,conf,req,"StatusInfo",version->value,1);
+
+  map* val=getMap(statusInfo,"JobID");
+  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
+  ns=usedNs[wpsId];
+  n = xmlNewNode(ns, BAD_CAST "JobID");
+  xmlAddChild(n,xmlNewText(BAD_CAST val->value));
+
+  xmlAddChild(n1,n);
+
+  val=getMap(statusInfo,"Status");
+  n = xmlNewNode(ns, BAD_CAST "Status");
+  xmlAddChild(n,xmlNewText(BAD_CAST val->value));
+
+  xmlAddChild(n1,n);
+
+  if(strncasecmp(val->value,"Failed",6)!=0 &&
+     strncasecmp(val->value,"Succeeded",9)!=0){
+    val=getMap(statusInfo,"PercentCompleted");
+    if(val!=NULL){
+      n = xmlNewNode(ns, BAD_CAST "PercentCompleted");
+      xmlAddChild(n,xmlNewText(BAD_CAST val->value));
+      xmlAddChild(n1,n);
+    }
+
+    val=getMap(statusInfo,"Message");
+    if(val!=NULL){    
+      xmlAddChild(n1,xmlNewComment(BAD_CAST val->value));
+    }
+  }
+  xmlDocSetRootElement(doc, n1);
+
+  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
+  printf("%s",xmlbuff);
+
+  xmlFree(xmlbuff);
+  xmlFreeDoc(doc);
+  xmlCleanupParser();
+  zooXmlCleanupNs();
+  
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/response_print.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/response_print.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/response_print.h	(revision 942)
@@ -0,0 +1,237 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2013 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_RESPONSE_PRINT_H
+#define ZOO_RESPONSE_PRINT_H 1
+
+#pragma once 
+
+/**
+ * The default service url (overriden by serverAddress)
+ */
+#define DEFAULT_SERVICE_URL "http://www.zoo-project.org/"
+/**
+ * The time size
+ */
+#define TIME_SIZE 40
+
+#include <libintl.h>
+#include <locale.h>
+
+/**
+ * ZOO-Kernel internal messages translation function
+ */
+#define _(String) dgettext ("zoo-kernel",String)
+/**
+ * ZOO-Services messages translation function
+ */
+#define _ss(String) dgettext ("zoo-services",String)
+
+/**
+ * ZOO-Kernel was unable to create a lock
+ */
+#define ZOO_LOCK_CREATE_FAILED -4
+/**
+ * ZOO-Kernel was unable to acquire a lock
+ */
+#define ZOO_LOCK_ACQUIRE_FAILED -5
+/**
+ * ZOO-Kernel was unable to release a lock
+ */
+#define ZOO_LOCK_RELEASE_FAILED -6
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#else
+#include <direct.h>
+#endif
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#ifdef WIN32
+#ifndef USE_RUBY
+#include <unistd.h>
+#endif
+#endif
+#ifndef WIN32
+//#include <locale.h>
+#include <locale.h> // knut: this appears to be a non-standard header file that has been removed in newer versions of glibc; it may be sufficient to include <locale.h> (see above) 
+#endif
+
+#include "service.h"
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include "cgic.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  /**
+   * Maximum number of XML namespaces
+   */
+#define ZOO_NS_MAX 10
+  /**
+   * Maximum number of XML docs
+   */
+#define ZOO_DOC_MAX 20
+
+  /**
+   * Global char* to store the serverAddress value of the [main] section
+   */
+  static char* SERVICE_URL;
+
+  /**
+   * Array of xmlNsPtr storing all used XML namespace
+   */
+  static xmlNsPtr usedNs[ZOO_NS_MAX];
+  /**
+   * Array storing names of the used XML namespace
+   */
+  static char* nsName[ZOO_NS_MAX];
+  /**
+   * Number of XML namespaces
+   */
+  static int nbNs=0;
+  /**
+   * Array of xmlDocPtr storing XML docs
+   */
+  static xmlDocPtr iDocs[ZOO_DOC_MAX];
+  /**
+   * Number of XML docs
+   */
+  static int nbDocs=0;
+
+  /**
+   * Definitions of acceptable final status
+   */
+  static char wpsStatus[3][11]={
+    "Succeeded",
+    "Failed",
+    "Running"
+  };
+  /**
+   * Definitions of schemas depending on the WPS version
+   */
+  static const char* schemas[2][8]={
+    {"1.0.0","http://www.opengis.net/ows/1.1","http://www.opengis.net/wps/1.0.0","http://schemas.opengis.net/wps/1.0.0","%s %s/wps%s_response.xsd","http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd","1.1.0"},
+    {"2.0.0","http://www.opengis.net/ows/2.0","http://www.opengis.net/wps/2.0","http://schemas.opengis.net/wps/2.0","http://www.opengis.net/wps/2.0 http://schemas.opengis.net/wps/2.0/wps.xsd","http://schemas.opengis.net/ows/2.0/owsExceptionReport.xsd","2.0.2","http://www.opengis.net/spec/wps/2.0/def/process-profile/"},
+  };
+  /**
+   * Definitions of support requests (depending on the WPS version)
+   */
+  static int nbSupportedRequests=7;
+  /**
+   * Definitions of requests depending on the WPS version
+   */
+  static const char* requests[2][7]={
+    {"GetCapabilities","DescribeProcess","Execute",NULL},
+    {"GetCapabilities","DescribeProcess","Execute","GetStatus","GetResult","Dismiss",NULL},
+  };
+  /**
+   * Definitions requests requiring identifier (depending on the WPS version)
+   */
+  static int nbReqIdentifier=2;
+  /**
+   * Definitions requests requiring jobid (only for WPS version 2.0.0)
+   */
+  static int nbReqJob=3;
+  /**
+   * Definitions of root node for response depending on the request and the WPS version
+   */
+  static const char* root_nodes[2][4]={
+    {"ProcessOfferings","ProcessDescriptions","ExecuteResponse",NULL},
+    {"Contents","ProcessOfferings","Result",NULL}
+  };
+
+  /**
+   * Name and corresponding attributes depending on the WPS version
+   */
+  static const char* capabilities[2][7]={
+    {
+      "Process",
+      "processVersion","1",
+      "storeSupported","true",
+      "statusSupported","true"
+    },
+    {
+      "ProcessSummary",
+      "processVersion","1.0.0",
+      "jobControlOptions","sync-execute async-execute dismiss",
+      "outputTransmission","value reference"
+    }
+  };
+
+  void addLangAttr(xmlNodePtr,maps*);
+
+  void printHeaders(maps*);
+
+  int zooXmlSearchForNs(const char*);
+  int zooXmlAddNs(xmlNodePtr,const char*,const char*);
+  void zooXmlCleanupNs();
+
+  int zooXmlAddDoc(xmlNodePtr,const char*,const char*);
+  void zooXmlCleanupDocs();
+  
+  void printExceptionReportResponse(maps*,map*);
+  xmlNodePtr createExceptionReportNode(maps*,map*,int);
+  void printProcessResponse(maps*,map*,int,service*,const char*,int,maps*,maps*);
+  xmlNodePtr printWPSHeader(xmlDocPtr,maps*,const char*,const char*,const char*,int);
+  xmlNodePtr printGetCapabilitiesHeader(xmlDocPtr,maps*,const char*);
+  void printGetCapabilitiesForProcess(registry*,maps*,xmlDocPtr,xmlNodePtr,service*);
+  void printDescribeProcessForProcess(registry*,maps*,xmlDocPtr,xmlNodePtr,service*);
+  void printFullDescription(xmlDocPtr,int,elements*,const char*,xmlNsPtr,xmlNsPtr,xmlNodePtr,int,int,const map*);
+  void printDocument(maps*,xmlDocPtr,int);
+  void printDescription(xmlNodePtr,xmlNsPtr,const char*,map*,int);
+  void printIOType(xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,xmlNsPtr,elements*,maps*,const char*,int);
+  map* parseBoundingBox(const char*);
+  void printBoundingBox(xmlNsPtr,xmlNodePtr,map*);
+  void printBoundingBoxDocument(maps*,maps*,FILE*);
+  void printOutputDefinitions(xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,elements*,maps*,const char*);
+  void printStatusInfo(maps*,map*,char*);
+  void addAdditionalParameters(map*,xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,int);
+  void addMetadata(map*,xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,int);
+
+  void outputResponse(service*,maps*,maps*,map*,int,maps*,int);
+
+  int errorException(maps *, const char *, const char *, const char*);
+
+  xmlNodePtr soapEnvelope(maps*,xmlNodePtr);
+  int checkForSoapEnvelope(xmlDocPtr);
+  
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/server_internal.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/server_internal.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/server_internal.c	(revision 942)
@@ -0,0 +1,1338 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "server_internal.h"
+#include "service_internal.h"
+#include "response_print.h"
+//#include "service_callback.h"
+#include "mimetypes.h"
+#ifndef WIN32
+#include <dlfcn.h>
+#include <uuid/uuid.h>
+#else
+#include <rpc.h>
+#define ERROR_MSG_MAX_LENGTH 1024
+#endif
+#include <signal.h>
+
+// #include <stdlib.h>
+/*
+ * Compare two file path strings to see if they refer to the same file.
+ *
+ * @param path1 the first file path
+ * @param path2 the second file path
+ * 
+ * @return 0 if the files are identical
+ */
+#define PATHBUFSIZE 4096
+int zoo_path_compare(char* path1, char* path2) {
+
+  if (path1 == NULL || path2 == NULL) {
+    return -1;
+  }
+
+  char realpath1[PATHBUFSIZE];
+  char realpath2[PATHBUFSIZE];
+
+#ifdef WIN32 
+  int res1 = GetFullPathName(path1, PATHBUFSIZE, realpath1, NULL);
+  int res2 = GetFullPathName(path2, PATHBUFSIZE, realpath2, NULL);
+
+  if (res1 == 0 || res2 == 0) {
+    return -1;
+  }
+  else {
+    return strncasecmp(realpath1, realpath2, PATHBUFSIZE);
+  }
+#else
+  char* ptr1 = realpath(path1, realpath1);
+  char* ptr2 = realpath(path2, realpath2);
+
+  if (ptr1 == NULL || ptr2 == NULL) {
+    return -1;
+  }
+  else {
+    return strncmp(realpath1, realpath2, PATHBUFSIZE);
+  }
+#endif
+}
+
+/**
+ * Detect WPS version used (1.0.0 or 2.0.0).
+ *
+ * @param version number as char* (1.0.0 or 2.0.0)
+ * @return 0 in case of version 1.0.0, 1 for 2.0.0, -1 in other case
+ */
+int getVersionId(const char* version){
+  int schemaId=0;
+  for(;schemaId<2;schemaId++){
+    if(strncasecmp(version,schemas[schemaId][0],5)==0)
+      return schemaId;
+  }
+  return -1;
+}
+
+/**
+ * Generate a UUID.
+ * ref: https://www.ietf.org/rfc/rfc4122.txt / 4.2 
+ *
+ * @return a new char* containing the UUID, make sure to free the returned 
+ *  resource once used.
+ */
+char *get_uuid(){
+  char *res=(char*)malloc(37*sizeof(char));
+#ifdef WIN32
+  UUID uuid;
+  UuidCreate(&uuid);
+  RPC_CSTR rest = NULL;
+  UuidToString(&uuid,&rest);
+#else
+  uuid_t uuid;
+  uuid_generate_time(uuid);
+  char rest[128];
+  uuid_unparse(uuid,rest);
+#endif
+  sprintf(res,"%s",rest);
+#ifdef WIN32
+  RpcStringFree(&rest);
+#endif
+  return res;
+}
+
+/**
+ * Extract the service identifier from the full service identifier
+ * ie: 
+ *  - Full service name: OTB.BandMath
+ *  - Service name: BandMath
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param conf_dir the full path to the ZOO-Kernel directory
+ * @param identifier the full service name (potentialy including a prefix, ie:
+ *  Prefix.MyService)
+ * @param buffer the resulting service identifier (without any prefix)
+ */
+void parseIdentifier(maps* conf,char* conf_dir,char *identifier,char* buffer){
+  setMapInMaps(conf,"lenv","oIdentifier",identifier);
+  char *lid=zStrdup(identifier);
+  char *saveptr1;
+  char *tmps1=strtok_r(lid,".",&saveptr1);
+  int level=0;
+  char key[25];
+  char levels[18];
+  while(tmps1!=NULL){
+    char *test=zStrdup(tmps1);
+    char* tmps2=(char*)malloc((strlen(test)+2)*sizeof(char));
+    sprintf(key,"sprefix_%d",level);
+    sprintf(tmps2,"%s.",test);
+    sprintf(levels,"%d",level);
+    setMapInMaps(conf,"lenv","level",levels);
+    setMapInMaps(conf,"lenv",key,tmps2);
+    free(tmps2);
+    free(test);
+    level++;
+    tmps1=strtok_r(NULL,".",&saveptr1);
+  }
+  int i=0;
+  sprintf(buffer,"%s",conf_dir);
+  for(i=0;i<level;i++){
+    char *tmp0=zStrdup(buffer);
+    sprintf(key,"sprefix_%d",i);
+    map* tmp00=getMapFromMaps(conf,"lenv",key);
+    if(tmp00!=NULL)
+      sprintf(buffer,"%s/%s",tmp0,tmp00->value);
+    free(tmp0);
+    buffer[strlen(buffer)-1]=0;
+    if(i+1<level){ 
+      #ifdef IGNORE_METAPATH
+        map* tmpMap = createMap("metapath", "");
+      #else  
+        map* tmpMap=getMapFromMaps(conf,"lenv","metapath");
+      #endif	  
+      if(tmpMap==NULL || strlen(tmpMap->value)==0){
+	char *tmp01=zStrdup(tmp00->value);
+	tmp01[strlen(tmp01)-1]=0;
+	setMapInMaps(conf,"lenv","metapath",tmp01);
+	free(tmp01);
+	tmp01=NULL;
+      }
+      else{
+	if(tmp00!=NULL && tmpMap!=NULL){
+	  char *tmp00s=zStrdup(tmp00->value);
+	  tmp00s[strlen(tmp00s)-1]=0;
+	  char *value=(char*)malloc((strlen(tmp00s)+strlen(tmpMap->value)+2)*sizeof(char));
+	  sprintf(value,"%s/%s",tmpMap->value,tmp00s);
+	  setMapInMaps(conf,"lenv","metapath",value);
+	  free(value);
+	  free(tmp00s);
+	  value=NULL;
+	}
+      }
+    }else{
+      char *tmp01=zStrdup(tmp00->value);
+      tmp01[strlen(tmp01)-1]=0;
+      setMapInMaps(conf,"lenv","Identifier",tmp01);
+      free(tmp01);
+    }
+  }
+  char *tmp0=zStrdup(buffer);
+  sprintf(buffer,"%s.zcfg",tmp0);
+  free(tmp0);
+  free(lid);
+}
+
+/**
+ * Converts a hex character to its integer value 
+ *
+ * @param ch the char to convert
+ * @return the converted char 
+ */
+char from_hex(char ch) {
+  return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+/**
+ * Converts an integer value to its hec character 
+ *
+ * @param code the char to convert
+ * @return the converted char 
+ */
+char to_hex(char code) {
+  static char hex[] = "0123456789abcdef";
+  return hex[code & 15];
+}
+
+/**
+ * URLEncode an url
+ *
+ * @param str the url to encode
+ * @return a url-encoded version of str
+ * @warning be sure to free() the returned string after use
+ */
+char *url_encode(char *str) {
+  char *pstr = str, *buf = (char*) malloc(strlen(str) * 3 + 1), *pbuf = buf;
+  while (*pstr) {
+    if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') 
+      *pbuf++ = *pstr;
+    else if (*pstr == ' ') 
+      *pbuf++ = '+';
+    else 
+      *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
+    pstr++;
+  }
+  *pbuf = '\0';
+  return buf;
+}
+
+/**
+ * Decode an URLEncoded url
+ *
+ * @param str the URLEncoded url to decode
+ * @return a url-decoded version of str
+ * @warning be sure to free() the returned string after use
+ */
+char *url_decode(char *str) {
+  char *pstr = str, *buf = (char*) malloc(strlen(str) + 1), *pbuf = buf;
+  while (*pstr) {
+    if (*pstr == '%') {
+      if (pstr[1] && pstr[2]) {
+        *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
+        pstr += 2;
+      }
+    } else if (*pstr == '+') { 
+      *pbuf++ = ' ';
+    } else {
+      *pbuf++ = *pstr;
+    }
+    pstr++;
+  }
+  *pbuf = '\0';
+  return buf;
+}
+
+/**
+ * Verify if a given language is listed in the lang list defined in the [main] 
+ * section of the main.cfg file.
+ * 
+ * @param conf the map containing the settings from the main.cfg file
+ * @param str the specific language
+ * @return 1 if the specific language is listed, -1 in other case.
+ */
+int isValidLang(maps* conf,const char *str){
+  map *tmpMap=getMapFromMaps(conf,"main","language");
+  char *tmp0=NULL,*tmp=NULL,*tmp1=NULL;
+  if(tmpMap!=NULL)
+    tmp0=zStrdup(tmpMap->value);
+  tmpMap=getMapFromMaps(conf,"main","lang");
+  if(tmpMap!=NULL)
+    tmp=zStrdup(tmpMap->value);
+  if(tmp0!=NULL && tmp!=NULL){
+    tmp1=(char*)malloc((strlen(tmp0)+strlen(tmp)+2)*sizeof(char));
+    sprintf(tmp1,"%s,%s",tmp0,tmp);
+    free(tmp0);
+    free(tmp);
+  }else{
+    if(tmp!=NULL){
+      tmp1=zStrdup(tmp);
+      free(tmp);
+    }else{
+      if(tmp0!=NULL){
+	tmp1=zStrdup(tmp0);
+	free(tmp0);
+      }
+    }
+  }
+  char *pToken,*saveptr;
+  pToken=strtok_r(tmp1,",",&saveptr);
+  int res=-1;
+  while(pToken!=NULL){
+    if(strcasecmp(str,pToken)==0){
+      res=1;
+      break;
+    }
+    pToken=strtok_r(NULL,",",&saveptr);
+  }
+  if(tmp1!=NULL)
+    free(tmp1);
+  return res;
+}
+
+
+/**
+ * Access the value of the encoding key in a maps
+ *
+ * @param m the maps to search for the encoding key
+ * @return the value of the encoding key in a maps if encoding key exists,
+ *  "UTF-8" in other case.
+ */
+char* getEncoding(maps* m){
+  if(m!=NULL){
+    map* tmp=getMap(m->content,"encoding");
+    if(tmp!=NULL){
+      return tmp->value;
+    }
+    else
+      return (char*)"UTF-8";
+  }
+  else
+    return (char*)"UTF-8";  
+}
+
+/**
+ * Access the value of the version key in a maps
+ *
+ * @param m the maps to search for the version key
+ * @return the value of the version key in a maps if encoding key exists,
+ *  "1.0.0" in other case.
+ */
+char* getVersion(maps* m){
+  if(m!=NULL){
+    map* tmp=getMap(m->content,"version");
+    if(tmp!=NULL){
+      return tmp->value;
+    }
+    else
+      return (char*)"1.0.0";
+  }
+  else
+    return (char*)"1.0.0";
+}
+
+/**
+ * Read a file generated by a service.
+ * 
+ * @param m the conf maps
+ * @param content the output item
+ * @param filename the file to read
+ */
+void readGeneratedFile(maps* m,map* content,char* filename){
+  char rsize[1024];
+  FILE * file=fopen(filename,"rb");
+  if(file==NULL){
+    setMapInMaps(m,"lenv","message","Unable to read produced file. Please try again later");
+    return ;
+  }
+  fseek(file, 0, SEEK_END);
+  zStatStruct f_status;
+  int s=zStat(filename, &f_status);
+  sprintf(rsize,"%lld",f_status.st_size);
+  rewind(file);
+  if(getMap(content,"storage")==NULL){
+    map* memUse=getMapFromMaps(m,"main","memory");
+    if(memUse==NULL || strncmp(memUse->value,"load",4)==0){
+      map* tmpMap1=getMap(content,"value");
+      if(tmpMap1==NULL){
+	addToMap(content,"value","");
+	tmpMap1=getMap(content,"value");
+      }
+      free(tmpMap1->value);
+      tmpMap1->value=(char*) malloc((f_status.st_size+1)*sizeof(char));
+      if(tmpMap1->value==NULL){
+	setMapInMaps(m,"lenv","message","Unable to allocate the memory required to read the produced file.");
+      }
+      fread(&tmpMap1->value,1,f_status.st_size,file);
+      tmpMap1->value[f_status.st_size]=0;
+    }
+  }
+  fclose(file);  
+  addToMap(content,"size",rsize);
+}
+
+
+/**
+ * Write a file from value and length
+ *
+ * @param fname the file name
+ * @param val the value
+ * @param length the value length
+ */
+int writeFile(char* fname,char* val,int length){
+  FILE* of=fopen(fname,"wb");
+  if(of==NULL){
+    return -1;
+  }
+  size_t ret=fwrite(val,sizeof(char),length,of);
+  if(ret<length){
+    fprintf(stderr,"Write error occurred!\n");
+    fclose(of);
+    return -1;
+  }
+  fclose(of);
+  return 1;
+}
+
+/**
+ * Dump all values in a maps as files
+ *
+ * @param main_conf the maps containing the settings of the main.cfg file
+ * @param in the maps containing values to dump as files
+ */
+void dumpMapsValuesToFiles(maps** main_conf,maps** in){
+  map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+  map* tmpUrl=getMapFromMaps(*main_conf,"main","tmpUrl");
+  map* tmpSid=getMapFromMaps(*main_conf,"lenv","usid");
+  maps* inputs=*in;
+  int length=0;
+  while(inputs!=NULL){
+    if(getMap(inputs->content,"mimeType")!=NULL &&
+       getMap(inputs->content,"cache_file")==NULL){
+      map* cMap=inputs->content;
+      if(getMap(cMap,"length")!=NULL){
+	map* tmpLength=getMap(cMap,"length");
+	int len=atoi(tmpLength->value);
+	int k=0;
+	for(k=0;k<len;k++){
+	  map* cMimeType=getMapArray(cMap,"mimeType",k);
+	  map* cValue=getMapArray(cMap,"value",k);
+	  map* cSize=getMapArray(cMap,"size",k);
+	  char file_ext[32];
+	  getFileExtension(cMimeType != NULL ? cMimeType->value : NULL, file_ext, 32);
+	  char* val=(char*)malloc((strlen(tmpPath->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	  sprintf(val,"%s/Input_%s_%s_%d.%s",tmpPath->value,inputs->name,tmpSid->value,k,file_ext);
+	  length=0;
+	  if(cSize!=NULL){
+	    length=atoi(cSize->value);
+	  }else
+	    length=strlen(cValue->value);
+	  writeFile(val,cValue->value,length);
+	  setMapArray(cMap,"cache_file",k,val);
+	  free(val);
+	  val=(char*)malloc((strlen(tmpUrl->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	  sprintf(val,"%s/Input_%s_%s_%d.%s",tmpUrl->value,inputs->name,tmpSid->value,k,file_ext);
+	  setMapArray(cMap,"cache_url",k,val);
+	  setMapArray(cMap,"byValue",k,"true");
+	  free(val);
+	}
+      }else{
+	int length=0;
+	map* cMimeType=getMap(cMap,"mimeType");
+	map* cValue=getMap(cMap,"value");
+	map* cSize=getMap(cMap,"size");
+	char file_ext[32];
+	getFileExtension(cMimeType != NULL ? cMimeType->value : NULL, file_ext, 32);
+	char *val=(char*)malloc((strlen(tmpPath->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	sprintf(val,"%s/Input_%s_%s_%d.%s",tmpPath->value,inputs->name,tmpSid->value,0,file_ext);
+	if(cSize!=NULL){
+	  length=atoi(cSize->value);
+	}else
+	  length=strlen(cValue->value);
+	writeFile(val,cValue->value,length);
+	addToMap(cMap,"cache_file",val);
+	free(val);
+	val=(char*)malloc((strlen(tmpUrl->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	sprintf(val,"%s/Input_%s_%s_%d.%s",tmpUrl->value,inputs->name,tmpSid->value,0,file_ext);
+	addToMap(cMap,"cache_url",val);
+	addToMap(cMap,"byValue",val);
+	free(val);
+      }
+    }
+    inputs=inputs->next;
+  }
+}
+
+
+/**
+ * Base64 encoding of a char*
+ *
+ * @param input the value to encode
+ * @param length the value length
+ * @return the buffer containing the base64 value
+ * @warning make sure to free the returned value
+ */
+char *base64(const char *input, int length)
+{
+  BIO *bmem, *b64;
+  BUF_MEM *bptr;
+
+  b64 = BIO_new(BIO_f_base64());
+  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+  bmem = BIO_new(BIO_s_mem());
+  b64 = BIO_push(b64, bmem);
+  BIO_write(b64, input, length);
+  BIO_flush(b64);
+  BIO_get_mem_ptr(b64, &bptr);
+
+  char *buff = (char *)malloc((bptr->length+1)*sizeof(char));
+  memcpy(buff, bptr->data, bptr->length);
+  buff[bptr->length] = 0;
+
+  BIO_free_all(b64);
+
+  return buff;
+}
+
+/**
+ * Base64 decoding of a char*
+ *
+ * @param input the value to decode
+ * @param length the value length
+ * @param red the value length
+ * @return the buffer containing the base64 value 
+ * @warning make sure to free the returned value
+ */
+char *base64d(const char *input, int length,int* red)
+{
+  BIO *b64, *bmem;
+
+  char *buffer = (char *)malloc(length);
+  if(buffer){
+    memset(buffer, 0, length);
+    b64 = BIO_new(BIO_f_base64());
+    if(b64){
+      bmem = BIO_new_mem_buf((unsigned char*)input,length);
+      bmem = BIO_push(b64, bmem);
+      *red=BIO_read(bmem, buffer, length);
+      buffer[length-1]=0;
+      BIO_free_all(bmem);
+    }
+  }
+  return buffer;
+}
+
+/**
+ * Read Base64 value and split it value by lines of 64 char.
+ *
+ * @param in the map containing the value to split
+ */
+void readBase64(map **in){
+  char *res = NULL;
+  char *curs = (*in)->value;
+  int i = 0;
+  for (i = 0; i <= strlen ((*in)->value) / 64;
+       i++)
+    {
+      if (res == NULL)
+	res =
+	  (char *) malloc (65 * sizeof (char));
+      else
+	res =
+	  (char *) realloc (res,
+			    (((i + 1) * 65) +
+			     i) * sizeof (char));
+      int csize = i * 65;
+      strncpy (res + csize, curs, 64);
+      if (i == strlen ((*in)->value) / 64)
+	strcat (res, "\n\0");
+      else
+	{
+	  strncpy (res + (((i + 1) * 64) + i),
+		   "\n\0", 2);
+	  curs += 64;
+	}
+    }
+  free ((*in)->value);
+  (*in)->value = zStrdup (res);
+  free (res);
+}
+
+
+/**
+ * Add the default values defined in the zcfg to a maps.
+ *
+ * @param out the maps containing the inputs or outputs given in the initial
+ *  HTTP request
+ * @param in the description of all inputs or outputs available for a service
+ * @param m the maps containing the settings of the main.cfg file
+ * @param type 0 for inputs and 1 for outputs
+ * @param err the map to store potential missing mandatory input parameters or
+ *  wrong output names depending on the type.
+ * @return "" if no error was detected, the name of last input or output causing
+ *  an error.
+ */
+char* addDefaultValues(maps** out,elements* in,maps* m,int type,map** err){
+  map *res=*err;
+  elements* tmpInputs=in;
+  elements* tmpInputss=NULL;
+  maps* out1=*out;
+  maps* out1s=NULL;
+  char *result=NULL;
+  int nb=0;
+  int inb=0;
+ loopOnInputs:
+  if(type==1){
+    while(out1!=NULL){
+      if(getElements(in,out1->name)==NULL){
+	if(res==NULL){
+	  res=createMap("value",out1->name);
+	}else{
+	  setMapArray(res,"value",nb,out1->name);
+	}
+	nb++;
+	result=out1->name;
+      }
+      inb++;
+      out1=out1->next;
+    }
+    if(res!=NULL){
+      fflush(stderr);
+      *err=res;
+      return result;
+    }
+    if(out1==NULL && inb>=1)
+      out1=*out;
+  }
+  while(tmpInputs!=NULL){
+    maps *tmpMaps=getMaps(out1,tmpInputs->name);
+    if(tmpMaps==NULL){
+      maps* tmpMaps2=createMaps(tmpInputs->name);
+      if(type==0){
+	map* tmpMapMinO=getMap(tmpInputs->content,"minOccurs");
+	if(tmpMapMinO!=NULL){
+	  if(atoi(tmpMapMinO->value)>=1){
+	    freeMaps(&tmpMaps2);
+	    free(tmpMaps2);
+	    if(res==NULL){
+	      res=createMap("value",tmpInputs->name);
+	    }else{
+	      setMapArray(res,"value",nb,tmpInputs->name);
+	    }
+	    nb++;
+	    result=tmpInputs->name;
+	  }
+	  else{
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("minOccurs",tmpMapMinO->value);
+	    else
+	      addToMap(tmpMaps2->content,"minOccurs",tmpMapMinO->value);
+	  }
+	}
+	if(res==NULL){
+	  map* tmpMaxO0=getMap(tmpInputs->content,"useMapserver");
+	  if(tmpMaxO0!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("useMapserver",tmpMaxO0->value);
+	    else
+	      addToMap(tmpMaps2->content,"useMapserver",tmpMaxO0->value);
+	  }
+	  map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
+	  if(tmpMaxO!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("maxOccurs",tmpMaxO->value);
+	    else
+	      addToMap(tmpMaps2->content,"maxOccurs",tmpMaxO->value);
+	  }
+	  map* tmpMaxMB=getMap(tmpInputs->content,"maximumMegabytes");
+	  if(tmpMaxMB!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("maximumMegabytes",tmpMaxMB->value);
+	    else
+	      addToMap(tmpMaps2->content,"maximumMegabytes",tmpMaxMB->value);
+	  }
+	}
+      }
+      
+      if(res==NULL){
+	iotype* tmpIoType=tmpInputs->defaults;
+	if(tmpIoType!=NULL){
+	  map* tmpm=tmpIoType->content;
+	  while(tmpm!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap(tmpm->name,tmpm->value);
+	    else{
+	      addToMap(tmpMaps2->content,tmpm->name,tmpm->value);
+	    }
+	    tmpm=tmpm->next;
+	  }
+	}
+	if(tmpMaps2->content==NULL){
+	  tmpMaps2->content=createMap("inRequest","false");
+	  dumpMaps(tmpMaps2);
+	}
+	else
+	  addToMap(tmpMaps2->content,"inRequest","false");
+	if(type==0){
+	  map *tmpMap=getMap(tmpMaps2->content,"value");
+	  if(tmpMap==NULL)
+	    addToMap(tmpMaps2->content,"value","NULL");
+	}
+	elements* tmpElements=getElements(in,tmpMaps2->name);
+	if(tmpElements!=NULL && tmpElements->child!=NULL){
+	  char *res=addDefaultValues(&tmpMaps2->child,tmpElements->child,m,type,err);
+	  if(strlen(res)>0){
+	    return res;
+	  }
+	}
+
+	if(out1==NULL){
+	  *out=dupMaps(&tmpMaps2);
+	  out1=*out;
+	}
+	else
+	  addMapsToMaps(&out1,tmpMaps2);
+	freeMap(&tmpMaps2->content);
+	free(tmpMaps2->content);
+	tmpMaps2->content=NULL;
+	freeMaps(&tmpMaps2);
+	free(tmpMaps2);
+	tmpMaps2=NULL;
+      }
+    }
+    else /*toto*/{ 
+      iotype* tmpIoType=NULL;
+      if(tmpMaps->content!=NULL){
+	tmpIoType=getIoTypeFromElement(tmpInputs,tmpInputs->name,
+				       tmpMaps->content);
+	if(type==0) {
+	  /**
+	   * In case of an Input maps, then add the minOccurs and maxOccurs to the
+	   * content map.
+	   */
+	  const char* keys[4]={
+	    "minOccurs",
+	    "maxOccurs",
+	    "maximumMegabytes",
+	    "useMapserver"
+	  };
+	  int i=0;
+	  for(i=0;i<4;i++){
+	    map* tmpMap1=getMap(tmpInputs->content,keys[i]);
+	    if(tmpMap1!=NULL){
+	      addToMap(tmpMaps->content,keys[i],tmpMap1->value);
+	    }
+	  }
+	  /**
+	   * Parsing BoundingBoxData, fill the following map and then add it to
+	   * the content map of the Input maps: 
+	   * lowerCorner, upperCorner, srs and dimensions
+	   * cf. parseBoundingBox
+	   */
+	  if(tmpInputs->format!=NULL && strcasecmp(tmpInputs->format,"BoundingBoxData")==0){
+	    maps* tmpI=getMaps(*out,tmpInputs->name);
+	    if(tmpI!=NULL){
+	      map* tmpV=getMap(tmpI->content,"value");
+	      if(tmpV!=NULL){
+		char *tmpVS=zStrdup(tmpV->value);
+		map* tmp=parseBoundingBox(tmpVS);
+		free(tmpVS);
+		map* tmpC=tmp;
+		while(tmpC!=NULL){
+		  addToMap(tmpMaps->content,tmpC->name,tmpC->value);
+		  tmpC=tmpC->next;
+		}
+		freeMap(&tmp);
+		free(tmp);
+	      }
+	    }
+	  }
+	}
+      }else{
+	if(tmpInputs!=NULL){
+	  tmpIoType=tmpInputs->defaults;
+	}
+      }
+
+      if(tmpIoType!=NULL){
+	map* tmpContent=tmpIoType->content;
+	map* cval=NULL;
+	int hasPassed=-1;
+	while(tmpContent!=NULL){
+	  if((cval=getMap(tmpMaps->content,tmpContent->name))==NULL){
+#ifdef DEBUG
+	    fprintf(stderr,"addDefaultValues %s => %s\n",tmpContent->name,tmpContent->value);
+#endif
+	    if(tmpMaps->content==NULL)
+	      tmpMaps->content=createMap(tmpContent->name,tmpContent->value);
+	    else
+	      addToMap(tmpMaps->content,tmpContent->name,tmpContent->value);
+	    
+	    if(hasPassed<0 && type==0 && getMap(tmpMaps->content,"isArray")!=NULL){
+	      map* length=getMap(tmpMaps->content,"length");
+	      int i;
+	      char *tcn=zStrdup(tmpContent->name);
+	      for(i=1;i<atoi(length->value);i++){
+#ifdef DEBUG
+		dumpMap(tmpMaps->content);
+		fprintf(stderr,"addDefaultValues %s_%d => %s\n",tcn,i,tmpContent->value);
+#endif
+		int len=strlen((char*) tcn);
+		char *tmp1=(char *)malloc((len+10)*sizeof(char));
+		sprintf(tmp1,"%s_%d",tcn,i);
+#ifdef DEBUG
+		fprintf(stderr,"addDefaultValues %s => %s\n",tmp1,tmpContent->value);
+#endif
+		addToMap(tmpMaps->content,tmp1,tmpContent->value);
+		free(tmp1);
+		hasPassed=1;
+	      }
+	      free(tcn);
+	    }
+	  }
+	  tmpContent=tmpContent->next;
+	}
+#ifdef USE_MS
+	/**
+	 * check for useMapServer presence
+	 */
+	if(tmpIoType!=NULL){
+	  map* tmpCheck=getMap(tmpIoType->content,"useMapserver");
+	  if(tmpCheck!=NULL && strncasecmp(tmpCheck->value,"true",4)==0){
+	    // Get the default value
+	    addToMap(tmpMaps->content,"useMapserver","true");
+	    tmpIoType=getIoTypeFromElement(tmpInputs,tmpInputs->name,NULL);
+	    tmpCheck=getMap(tmpMaps->content,"mimeType");
+	    addToMap(tmpMaps->content,"requestedMimeType",tmpCheck->value);
+	    map* cursor=tmpIoType->content;
+	    while(cursor!=NULL){
+	      addToMap(tmpMaps->content,cursor->name,cursor->value);
+	      cursor=cursor->next;
+	    }
+	  
+	    cursor=tmpInputs->content;
+	    while(cursor!=NULL){
+	      if(strcasecmp(cursor->name,"Title")==0 ||
+		 strcasecmp(cursor->name,"Abstract")==0)
+		addToMap(tmpMaps->content,cursor->name,cursor->value);
+	      cursor=cursor->next;
+	    }
+	  }
+	}
+#endif
+      }
+      if(tmpMaps->content==NULL)
+	tmpMaps->content=createMap("inRequest","true");
+      else
+	addToMap(tmpMaps->content,"inRequest","true");
+      elements* tmpElements=getElements(in,tmpMaps->name);
+      if(/*tmpMaps->child!=NULL && */tmpElements!=NULL && tmpElements->child!=NULL){
+	char *res=addDefaultValues(&tmpMaps->child,tmpElements->child,m,type,err);
+	if(strlen(res)>0){
+	  return res;
+	}
+      }
+    }
+    if(tmpInputs->child!=NULL){
+      tmpInputss=tmpInputs->next;
+      tmpInputs=tmpInputs->child;
+      if(tmpMaps!=NULL){
+	out1=tmpMaps->child;
+	out1s=tmpMaps;
+      }
+    }
+    tmpInputs=tmpInputs->next;
+  }
+  if(tmpInputss!=NULL){
+    out1=out1s;
+    tmpInputs=tmpInputss;
+    tmpInputss=NULL;
+    out1s=NULL;
+    goto loopOnInputs;
+  }
+  if(res!=NULL){
+    *err=res;
+    return result;
+  }
+  return "";
+}
+
+/**
+ * Access the last error message returned by the OS when trying to dynamically
+ * load a shared library.
+ *
+ * @return the last error message
+ * @warning The character string returned from getLastErrorMessage resides
+ * in a static buffer. The application should not write to this
+ * buffer or attempt to free() it.
+ */ 
+char* getLastErrorMessage() {                                              
+#ifdef WIN32
+  LPVOID lpMsgBuf;
+  DWORD errCode = GetLastError();
+  static char msg[ERROR_MSG_MAX_LENGTH];
+  size_t i;
+  
+  DWORD length = FormatMessage(
+			       FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+			       FORMAT_MESSAGE_FROM_SYSTEM |
+			       FORMAT_MESSAGE_IGNORE_INSERTS,
+			       NULL,
+			       errCode,
+			       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+			       (LPTSTR) &lpMsgBuf,
+			       0, NULL );	
+  
+#ifdef UNICODE		
+  wcstombs_s( &i, msg, ERROR_MSG_MAX_LENGTH,
+	      (wchar_t*) lpMsgBuf, _TRUNCATE );
+#else
+  strcpy_s( msg, ERROR_MSG_MAX_LENGTH,
+	    (char *) lpMsgBuf );		
+#endif	
+  LocalFree(lpMsgBuf);
+
+  return msg;
+#else
+  return dlerror();
+#endif
+}
+
+#include <dirent.h>
+#ifndef RELY_ON_DB
+/**
+ * Read the Result file (.res).
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ */
+void readFinalRes(maps* conf,char* pid,map* statusInfo){
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  char* fbkpid =
+    (char *)
+    malloc ((strlen (r_inputs->value) + strlen (pid) + 7) * sizeof (char));
+  sprintf (fbkpid, "%s/%s.res", r_inputs->value, pid);
+  struct stat file_status;
+  int istat = stat (fbkpid, &file_status);
+  if (istat == 0 && file_status.st_size > 0)
+    {
+      maps *res = (maps *) malloc (MAPS_SIZE);
+      conf_read (fbkpid, res);
+      res->child=NULL;
+      map* status=getMapFromMaps(res,"status","status");
+      addToMap(statusInfo,"Status",status->value);
+      freeMaps(&res);
+      free(res);
+    }
+  else
+    addToMap(statusInfo,"Status","Failed");  
+  free(fbkpid);
+}
+
+/**
+ * Check if a service is running.
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the unique service identifier (usid from the lenv section)
+ * @return 1 in case the service is still running, 0 otherwise
+ */
+int isRunning(maps* conf,char* pid){
+  int res=0;
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  char* fbkpid =
+    (char *)
+    malloc ((strlen (r_inputs->value) + strlen (pid) + 7) * sizeof (char));
+  sprintf (fbkpid, "%s/%s.pid", r_inputs->value, pid);  
+  FILE* f0 = fopen (fbkpid, "r");
+  if(f0!=NULL){
+    fclose(f0);
+    res=1;
+  }
+  free(fbkpid);
+  return res;
+}
+#else
+#include "sqlapi.h"
+#endif
+
+/**
+ * Run GetStatus requests.
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ * @param req the request (GetStatus / GetResult)
+ */
+void runGetStatus(maps* conf,char* pid,char* req){
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  char *sid=getStatusId(conf,pid);
+  if(sid==NULL){
+    errorException (conf, _("The JobID from the request does not match any of the Jobs running on this server"),
+		    "NoSuchJob", pid);
+  }else{
+    map* statusInfo=createMap("JobID",pid);
+    if(isRunning(conf,pid)>0){		
+      if(strncasecmp(req,"GetResult",strlen(req))==0){
+	errorException (conf, _("The result for the requested JobID has not yet been generated. The service is currently running."),
+			"ResultNotReady", pid);
+	return;
+      }
+      else
+	if(strncasecmp(req,"GetStatus",strlen(req))==0){
+	  addToMap(statusInfo,"Status","Running");
+	  char* tmpStr=_getStatus(conf,pid);
+	  if(tmpStr!=NULL && strncmp(tmpStr,"-1",2)!=0){
+	    char *tmpStr1=zStrdup(tmpStr);
+	    char *tmpStr0=zStrdup(strstr(tmpStr,"|")+1);
+	    free(tmpStr);
+	    tmpStr1[strlen(tmpStr1)-strlen(tmpStr0)-1]='\0';
+	    addToMap(statusInfo,"PercentCompleted",tmpStr1);
+	    addToMap(statusInfo,"Message",tmpStr0);
+	    free(tmpStr0);
+	    free(tmpStr1);
+	  }
+	}
+    }
+    else{
+      if(strncasecmp(req,"GetResult",strlen(req))==0){
+	char* result=_getStatusFile(conf,pid);
+	if(result!=NULL){
+	  char *encoding=getEncoding(conf);
+	  printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
+	  printf("%s",result);
+	  fflush(stdout);
+	  free(sid);
+	  freeMap(&statusInfo);
+	  free(statusInfo);
+	  free(result);
+	  return;
+	}else{
+	  errorException (conf, _("The result for the requested JobID has not yet been generated. The service ends but it still needs to produce the outputs."),
+			  "ResultNotReady", pid);
+	  freeMap(&statusInfo);
+	  free(statusInfo);
+	  return;
+	}
+      }else
+	if(strncasecmp(req,"GetStatus",strlen(req))==0){
+	  readFinalRes(conf,pid,statusInfo);
+	  char* tmpStr=_getStatus(conf,pid);
+	  if(tmpStr!=NULL && strncmp(tmpStr,"-1",2)!=0){
+	    char *tmpStr1=zStrdup(tmpStr);
+	    char *tmpStr0=zStrdup(strstr(tmpStr,"|")+1);
+	    free(tmpStr);
+	    tmpStr1[strlen(tmpStr1)-strlen(tmpStr0)-1]='\0';
+	    addToMap(statusInfo,"PercentCompleted",tmpStr1);
+	    addToMap(statusInfo,"Message",tmpStr0);
+	    free(tmpStr0);
+	    free(tmpStr1);
+	  }
+	}
+    }
+    free(sid);
+    printStatusInfo(conf,statusInfo,req);
+    freeMap(&statusInfo);
+    free(statusInfo);
+  }
+  return;
+}
+
+/**
+ * Run Dismiss requests.
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ */
+void runDismiss(maps* conf,char* pid){
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  char *sid=getStatusId(conf,pid);
+  if(sid==NULL){
+    errorException (conf, _("The JobID from the request does not match any of the Jobs running on this server"),
+		    "NoSuchJob", pid);
+  }else{
+    // We should send the Dismiss request to the target host if it differs
+    char* fbkpid =
+      (char *)
+      malloc ((strlen (r_inputs->value) + strlen (pid) + 7) * sizeof (char));
+    sprintf (fbkpid, "%s/%s.pid", r_inputs->value, pid);
+    FILE* f0 = fopen (fbkpid, "r");
+    if(f0!=NULL){
+      long flen;
+      char *fcontent;
+      fseek (f0, 0, SEEK_END);
+      flen = ftell (f0);
+      fseek (f0, 0, SEEK_SET);
+      fcontent = (char *) malloc ((flen + 1) * sizeof (char));
+      fread(fcontent,flen,1,f0);
+      fcontent[flen]=0;
+      fclose(f0);
+#ifndef WIN32
+      kill(atoi(fcontent),SIGKILL);
+#else
+      HANDLE myZooProcess=OpenProcess(PROCESS_ALL_ACCESS,false,atoi(fcontent));
+      TerminateProcess(myZooProcess,1);
+      CloseHandle(myZooProcess);
+#endif
+      free(fcontent);
+    }
+    free(fbkpid);
+    struct dirent *dp;
+    DIR *dirp = opendir(r_inputs->value);
+    char fileName[1024];
+    int hasFile=-1;
+    if(dirp!=NULL){
+      while ((dp = readdir(dirp)) != NULL){
+#ifdef DEBUG
+	fprintf(stderr,"File : %s searched : %s\n",dp->d_name,tmp);
+#endif
+	if(strstr(dp->d_name,pid)!=0){
+	  sprintf(fileName,"%s/%s",r_inputs->value,dp->d_name);
+	  if(zUnlink(fileName)!=0){
+	    errorException (conf, 
+			    _("The job cannot be removed, a file cannot be removed"),
+			    "NoApplicableCode", NULL);
+	    return;
+	  }
+	}
+      }
+    }
+#ifdef RELY_ON_DB
+    removeService(conf,pid);
+#endif
+    /* No need to call 7_1 when an execution is dismissed.
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+      invokeCallback(conf,NULL,NULL,7,1);
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    */
+    map* statusInfo=createMap("JobID",pid);
+    addToMap(statusInfo,"Status","Dismissed");
+    printStatusInfo(conf,statusInfo,"Dismiss");
+    free(statusInfo);
+  }
+  return;
+}
+
+extern int getServiceFromFile (maps *, const char *, service **);
+
+/**
+ * Parse the service file using getServiceFromFile or use getServiceFromYAML
+ * if YAML support was activated.
+ *
+ * @param conf the conf maps containing the main.cfg settings
+ * @param file the file name to parse
+ * @param service the service to update witht the file content
+ * @param name the service name
+ * @return true if the file can be parsed or false
+ * @see getServiceFromFile, getServiceFromYAML
+ */
+int readServiceFile (maps * conf, char *file, service ** service, char *name){
+  int t = getServiceFromFile (conf, file, service);
+#ifdef YAML
+  if (t < 0){
+    t = getServiceFromYAML (conf, file, service, name);
+  }
+#endif
+  return t;
+}
+
+/**
+ * Create the profile registry.
+ *
+ * The profile registry is optional (created only if the registry key is
+ * available in the [main] section of the main.cfg file) and can be used to
+ * store the profiles hierarchy. The registry is a directory which should
+ * contain the following sub-directories: 
+ *  * concept: direcotry containing .html files describing concept
+ *  * generic: directory containing .zcfg files for wps:GenericProcess
+ *  * implementation: directory containing .zcfg files for wps:Process
+ *
+ * @param m the conf maps containing the main.cfg settings
+ * @param r the registry to update
+ * @param reg_dir the resgitry 
+ * @return 0 if the resgitry is null or was correctly updated, -1 on failure
+ */
+int createRegistry (maps* m,registry ** r, char *reg_dir)
+{
+  char registryKeys[3][15]={
+    "concept",
+    "generic",
+    "implementation"
+  };
+  int scount = 0,i=0;
+  if (reg_dir == NULL)
+    return 0;
+  for(i=0;i<3;i++){
+    char * tmpName =
+      (char *) malloc ((strlen (reg_dir) + strlen (registryKeys[i]) + 2) *
+		       sizeof (char));
+    sprintf (tmpName, "%s/%s", reg_dir, registryKeys[i]);
+    
+    DIR *dirp1 = opendir (tmpName);
+    if(dirp1==NULL){
+      setMapInMaps(m,"lenv","message",_("Unable to open the registry directory."));
+      setMapInMaps(m,"lenv","type","InternalError");
+      return -1;
+    }
+    struct dirent *dp1;
+    while ((dp1 = readdir (dirp1)) != NULL){
+      char* extn = strstr(dp1->d_name, ".zcfg");
+      if(dp1->d_name[0] != '.' && extn != NULL && strlen(extn) == 5)
+	{
+	  int t;
+	  char *tmps1=
+	    (char *) malloc ((strlen (tmpName) + strlen (dp1->d_name) + 2) *
+			     sizeof (char));
+	  sprintf (tmps1, "%s/%s", tmpName, dp1->d_name);
+	  char *tmpsn = zStrdup (dp1->d_name);
+	  tmpsn[strlen (tmpsn) - 5] = 0;
+	  service* s1 = (service *) malloc (SERVICE_SIZE);
+	  if (s1 == NULL)
+	    {
+	      setMapInMaps(m,"lenv","message",_("Unable to allocate memory."));
+	      setMapInMaps(m,"lenv","type","InternalError");
+	      return -2;
+	    }
+	  t = readServiceFile (m, tmps1, &s1, tmpsn);
+	  free (tmpsn);
+	  if (t < 0)
+	    {
+	      map *tmp00 = getMapFromMaps (m, "lenv", "message");
+	      char tmp01[1024];
+	      if (tmp00 != NULL)
+		sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"),
+			 dp1->d_name, tmp00->value);
+	      else
+		sprintf (tmp01, _("Unable to parse the ZCFG file: %s."),
+			 dp1->d_name);
+	      setMapInMaps(m,"lenv","message",tmp01);
+	      setMapInMaps(m,"lenv","type","InternalError");
+	      return -1;
+	    }
+	  if(strncasecmp(registryKeys[i],"implementation",14)==0){
+	    inheritance(*r,&s1);
+	  }
+	  addServiceToRegistry(r,registryKeys[i],s1);
+	  freeService (&s1);
+	  free (s1);
+	  scount++;
+	}
+    }
+    (void) closedir (dirp1);
+  }
+  return 0;
+}
+
+#ifdef WIN32
+/**
+ * Create a KVP request for executing background task.
+ * TODO: use the XML request in case of input POST request.
+ *
+ * @param m the maps containing the parameters from the main.cfg file
+ * @param length the total length of the KVP parameters
+ * @param type
+ */
+char* getMapsAsKVP(maps* m,int length,int type){
+  char *dataInputsKVP=(char*) malloc(length*sizeof(char));
+  char *dataInputsKVPi=NULL;
+  maps* curs=m;
+  int i=0;
+  while(curs!=NULL){
+    map *inRequest=getMap(curs->content,"inRequest");
+    map *hasLength=getMap(curs->content,"length");
+    if((inRequest!=NULL && strncasecmp(inRequest->value,"true",4)==0) ||
+       inRequest==NULL){
+      if(i==0)
+	if(type==0){
+	  sprintf(dataInputsKVP,"%s=",curs->name);
+	  if(hasLength!=NULL){
+	    dataInputsKVPi=(char*)malloc((strlen(curs->name)+2)*sizeof(char));
+	    sprintf(dataInputsKVPi,"%s=",curs->name);
+	  }
+	}
+	else
+	  sprintf(dataInputsKVP,"%s",curs->name);
+      else{
+	char *temp=zStrdup(dataInputsKVP);
+	if(type==0)
+	  sprintf(dataInputsKVP,"%s;%s=",temp,curs->name);
+	else
+	  sprintf(dataInputsKVP,"%s;%s",temp,curs->name);
+      }
+      map* icurs=curs->content;
+      if(type==0){
+	char *temp=zStrdup(dataInputsKVP);
+	if(getMap(curs->content,"xlink:href")!=NULL)
+	  sprintf(dataInputsKVP,"%sReference",temp);
+	else{
+	  if(hasLength!=NULL){
+	    int j;
+	    for(j=0;j<atoi(hasLength->value);j++){
+	      map* tmp0=getMapArray(curs->content,"value",j);
+	      if(j==0)
+		free(temp);
+	      temp=zStrdup(dataInputsKVP);
+	      if(j==0)
+		sprintf(dataInputsKVP,"%s%s",temp,tmp0->value);
+	      else
+		sprintf(dataInputsKVP,"%s;%s%s",temp,dataInputsKVPi,tmp0->value);
+	    }
+	  }
+	  else
+	    sprintf(dataInputsKVP,"%s%s",temp,icurs->value);
+	}
+	free(temp);
+      }
+      while(icurs!=NULL){
+	if(strncasecmp(icurs->name,"value",5)!=0 &&
+	   strncasecmp(icurs->name,"mimeType_",9)!=0 &&
+	   strncasecmp(icurs->name,"dataType_",9)!=0 &&
+	   strncasecmp(icurs->name,"size",4)!=0 &&
+	   strncasecmp(icurs->name,"length",4)!=0 &&
+	   strncasecmp(icurs->name,"isArray",7)!=0 &&
+	   strcasecmp(icurs->name,"Reference")!=0 &&
+	   strcasecmp(icurs->name,"minOccurs")!=0 &&
+	   strcasecmp(icurs->name,"maxOccurs")!=0 &&
+	   strncasecmp(icurs->name,"fmimeType",9)!=0 &&
+	   strcasecmp(icurs->name,"inRequest")!=0){
+	  char *itemp=zStrdup(dataInputsKVP);
+	  if(strcasecmp(icurs->name,"xlink:href")!=0)
+	    sprintf(dataInputsKVP,"%s@%s=%s",itemp,icurs->name,icurs->value);
+	  else
+	    sprintf(dataInputsKVP,"%s@%s=%s",itemp,icurs->name,url_encode(icurs->value));
+	  free(itemp);
+	}
+	icurs=icurs->next;
+      }
+    }
+    curs=curs->next;
+    i++;
+  }
+  return dataInputsKVP;
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/server_internal.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/server_internal.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/server_internal.h	(revision 942)
@@ -0,0 +1,80 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef WIN32
+#pragma comment(lib, "rpcrt4.lib")
+#endif
+
+#ifndef IMPORTSERVICE
+#define IMPORTSERVICE "include" // default name of [include] block in main.cfg
+
+#include "service.h"
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+
+extern   int conf_read(const char*,maps*);
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  char *get_uuid();  
+  char *base64(const char*,int);
+  char *base64d(const char*,int,int*);
+  void readBase64(map **);
+  char *url_decode(char *);
+  int getVersionId(const char*);
+  void readGeneratedFile(maps*,map*,char*);
+  int getServiceFromYAML(maps*,char*,service**,char *name);
+  char* addDefaultValues(maps**,elements*,maps*,int,map**);
+  char* getEncoding(maps*);
+  void parseIdentifier(maps*,char*,char*,char*);
+  void dumpMapsValuesToFiles(maps**,maps**);
+  void runDismiss(maps*,char*);
+  void runGetStatus(maps*,char*,char*);
+
+  int isValidLang(maps*,const char*);
+  
+  char* getLastErrorMessage();
+  int readServiceFile (maps *, char *, service **, char *);
+  int createRegistry (maps*,registry **,char *);
+
+  int zoo_path_compare(char* path1, char* path2);
+
+#ifdef WIN32
+  char* getMapsAsKVP(maps*,int,int);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service.c	(revision 942)
@@ -0,0 +1,1810 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2015-2019 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service.h"
+
+// knut: time utilities required for new log function (logMessage)
+#include <ctime>
+#include <chrono>
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#include <stdarg.h>
+/**
+ * snprintf for Visual Studio compiler.
+ *
+ * See https://dxr.mozilla.org/mozilla-central/source/media/mtransport/third_party/nrappkit/src/util/util.c
+ */
+int snprintf(char *buffer, size_t n, const char *format, ...)
+{
+  va_list argp;
+  int ret;
+  va_start(argp, format);
+  ret = _vscprintf(format, argp);
+  vsnprintf_s(buffer, n, _TRUNCATE, format, argp);
+  va_end(argp);
+  return ret;
+}
+#endif
+
+/**
+ * Dump a map on stderr
+ *
+ * @param t the map to dump
+ */
+void _dumpMap(map* t){
+  if(t!=NULL){
+    fprintf(stderr,"%s: %s\n",t->name,t->value);
+    fflush(stderr);
+  }else{
+    fprintf(stderr,"NULL\n");
+    fflush(stderr);
+  }
+}
+
+/**
+ * Dump a map on stderr, see _dumpMap()
+ *
+ * @param t the map to dump
+ */
+void dumpMap(map* t){
+  map* tmp=t;
+  while(tmp!=NULL){
+    _dumpMap(tmp);
+    tmp=tmp->next;
+  }
+}
+
+/**
+ * Dump a map to a file 
+ *
+ * @param t the map to dump to file
+ * @param file the file pointer to store the map
+ */
+void dumpMapToFile(map* t,FILE* file){
+  map* tmp=t;
+  while(tmp!=NULL){
+    fprintf(file,"%s = %s\n",tmp->name,tmp->value);
+    tmp=tmp->next;
+  }
+}
+
+/**
+ * Dump a maps on stderr, see dumpMap().
+ *
+ * @param m the map to dump
+ */
+void dumpMaps(maps* m){
+  maps* tmp=m;
+  while(tmp!=NULL){
+    fprintf(stderr,"MAP => [%s] \n",tmp->name);
+    fprintf(stderr," * CONTENT [%s] \n",tmp->name);
+    dumpMap(tmp->content);
+    if(tmp->child!=NULL){
+      fprintf(stderr," * CHILD [%s] \n",tmp->name);
+      dumpMaps(tmp->child);
+      fprintf(stderr," * /CHILD [%s] \n",tmp->name);
+    }
+    tmp=tmp->next;
+  }
+}
+
+/**
+ * Dump a maps to a file, see dumpMapToFile().
+ *
+ * @param m the map to dump
+ * @param file the the file pointer to store the map
+ */
+void _dumpMapsToFile(maps* m,FILE* file,int limit){
+  maps* tmp=m;
+  int cnt=0;
+  while(tmp!=NULL){
+    fprintf(file,"[%s]\n",tmp->name);
+    if(tmp->child!=NULL){
+      _dumpMapsToFile(tmp->child,file,limit);
+    }else
+      dumpMapToFile(tmp->content,file);
+    fflush(file);
+    tmp=tmp->next;
+    if(limit>=0 && cnt==limit)
+      tmp=NULL;
+    cnt++;
+  }
+  fflush(file);
+}
+
+/**
+ * Dump a maps to a file, see _dumpMapsToFile().
+ *
+ * @param m the map to dump
+ * @param file_path the full path to the file name to store the map
+ * @param limit the number limiting the maps to be dumped
+ */
+void dumpMapsToFile(maps* m,char* file_path,int limit){
+  FILE* file=fopen(file_path,"w+");
+  _dumpMapsToFile(m,file,limit);
+  fflush(file);
+  fclose(file);
+}
+
+/**
+ * Create a new iotype*
+ *
+ * @return a pointer to the allocated iotype 
+ */
+iotype* createIoType(){
+  iotype* io=(iotype*)malloc(IOTYPE_SIZE);
+  io->content=NULL;
+  io->next=NULL;
+  return io;
+}
+
+/**
+ * Create a new map
+ *
+ * @param name the key to add to the map
+ * @param value the corresponding value to add to the map
+ * @return a pointer to the allocated map 
+ */
+map* createMap(const char* name,const char* value){
+  map* tmp=(map *)malloc(MAP_SIZE);
+  tmp->name=zStrdup(name);
+  tmp->value=zStrdup(value);
+  tmp->next=NULL;
+  return tmp;
+}
+
+/**
+ * Create a new maps with the given name
+ *
+ * @param name of the maps
+ * @return the allocated map
+ */
+maps* createMaps(const char* name){
+  maps* tmp = (maps *) malloc (MAPS_SIZE);
+  tmp->name = zStrdup (name);
+  tmp->content = NULL;
+  tmp->child = NULL;
+  tmp->next = NULL;
+  return tmp;
+}
+
+/**
+ * Count number of map in a map
+ *
+ * @param m the map to count
+ * @return number of map in a map
+ */
+int count(map* m){
+  map* tmp=m;
+  int c=0;
+  while(tmp!=NULL){
+    c++;
+    tmp=tmp->next;
+  }
+  return c;
+}
+
+/**
+ * Count number of maps in a maps
+ *
+ * @param m the maps to count
+ * @return number of maps in a maps
+ */
+int maps_length(maps* m){
+  maps* tmp=m;
+  int c=0;
+  while(tmp!=NULL){
+    c++;
+    tmp=tmp->next;
+  }
+  return c;
+}
+
+/**
+ * Verify if a key exist in a map
+ *
+ * @param m the map to search for the key
+ * @param key the key to search in the map
+ * @return true if the key wwas found, false in other case
+ */
+bool hasKey(map* m,const char *key){
+  map* tmp=m;
+  while(tmp!=NULL){
+    if(strcasecmp(tmp->name,key)==0)
+      return true;
+    tmp=tmp->next;
+  }
+#ifdef DEBUG_MAP
+  fprintf(stderr,"NOT FOUND \n");
+#endif
+  return false;
+}
+
+/**
+ * Access a specific maps
+ *
+ * @param m the maps to search for the key
+ * @param key the key to search in the maps
+ * @return a pointer on the maps found or NULL if not found
+ */
+maps* getMaps(maps* m,const char *key){
+  maps* tmp=m;
+  while(tmp!=NULL){
+    if(strcasecmp(tmp->name,key)==0){
+      return tmp;
+    }
+    tmp=tmp->next;
+  }
+  return NULL;
+}
+
+/**
+ * Access a specific map
+ *
+ * @param m the map to search for the key
+ * @param key the key to search in the map
+ * @return a pointer on the map found or NULL if not found
+ */
+map* getMap(map* m,const char *key){
+  map* tmp=m;
+  while(tmp!=NULL){
+    if(strcasecmp(tmp->name,key)==0){
+      return tmp;
+    }
+    tmp=tmp->next;
+  }
+  return NULL;
+}
+
+
+/**
+ * Access the last map
+ *
+ * @param m the map to search for the lastest map
+ * @return a pointer on the lastest map found or NULL if not found
+ */
+map* getLastMap(map* m){
+  map* tmp=m;
+  while(tmp!=NULL){
+    if(tmp->next==NULL){
+      return tmp;
+    }
+    tmp=tmp->next;
+  }
+  return NULL;
+}
+
+/**
+ * Access a specific map from a maps
+ *
+ * @param m the maps to search for the key
+ * @param key the key to search in the maps
+ * @param subkey the key to search in the map (found for the key, if any)
+ * @return a pointer on the map found or NULL if not found
+ */
+map* getMapFromMaps(maps* m,const char* key,const char* subkey){
+  maps* _tmpm=getMaps(m,key);
+  if(_tmpm!=NULL){
+    map* _ztmpm=getMap(_tmpm->content,subkey);
+    return _ztmpm;
+  }
+  else return NULL;
+}
+
+/**
+ * Free allocated memory of a map.
+ * Require to call free on mo after calling this function.
+ *
+ * @param mo the map to free
+ */
+void freeMap(map** mo){
+  map* _cursor=*mo;
+  if(_cursor!=NULL){
+#ifdef DEBUG
+    fprintf(stderr,"freeMap\n");
+#endif
+    free(_cursor->name);
+    free(_cursor->value);
+    if(_cursor->next!=NULL){
+      freeMap(&_cursor->next);
+      free(_cursor->next);
+    }
+  }
+}
+
+/**
+ * Free allocated memory of a maps.
+ * Require to call free on mo after calling this function.
+ *
+ * @param mo the maps to free
+ */
+void freeMaps(maps** mo){
+  maps* _cursor=*mo;
+  if(_cursor && _cursor!=NULL){
+#ifdef DEBUG
+    fprintf(stderr,"freeMaps\n");
+#endif
+    free(_cursor->name);
+    if(_cursor->content!=NULL){
+      freeMap(&_cursor->content);
+      free(_cursor->content);
+    }
+    if(_cursor->child!=NULL){
+      freeMaps(&_cursor->child);
+      free(_cursor->child);
+    }
+    if(_cursor->next!=NULL){
+      freeMaps(&_cursor->next);
+      free(_cursor->next);
+    }
+  }
+}
+
+/**
+ * Verify if an elements contains a name equal to the given key.
+ *
+ * @param e the elements to search for the key
+ * @param key the elements name to search
+ * @return true if the elements contains the name, false in other cases.
+ */ 
+bool hasElement(elements* e,const char* key){
+  elements* tmp=e;
+  while(tmp!=NULL){
+    if(strcasecmp(key,tmp->name)==0)
+      return true;
+    tmp=tmp->next;
+  }
+  return false;
+}
+
+/**
+ * Access a specific elements named key.
+ *
+ * @param m the elements to search
+ * @param key the elements name to search
+ * @return a pointer to the specific element if found, NULL in other case.
+ */ 
+elements* getElements(elements* m,char *key){
+  elements* tmp=m;
+  while(tmp!=NULL){
+    if(strcasecmp(tmp->name,key)==0)
+      return tmp;
+    tmp=tmp->next;
+  }
+  return NULL;
+}
+
+/**
+ * Free allocated memory of an iotype.
+ * Require to call free on i after calling this function.
+ *
+ * @param i the iotype to free
+ */
+void freeIOType(iotype** i){
+  iotype* _cursor=*i;
+  if(_cursor!=NULL){
+    if(_cursor->next!=NULL){
+      freeIOType(&_cursor->next);
+      free(_cursor->next);
+    }
+    freeMap(&_cursor->content);
+    free(_cursor->content);
+  }
+}
+
+/**
+ * Free allocated memory of an elements.
+ * Require to call free on e after calling this function.
+ *
+ * @param e the iotype to free
+ */
+void freeElements(elements** e){
+  elements* tmp=*e;
+  if(tmp!=NULL){
+    if(tmp->name!=NULL)
+      free(tmp->name);
+    freeMap(&tmp->content);
+    if(tmp->content!=NULL)
+      free(tmp->content);
+    freeMap(&tmp->metadata);
+    if(tmp->metadata!=NULL)
+      free(tmp->metadata);
+    freeMap(&tmp->additional_parameters);
+    if(tmp->additional_parameters!=NULL)
+      free(tmp->additional_parameters);
+    if(tmp->format!=NULL)
+      free(tmp->format);
+    freeElements(&tmp->child);
+    if(tmp->child!=NULL){
+      free(tmp->child);
+    }
+    if(tmp->defaults!=NULL){
+      freeIOType(&tmp->defaults);
+      free(tmp->defaults);
+    }
+    if(tmp->supported!=NULL){
+      freeIOType(&tmp->supported);
+      free(tmp->supported);
+    }
+    if(tmp->next!=NULL){
+      freeElements(&tmp->next);
+      free(tmp->next);
+    }
+  }
+}
+
+
+/**
+ * Allocate memory for a service.
+ * Require to call free after calling this function.
+ *
+ * @return the service
+ */
+service* createService(){
+  service *s1 = (service *) malloc (SERVICE_SIZE);
+  s1->name=NULL;
+  s1->content=NULL;
+  s1->metadata=NULL;
+  s1->additional_parameters=NULL;
+  s1->inputs=NULL;
+  s1->outputs=NULL;
+  return s1;
+}
+
+/**
+ * Free allocated memory of a service.
+ * Require to be invoked for every createService call.
+ *
+ * @param s the service to free
+ */
+void freeService(service** s){
+  service* tmp=*s;
+  if(tmp!=NULL){
+    if(tmp->name!=NULL)
+      free(tmp->name);
+    freeMap(&tmp->content);
+    if(tmp->content!=NULL)
+      free(tmp->content);
+    freeMap(&tmp->metadata);
+    if(tmp->metadata!=NULL)
+      free(tmp->metadata);
+    freeMap(&tmp->additional_parameters);
+    if(tmp->additional_parameters!=NULL)
+      free(tmp->additional_parameters);
+    freeElements(&tmp->inputs);
+    if(tmp->inputs!=NULL)
+      free(tmp->inputs);
+    freeElements(&tmp->outputs);
+    if(tmp->outputs!=NULL)
+      free(tmp->outputs);
+  }
+}
+
+/**
+ * Add key value pair to an existing map.
+ *
+ * @param m the map to add the KVP
+ * @param n the key to add
+ * @param v the corresponding value to add
+ */
+void addToMap(map* m,const char* n,const char* v){
+    if (m != NULL) { // knut: add NULL-pointer check
+        if (hasKey(m, n) == false) {
+            map* _cursor = m;
+            while (_cursor->next != NULL) {
+                _cursor = _cursor->next;
+            }
+            _cursor->next = createMap(n, v);
+        }
+        else {
+            map *tmp = getMap(m, n);
+            if (tmp->value != NULL)
+                free(tmp->value);
+            tmp->value = zStrdup(v);
+        }
+    }
+}
+
+/**
+ * Add a key and an integer value to an existing map.
+ *
+ * @param m the map to add the KVP
+ * @param n the key to add
+ * @param v the corresponding value to add
+ */
+void addIntToMap(map* m,const char* n,const int v){
+  char svalue[10];
+  sprintf(svalue,"%d",v);
+  if(hasKey(m,n)==false){
+    map* _cursor=m;
+    while(_cursor->next!=NULL){
+      _cursor=_cursor->next;
+    }
+    _cursor->next=createMap(n,svalue);
+  }
+  else{
+    map *tmp=getMap(m,n);
+    if(tmp->value!=NULL)
+      free(tmp->value);
+    tmp->value=zStrdup(svalue);
+  }
+}
+
+/**
+ * Add a key and a binary value to an existing map.
+ *
+ * @param m the map to add the KVP
+ * @param n the key to add
+ * @param v the corresponding value to add
+ * @param size the size of the given value
+ * @return a pointer to the updated map m
+ */
+map* addToMapWithSize(map* m,const char* n,const char* v,int size){
+  char sin[128];
+  char sname[10]="size";
+  map *tmp;
+  if(hasKey(m,n)==false){
+    map* _cursor=m;
+    if(_cursor!=NULL){
+      addToMap(m,n,"");
+    }else{
+      m=createMap(n,"");
+    }
+  }
+  if(strlen(n)>5)
+    sprintf(sname,"size_%s",n+6);
+  tmp=getMap(m,n);
+  if(tmp->value!=NULL)
+    free(tmp->value);
+  tmp->value=(char*)malloc((size+1)*sizeof(char));
+  if(v!=NULL)
+    memmove(tmp->value,v,size*sizeof(char));
+  tmp->value[size]=0;
+  sprintf(sin,"%d",size);
+  addToMap(m,sname,sin);
+  return m;
+}
+
+/**
+ * Add a map at the end of another map.
+ *
+ * @param mo the map to add mi
+ * @param mi the map to add to mo
+ */
+void addMapToMap(map** mo,map* mi){
+  map* tmp=mi;
+  map* _cursor=*mo;
+  while(tmp!=NULL){
+    if(_cursor==NULL){
+      *mo=createMap(tmp->name,tmp->value);
+      (*mo)->next=NULL;
+    }
+    else{
+      map* tmp1=getMap(*mo,tmp->name);
+      if(tmp1==NULL){
+	while(_cursor->next!=NULL)
+	  _cursor=_cursor->next;
+	_cursor->next=createMap(tmp->name,tmp->value);
+      }
+      else{
+	addToMap(*mo,tmp->name,tmp->value);
+      }
+    }
+    _cursor=*mo;
+    tmp=tmp->next;
+  }
+}
+
+/**
+ * Add a map to iotype.
+ *
+ * @param io the iotype to add the map
+ * @param mi the map to add to io
+ */
+void addMapToIoType(iotype** io,map* mi){
+  iotype* tmp=*io;
+  while(tmp->next!=NULL){
+    tmp=tmp->next;
+  }
+  tmp->next=(iotype*)malloc(IOTYPE_SIZE);
+  tmp->next->content=NULL;
+  addMapToMap(&tmp->next->content,mi);
+  tmp->next->next=NULL;
+}
+
+/**
+ * Access a specific map or set its value.
+ *
+ * @param m the map to search for the key
+ * @param key the key to search/add in the map
+ * @param value the value to add if the key does not exist
+ * @return a pointer on the map found or NULL if not found
+ */
+map* getMapOrFill(map** m,const char *key,const char* value){
+  map* tmp=*m;
+  map* tmpMap=getMap(tmp,key);
+  if(tmpMap==NULL){
+    if(tmp!=NULL){
+      addToMap((*m),key,value);
+    }
+    else
+      (*m)=createMap(key,value);
+    tmpMap=getMap(*m,key);
+  }
+  return tmpMap;
+}
+
+/**
+ * Verify if a map is contained in another map.
+ *
+ * @param m the map to search for i
+ * @param i the map to search in m
+ * @return true if i was found in m, false in other case
+ */
+bool contains(map* m,map* i){
+  while(i!=NULL){      
+    if(strcasecmp(i->name,"value")!=0 &&
+       strcasecmp(i->name,"xlink:href")!=0 &&
+       strcasecmp(i->name,"useMapServer")!=0 &&
+       strcasecmp(i->name,"asReference")!=0){
+      map *tmp;
+      if(hasKey(m,i->name) && (tmp=getMap(m,i->name))!=NULL && 
+	 strcasecmp(i->value,tmp->value)!=0)
+	return false;
+    }
+    i=i->next;
+  }
+  return true;
+}
+
+/**
+ * Access a specific iotype from an elements.
+ *
+ * @param e the elements to search for the name
+ * @param name the name to search in the elements e
+ * @param values the map to verify it was contained in the defaults or 
+ *  supported content of the elements e
+ * @return a pointer on the iotype found or NULL if not found
+ */
+iotype* getIoTypeFromElement(elements* e,char *name, map* values){
+  elements* cursor=e;
+  if(values!=NULL){
+    while(cursor!=NULL){
+      if(strcasecmp(cursor->name,name)==0 && (cursor->defaults!=NULL || cursor->supported!=NULL)){
+	if(contains(cursor->defaults->content,values)==true)
+	  return cursor->defaults;
+	else{
+	  iotype* tmp=cursor->supported;
+	  while(tmp!=NULL){
+	    if(contains(tmp->content,values)==true)
+	      return tmp;	    
+	    tmp=tmp->next;
+	  }
+	}
+      }
+      cursor=cursor->next;
+    }
+  }else{
+    while(cursor!=NULL){
+      if(strcasecmp(cursor->name,name)==0 && cursor->defaults!=NULL){
+	return cursor->defaults;
+      }
+      cursor=cursor->next;
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Load binary values from a map (in) and add them to another map (out)
+ *
+ * @param out the map to add binaries values
+ * @param in the map containing the binary values to add ti out
+ * @param pos index of the binary in an array (in case of "MapArray")
+ */
+void loadMapBinary(map** out,map* in,int pos){
+  map* size=getMap(in,"size");
+  map *lout=*out;
+  map *tmpVin,*tmpVout;
+  if(size!=NULL && pos>0){
+    char tmp[11];
+    sprintf(tmp,"size_%d",pos);
+    size=getMap(in,tmp);
+    sprintf(tmp,"value_%d",pos);
+    tmpVin=getMap(in,tmp);
+    tmpVout=getMap(lout,tmp);
+    free(tmpVout->value);
+    tmpVout->value=(char*)malloc((atoi(size->value)+1)*sizeof(char));
+    memmove(tmpVout->value,tmpVin->value,atoi(size->value)*sizeof(char));
+    tmpVout->value[atoi(size->value)]=0;
+  }else{
+    if(size!=NULL){
+      tmpVin=getMap(in,"value");
+      tmpVout=getMap(lout,"value");
+      free(tmpVout->value);
+      tmpVout->value=(char*)malloc((atoi(size->value)+1)*sizeof(char));
+      memmove(tmpVout->value,tmpVin->value,atoi(size->value)*sizeof(char));
+      tmpVout->value[atoi(size->value)]=0;
+    }
+  }
+}
+  
+/**
+ * Load binary values from a map (in) and add them to another map (out).
+ * This function will take care of MapArray.
+ * @see loadMapBinary
+ *
+ * @param out the map to add binaries values
+ * @param in the map containing the binary values to add ti out
+ */
+void loadMapBinaries(map** out,map* in){
+  map* size=getMap(in,"size");
+  map* length=getMap(in,"length");
+  map* toload=getMap(in,"to_load");
+  if(toload!=NULL && strcasecmp(toload->value,"false")==0){
+#ifdef DEBUG
+    fprintf(stderr,"NO LOAD %s %d \n",__FILE__,__LINE__);
+#endif
+    return ;
+  }
+  if(length!=NULL){
+    int len=atoi(length->value);
+    int i=0;
+    for(i=0;i<len;i++){
+      loadMapBinary(out,in,i);
+    }
+  }
+  else
+    if(size!=NULL)
+      loadMapBinary(out,in,-1);
+}
+
+/**
+ * Duplicate a Maps
+ * 
+ * @param mo the maps to clone
+ * @return the allocated maps containing a copy of the mo maps
+ */
+maps* dupMaps(maps** mo){
+  maps* _cursor=*mo;
+  maps* res=NULL;
+  if(_cursor!=NULL){
+    map* mc=_cursor->content;
+    maps* mcs=_cursor->child;
+    res=createMaps(_cursor->name);
+    if(mc!=NULL){
+      addMapToMap(&res->content,mc);
+      loadMapBinaries(&res->content,mc);
+    }
+    if(mcs!=NULL){
+      res->child=dupMaps(&mcs);
+    }
+    res->next=dupMaps(&_cursor->next);
+  }
+  return res;
+}
+
+/**
+ * Add a maps at the end of another maps.
+ *
+ * @see addMapToMap, dupMaps, getMaps
+ * @param mo the maps to add mi
+ * @param mi the maps to add to mo
+ */
+void addMapsToMaps(maps** mo,maps* mi){
+  maps* tmp=mi;
+  maps* _cursor=*mo;
+  while(tmp!=NULL){
+    if(_cursor==NULL){
+      *mo=dupMaps(&mi);
+    }
+    else{
+      maps* tmp1=getMaps(*mo,tmp->name);
+      while(_cursor->next!=NULL)
+	_cursor=_cursor->next;
+      if(tmp1==NULL){
+	_cursor->next=dupMaps(&tmp);
+	if(tmp->child!=NULL)
+	  _cursor->next->child=dupMaps(&tmp->child);
+	else
+	  _cursor->next->child=NULL;
+      }
+      else{
+	addMapToMap(&tmp1->content,tmp->content);
+	if(tmp->child!=NULL)
+	  tmp1->child=dupMaps(&tmp->child);
+	else
+	  tmp1->child=NULL;
+      }
+      _cursor=*mo;
+    }
+    tmp=tmp->next;
+  }
+}
+
+/**
+ * Access a specific map array element
+ *
+ * @param m the map to search for the key
+ * @param key the key to search in the map
+ * @param index of the MapArray 
+ * @return a pointer on the map found or NULL if not found
+ */
+map* getMapArray(map* m,const char* key,int index){
+  char tmp[1024];
+  map* tmpMap;
+  if(index>0)
+    sprintf(tmp,"%s_%d",key,index);
+  else
+    sprintf(tmp,"%s",key);
+#ifdef DEBUG
+  fprintf(stderr,"** KEY %s\n",tmp);
+#endif
+  tmpMap=getMap(m,tmp);
+#ifdef DEBUG
+  if(tmpMap!=NULL)
+    dumpMap(tmpMap);
+#endif
+  return tmpMap;
+}
+
+/**
+ * Add a key value in a MapArray for a specific index
+ *
+ * @param m the map to search for the key
+ * @param key the key to search in the map
+ * @param index the index of the MapArray 
+ * @param value the value to set in the MapArray 
+ * @return a pointer on the map found or NULL if not found
+ */
+void setMapArray(map* m,const char* key,int index,const char* value){
+  char tmp[1024];
+  map* tmpSize;
+  if(index>0){
+    map* len=getMap(m,"length");
+    sprintf(tmp,"%s_%d",key,index);
+    if((len!=NULL && atoi(len->value)<index+1) || len==NULL){
+      char tmp0[5];
+      sprintf(tmp0,"%d",index+1);
+      addToMap(m,"length",tmp0);
+    }
+  }
+  else{
+    sprintf(tmp,"%s",key);
+    addToMap(m,"length","1");
+  }
+  tmpSize=getMapArray(m,"size",index);
+  if(tmpSize!=NULL && strncasecmp(key,"value",5)==0){
+    map* ptr=getMapOrFill(&m,tmp,(char *)"");
+#ifdef DEBUG
+    fprintf(stderr,"%s\n",tmpSize->value);
+#endif
+    free(ptr->value);
+    ptr->value=(char*)malloc((atoi(tmpSize->value)+1)*sizeof(char));
+    memcpy(ptr->value,value,atoi(tmpSize->value)); 
+  }
+  else
+    addToMap(m,tmp,value);
+}
+
+/**
+ * Add a key and an integer value to an existing map array.
+ *
+ * @param m the map to add the KVP
+ * @param n the key to add
+ * @param index the index of the MapArray 
+ * @param v the corresponding value to add
+ */
+void addIntToMapArray(map* m,const char* n,int index,const int v){
+  char svalue[10];
+  sprintf(svalue,"%d",v);
+  setMapArray(m,n,index,svalue);
+}
+
+/**
+ * Access the map "type"
+ *
+ * @param mt the map
+ * @return a pointer on the map for mimeType/dataType/CRS if found, NULL in
+ *  other case
+ */
+map* getMapType(map* mt){
+  map* tmap=getMap(mt,(char *)"mimeType");
+  if(tmap==NULL){
+    tmap=getMap(mt,"dataType");
+    if(tmap==NULL){
+      tmap=getMap(mt,"CRS");
+    }
+  }
+#ifdef DEBUG
+  dumpMap(tmap);
+#endif
+  return tmap;
+}
+
+/**
+ * Add a Maps containing a MapArray to a Maps
+ *
+ * @see getMapType
+ * @param mo the maps
+ * @param mi the maps
+ * @param typ the map "type"
+ * @return 
+ */
+int addMapsArrayToMaps(maps** mo,maps* mi,char* typ){
+  maps* tmp=mi;    
+  maps* _cursor=getMaps(*mo,tmp->name);
+  char tmpLen[10];
+  int len=1;
+  char *tmpV[14]={
+    (char*)"size",
+    (char*)"value",
+    (char*)"uom",
+    (char*)"Reference",
+    (char*)"Order",
+    (char*)"cache_file",
+    (char*)"fmimeType",
+    (char*)"xlink:href",
+    typ,
+    (char*)"schema",
+    (char*)"encoding",
+    (char*)"isCached",
+    (char*)"LowerCorner",
+    (char*)"UpperCorner"
+  };
+  int i=0;
+  map* tmpLength;
+  
+  if(_cursor==NULL)
+    return -1;
+
+  tmpLength=getMap(_cursor->content,"length");
+  if(tmpLength!=NULL){
+    len=atoi(tmpLength->value);
+  }
+
+  sprintf(tmpLen,"%d",len+1);
+  addToMap(_cursor->content,"length",tmpLen);
+  for(i=0;i<14;i++){
+    map* tmpVI=getMap(tmp->content,tmpV[i]);
+    if(tmpVI!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"%s = %s\n",tmpV[i],tmpVI->value);
+#endif
+      setMapArray(_cursor->content,tmpV[i],len,tmpVI->value);
+    }
+  }
+    
+  addToMap(_cursor->content,"isArray","true");
+  return 0;
+}
+
+/**
+ * Set a key value pair to a map contained in a Maps
+ *
+ * @param m the maps
+ * @param key the maps name
+ * @param subkey the map name included in the maps corresponding to key
+ * @param value the corresponding value to add in the map
+ */
+void setMapInMaps(maps* m,const char* key,const char* subkey,const char *value){
+  maps* _tmpm=getMaps(m,key);
+  if(_tmpm!=NULL){
+    map* _ztmpm=getMap(_tmpm->content,subkey);
+    if(_ztmpm!=NULL){
+      if(_ztmpm->value!=NULL)
+	free(_ztmpm->value);
+      _ztmpm->value=zStrdup(value);
+    }else{
+      maps *tmp=createMaps(key);
+      tmp->content=createMap(subkey,value);
+      addMapsToMaps(&_tmpm,tmp);
+      freeMaps(&tmp);
+      free(tmp);
+    }
+  }else{
+    maps *tmp=createMaps(key);
+    tmp->content=createMap(subkey,value);
+    addMapsToMaps(&m,tmp);
+    freeMaps(&tmp);
+    free(tmp);
+  }
+}
+
+/**
+ * Create an empty elements
+ *
+ * @return a pointer to the allocated elements
+ */
+elements* createEmptyElements(){
+  elements* res=(elements*)malloc(ELEMENTS_SIZE);
+  res->name=NULL;
+  res->content=NULL;
+  res->metadata=NULL;
+  res->additional_parameters=NULL;  
+  res->format=NULL;
+  res->defaults=NULL;
+  res->supported=NULL;
+  res->child=NULL;
+  res->next=NULL;
+  return res;
+}
+
+/**
+ * Create a named elements
+ *
+ * @param name the elements name
+ * @return a pointer to the allocated elements
+ */
+elements* createElements(const char* name){
+  elements* res=(elements*)malloc(ELEMENTS_SIZE);
+  res->name=zStrdup(name);
+  res->content=NULL;
+  res->metadata=NULL;
+  res->additional_parameters=NULL;
+  res->format=NULL;
+  res->defaults=NULL;
+  res->supported=NULL;
+  res->child=NULL;
+  res->next=NULL;
+  return res;
+}
+
+/**
+ * Set the name of an elements
+ *
+ * @param name the elements name
+ * @return a pointer to the allocated elements
+ */
+void setElementsName(elements** elem,char* name){
+  elements* res=*elem;
+  res->name=zStrdup(name);
+  res->content=NULL;
+  res->metadata=NULL;
+  res->format=NULL;
+  res->defaults=NULL;
+  res->supported=NULL;
+  res->child=NULL;
+  res->next=NULL;
+}
+
+/**
+ * Dump an elements on stderr
+ *
+ * @param e the elements to dump
+ */
+void dumpElements(elements* e){
+  elements* tmp=e;
+  while(tmp!=NULL){
+    iotype* tmpio=tmp->defaults;
+    int ioc=0;
+    fprintf(stderr,"ELEMENT [%s]\n",tmp->name);
+    fprintf(stderr," > CONTENT [%s]\n",tmp->name);
+    dumpMap(tmp->content);
+    fprintf(stderr," > METADATA [%s]\n",tmp->name);
+    dumpMap(tmp->metadata);
+    fprintf(stderr," > ADDITIONAL PARAMETERS [%s]\n",tmp->name);
+    dumpMap(tmp->additional_parameters);
+    fprintf(stderr," > FORMAT [%s]\n",tmp->format);
+    while(tmpio!=NULL){
+      fprintf(stderr," > DEFAULTS [%s] (%i)\n",tmp->name,ioc);
+      dumpMap(tmpio->content);
+      tmpio=tmpio->next;
+      ioc++;
+    }
+    tmpio=tmp->supported;
+    ioc=0;
+    while(tmpio!=NULL){
+      fprintf(stderr," > SUPPORTED [%s] (%i)\n",tmp->name,ioc);
+      dumpMap(tmpio->content);
+      tmpio=tmpio->next;
+      ioc++;
+    }
+    if(tmp->child!=NULL){
+      fprintf(stderr," > CHILD \n");
+      dumpElements(tmp->child);
+    }
+    fprintf(stderr,"------------------\n");
+    tmp=tmp->next;
+  }
+}
+
+/**
+ * Dump an elements on stderr using the YAML syntaxe
+ *
+ * @param e the elements to dump
+ */
+void dumpElementsAsYAML(elements* e,int level){
+  elements* tmp=e;
+  int i;
+  while(tmp!=NULL){
+    map* mcurs=tmp->content;
+    int ioc=0;
+    iotype* tmpio;
+    for(i=0;i<2+(4*level);i++)
+      fprintf(stderr," ");
+    fprintf(stderr,"%s:\n",tmp->name);
+    while(mcurs!=NULL){
+      for(i=0;i<4+(4*level);i++)
+	fprintf(stderr," ");
+      _dumpMap(mcurs);
+      mcurs=mcurs->next;
+    }
+    mcurs=tmp->metadata;
+    if(mcurs!=NULL){
+      for(i=0;i<4+(4*level);i++)
+	fprintf(stderr," ");
+      fprintf(stderr,"MetaData:\n");
+      while(mcurs!=NULL){
+	for(i=0;i<6+(4*level);i++)
+	  fprintf(stderr," ");
+	_dumpMap(mcurs);
+	mcurs=mcurs->next;
+      }
+    }
+    for(i=0;i<4+(4*level);i++)
+      fprintf(stderr," ");
+    if(tmp->format!=NULL)
+      fprintf(stderr,"%s:\n",tmp->format);
+    else{
+      fprintf(stderr,"Child:\n");
+      if(tmp->child!=NULL)
+	dumpElementsAsYAML(tmp->child,level+1);
+    }
+    tmpio=tmp->defaults;
+    while(tmpio!=NULL){
+      for(i=0;i<6+(4*level);i++)
+	fprintf(stderr," ");
+      fprintf(stderr,"default:\n");
+      mcurs=tmpio->content;
+      while(mcurs!=NULL){
+	for(i=0;i<8+(4*level);i++)
+	  fprintf(stderr," ");
+	if(strcasecmp(mcurs->name,"range")==0){
+	  fprintf(stderr,"range: \"%s\"\n",mcurs->value);
+	}else
+	  _dumpMap(mcurs);
+	mcurs=mcurs->next;
+      }
+      tmpio=tmpio->next;
+      ioc++;
+    }
+    tmpio=tmp->supported;
+    ioc=0;
+    while(tmpio!=NULL){
+      for(i=0;i<6+(4*level);i++)
+	fprintf(stderr," ");
+      fprintf(stderr,"supported:\n");
+      mcurs=tmpio->content;
+      while(mcurs!=NULL){
+	for(i=0;i<8+(4*level);i++)
+	  fprintf(stderr," ");
+	if(strcasecmp(mcurs->name,"range")==0){
+	  fprintf(stderr,"range: \"%s\"\n",mcurs->value);
+	}else
+	  _dumpMap(mcurs);
+	mcurs=mcurs->next;
+      }
+      tmpio=tmpio->next;
+      ioc++;
+    }
+    tmp=tmp->next;
+  }
+}
+
+/**
+ * Duplicate an elements
+ * 
+ * @param e the elements to clone
+ * @return the allocated elements containing a copy of the elements e
+ */
+elements* dupElements(elements* e){
+  elements* cursor=e;
+  elements* tmp=NULL;
+  if(cursor!=NULL && cursor->name!=NULL){
+#ifdef DEBUG
+    fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
+    dumpElements(e);
+    fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
+#endif
+    tmp=(elements*)malloc(ELEMENTS_SIZE);
+    tmp->name=zStrdup(cursor->name);
+    tmp->content=NULL;
+    addMapToMap(&tmp->content,cursor->content);
+    tmp->metadata=NULL;
+    addMapToMap(&tmp->metadata,cursor->metadata);
+    tmp->additional_parameters=NULL;
+    addMapToMap(&tmp->additional_parameters,cursor->additional_parameters);
+    if(cursor->format!=NULL)
+      tmp->format=zStrdup(cursor->format);
+    else
+      tmp->format=NULL;
+    if(cursor->defaults!=NULL){
+      tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
+      tmp->defaults->content=NULL;
+      addMapToMap(&tmp->defaults->content,cursor->defaults->content);
+      tmp->defaults->next=NULL;
+#ifdef DEBUG
+      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
+      dumpMap(tmp->defaults->content);
+#endif
+    }else
+      tmp->defaults=NULL;
+    if(cursor->supported!=NULL && cursor->supported->content!=NULL){
+      iotype *tmp2=cursor->supported->next;
+      tmp->supported=(iotype*)malloc(IOTYPE_SIZE);
+      tmp->supported->content=NULL;
+      addMapToMap(&tmp->supported->content,cursor->supported->content);
+      tmp->supported->next=NULL;
+            while(tmp2!=NULL){
+	addMapToIoType(&tmp->supported,tmp2->content);
+#ifdef DEBUG
+	fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
+	dumpMap(tmp->defaults->content);
+#endif
+	tmp2=tmp2->next;
+      }
+    }
+    else
+      tmp->supported=NULL;
+    if(cursor->child!=NULL)
+      tmp->child=dupElements(cursor->child);
+    else
+      tmp->child=NULL;
+    if(cursor->next!=NULL)
+      tmp->next=dupElements(cursor->next);
+    else
+      tmp->next=NULL;
+  }
+  return tmp;
+}
+
+/**
+ * Add an elements to another elements.
+ *
+ * @see dupElements
+ * @param m the elements to add the e
+ * @param e the elements to be added to m
+ */
+void addToElements(elements** m,elements* e){
+  elements* tmp=e;
+  if(*m==NULL){
+    (*m)=dupElements(tmp);
+  }else{
+    addToElements(&(*m)->next,tmp);
+  }
+}
+
+/**
+ * Set the name of a service
+ *
+ * @param name the service name
+ */
+void setServiceName(service** serv,char* name){
+  service* res=*serv;
+  res->name=zStrdup(name);
+  res->content=NULL;
+  res->metadata=NULL;
+  res->inputs=NULL;
+  res->outputs=NULL;
+}
+
+/**
+ * Dump a service on stderr
+ *
+ * @param s the service to dump
+ */
+void dumpService(service* s){
+  if(s==NULL)
+    return;
+  fprintf(stderr,"++++++++++++++++++\nSERVICE [%s]\n++++++++++++++++++\n",s->name);
+  if(s->content!=NULL){
+    fprintf(stderr,"CONTENT MAP\n");
+    dumpMap(s->content);
+    if(s->metadata!=NULL)
+      fprintf(stderr,"CONTENT METADATA\n");
+    dumpMap(s->metadata);
+    if(s->additional_parameters!=NULL)
+      fprintf(stderr,"CONTENT AdditionalParameters\n");
+    dumpMap(s->additional_parameters);
+  }
+  if(s->inputs!=NULL){
+    fprintf(stderr,"INPUT ELEMENTS [%s]\n------------------\n",s->name);
+    dumpElements(s->inputs);
+  }
+  if(s->outputs!=NULL){
+    fprintf(stderr,"OUTPUT ELEMENTS [%s]\n------------------\n",s->name);
+    dumpElements(s->outputs);
+  }
+  fprintf(stderr,"++++++++++++++++++\n");
+}
+
+/**
+ * Dump a service on stderr using the YAML syntaxe
+ *
+ * @param s the service to dump
+ */
+void dumpServiceAsYAML(service* s){
+  int i;
+  fprintf(stderr,"# %s\n\n",s->name);
+  if(s->content!=NULL){
+    map* mcurs=s->content;
+    dumpMap(mcurs);
+    mcurs=s->metadata;
+    if(mcurs!=NULL){
+      fprintf(stderr,"MetaData:\n");
+      while(mcurs!=NULL){
+	for(i=0;i<2;i++)
+	  fprintf(stderr," ");
+	_dumpMap(mcurs);
+	mcurs=mcurs->next;
+      }
+    }
+  }
+  if(s->inputs!=NULL){
+    fprintf(stderr,"\ninputs:\n");
+    dumpElementsAsYAML(s->inputs,0);
+  }
+  if(s->outputs!=NULL){
+    fprintf(stderr,"\noutputs:\n");
+    dumpElementsAsYAML(s->outputs,0);
+  }
+}
+
+/**
+ * Duplicate a service
+ * 
+ * @param s the service to clone
+ * @return the allocated service containing a copy of the serfvice s
+ */
+service* dupService(service* s){
+  service *res=(service*)malloc(SERVICE_SIZE);
+  res->name=zStrdup(s->name);
+  res->content=NULL;
+  addMapToMap(&res->content,s->content);
+  res->metadata=NULL;
+  addMapToMap(&res->metadata,s->metadata);
+  res->additional_parameters=NULL;
+  addMapToMap(&res->additional_parameters,s->additional_parameters);
+  res->inputs=dupElements(s->inputs);
+  res->outputs=dupElements(s->outputs);
+  return res;
+}
+
+/**
+ * Print the registry on stderr.
+ * 
+ * @param r the registry
+ */
+void dumpRegistry(registry* r){
+  registry* p=r;
+  while(p!=NULL){
+    services* s=p->content;
+    fprintf(stderr,"%s \n",p->name);
+    s=p->content;
+    while(s!=NULL){
+      dumpService(s->content);
+      s=s->next;
+    }
+    p=p->next;
+  }
+}
+
+/**
+ * Add a service to the registry
+ *
+ * @param reg the resgitry to add the service
+ * @param name the registry name to update
+ * @param content the service to add
+ */
+bool addServiceToRegistry(registry** reg,char* name,service* content){
+  registry *l=*reg;
+  int isInitial=-1;
+  if(l==NULL){
+    l=(registry*)malloc(REGISTRY_SIZE);
+    isInitial=1;
+  }
+  if(l!=NULL){
+    int hasLevel=-1;
+    while(isInitial<0 && l!=NULL){
+      if(l->name!=NULL && strcasecmp(name,l->name)==0){
+	hasLevel=1;
+	break;
+      }
+      l=l->next;
+    }
+    if(hasLevel<0){
+      if(isInitial<0)
+	l=(registry*)malloc(REGISTRY_SIZE);
+      l->name=zStrdup(name);
+      l->content=NULL;
+      l->next=NULL;
+    }
+    if(l->content==NULL){
+      l->content=(services*)malloc(SERVICES_SIZE);
+      l->content->content=dupService(content);
+      l->content->next=NULL;
+    }
+    else{
+      services* s=l->content;
+      while(s->next!=NULL)
+	s=s->next;
+      s->next=(services*)malloc(SERVICES_SIZE);
+      s->next->content=dupService(content);
+      s->next->next=NULL;
+    }
+    l->next=NULL;
+    if(isInitial>0)
+      *reg=l;
+    else{
+      registry *r=*reg;
+      while(r->next!=NULL)
+	r=r->next;
+      r->next=l;
+      r->next->next=NULL;
+    }
+    return true;
+  }
+  else
+    return false;
+}
+
+/**
+ * Free memory allocated for the registry
+ *
+ * @param r the registry
+ */
+void freeRegistry(registry** r){
+  registry* lr=*r;
+  while(lr!=NULL){
+    services* s=lr->content;
+    free(lr->name);
+    while(s!=NULL){
+      service* s1=s->content;
+      s=s->next;
+      if(s1!=NULL){
+	freeService(&s1);
+	free(s1);
+	s1=NULL;
+      }
+    }
+    lr=lr->next;
+  }    
+}
+
+/**
+ * Access a service in the registry
+ *
+ * @param r the registry
+ * @param level the regitry to search ("concept", "generic" or "implementation")
+ * @param sname the service name
+ * @return the service pointer if a corresponding service was found or NULL
+ */
+service* getServiceFromRegistry(registry* r,char  *level,char* sname){
+  registry *lr=r;
+  while(lr!=NULL){
+    if(strcasecmp(lr->name,level)==0){
+      services* s=lr->content;
+      while(s!=NULL){
+	if(s->content!=NULL && strcasecmp(s->content->name,sname)==0)
+	  return s->content;
+	s=s->next;
+      }
+      break;
+    }
+    lr=lr->next;
+  }
+  return NULL;
+}
+
+/**
+ * Apply inheritance to an out map from a reference in map
+ *
+ * @param out the map to update
+ * @param in the reference map (containing inherited properties)
+ */
+void inheritMap(map** out,map* in){
+  map* content=in;
+  if((*out)==NULL){
+    addMapToMap(out,in);
+    return;
+  }
+  while(content!=NULL){
+    map* cmap=getMap(*out,content->name);
+    if(cmap==NULL)
+      addToMap(*out,content->name,content->value);
+    content=content->next;
+  }
+}
+
+/**
+ * Apply inheritance to an out iotype from a reference in iotype
+ * 
+ * @param out the iotype to update
+ * @param in the reference iotype (containing inherited properties)
+ */
+void inheritIOType(iotype** out,iotype* in){
+  iotype* io=in;
+  iotype* oio=*out;
+  if(io!=NULL){
+    if(*out==NULL){
+      *out=(iotype*)malloc(IOTYPE_SIZE);
+      (*out)->content=NULL;
+      addMapToMap(&(*out)->content,io->content);
+      (*out)->next=NULL;
+      oio=*out;
+      inheritIOType(&oio->next,io->next);
+    }else{
+      inheritIOType(&oio->next,io->next);
+    }
+  }
+}
+
+/**
+ * Apply inheritance to an out elements from a reference in elements
+ * 
+ * @param out the elements to update
+ * @param in the reference elements (containing inherited properties)
+ */
+void inheritElements(elements** out,elements* in){
+  elements* content=in;
+  while(content!=NULL && *out!=NULL){
+    elements* cmap=getElements(*out,content->name);
+    if(cmap==NULL)
+      addToElements(out,content);
+    else{
+      inheritMap(&cmap->content,content->content);
+      inheritMap(&cmap->metadata,content->metadata);
+      if(cmap->format==NULL && content->format!=NULL)
+	cmap->format=zStrdup(content->format);
+      inheritIOType(&cmap->defaults,content->defaults);
+      if(cmap->supported==NULL)
+	inheritIOType(&cmap->supported,content->supported);
+      else{
+	iotype* p=content->supported;
+	while(p!=NULL){
+	  addMapToIoType(&cmap->supported,p->content);
+	  p=p->next;
+	}
+      }
+    }
+    content=content->next;
+  }
+}
+
+/**
+ * Apply inheritance to a service based on a registry
+ * 
+ * @param r the registry storing profiles hierarchy
+ * @param s the service to update depending on its inheritance
+ */
+void inheritance(registry *r,service** s){
+  service* ls=*s;
+  map *profile,*level;
+  if(r==NULL)
+    return;
+  if(ls==NULL || ls->content==NULL)
+    return;
+  profile=getMap(ls->content,"extend");
+  level=getMap(ls->content,"level");
+  if(profile!=NULL&&level!=NULL){
+    service* s1;
+    if(strncasecmp(level->value,"profile",7)==0)
+      s1=getServiceFromRegistry(r,(char*)"generic",profile->value);
+    else
+      s1=getServiceFromRegistry(r,level->value,profile->value);
+      
+    inheritMap(&ls->content,s1->content);
+    inheritMap(&ls->metadata,s1->metadata);
+    if(ls->inputs==NULL && s1->inputs!=NULL){
+      ls->inputs=dupElements(s1->inputs);
+    }else{
+      inheritElements(&ls->inputs,s1->inputs);
+    }
+    if(ls->outputs==NULL && s1->outputs!=NULL){
+      ls->outputs=dupElements(s1->outputs);
+    }else
+      inheritElements(&ls->outputs,s1->outputs);
+  }
+}
+
+/**
+ * Convert a maps to a char*** (only used for Fortran support)
+ *
+ * @param m the maps to convert
+ * @param c the resulting array
+ */
+void mapsToCharXXX(maps* m,char*** c){
+  maps* tm=m;
+  int i=0;
+  int j=0;
+  char tmp[10][30][1024];
+  memset(tmp,0,1024*10*10);
+  while(tm!=NULL){
+    map* tc=tm->content;
+    if(i>=10)
+      break;
+    strcpy(tmp[i][j],"name");
+    j++;
+    strcpy(tmp[i][j],tm->name);
+    j++;
+    while(tc!=NULL){
+      if(j>=30)
+	break;
+      strcpy(tmp[i][j],tc->name);
+      j++;
+      strcpy(tmp[i][j],tc->value);
+      j++;
+      tc=tc->next;
+    }
+    tm=tm->next;
+    j=0;
+    i++;
+  }
+  memcpy(c,tmp,10*10*1024);
+}
+
+/**
+ * Convert a char*** to a maps (only used for Fortran support)
+ *
+ * @param c the array to convert
+ * @param m the resulting maps
+ */
+void charxxxToMaps(char*** c,maps**m){
+  maps* trorf=*m;
+  int i,j;
+  char tmp[10][30][1024];
+  memcpy(tmp,c,10*30*1024);
+  for(i=0;i<10;i++){
+    if(strlen(tmp[i][1])==0)
+      break;
+    trorf->name=tmp[i][1];
+    trorf->content=NULL;
+    trorf->next=NULL;
+    for(j=2;j<29;j+=2){
+      if(strlen(tmp[i][j+1])==0)
+	break;
+      if(trorf->content==NULL)
+	trorf->content=createMap(tmp[i][j],tmp[i][j+1]);
+      else
+	addToMap(trorf->content,tmp[i][j],tmp[i][j+1]);
+    }
+    trorf=trorf->next;
+  }
+  m=&trorf;
+}
+
+/**
+ * Verify that a map has a value
+ *
+ * @param map pointer to map that should be checked
+ * @return true if map has a value or false if value is missing/empty/NULL
+ */
+bool nonempty(map* map) {
+	return (map != NULL && map->value != NULL && strlen(map->value) > 0 && strcmp(map->value, "NULL") != 0);
+}
+
+/**
+ * Verify that a particular map value exists in a maps
+ * data structure, and obtain that value
+ *
+ * @param source pointer to maps structure
+ * @param node name of maps node to search
+ * @param key name of map node to find
+ * @param kvp address to the map* if it exists, otherwise NULL
+ * @return true if map has a value or false if value is missing/NULL
+ *
+ * @note The map assigned to kvp is owned by the source maps
+ */
+bool hasvalue(maps* source, const char* node, const char* key, map** kvp) {
+	*kvp = getMapFromMaps(source, node, key);
+	return (*kvp != NULL && (*kvp)->value != NULL &&
+		strlen((*kvp)->value) > 0 && strcmp((*kvp)->value, "NULL") != 0);
+}
+
+/*
+ * Set error message in configuration maps
+ *
+ * @param conf reference to configuration maps
+ * @param service name of service
+ * @param exc WPSException code
+ * @param message exception text (default: exception text in WPS specification)
+ */
+void setErrorMessage(maps*& conf, const char* service, WPSException exc, const char* message) {
+
+	if (message == NULL) {
+		message = WPSExceptionText[exc];
+	}
+
+	size_t len = strlen(service) + strlen(": ") + strlen(message) + strlen(": ") + strlen(WPSExceptionCode[exc]) + 16;
+	char* msg = (char*)malloc(len * sizeof(char));
+
+	if (msg != NULL) {
+		snprintf(msg, len * sizeof(char), "\n%s: %s: %s\n", service, message, WPSExceptionCode[exc]);
+		setMapInMaps(conf, "lenv", "message", msg);
+		free(msg);
+	}
+}
+
+void logMessage(const char* source, const char* function, int line, const char* file, const char* message) { //, const char* source, const char* function, int line) {
+
+	size_t msglen = 512;
+	const char empty[] = "";
+
+	FILE* log;
+
+	// system time, process time [nanoseconds]   
+	unsigned long long sys_t, proc_t;
+
+	// processor time consumed by the program:
+	clock_t t = clock();
+
+	// system time:
+	std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
+
+	std::time_t now_t = std::chrono::system_clock::to_time_t(now);
+	std::tm* tm = localtime(&now_t);
+	char* str = asctime(tm);
+	str[strlen(str) - 1] = '\0'; // remove newline
+
+	sys_t = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
+	//proc_t = (unsigned long long)(1.0e9*t/CLOCKS_PER_SEC);
+	proc_t = t;
+
+	if (message != NULL) {
+		msglen += strlen(message);
+	}
+	else {
+		message = empty;
+	}
+	//getLastErrorMessage(); // cgiScriptName  
+	char* text = (char*)malloc(sizeof(char)*msglen);
+
+	snprintf(text, msglen, "pid: %d %s line %d %s() %s systime: %lld ns ticks: %lld %s\n",
+		zGetpid(), source, line, function, str, sys_t, proc_t, message); // __FILE__ __LINE__ __func__ //
+
+	if (file != NULL && (log = fopen(file, "a+")) != NULL) {
+		fputs(text, log);
+		fclose(log);
+	}
+	else {
+#ifdef MSG_LOG_FILE
+		if ((log = fopen(MSG_LOG_FILE, "a+")) != NULL) {
+			fputs(text, log);
+			fclose(log);
+		}
+#endif
+	}
+
+	if (text != NULL) free(text);
+}
+
+// knut:
+// Example:
+// zooLog;
+// zooLogMsg(NULL, getLastErrorMessage()); 
+// zooLogMsg("log.txt", getLastErrorMessage()); 
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service.h	(revision 942)
@@ -0,0 +1,488 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2019 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_H
+#define ZOO_SERVICE_H 1
+
+#pragma once
+
+#ifdef WIN32
+#define ZOO_DLL_EXPORT __declspec( dllexport )
+#else
+#define ZOO_DLL_EXPORT 
+#endif
+
+ // knut: add bool if necessary
+#ifndef __cplusplus
+#ifndef WIN32
+#include <stdbool.h>
+#else
+typedef int bool;
+#define false 0
+#define true 1	
+#endif
+#endif
+#ifndef __bool_true_false_are_defined
+#define __bool_true_false_are_defined 1
+#endif
+
+#ifdef WIN32
+#define strtok_r strtok_s
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+#define zStrdup _strdup
+#define zMkdir _mkdir
+#define zGetpid _getpid
+#define zOpen _open
+#define zClose _close
+#define zUnlink _unlink
+#define zDup _dup
+#define zDup2 _dup2
+#define zWrite _write
+#define zSleep Sleep
+#include <sys/timeb.h>
+struct ztimeval {
+  long tv_sec; /* seconds */
+  long tv_usec; /* and microseconds */
+};
+static int zGettimeofday(struct ztimeval* tp, void* tzp)
+{
+  if (tp == 0) {
+    return -1;
+  }
+  
+  struct _timeb theTime;
+  _ftime(&theTime);
+  tp->tv_sec = theTime.time;
+  tp->tv_usec = theTime.millitm * 1000;
+  
+  return 0; // The gettimeofday() function shall return 0 on success
+}
+
+#define zStatStruct struct _stati64
+#define zStat _stati64
+
+#else
+/**
+ * The crossplatform strdup alias
+ */
+#define zStrdup strdup
+/**
+ * The crossplatform mkdir alias
+ */
+#define zMkdir mkdir
+/**
+ * The crossplatform open alias
+ */
+#define zOpen open
+/**
+ * The crossplatform close alias
+ */
+#define zClose close
+/**
+ * The crossplatform unlink alias
+ */
+#define zUnlink unlink
+/**
+ * The crossplatform dup alias
+ */
+#define zDup dup
+/**
+ * The crossplatform dup2 alias
+ */
+#define zDup2 dup2
+/**
+ * The crossplatform write alias
+ */
+#define zWrite write
+#include "unistd.h"
+/**
+ * The crossplatform sleep alias
+ */
+static int zSleep(const long millisecond){
+  return usleep(millisecond*1000);
+}
+/**
+ * The crossplatform gettimeofday alias
+ */
+#define zGettimeofday gettimeofday
+/**
+ * The crossplatform timeval alias
+ */
+#define ztimeval timeval
+/**
+ * The crossplatform getpid alias
+ */
+#define zGetpid getpid
+
+#define zStatStruct struct stat64
+#define zStat stat64
+
+#endif 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+#ifdef USE_MS
+#include <mapserver.h>
+#endif
+#endif
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <stdio.h>
+
+#include <string.h>
+#ifndef WIN32
+#include <ctype.h>
+#include <stdbool.h>
+#endif
+
+/**
+ * The global accepted status for a service
+ */
+#define SERVICE_ACCEPTED 0
+/**
+ * The global started status for a service
+ */
+#define SERVICE_STARTED 1
+/**
+ * The global paused status for a service
+ */
+#define SERVICE_PAUSED 2
+/**
+ * The global succeeded status for a service
+ */
+#define SERVICE_SUCCEEDED 3
+/**
+ * The global failed status for a service
+ */
+#define SERVICE_FAILED 4
+
+/**
+ * The memory size to create an elements
+ */
+#define ELEMENTS_SIZE (sizeof(char*)+(((2*sizeof(char*))+sizeof(maps*))*3)+sizeof(char*)+((sizeof(map*) + sizeof(iotype*))*2)+(2*sizeof(elements*)))
+/**
+ * The memory size to create a map
+ */
+//#define MAP_SIZE (2*sizeof(char*))+sizeof(NULL) // knut: size of NULL pointer may be different from regular pointer (platform dependent)
+#define MAP_SIZE (2*sizeof(char*))+sizeof(map*)
+/**
+ * The memory size to create an iotype
+ */
+//#define IOTYPE_SIZE MAP_SIZE+sizeof(NULL)
+#define IOTYPE_SIZE sizeof(map*) + sizeof(iotype*)
+/**
+ * The memory size to create a maps
+ */
+//#define MAPS_SIZE (2*sizeof(char*))+sizeof(map*)+MAP_SIZE
+#define MAPS_SIZE sizeof(char*)+sizeof(map*)+(2*sizeof(maps*))
+/**
+ * The memory size to create a service
+ */
+//#define SERVICE_SIZE (ELEMENTS_SIZE*2)+(MAP_SIZE*2)+sizeof(char*)
+#define SERVICE_SIZE sizeof(char*) + 3*sizeof(map*) + 2*sizeof(elements*)
+/**
+ * The memory size to create a services
+ */
+//#define SERVICES_SIZE SERVICE_SIZE+sizeof(services*)
+#define SERVICES_SIZE sizeof(service*)+sizeof(services*)
+/**
+ * The memory size to create a registry
+ */
+//#define REGISTRY_SIZE SERVICES_SIZE+sizeof(char*)
+#define REGISTRY_SIZE sizeof(char*)+sizeof(services*)+sizeof(registry*)
+
+#define SHMSZ     27
+
+#include "version.h" 
+
+#ifdef DEBUG_STACK
+  void debugStack(const char* file,const int line){
+    int stack;
+    fprintf(stderr,"stack %p (%s: %d) \n",&stack,file,line);
+  }
+#endif
+
+  /**
+   * KVP linked list
+   */
+  typedef struct map{
+    char* name; //!< the key
+    char* value; //!< the value
+    struct map* next; //!< the pointer to the next map if any or NULL
+  } map;
+
+#ifdef WIN32
+#define NULLMAP ((map*) 0)
+// knut: see new definition above
+//#define bool int
+//#define true 1
+//#define false 0
+#else
+#define NULLMAP NULL
+#endif
+
+  /**
+   * linked list of map pointer
+   *
+   * Small object to store WPS KVP set.
+   */
+  typedef struct maps{
+    char* name; //!< the maps name
+    struct map* content; //!< the content map
+    struct maps* child; //!< the child maps
+    struct maps* next; //!< the pointer to the next maps if any or NULL
+  } maps;
+  
+  /**
+   * Not named linked list
+   *
+   * Used to store information about formats, such as mimeType, encoding ... 
+   */
+  typedef struct iotype{
+    struct map* content; //!< the content map
+    struct iotype* next; //!< the pointer to the next iotype if any or NULL
+  } iotype;
+
+  /**
+   * Metadata information about input or output.
+   *
+   * The elements are used to store metadata information defined in the ZCFG.
+   */
+  typedef struct elements{
+    char* name; //!< the name
+    struct map* content; //!< the content map
+    struct map* metadata; //!< the metadata map
+    struct map* additional_parameters; //!< the additional parameters map
+    char* format; //!< the format: LiteralData or ComplexData or BoundingBoxData
+    struct iotype* defaults; //!< the default iotype 
+    struct iotype* supported; //!< the supported iotype 
+    struct elements* child; //!< the pointer to the children element if any (or NULL)
+    struct elements* next; //!< the pointer to the next element if any (or NULL)
+  } elements;
+
+  /**
+   * Metadata information about a full Service.
+   */
+  typedef struct service{
+    char* name; //!< the name
+    struct map* content; //!< the content map
+    struct map* metadata; //!< the metadata map
+    struct map* additional_parameters; //!< the additional parameters map
+    struct elements* inputs; //!< the inputs elements
+    struct elements* outputs; //!< the outputs elements
+  } service;
+
+  /**
+   * Services chained list.
+   */
+  typedef struct services{
+    struct service* content; //!< the content service pointer
+    struct services* next; //!< the pointer to the next services*
+  } services;
+
+  /**
+   * Profile registry.
+   */
+  typedef struct registry{
+    char *name; //!< the name
+    struct services* content; //!< the content services pointer
+    struct registry* next; //!< the next registry pointer
+  } registry;
+
+  // knut
+  enum WPSException {
+	  /*
+	  * StatusOK is not a WPS exception, it is added
+	  * here for convenience.
+	  */
+	  StatusOK,
+	  /*
+	  * See WPS 1.0 specification, Table 38 and Table 62.
+	  */
+	  MissingParameterValue,
+	  InvalidParameterValue,
+	  NoApplicableCode,
+	  NotEnoughStorage,
+	  ServerBusy,
+	  FileSizeExceeded,
+	  StorageNotSupported,
+	  VersionNegotiationFailed,
+	  /*
+	  * See WPS 2.0 specification, Tables 41, 46, 48, and 50.
+	  */
+	  NoSuchProcess,
+	  NoSuchMode,
+	  NoSuchInput,
+	  NoSuchOutput,
+	  DataNotAccessible,
+	  SizeExceeded,
+	  TooManyInputs,
+	  TooManyOutputs,
+	  NoSuchFormat,
+	  WrongInputData,
+	  InternalServerError,
+	  NoSuchJob,
+	  ResultNotReady
+  };
+
+  static const char* const WPSExceptionCode[] = {
+	"StatusOK",
+	"MissingParameterValue",
+	"InvalidParameterValue",
+	"NoApplicableCode",
+	"NotEnoughStorage",
+	"ServerBusy",
+	"FileSizeExceeded",
+	"StorageNotSupported",
+	"VersionNegotiationFailed",
+	"NoSuchProcess",
+	"NoSuchMode",
+	"NoSuchInput",
+	"NoSuchOutput",
+	"DataNotAccessible",
+	"SizeExceeded",
+	"TooManyInputs",
+	"TooManyOutputs",
+	"NoSuchFormat",
+	"WrongInputData",
+	"InternalServerError",
+	"NoSuchJob",
+	"ResultNotReady"
+  };
+
+  static const char* const WPSExceptionText[] = {
+	"No problem detected",
+	"Operation request does not include a parameter value, and this server did not declare a default value for that parameter.",
+	"Operation request contains an invalid parameter value.",
+	"No other exceptionCode specified by this service and server applies to this exception.",
+	"The server does not have enough space available to store the inputs and outputs associated with the request.",
+	"The server is too busy to accept and queue the request at this time.",
+	"The file size of one of the input parameters was too large for this process to handle.",
+	"Execute operation request included transmission=”reference” for one of the outputs, but storage is not offered by this server.",
+	"Service version for a ComplexData xlink:href input was not supported by the referenced server, and version negotiation failed.",
+	"One of the identifiers passed does not match with any of the processes offered by this server.",
+	"The process does not permit the desired execution mode.",
+	"One or more of the input identifiers passed does not match with any of the input identifiers of this process.",
+	"One or more of the output identifiers passed does not match with any of the input identifiers of this process.",
+	"One of the referenced input data sets was inaccessible.",
+	"The size of one of the input parameters was too large for this process to handle.",
+	"Too many input items have been specified.",
+	"Too many output items have been specified.",
+	"One or more of the input or output formats specified in the request did not match with any of the formats defined for that particular input or output.",
+	"One or more of inputs for which the service was able to retrieve the data but could not read it.",
+	"",
+	"The JobID from the request does not match any of the Jobs running on this server.",
+	"The result for the requested JobID has not yet been generated."
+  };
+
+  ZOO_DLL_EXPORT void _dumpMap(map*);
+  ZOO_DLL_EXPORT void dumpMap(map*);
+  ZOO_DLL_EXPORT void dumpMaps(maps* m);
+  ZOO_DLL_EXPORT void dumpMapToFile(map*,FILE*); // (used only internally)
+  ZOO_DLL_EXPORT void dumpMapsToFile(maps*,char*,int);
+  ZOO_DLL_EXPORT map* createMap(const char*,const char*);
+  ZOO_DLL_EXPORT maps* createMaps(const char*);
+  ZOO_DLL_EXPORT int count(map*);
+  ZOO_DLL_EXPORT bool hasKey(map*,const char*);
+  ZOO_DLL_EXPORT maps* getMaps(maps*,const char*);
+  ZOO_DLL_EXPORT map* getMap(map*,const char*);
+  ZOO_DLL_EXPORT map* getLastMap(map*);
+  ZOO_DLL_EXPORT map* getMapFromMaps(maps*,const char*,const char*);
+  ZOO_DLL_EXPORT void freeMap(map**);
+  ZOO_DLL_EXPORT void freeMaps(maps** mo);
+  ZOO_DLL_EXPORT iotype* createIoType();
+  ZOO_DLL_EXPORT elements* createEmptyElements();
+  ZOO_DLL_EXPORT elements* createElements(const char*);
+  ZOO_DLL_EXPORT void setElementsName(elements**,char*);
+  ZOO_DLL_EXPORT bool hasElement(elements*,const char*);
+  ZOO_DLL_EXPORT elements* getElements(elements*,char*);
+  ZOO_DLL_EXPORT void freeIOType(iotype**);
+  ZOO_DLL_EXPORT void freeElements(elements**);
+  ZOO_DLL_EXPORT void setServiceName(service**,char*);
+  ZOO_DLL_EXPORT service* createService();
+  ZOO_DLL_EXPORT void freeService(service**);
+  ZOO_DLL_EXPORT void addToMap(map*,const char*,const char*);
+  ZOO_DLL_EXPORT void addIntToMap(map*,const char*,const int);
+  ZOO_DLL_EXPORT void addIntToMapArray(map*,const char*,int,const int);
+  ZOO_DLL_EXPORT map* addToMapWithSize(map*,const char*,const char*,int);
+  ZOO_DLL_EXPORT void addMapToMap(map**,map*);
+  ZOO_DLL_EXPORT void addMapToIoType(iotype**,map*);
+  ZOO_DLL_EXPORT map* getMapOrFill(map**,const char*,const char*);
+  ZOO_DLL_EXPORT bool contains(map*,map*);
+  ZOO_DLL_EXPORT iotype* getIoTypeFromElement(elements*,char*, map*);
+  ZOO_DLL_EXPORT void loadMapBinary(map**,map*,int);
+  ZOO_DLL_EXPORT void loadMapBinaries(map**,map*);
+  ZOO_DLL_EXPORT maps* dupMaps(maps**);
+  ZOO_DLL_EXPORT void addMapsToMaps(maps**,maps*);
+  ZOO_DLL_EXPORT map* getMapArray(map*,const char*,int);
+  ZOO_DLL_EXPORT void setMapArray(map*,const char*,int,const char*);
+  ZOO_DLL_EXPORT map* getMapType(map*);
+  ZOO_DLL_EXPORT int addMapsArrayToMaps(maps**,maps*,char*);
+  ZOO_DLL_EXPORT void setMapInMaps(maps*,const char*,const char*,const char*);
+  ZOO_DLL_EXPORT void dumpElements(elements*);
+  ZOO_DLL_EXPORT void dumpElementsAsYAML(elements*,int);
+  ZOO_DLL_EXPORT elements* dupElements(elements*);
+  ZOO_DLL_EXPORT void addToElements(elements**,elements*);
+  ZOO_DLL_EXPORT void dumpService(service*);
+  ZOO_DLL_EXPORT void dumpServiceAsYAML(service*);
+  ZOO_DLL_EXPORT service* dupService(service*);
+  ZOO_DLL_EXPORT void dumpRegistry(registry*);
+  ZOO_DLL_EXPORT bool addServiceToRegistry(registry**,char*,service*);
+  ZOO_DLL_EXPORT void freeRegistry(registry**);
+  ZOO_DLL_EXPORT service* getServiceFromRegistry(registry*,char*,char*);
+  ZOO_DLL_EXPORT void inheritMap(map**,map*);
+  ZOO_DLL_EXPORT void inheritIOType(iotype**,iotype*);
+  ZOO_DLL_EXPORT void inheritElements(elements**,elements*);
+  ZOO_DLL_EXPORT void inheritance(registry*,service**);
+  ZOO_DLL_EXPORT void mapsToCharXXX(maps*,char***);
+  ZOO_DLL_EXPORT void charxxxToMaps(char***,maps**);
+#if defined(_MSC_VER) && _MSC_VER < 1800
+  // snprintf for Visual Studio compiler;
+  // it is also used by services (e.g., GetStatus), therefore exported to shared library
+  ZOO_DLL_EXPORT int snprintf(char *buffer, size_t n, const char *format, ...);
+#endif
+
+  // knut: some new utility functions; logMessage is primarily intended for debugging 	
+  ZOO_DLL_EXPORT bool nonempty(map* map);
+  ZOO_DLL_EXPORT bool hasvalue(maps* source, const char* node, const char* key, map** kvp);
+#ifdef __cplusplus
+  ZOO_DLL_EXPORT void setErrorMessage(maps*& conf, const char* service, WPSException exc, const char* message = NULL);
+  ZOO_DLL_EXPORT void logMessage(const char* source, const char* function, int line, const char* file = NULL, const char* message = NULL);
+#endif
+  #define zooLogMsg(file,message) logMessage(__FILE__, __func__, __LINE__, (file), (message)) 
+  #define zooLog logMessage(__FILE__, __func__, __LINE__)  
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_callback.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_callback.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_callback.c	(revision 942)
@@ -0,0 +1,878 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2017-2019 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_callback.h"
+#include "service_json.h"
+#include "service_internal_ms.h"
+#include "sqlapi.h"
+#include <pthread.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  /**
+   * Parameter definition to be used for sending parameters to a thread.
+   */
+  typedef struct {
+    maps *conf;      //!< the main configuration file
+    map *url;        //!< the callback url maps
+    json_object *res;//!< the JSON object to post 
+    int step;        //!< the current step [0,6]
+    int state;       //!< the current state [0,1]
+  } local_params;
+
+  /**
+   * Number of threads
+   */
+  int nbThreads=0;
+  /**
+   * Current step
+   */
+  int cStep=0;
+  /**
+   * Is there any ongoing HTTP request
+   */
+  int isOngoing=0;
+  /**
+   * Threads array
+   */
+  pthread_t* myThreads=NULL;
+  /**
+   * Steps array
+   */
+  bool steps[7][2]={
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false},
+    {false,false}
+  };
+  /**
+   * Arguments array to give to the _invokeCallback thread's function
+   */
+  local_params** local_arguments;
+  
+  /**
+   * Check if a service name is prohibited, meaning that the Kernel doesn't have
+   * to invoke the callback for this specific service.
+   *
+   * @param conf the main configuration file maps
+   * @param serviceName the serviceName
+   * @return a bool true if the service is prohibited, false in other case
+   */
+  bool isProhibited(maps* conf,const char* serviceName){
+    map* plist=getMapFromMaps(conf,"callback","prohibited");
+    if(plist!=NULL){
+      char *tmp=plist->value;
+      char *tmpS=strtok(tmp,",");
+      while(tmpS!=NULL){
+	if(strcmp(serviceName,tmpS)==0)
+	  return true;
+	tmpS=strtok(NULL,",");
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Practically invoke the callback, meaning sending the HTTP POST request.
+   * 
+   * @param args local_params containing all the variables required
+   */
+  void* _invokeCallback(void* args){
+    local_params* arg=(local_params*)args;
+    HINTERNET hInternet,res1;
+    const struct tm *tm;
+    size_t len;
+    time_t now;
+    char *tmp1;
+    map *tmpStatus;
+    maps* tmpConf=createMaps("main");
+    tmpConf->content=createMap("memory","load");
+    hInternet=InternetOpen("ZooWPSClient\0",
+			   INTERNET_OPEN_TYPE_PRECONFIG,
+			   NULL,NULL, 0);
+    if(!CHECK_INET_HANDLE(hInternet)){
+      InternetCloseHandle (&hInternet);
+      return NULL;
+    }
+    char *URL=(char*)malloc((strlen(arg->url->value)+5)*sizeof(char));
+    sprintf(URL,"%s%d_%d/",arg->url->value,arg->step,arg->state);
+    const char* jsonStr=json_object_to_json_string_ext(arg->res,JSON_C_TO_STRING_PLAIN);
+    hInternet.waitingRequests[0] = zStrdup(URL);
+    free(URL);
+#ifdef CALLBACK_DEBUG
+    now = time ( NULL );
+    tm = localtime ( &now );
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST PARAMETERS cStep %d %d\n",pthread_self(),__FILE__,__LINE__,cStep,isOngoing);
+    fprintf(stderr," * JSON: [%s] \n",jsonStr);
+    fprintf(stderr," * URL: %s/ \n\n",hInternet.waitingRequests[0]);
+    fprintf(stderr," * DATE: %s/ \n\n",tmp1);
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST PARAMETERS\n",pthread_self(),__FILE__,__LINE__);
+    free(tmp1);
+#endif
+    while( (arg->step!=7 || isOngoing>0) &&
+	   ( cStep!=arg->step || (arg->state!=0 && steps[arg->step][0]==false) )
+	   ){
+      zSleep(100);
+    }
+    isOngoing=1;
+#ifdef CALLBACK_DEBUG
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST START\n\n",pthread_self(),__FILE__,__LINE__);
+    int i=0;
+    for(i=0;i<7;i++){
+      fprintf(stderr,"%d) %d %d\n",i,steps[i][0],steps[i][1]);
+    }
+#endif
+    
+    now = time ( NULL );
+    tm = localtime ( &now );
+    
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+
+#ifdef CALLBACK_DEBUG    
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST START (%s)\n",pthread_self(),__FILE__,__LINE__,tmp1);
+    fflush(stderr);
+#endif    
+    free(tmp1);
+    res1 = InternetOpenUrl (&hInternet,
+			    hInternet.waitingRequests[0], 
+			    (char*)jsonStr, strlen(jsonStr),
+			    INTERNET_FLAG_NO_CACHE_WRITE,
+			    0,tmpConf);
+    AddHeaderEntries(&hInternet,arg->conf);
+    //curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_VERBOSE, 1);x
+    processDownloads(&hInternet);
+    freeMaps(&tmpConf);
+    free(tmpConf);
+    now = time ( NULL );
+    tm = localtime ( &now );
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+    
+#ifdef CALLBACK_DEBUG    
+    fprintf(stderr,"************************* From thread %d %s %d: REQUEST END (%s)\n\n",pthread_self(),__FILE__,__LINE__,tmp1);
+#endif
+    free(tmp1);
+    char *tmp = (char *) malloc ((hInternet.ihandle[0].nDataLen + 1)
+				 * sizeof (char));
+    if (tmp == NULL)
+      {
+	setMapInMaps(arg->conf,"lenv","message",_("Unable to allocate memory"));
+	setMapInMaps(arg->conf,"lenv","code","InternalError");
+	return NULL;
+      }
+    size_t bRead;
+    InternetReadFile (hInternet.ihandle[0],
+		      (LPVOID) tmp,
+		      hInternet.
+		      ihandle[0].nDataLen,
+		      &bRead);
+    tmp[hInternet.ihandle[0].nDataLen] = 0;
+    json_object_put(arg->res);
+    InternetCloseHandle(&hInternet);
+    isOngoing=0;
+    if(cStep==0 || cStep==6 || arg->state==1)
+      cStep=arg->step+1;
+#ifdef CALLBACK_DEBUG
+    now = time ( NULL );
+    tm = localtime ( &now );
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
+    fprintf(stderr,"************************* From thread %d %s %d: RESPONSE CONTENT (%s)\n",pthread_self(),__FILE__,__LINE__,tmp1);
+    for(i=0;i<7;i++){
+      fprintf(stderr,"%d) %d %d\n",i,steps[i][0],steps[i][1]);
+    }
+    fprintf(stderr,"Result: \n%s\n\n",tmp);
+    fprintf(stderr,"************************* From thread %d %s %d\n\n",pthread_self(),__FILE__,__LINE__);
+    fflush(stderr);
+    free(tmp1);
+#endif
+    steps[arg->step][arg->state]=true;
+    free(tmp);
+#ifdef CALLBACK_DEBUG
+    fprintf(stderr,"************************* From thread %d %s %d: EXIT\n\n",pthread_self(),__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    pthread_exit(NULL);
+  }
+  
+  /**
+   * Invoke the callback in case there is a [callback] section containing a url parameter
+   * 
+   * @param m the maps containing the main configuration file definitions
+   * @param inputs the inputs defined in the request (can be null if not yet initialized)
+   * @param inputs the outputs provided in the request (can be null if not yet initialized)
+   * @param step the step number, steps are defined as: 
+   *  0: Analyze creation
+   *  1: Fetching Data Inputs 
+   *  2: Uploading data inputs to cluster
+   *  3: Creating Job Script
+   *  4: Submitting Job to Cluster
+   *  5: Downloading processed output from cluster
+   *  6: Finalize
+   *  7: Dismiss or Error
+   * @param state 0 in case the step starts, 1 when it ends
+   * @return bool true in case of success, false in other cases
+   */
+  bool invokeCallback(maps* conf,maps* inputs,maps* outputs,int step,int state){
+    map* url=getMapFromMaps(conf,"callback","url");
+    if(url==NULL)
+      return false;
+      
+    maps* lenv=getMaps(conf,"lenv");
+    map* sname=getMap(lenv->content,"identifier");
+    if(sname!=NULL && isProhibited(conf,sname->value))
+      return false;
+      
+    json_object *res=json_object_new_object();
+
+    map* sid=getMapFromMaps(conf,"lenv","usid");
+    if(sid!=NULL){
+      json_object *jsStr=json_object_new_string(sid->value);
+      json_object_object_add(res,"jobid",jsStr);
+    }
+    const struct tm *tm;
+    size_t len;
+    time_t now;
+    char *tmp1;
+    map *tmpStatus;
+  
+    now = time ( NULL );
+    tm = localtime ( &now );
+
+    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
+    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm );
+    json_object *jsStr0=json_object_new_string(tmp1);
+    json_object_object_add(res,"datetime",jsStr0);
+    free(tmp1);
+    
+    switch(step){
+    case 0: {
+      // Create a new analyze
+      maps* lenv=getMaps(conf,"lenv");
+      sid=getMapFromMaps(conf,"renv","xrequest");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"request_execute_content",jsStr);
+      }
+      sid=getMapFromMaps(conf,"lenv","identifier");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"process_identifier",jsStr);
+      }
+      // Save the Execute request on disk 
+      map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+      map* req=getMapFromMaps(conf,"renv","xrequest");
+      sid=getMapFromMaps(conf,"lenv","usid");
+      char* executePath=(char*)malloc((strlen(tmpPath->value)+strlen(sid->value)+14)*sizeof(char));
+      sprintf(executePath,"%s/execute_%s.xml",tmpPath->value,sid->value);
+      FILE* saveExecute=fopen(executePath,"wb");
+      fwrite(req->value,1,strlen(req->value)*sizeof(char),saveExecute);
+      fflush(saveExecute);
+      fclose(saveExecute);
+      setMapInMaps(conf,"lenv","execute_file",executePath);
+      free(executePath);
+      break;
+    }
+      
+    case 1: {
+      // Update the execute request stored on disk at step 0,0 to modify the references used.
+      if(state==1){
+	maps* curs=inputs;
+	xmlInitParser();
+	map* xmlPath=getMapFromMaps(conf,"lenv","execute_file");
+	while(curs!=NULL){
+	  map* length=getMap(curs->content,"length");
+	  map* useMS=getMap(curs->content,"useMapserver");
+	  if(length==NULL){
+	    addToMap(curs->content,"length","1");
+	    length=getMap(curs->content,"length");
+	  }
+	  int len=atoi(length->value);
+	  for(int ii=0;ii<len;ii++){
+	    if(getMapArray(curs->content,"byValue",ii)!=NULL && getMapArray(curs->content,"mimeType",ii)!=NULL && useMS!=NULL && strncasecmp(useMS->value,"true",4)==0){
+	      map* tmpMap=getMapArray(curs->content,"value",ii);
+	      char tmpStr[100];
+	      sprintf(tmpStr,"%d",strlen(tmpMap->value));
+	      setMapArray(curs->content,"size",ii,tmpStr);
+	      tmpMap=getMapArray(curs->content,"mimeType",ii);
+	      setMapArray(curs->content,"fmimeType",ii,tmpMap->value);
+	      tmpMap=getMapArray(curs->content,"cache_file",ii);
+	      setMapArray(curs->content,"generated_file",ii,tmpMap->value);
+	      setMapArray(curs->content,"storage",ii,tmpMap->value);
+	      setReferenceUrl(conf,curs);
+	      addIntToMap(curs->content,"published_id",ii+1);
+	      const char *params[7];
+	      int xmlLoadExtDtdDefaultValue;
+	      int hasFile=-1;
+	      map* xslPath=getMapFromMaps(conf,"callback","template");
+	      map* filePath=getMapArray(curs->content,"ref_wfs_link",ii);
+	      if(filePath==NULL)
+		filePath=getMap(curs->content,"ref_wcs_link");
+	      char* inputName=curs->name;
+	      if(xslPath==NULL || xmlPath==NULL || filePath==NULL)
+		break;
+	      char *tmpParam=(char*)malloc((strlen(curs->name)+11)*sizeof(char));
+	      char *tmpParam1=(char*)malloc((strlen(filePath->value)+11)*sizeof(char));
+	      char tmpParam2[16];
+	      sprintf(tmpParam2,"string(\"%d\")",ii);
+	      setMapArray(curs->content,"href",ii,filePath->value);
+	      setMapArray(curs->content,"xlink:href",ii,filePath->value);
+	      tmpMap=getMapArray(curs->content,"cache_url",ii);
+	      if(tmpMap!=NULL)
+		setMapArray(curs->content,"xlink:href",ii,tmpMap->value);
+	      else
+		setMapArray(curs->content,"xlink:href",ii,filePath->value);
+	      sprintf(tmpParam,"string(\"%s\")",curs->name);
+	      sprintf(tmpParam1,"string(\"%s\")",filePath->value);
+	      sprintf(tmpParam2,"string(\"%d\")",ii);
+	      params[0]="attr";
+	      params[1]=tmpParam;
+	      params[2]="value";
+	      params[3]=tmpParam1;//filePath->value;
+	      params[4]="cnt";
+	      params[5]=tmpParam2;
+	      params[6]=NULL;
+	      fprintf(stderr, "## XSLT PARAMETERS ATTR: %s VALUE: %s INDEX: %s\n",
+		      tmpParam,tmpParam1,tmpParam2);
+	      fflush(stderr);
+	      xmlSubstituteEntitiesDefault(1);
+	      xmlLoadExtDtdDefaultValue = 0;
+	      xsltStylesheetPtr cur = NULL;
+	      xmlDocPtr doc, res;
+	      cur = xsltParseStylesheetFile(BAD_CAST xslPath->value);
+	      doc = xmlParseFile(xmlPath->value);
+	      fflush(stderr);
+	      res = xsltApplyStylesheet(cur, doc, params);
+	      xmlChar *xmlbuff;
+	      int buffersize;
+	      xmlDocDumpFormatMemory(res, &xmlbuff, &buffersize, 1);
+	      // Store the executeRequest in file again
+	      free(tmpParam);
+	      free(tmpParam1);
+	      fprintf(stderr," # Request / XSLT: %s\n",xmlbuff);
+	      fflush(stderr);
+	      FILE* saveExecute=fopen(xmlPath->value,"wb");
+	      if(saveExecute!=NULL){
+		fwrite(xmlbuff,1,buffersize,saveExecute);
+		fflush(saveExecute);
+		fclose(saveExecute);
+	      }
+	      xmlFree(xmlbuff);
+	      xmlFreeDoc(doc);
+	      xsltFreeStylesheet(cur);
+	    }
+	  }
+	  addIntToMap(curs->content,"published_id",0);
+	  curs=curs->next;
+	}
+	xmlCleanupParser();
+	FILE* f0=fopen(xmlPath->value,"rb");
+	if(f0!=NULL){
+	  long flen;
+	  char *fcontent;
+	  fseek (f0, 0, SEEK_END);
+	  flen = ftell (f0);
+	  fseek (f0, 0, SEEK_SET);
+	  fcontent = (char *) malloc ((flen + 1) * sizeof (char));
+	  fread(fcontent,flen,1,f0);
+	  fcontent[flen]=0;
+	  fclose(f0);
+	  map *schema=getMapFromMaps(conf,"database","schema");
+	  map* sid=getMapFromMaps(conf,"lenv","usid");
+	  char *req=(char*)malloc((flen+strlen(schema->value)+strlen(sid->value)+66)*sizeof(char));
+	  sprintf(req,"UPDATE %s.services set request_execute_content=$$%s$$ WHERE uuid=$$%s$$",schema->value,fcontent,sid->value);
+#ifdef RELY_ON_DB
+	  execSql(conf,1,req);
+#endif
+	  free(fcontent);
+	  free(req);
+	}
+      }
+
+      // Fetching data inputs
+      maps* curs=inputs;
+      dumpMaps(curs);
+      const char *keys[11][2]={
+	{
+	  "xlink:href",
+	  "ref_download_link"
+	},
+	{
+	  "cache_file",
+	  "cachefile"
+	},
+	{
+	  "fmimeType",
+	  "mimetype"
+	},
+	{
+	  "size",
+	  "size"
+	},
+	{
+	  "ref_wms_link",
+	  "ref_wms_link"
+	},
+	{
+	  "ref_wfs_link",
+	  "ref_wfs_link"
+	},
+	{
+	  "ref_wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "ref_wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "ref_wcs_preview_link",
+	  "ref_wcs_preview_link"
+	},
+	{
+	  "geodatatype",
+	  "datatype"
+	},
+	{
+	  "wgs84_extent",
+	  "boundingbox"
+	}	
+      };
+      json_object *res1=json_object_new_object();
+      while(curs!=NULL){
+	if(getMap(curs->content,"length")==NULL){
+	  addToMap(curs->content,"length","1");
+	}
+	map* length=getMap(curs->content,"length");
+	int len=atoi(length->value);
+	json_object *res3;
+	int hasRef=-1;
+	for(int ii=0;ii<len;ii++){
+	  map* tmpMap=getMapArray(curs->content,"cache_file",ii);
+	  sid=getMapArray(curs->content,"ref_wms_link",ii);
+	  json_object *res2=json_object_new_object();
+	  if(tmpMap!=NULL){
+	    if(sid==NULL){
+	      setMapArray(curs->content,"generated_file",ii,tmpMap->value);
+	      setMapArray(curs->content,"storage",ii,tmpMap->value);
+	    }
+	    struct stat buf;
+	    char timeStr[ 100 ] = "";
+	    if (stat(tmpMap->value, &buf)==0){
+	      strftime(timeStr, 100, "%d-%m-%Y %H:%M:%S", localtime( &buf.st_mtime));
+	      json_object *jsStr=json_object_new_string(timeStr);
+	      json_object_object_add(res2,"creation_date",jsStr);
+	    }
+	    tmpMap=getMapArray(curs->content,"fmimeType",ii);
+	    if(tmpMap!=NULL){
+	      setMapArray(curs->content,"mimeType",ii,tmpMap->value);
+	    }
+	    setReferenceUrl(conf,curs);
+	  }else{	  
+	  }
+	  addIntToMap(curs->content,"published_id",ii+1);
+	  int i=0;
+	  for(;i<11;i++){
+	    sid=getMapArray(curs->content,keys[i][0],ii);
+	    if(sid!=NULL){
+	      json_object *jsStr=json_object_new_string(sid->value);
+	      json_object_object_add(res2,keys[i][1],jsStr);
+	      if(i==0){
+		hasRef=1;
+		json_object *jsStr1=json_object_new_string(getProvenance(conf,sid->value));
+		json_object_object_add(res2,"dataOrigin",jsStr1);
+	      }
+	    }
+	  }
+	  if(len>1){
+	    if(ii==0)
+	      res3=json_object_new_array();
+	    json_object_array_add(res3,res2);
+	  }else
+	    res3=res2;
+	}
+	if(hasRef<0)
+	  json_object_put(res3);
+	else{
+	  json_object_object_add(res1,curs->name,json_object_get(res3));
+	  json_object_put(res3);
+	}
+	addIntToMap(curs->content,"published_id",0);
+	curs=curs->next;
+      }
+      json_object_object_add(res,"inputs",res1);
+      break;
+    }
+      
+    case 2: {
+      // Uploading data input to cluster
+      maps* in=getMaps(conf,"uploadQueue");
+      if(in!=NULL){
+	maps* curs=in;
+	map* length=getMapFromMaps(in,"uploadQueue","length");
+	if(length!=NULL){
+	  json_object *res1=json_object_new_object();
+	  int limit=atoi(length->value);
+	  int i=0;
+	  maps* uploadQueue=getMaps(in,"uploadQueue");
+	  map* tmp=uploadQueue->content;
+	  for(;i<limit;i++){
+	    map* tmp0=getMapArray(tmp,"input",i);
+	    map* tmp1=getMapArray(tmp,"localPath",i);
+	    map* tmp2=getMapArray(tmp,"targetPath",i);
+	    if(tmp0!=NULL && tmp1!=NULL && tmp2!=NULL){
+	      json_object *res2=json_object_new_object();
+	      json_object *jsStr=json_object_new_string(tmp1->value);
+	      json_object_object_add(res2,"local_path",jsStr);
+	      jsStr=json_object_new_string(tmp2->value);
+	      json_object_object_add(res2,"target_path",jsStr);
+	      json_object *res4=json_object_object_get(res1,tmp0->value);
+	      if(json_object_is_type(res4,json_type_null)){
+		json_object_object_add(res1,tmp0->value,res2);
+	      }else{
+		if(json_object_is_type(res4,json_type_object) && !json_object_is_type(res4, json_type_array)){
+		  json_object *res3=json_object_new_array();
+		  json_object_array_add(res3,json_object_get(res4));
+		  json_object_array_add(res3,res2);
+		  json_object_object_del(res1,tmp0->value);
+		  json_object_object_add(res1,tmp0->value,res3);
+		}else
+		  json_object_array_add(res4,res2);
+	      }
+	    }
+	  }
+	  json_object_object_add(res,"inputs",res1);
+	}
+      }
+      break;
+    }
+      
+    case 3: {
+      // Generating job script
+      sid=getMapFromMaps(conf,"lenv","local_script");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"script",jsStr);
+      }
+      break;
+    }
+      
+    case 4: {
+      // Submitting job to cluster
+      sid=getMapFromMaps(conf,"lenv","remote_script");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"script",jsStr);
+      }
+      break;
+    }
+      
+    case 5: {
+      // Downloading process outputs from cluster
+      maps* curs=outputs;
+      dumpMaps(curs);
+      const char *keys[10][2]={
+	{
+	  "Reference",
+	  "ref"
+	},
+	{
+	  "generated_file",
+	  "cachefile"
+	},
+	{
+	  "mimeType",
+	  "mimetype"
+	},
+	{
+	  "size",
+	  "size"
+	},
+	{
+	  "geodatatype",
+	  "datatype"
+	},
+	{
+	  "wgs84_extent",
+	  "boundingbox"
+	},
+	{
+	  "ref_wms_link",
+	  "ref_wms_link"
+	},
+	{
+	  "ref_wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "ref_wcs_preview_link",
+	  "ref_wcs_preview_link"
+	},
+	{
+	  "ref_wfs_link",
+	  "ref_wfs_link"
+	}	
+      };
+      const char* specifics[5][2]={
+	{
+	  "download_link",
+	  "ref_download_link"
+	},
+	{
+	  "wms_link",
+	  "ref_wms_link"
+	},
+	{
+	  "wfs_link",
+	  "ref_wfs_link"
+	},
+	{
+	  "wcs_link",
+	  "ref_wcs_link"
+	},
+	{
+	  "wcs_link",
+	  "ref_wcs_preview_link"
+	}
+      };
+      json_object *res1=json_object_new_object();
+      while(curs!=NULL){	
+	json_object *res2=json_object_new_object();
+	int i=0;
+	int hasRef=-1;
+	for(;i<10;i++){
+	  sid=getMap(curs->content,keys[i][0]);
+	  if(sid!=NULL){
+	    json_object *jsStr=json_object_new_string(sid->value);
+	    json_object_object_add(res2,keys[i][1],jsStr);
+	    if(i==0){
+	      hasRef=1;
+	      json_object_object_add(res2,"ref_download_link",jsStr);
+	    }
+	    if(i==1){
+	      struct stat buf;
+	      char timeStr[ 100 ] = "";
+	      if (stat(sid->value, &buf)==0){
+		strftime(timeStr, 100, "%d-%m-%Y %H:%M:%S", localtime( &buf.st_mtime));
+		json_object *jsStr=json_object_new_string(timeStr);
+		json_object_object_add(res2,"creation_date",jsStr);
+	      }
+	    }
+	  }
+	}
+	if(hasRef>0)
+	  json_object_object_add(res1,curs->name,res2);
+	else{
+	  maps* curs0=curs->child;
+	  int i=0;
+	  int bypass=-1;
+	  for(i=0;i<5;i++){
+	    maps* specificMaps;
+	    if((specificMaps=getMaps(curs0,specifics[i][0]))!=NULL){
+	      int hasRef0=-1;
+	      int i0=0;
+	      for(;i0<6;i0++){
+		sid=getMap(specificMaps->content,keys[i0][0]);
+		if(sid!=NULL){
+		  json_object *jsStr=json_object_new_string(sid->value);
+		  if(i0==0){
+		    json_object_object_add(res2,specifics[i][1],jsStr);
+		  }
+		  else
+		    json_object_object_add(res2,keys[i0][1],jsStr);
+		  hasRef0=1;
+		  bypass=1;
+		  if(i==1){
+		    struct stat buf;
+		    char timeStr[ 100 ] = "";
+		    if (stat(sid->value, &buf)==0){
+		      strftime(timeStr, 100, "%d-%m-%Y %H:%M:%S", localtime( &buf.st_mtime));
+		      json_object *jsStr=json_object_new_string(timeStr);
+		      json_object_object_add(res2,"creation_date",jsStr);
+		    }
+		  }
+		}
+	      }	      
+	    }
+	  }
+	  if(bypass<0)
+	    while(curs0!=NULL){
+	      json_object *res3=json_object_new_object();
+	      int i0=0;
+	      int hasRef0=-1;
+	      for(;i0<10;i0++){
+		sid=getMap(curs0->content,keys[i0][0]);
+		if(sid!=NULL){
+		  json_object *jsStr=json_object_new_string(sid->value);
+		  json_object_object_add(res3,keys[i0][1],jsStr);
+		  hasRef0=1;
+		}
+	      }
+	      if(hasRef0<0)
+		json_object_put(res3);
+	      else
+		json_object_object_add(res2,curs0->name,res3);
+	      curs0=curs0->next;
+	    }
+	  json_object_object_add(res1,curs->name,res2);
+	}
+	curs=curs->next;
+      }
+      json_object_object_add(res,"outputs",res1);
+      break;
+    }
+      
+    case 6: {
+      // Finalize HPC
+      const char *keys[6][2]={
+	{
+	  //"SubmitTime",
+	  "Submit",
+	  "hpc_submission_date"
+	},
+	{
+	  "JobId",
+	  "hpc_job_identifier"
+	},
+	{
+	  "JobName",
+	  "hpc_job_name"
+	},
+	{
+	  //"StartTime",
+	  "Start",
+	  "hpc_start_date"
+	},
+	{
+	  //"EndTime",
+	  "End",
+	  "hpc_end_date"
+	},
+	{
+	  //"JobState",
+	  "State",
+	  "hpc_status"
+	}	
+      };
+      int i=0;
+      if(getMaps(conf,"henv")!=NULL){
+	for(i=0;i<6;i++){
+	  sid=getMapFromMaps(conf,"henv",keys[i][0]);
+	  if(sid!=NULL){
+	    json_object *jsStr=json_object_new_string(sid->value);
+	    json_object_object_add(res,keys[i][1],jsStr);
+	  }
+	}
+      }
+      if((sid=getMapFromMaps(conf,"henv","billing_nb_cpu"))!=NULL){
+        json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"hpc_cpu_usage",jsStr);
+      }else{
+	json_object *jsStr=json_object_new_string("1");
+	json_object_object_add(res,"hpc_cpu_usage",jsStr);
+      }
+      json_object *jsStr=json_object_new_string("succeeded");
+      json_object_object_add(res,"wps_status",jsStr);
+      break;
+    }
+      
+    case 7: {
+      // Error or Dismiss
+      sid=getMapFromMaps(conf,"lenv","message");
+      if(sid!=NULL){
+	json_object *jsStr=json_object_new_string(sid->value);
+	json_object_object_add(res,"message",jsStr);
+      }
+      json_object *jsStr;
+      if(state==1)
+	jsStr=json_object_new_string("dismissed");
+      else
+	jsStr=json_object_new_string("failed");
+      json_object_object_add(res,"wps_status",jsStr);
+      break;
+    }
+    others: {
+	break;
+      }
+    }
+
+    if(local_arguments==NULL)
+      local_arguments=(local_params**)malloc(sizeof(local_params*));
+    else
+      local_arguments=(local_params**)realloc(local_arguments,(nbThreads+1)*sizeof(local_params*));
+    local_arguments[nbThreads]=(local_params*)malloc(MAPS_SIZE+MAP_SIZE+sizeof(json_object*)+(2*sizeof(int)));	
+    local_arguments[nbThreads]->conf=conf;
+    local_arguments[nbThreads]->url=url;
+    local_arguments[nbThreads]->res=res;
+    local_arguments[nbThreads]->step=step;
+    local_arguments[nbThreads]->state=state;
+    if(myThreads==NULL)
+      myThreads=(pthread_t*)malloc((nbThreads+1)*sizeof(pthread_t));
+    else
+      myThreads=(pthread_t*)realloc(myThreads,(nbThreads+1)*sizeof(pthread_t));
+    if(pthread_create(&myThreads[nbThreads], NULL, _invokeCallback, (void*)local_arguments[nbThreads])==-1){
+      setMapInMaps(conf,"lenv","message",_("Unable to create a new thread"));
+      return false;
+    }
+    nbThreads++;
+    return true;
+  }
+
+  /**
+   * Wait for the threads to end then, clean used memory.
+   */
+  void cleanupCallbackThreads(){
+    int i=0;
+    for(i=0;i<nbThreads;i++){
+      pthread_join(myThreads[i],NULL);
+      free(local_arguments[i]);
+    }
+    free(local_arguments);
+    free(myThreads);
+  }
+
+#ifdef __cplusplus
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_callback.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_callback.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_callback.h	(revision 942)
@@ -0,0 +1,49 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2014 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_CALLBACK_H
+#define ZOO_CALLBACK_H 1
+
+#pragma once
+
+#include <stdio.h>
+#include <ctype.h>
+#include <service.h>
+#include <ulinet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  bool invokeCallback(maps*,maps*,maps*,int,int);
+  void cleanupCallbackThreads();
+  
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_conf.l
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_conf.l	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_conf.l	(revision 942)
@@ -0,0 +1,102 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 209-2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+%option noyywrap
+%option yylineno
+
+
+%{
+
+#include <string.h>
+#include "service_conf.tab.h"
+
+char *lmsg=NULL;
+
+%}
+
+S		[ \t\r\n]+
+
+CharRef		"&#"[0-9]+";"|"&#x"[0-9a-fA-F]+";"
+
+egalevolue		{S}?"="{S}?
+
+Name		([_:]|[\x41-\x5A]|[\x61-\x7A]|[\xC0-\xD6]|[\xD8-\xF6]|[\xF8-\xFF])(([\x41-\x5A]|[\x61-\x7A]|[\xC0-\xD6]|[\xD8-\xF6]|[\xF8-\xFF])|[0-9.\-_:])*
+
+chardata	[^<]*
+
+attname	[a-zA-Z0-9._\-]+
+attvalue1      [\x80-\xbf\xc2-\xdf\xe0-\xef\xf0-\xf4="#°²θé\^\*\+\,\;;?!~`Ãº@a-zA-Z0-9%_\-:\:.:" "\"\'/\\\(\)\t\|\$\&>\[\]]+
+
+attvalue		\"[^"]*\"|\'[^']*\'\(\)
+
+whitespace                      [\t]{0,}|[ ]{0,}
+whitesp                      [\t]|[ ]
+newline                 [\r\n]|[\n]
+newlines                 [\r\n]{1,}|[\n]{1,}
+
+
+%x DANSBALISE HORSBALISE PAIRSTART
+
+
+
+
+%%
+
+"\n" { }
+
+{newline}+{whitesp}*			{ return NEWLINE; }
+
+<INITIAL,HORSBALISE>"["{attname}"]"             {  srlval.chaine=yytext;return ANID; }
+
+<INITIAL,HORSBALISE>{attname}             {  srlval.chaine=yytext; return SPAIR; }
+
+<PAIRSTART,HORSBALISE>{attvalue1}             { srlval.chaine=yytext;/*BEGIN(INITIAL);*/ return EPAIR;}
+
+<PAIRSTART,INITIAL,HORSBALISE>{whitesp}*"="{whitesp}*             {  BEGIN(PAIRSTART);}
+
+<PAIRSTART,INITIAL,HORSBALISE>{newline}+{whitesp}*             { BEGIN(INITIAL);  return NEWLINE;}
+
+<DANSBALISE,INITIAL,HORSBALISE>{S}   {  }
+
+<INITIAL,HORSBALISE>{newline}*"<"		    { BEGIN(DANSBALISE); return INFCAR;}
+
+
+<DANSBALISE>">"			{ BEGIN(HORSBALISE);return SUPCAR;}
+
+
+<DANSBALISE>"/"		{return SLASH;}
+
+
+<DANSBALISE>{egalevolue}			{return Eq;}
+
+
+<DANSBALISE>{Name}{newline}*			{memmove(srlval.chaine,yytext,(strlen(yytext)+1)*sizeof(char));return ID;}
+
+
+<DANSBALISE>{attvalue}		{return ATTVALUE;}
+
+
+<INITIAL,DANSBALISE,HORSBALISE>.|\n	{lmsg=(char*)malloc(1024*sizeof(char));sprintf(lmsg,"error: line %d: character not allowed '%s'",srlineno,yytext);fprintf(stderr,"%s \n",lmsg);srlval.chaine=lmsg;fprintf(stderr,"%s \n",lmsg);return -1;}
+
+%%
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_conf.y
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_conf.y	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_conf.y	(revision 942)
@@ -0,0 +1,1033 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 209-2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+%{
+
+#include <string>
+#include <stdio.h>
+#include <ctype.h>
+#include <service.h>
+
+static int tmp_count=1;
+static int defaultsc=0;
+static bool wait_maincontent=true;
+static bool wait_mainmetadata=false;
+static bool wait_mainap=false;
+static bool wait_metadata=false;
+static bool wait_ap=false;
+static bool wait_nested=false;
+static bool wait_inputs=false;
+static bool wait_defaults=false;
+static bool wait_supporteds=false;
+static bool wait_outputs=false;
+static bool wait_data=false;
+static service* my_service=NULL;
+static map* current_content=NULL;
+static elements* current_element=NULL;
+static char* curr_key;
+static int debug=0;
+static int data=-1;
+static int previous_data=0;
+static int current_data=0;
+static int nested_level=0;
+// namespace
+using namespace std;
+
+// srerror
+void srerror(const char *s);
+
+// usage ()
+void usage(void) ;
+
+// srdebug
+extern int srdebug;
+
+extern char srtext[];
+
+// srlineno
+extern int srlineno;
+
+// srin
+extern FILE* srin;
+
+// srlex
+extern int srlex(void);
+extern int srlex_destroy(void);
+
+%}
+
+
+
+%union 
+{char * s;char* chaine;char* key;char* val;}
+
+// jetons //
+%token <s> ID
+%token <s> CHAINE
+
+%token INFCAR SUPCAR 
+
+/* / = a1  texte "texte" */
+%token SLASH Eq CHARDATA ATTVALUE PAIR SPAIR EPAIR ANID
+%type <chaine> PAIR
+%type <chaine> EPAIR
+%type <chaine> SPAIR
+
+/* <!-- xxx -> <? xxx yyy ?> */
+%token PI PIERROR /** COMMENT **/
+
+/* <!-- xxx -> <? xxx yyy ?> */
+%token ERREURGENERALE CDATA WHITESPACE NEWLINE
+%type <s> STag
+%type <s> ETag
+%type <s> ANID
+
+// % start
+
+%%
+// document 
+// regle 1
+// on est a la racine du fichier xml
+document
+ : miscetoile element miscetoile {}
+ | contentetoile processid contentetoile document {}
+ ;
+
+miscetoile
+ : miscetoile PIERROR {  srerror("processing instruction beginning with <?xml ?> impossible\n");}
+ | miscetoile PI {}
+ | {}
+ ;
+// element
+// regle 39
+// OUVRANTE CONTENU FERMANTE obligatoirement
+// ou neutre
+// on ne peut pas avoir Epsilon
+// un fichier xml ne peut pas etre vide ou seulement avec un prolog
+element
+ : STag contentetoile ETag	
+{
+}
+
+// pour neutre
+// on a rien a faire, meme pas renvoyer l identificateur de balise
+// vu qu'il n y a pas de comparaison d'identificateurs avec un balise jumelle .
+ | EmptyElemTag          {}
+ ;
+
+// STag
+// regle 40
+// BALISE OUVRANTE
+// on est obligé de faire appel a infcar et supcar
+// pour acceder aux start conditions DANSBALISE et INITIAL
+STag
+: INFCAR ID Attributeetoile SUPCAR
+{
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"STag (%s %d) %s %d %d \n",__FILE__,__LINE__,$2,current_data,previous_data);
+  fflush(stderr);
+  dumpMap(current_content);
+#endif
+  if(my_service->content==NULL && current_content!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+    fprintf(stderr,"NO CONTENT\n");
+#endif
+    addMapToMap(&my_service->content,current_content);
+    freeMap(&current_content);
+    free(current_content);
+    current_content=NULL;
+    my_service->metadata=NULL;
+    my_service->additional_parameters=NULL;
+    wait_maincontent=false;
+  }
+  if(strncasecmp($2,"EndNested",9)==0){
+#ifdef DEBUG_SERVICE_CONF
+    fprintf(stderr,"(ENDNESTED - %d) \n",__LINE__);
+    fflush(stderr);
+#endif
+    nested_level-=1;
+    if(nested_level==0){
+      wait_nested=false;
+    }
+  }
+
+  if(strncasecmp($2,"DataInputs",10)==0){
+    if(current_element==NULL){
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"(DATAINPUTS - %d) FREE current_element\n",__LINE__);
+#endif
+      freeElements(&current_element);
+      free(current_element);
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"(DATAINPUTS - %d) ALLOCATE current_element\n",__LINE__);
+#endif
+      current_element=NULL;
+      current_element=createEmptyElements();
+    }
+    wait_inputs=true;
+    current_data=1;
+    previous_data=1;
+  }
+  else
+    if(strncasecmp($2,"DataOutputs",11)==0){
+      if(wait_inputs==true){
+#ifdef DEBUG_SERVICE_CONF
+	fprintf(stderr,"(DATAOUTPUTS %d) DUP INPUTS current_element\n",__LINE__);
+	fprintf(stderr,"CURRENT_ELEMENT\n");
+	dumpElements(current_element);
+	fprintf(stderr,"SERVICE INPUTS\n");
+	dumpElements(my_service->inputs);
+	dumpService(my_service);
+#endif	
+	if(my_service->inputs==NULL && current_element!=NULL && current_element->name!=NULL){
+	  my_service->inputs=dupElements(current_element);
+	  my_service->inputs->next=NULL;
+	  freeElements(&current_element);
+	}
+	else if(current_element!=NULL && current_element->name!=NULL){
+	  addToElements(&my_service->inputs,current_element);
+	  freeElements(&current_element);
+	}
+#ifdef DEBUG_SERVICE_CONF
+	fprintf(stderr,"CURRENT_ELEMENT\n");
+	dumpElements(current_element);
+	fprintf(stderr,"SERVICE INPUTS\n");
+	dumpElements(my_service->inputs);
+	fprintf(stderr,"(DATAOUTPUTS) FREE current_element\n");
+#endif
+	free(current_element);
+	current_element=NULL;
+	wait_inputs=false;
+      }
+      if(current_element==NULL){
+#ifdef DEBUG_SERVICE_CONF
+	fprintf(stderr,"(DATAOUTPUTS - %d) ALLOCATE current_element (%s)\n",__LINE__,$2);
+	fflush(stderr);
+#endif
+	current_element=createEmptyElements();
+      }
+      wait_outputs=1;
+      current_data=2;
+      previous_data=2;
+    }
+    else
+      if(strncasecmp($2,"MetaData",8)==0 ||
+	 strncasecmp($2,"AdditionalParameters",8)==0){
+	if(strncasecmp($2,"AdditionalParameters",8)==0){
+	  previous_data=current_data;
+	  current_data=4;
+	  if(current_element!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"add current_content to current_element->content\n");
+	    fprintf(stderr,"LINE %d",__LINE__);
+#endif
+	    if(wait_mainmetadata)
+	      addMapToMap(&my_service->metadata,current_content);
+	    else
+	      if(wait_metadata)
+		addMapToMap(&current_element->metadata,current_content);
+	      else
+		addMapToMap(&current_element->content,current_content);		
+	    freeMap(&current_content);
+	    free(current_content);
+	    if(previous_data==1 || previous_data==2)
+	      wait_ap=true;
+	    else
+	      wait_mainap=true;
+	  }
+	  else{
+	    if(previous_data==1 || previous_data==2)
+	      wait_ap=true;
+	    else
+	      wait_mainap=true;
+	  }
+	}else{
+	  previous_data=current_data;
+	  current_data=3;
+	  if(current_element!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"add current_content to current_element->content\n");
+	    fprintf(stderr,"LINE %d",__LINE__);
+#endif
+	    addMapToMap(&current_element->content,current_content);
+	    freeMap(&current_content);
+	    free(current_content);
+	    if(previous_data==1 || previous_data==2)
+	      wait_metadata=true;
+	    else
+	      wait_mainmetadata=true;
+	  }
+	  else{
+	    if(previous_data==1 || previous_data==2)
+	      wait_metadata=true;
+	    else
+	      wait_mainmetadata=true;
+	  }
+	}
+	current_content=NULL;
+      }
+      else
+	if(strncasecmp($2,"ComplexData",11)==0 || strncasecmp($2,"LiteralData",10)==0
+	   || strncasecmp($2,"ComplexOutput",13)==0 || strncasecmp($2,"LiteralOutput",12)==0
+	   || strncasecmp($2,"BoundingBoxOutput",13)==0 || strncasecmp($2,"BoundingBoxData",12)==0){
+	  current_data=4;
+	  addMapToMap(&current_element->content,current_content);
+	  freeMap(&current_content);
+	  free(current_content);
+	  current_element->next=NULL;
+	  if($2!=NULL)
+	    current_element->format=zStrdup($2);
+	  current_element->defaults=NULL;
+	  current_element->supported=NULL;
+	  current_element->child=NULL;
+	  current_content=NULL;
+	}
+	else
+	  if(strncasecmp($2,"Default",7)==0){
+	    wait_defaults=true;
+	    current_data=5;
+	  }
+	  else
+	    if(strncasecmp($2,"Supported",9)==0){
+	      wait_supporteds=true;
+	      if(wait_defaults==true){
+		defaultsc++;
+	      }
+	      current_data=5;
+	    }
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"* Identifiant : %s\n",$2);
+  fflush(stderr);
+#endif
+}
+ ;
+
+// Attributeetoile
+// regle 41
+// une liste qui peut etre vide d'attributs
+// utiliser la récursivité a gauche
+Attributeetoile
+: Attributeetoile attribute  {}
+ | 	                          {/* Epsilon */}
+ ;
+
+// attribute
+// regle 41
+// un attribut est compose d'un identifiant
+// d'un "="
+// et d'une définition de chaine de caractere
+// ( "xxx" ou 'xxx' )
+attribute
+ : ID Eq ATTVALUE		
+{
+#ifdef DEBUG_SERVICE_CONF
+  printf ("attribute : %s\n",$1) ;
+#endif
+}
+ ;
+
+// EmptyElemTag
+// regle 44
+// ICI ON DEFINIT NEUTRE
+// on ne renvoie pas de char*
+// parce qu'il n'y a pas de comparaisons a faire
+// avec un identifiant d'une balise jumelle
+EmptyElemTag
+ : INFCAR ID Attributeetoile SLASH SUPCAR	{
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"(%s %d)\n",__FILE__,__LINE__);
+#endif
+   if(strncasecmp($2,"Default",7)==0){
+     wait_defaults=false;
+     current_data=previous_data;
+     if(current_element->defaults==NULL){
+       current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+       current_element->defaults->content=NULL;
+     }
+     addMapToMap(&current_element->defaults->content,current_content);
+     freeMap(&current_content);
+     free(current_content);
+     current_element->defaults->next=NULL;
+     wait_defaults=false;
+     current_content=NULL;
+     current_element->supported=NULL;
+     current_element->child=NULL;
+     current_element->next=NULL;
+   }
+   if(strncasecmp($2,"EndNested",9)==0){
+     if(current_data==1){
+       elements* cursor=my_service->inputs;
+       while(cursor->next!=NULL)
+	 cursor=cursor->next;
+       if(nested_level>1){
+	 for(int j=0;j<nested_level-1;j++){
+	   cursor=cursor->child;
+	   while(cursor->next!=NULL)
+	     cursor=cursor->next;
+	 }
+       }
+       if(cursor->child==NULL){
+	 cursor->child=dupElements(current_element);
+       }else{
+	 addToElements(&cursor->child,current_element);
+       }
+     }else{
+       if(current_element->name!=NULL){
+	 elements* cursor=my_service->outputs;
+	 while(cursor->next!=NULL)
+	   cursor=cursor->next;
+	 if(nested_level>1){
+	   for(int j=0;j<nested_level-1;j++){
+	     cursor=cursor->child;
+	     while(cursor->next!=NULL)
+	       cursor=cursor->next;
+	   }
+	 }
+	 if(cursor->child==NULL){
+	   cursor->child=dupElements(current_element);
+	 }else
+	   addToElements(&cursor->child,current_element);
+       }
+     }
+     freeElements(&current_element);
+     free(current_element);
+     current_element=NULL;
+     current_element=createEmptyElements();
+     nested_level-=1;
+     if(nested_level==0){
+       wait_nested=false;       
+     }
+   }
+ }
+ ;
+
+// ETag
+// BALISE FERMANTE
+// les separateurs après ID sont filtrés
+ETag
+ : INFCAR SLASH ID SUPCAR
+{
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"ETag %s (%s %d) %d %d \n",$3,__FILE__,__LINE__,current_data,previous_data);
+#endif
+  if(strcmp($3,"DataInputs")==0){
+    current_data=1;
+    if(current_content!=NULL){
+      if(current_element->content==NULL){
+	addMapToMap(&current_element->content,current_content);
+      }
+      freeMap(&current_content);
+      free(current_content);
+      current_content=NULL;
+    }
+    if(current_element!=NULL){
+      if(my_service->content!=NULL && current_element->name!=NULL){
+	if(my_service->inputs==NULL){
+	  my_service->inputs=dupElements(current_element);
+	  my_service->inputs->next=NULL;
+	  tmp_count++;
+	}
+	else{
+	  addToElements(&my_service->inputs,current_element);
+	}
+	freeElements(&current_element);
+	free(current_element);
+	current_element=NULL;
+      }
+    }
+  }
+  if(strcmp($3,"DataOutputs")==0){
+    current_data=2;
+  }  
+  if(strcmp($3,"AdditionalParameters")==0){
+    if(current_content!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"add current_content to current_element->content\n");
+      fprintf(stderr,"LINE %d",__LINE__);
+#endif
+      if(wait_ap){
+	current_element->additional_parameters=NULL;
+	addMapToMap(&current_element->additional_parameters,current_content);
+	current_element->next=NULL;
+	current_element->defaults=NULL;
+	current_element->supported=NULL;
+	current_element->child=NULL;
+      }else{
+	if(wait_mainap){
+	  addMapToMap(&my_service->additional_parameters,current_content);
+	}
+      }
+
+      freeMap(&current_content);
+      free(current_content);
+      current_content=NULL;
+    }
+    current_data=previous_data;
+    wait_mainap=false;
+    wait_ap=false;
+  }
+  if(strcmp($3,"MetaData")==0){
+    if(current_content!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"add current_content to current_element->content\n");
+      fprintf(stderr,"LINE %d",__LINE__);
+#endif
+      if(wait_metadata){
+	current_element->metadata=NULL;
+	addMapToMap(&current_element->metadata,current_content);
+	current_element->next=NULL;
+	current_element->defaults=NULL;
+	current_element->supported=NULL;
+	current_element->child=NULL;
+      }else{
+	if(wait_mainmetadata){
+	  addMapToMap(&my_service->metadata,current_content);
+	}
+      }
+
+      freeMap(&current_content);
+      free(current_content);
+      current_content=NULL;
+    }
+    current_data=previous_data;
+    wait_mainmetadata=false;
+    wait_metadata=false;
+  }
+  if(strcmp($3,"ComplexData")==0 || strcmp($3,"LiteralData")==0 
+     || strcmp($3,"ComplexOutput")==0 || strcmp($3,"LiteralOutput")==0){
+    if(current_element->format==NULL)
+      current_element->format=zStrdup($3);
+    current_content=NULL;
+  }
+  if(strcmp($3,"Default")==0){
+    current_data=previous_data;
+    if(current_element->defaults==NULL){
+      current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+      current_element->defaults->content=NULL;
+    }
+    addMapToMap(&current_element->defaults->content,current_content);
+    freeMap(&current_content);
+    free(current_content);
+    current_element->defaults->next=NULL;
+    wait_defaults=false;
+    current_content=NULL;
+    current_element->supported=NULL;
+    current_element->child=NULL;
+    current_element->next=NULL;
+  }
+  if(strcmp($3,"Supported")==0){
+    current_data=previous_data;
+    if(current_element->supported==NULL){
+      if(current_content!=NULL){
+	current_element->supported=(iotype*)malloc(IOTYPE_SIZE);
+	current_element->supported->content=NULL;
+	addMapToMap(&current_element->supported->content,current_content);
+	freeMap(&current_content);
+	free(current_content);
+	current_element->supported->next=NULL;
+	current_content=NULL;
+      }else{
+	current_element->supported=NULL;
+	current_element->child=NULL;
+	current_element->next=NULL;
+      }
+    }
+    else{
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"SECOND SUPPORTED FORMAT !!!!\n");
+#endif
+      addMapToIoType(&current_element->supported,current_content);
+      freeMap(&current_content);
+      free(current_content);
+      current_content=NULL;
+#ifdef DEBUG_SERVICE_CONF
+      dumpElements(current_element);
+      fprintf(stderr,"SECOND SUPPORTED FORMAT !!!!\n");
+#endif
+    }
+    current_content=NULL;
+  }
+}
+ ;
+
+//======================================================
+// contentetoile
+//======================================================
+// regle 43
+// ENTRE 2 BALISES
+// entre 2 balises, on peut avoir :
+// --- OUVRANTE CONTENU FERMANTE (recursivement !)
+// --- DU TEXTE quelconque
+// --- COMMENTS 
+// --- DES PROCESSES INSTRUCTIONS
+// --- /!\ il peut y avoir une processing instruction invalide ! <?xml
+// --- EPSILON
+// ### et/ou tout ca a la suite en nombre indeterminé
+// ### donc c'est un operateur etoile (*)
+//======================================================
+contentetoile
+: contentetoile element	          {}
+ | contentetoile PIERROR	          {srerror("processing instruction <?xml ?> impossible\n");}
+ | contentetoile PI	                  {}
+///// on filtre les commentaires | contentetoile comment              {} 
+ | contentetoile NEWLINE {/*printf("NEWLINE FOUND !!");*/}
+ | contentetoile pair {}
+ | contentetoile processid {}
+ | contentetoile texteinterbalise	  {}
+ | contentetoile CDATA {}  
+ | {/* Epsilon */}
+ ;
+
+// texteinterbalise
+// regle 14
+// DU TEXTE quelconque
+// c'est du CHARDATA
+// il y a eut un probleme avec ID,
+// on a mis des starts conditions,
+// maintenant on croise les ID dans les dbalises
+// et des CHARDATA hors des balises
+texteinterbalise
+ : CHARDATA		{}
+ ;
+
+pair: PAIR { if(debug) fprintf(stderr,"PAIR FOUND !!\n");if(curr_key!=NULL){free(curr_key);curr_key=NULL;} }
+| EPAIR {
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"EPAIR (%s %d)\n",__FILE__,__LINE__);
+  fprintf(stderr,"[%s=>%s]\n",curr_key,$1);
+  dumpMap(current_content);
+  fflush(stderr);
+#endif
+  if($1!=NULL && curr_key!=NULL){
+    if(current_content==NULL){
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"[ZOO: service_conf.y line %d free(%s)]\n",__LINE__,curr_key);
+#endif
+      current_content=createMap(curr_key,$1);
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"[ZOO: service_conf.y line %d free(%s)]\n",__LINE__,curr_key);
+#endif
+    }
+    else{ 
+#ifdef DEBUG_SERVICE_CONF
+      dumpMap(current_content);
+      fprintf(stderr,"addToMap(current_content,%s,%s) !! \n",curr_key,$1); 
+#endif
+      addToMap(current_content,curr_key,$1);
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"addToMap(current_content,%s,%s) end !! \n",curr_key,$1); 
+#endif    
+    }
+  }
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"[%s=>%s]\n",curr_key,$1);
+  fprintf(stderr,"[ZOO: service_conf.y line %d free(%s)]\n",__LINE__,curr_key);
+  dumpMap(current_content);
+  fflush(stderr);
+#endif
+  if(curr_key!=NULL){
+    free(curr_key);
+    curr_key=NULL;
+  }
+  }
+| SPAIR  { if(curr_key!=NULL) {free(curr_key);curr_key=NULL;} if($1!=NULL) curr_key=zStrdup($1);if(debug) fprintf(stderr,"SPAIR FOUND !!\n"); }
+ ;
+
+
+processid
+: ANID  {
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"processid (%s %d) %s\n",__FILE__,__LINE__,$1);
+#endif
+  if(::data==-1){ // knut: add namespace to avoid ambiguous symbol
+    ::data=1;	
+    if($1!=NULL){
+      char *cen=zStrdup($1);
+      cen[strlen(cen)-1]=0;
+      cen+=1;
+      setServiceName(&my_service,cen);
+      cen-=1;
+      free(cen);
+    }
+  } else {
+    if(current_data==1){
+      if(my_service->content!=NULL && current_element->name!=NULL){
+	if(my_service->inputs==NULL){
+	  my_service->inputs=dupElements(current_element);
+	  my_service->inputs->next=NULL;
+	  tmp_count++;
+	}
+	else{
+	  if(wait_nested){
+	    elements* cursor=my_service->inputs;
+	    while(cursor->next!=NULL)
+	      cursor=cursor->next;
+	    if(nested_level>1){
+	      for(int j=0;j<nested_level-1;j++){
+		cursor=cursor->child;
+		while(cursor->next!=NULL)
+		  cursor=cursor->next;
+	      }
+	    }
+	    if(cursor->child==NULL){
+	      cursor->child=dupElements(current_element);
+	    }else{
+	      addToElements(&cursor->child,current_element);
+	    }
+	  }else
+	    addToElements(&my_service->inputs,current_element);
+	}
+	if(current_element->format==NULL){
+	  wait_nested=true;
+	  nested_level+=1;
+	  if(current_content!=NULL){
+	    elements* cursor=my_service->inputs;
+	    while(cursor->next!=NULL)
+	      cursor=cursor->next;
+	    if(nested_level>1){
+	      for(int j=0;j<nested_level-1;j++){
+		cursor=cursor->child;
+		while(cursor->next!=NULL)
+		  cursor=cursor->next;
+	      }
+	    }
+	    addMapToMap(&cursor->content,current_content);
+	    freeMap(&current_content);
+	    free(current_content);
+	    current_content=NULL;
+	  }
+	}
+#ifdef DEBUG_SERVICE_CONF
+	fprintf(stderr,"(%s %d)FREE current_element (after adding to allread existing inputs)",__FILE__,__LINE__);
+	dumpElements(current_element);
+	fprintf(stderr,"(%s %d)FREE current_element (after adding to allread existing inputs)",__FILE__,__LINE__);
+	dumpElements(my_service->inputs);
+#endif
+	freeElements(&current_element);
+	free(current_element);
+	current_element=NULL;
+#ifdef DEBUG_SERVICE_CONF
+	fprintf(stderr,"(DATAINPUTS - 489) ALLOCATE current_element\n");
+#endif
+	current_element=createEmptyElements();
+      }
+      if(current_element->name==NULL){
+#ifdef DEBUG_SERVICE_CONF
+	fprintf(stderr,"NAME IN %s (current - %s)\n",
+		$1,current_element->name);
+#endif
+	wait_inputs=true;
+#ifdef DEBUG_SERVICE_CONF
+	fprintf(stderr,"(DATAINPUTS - 501) SET NAME OF current_element\n");
+#endif
+	if($1!=NULL){ 
+	  char *cen=zStrdup($1);
+	  cen[strlen(cen)-1]=0;
+	  cen+=1;
+	  setElementsName(&current_element,cen);
+	  cen-=1;
+	  free(cen);
+#ifdef DEBUG_SERVICE_CONF
+	  fprintf(stderr,"NAME IN %s (current - %s)\n",$1,current_element->name);
+#endif
+#ifdef DEBUG_SERVICE_CONF
+	  fprintf(stderr,"NAME IN %s (current - %s)\n",$1,current_element->name);
+#endif
+	}
+      }
+    }
+    else
+      if(current_data==2){ 
+	wait_outputs=1;
+	if(wait_inputs){
+	  if(current_element!=NULL && current_element->name!=NULL){
+	    if(my_service->outputs==NULL){
+	      my_service->outputs=dupElements(current_element);
+	      my_service->outputs->next=NULL;
+	    }
+	    else{
+#ifdef DEBUG_SERVICE_CONF
+	      fprintf(stderr,"LAST NAME IN %s (current - %s)\n",$1,current_element->name);
+#endif
+	      addToElements(&my_service->outputs,current_element);
+	    }
+#ifdef DEBUG_SERVICE_CONF
+	    dumpElements(current_element);
+	    fprintf(stderr,"(DATAOUTPUTS) FREE current_element %s %i\n",__FILE__,__LINE__);
+#endif
+	    freeElements(&current_element);
+	    free(current_element);
+	    current_element=NULL;
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"(DATAOUTPUTS -%d) ALLOCATE current_element %s \n",__LINE__,__FILE__);
+#endif
+	    current_element=createEmptyElements();
+	  }
+	  if(current_element->name==NULL){
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"NAME OUT %s\n",$1);
+	    fprintf(stderr,"(DATAOUTPUTS - %d) SET NAME OF current_element\n",__LINE__);
+#endif
+	    if($1!=NULL){ 
+	      char *cen=zStrdup($1);
+	      cen[strlen(cen)-1]=0;
+	      cen+=1;
+	      setElementsName(&current_element,cen);
+	      cen-=1;
+	      free(cen);
+	    }
+	  }
+
+	  current_content=NULL;
+	}
+	else
+	  if(current_element!=NULL && current_element->name!=NULL){
+	    if(my_service->outputs==NULL)
+	      my_service->outputs=dupElements(current_element);
+	    else{
+	      if(wait_nested){
+		elements* cursor=my_service->outputs;
+		while(cursor->next!=NULL)
+		  cursor=cursor->next;
+		if(nested_level>1){
+		  for(int j=0;j<nested_level-1;j++){
+		    cursor=cursor->child;
+		    while(cursor->next!=NULL)
+		      cursor=cursor->next;
+		  }
+		}
+		if(cursor->child==NULL){
+		  cursor->child=dupElements(current_element);
+		}else
+		  addToElements(&cursor->child,current_element);
+	      }else
+		addToElements(&my_service->outputs,current_element);
+	    }
+	    if(current_element->format==NULL){
+	      wait_nested=true;
+	      nested_level+=1;
+	      if(current_content!=NULL){
+		elements* cursor=my_service->outputs;
+		while(cursor->next!=NULL)
+		  cursor=cursor->next;
+		if(nested_level>1){
+		  for(int j=0;j<nested_level-1;j++){
+		    cursor=cursor->child;
+		    while(cursor->next!=NULL)
+		      cursor=cursor->next;
+		  }
+		}
+		addMapToMap(&cursor->content,current_content);
+		freeMap(&current_content);
+		free(current_content);
+		current_content=NULL;
+	      }
+	    }
+
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"ADD TO OUTPUTS Elements\n");
+	    dupElements(current_element);
+#endif
+	    freeElements(&current_element);
+	    free(current_element);
+	    current_element=NULL;
+	    
+	    char *cen=zStrdup($1);
+	    cen[strlen(cen)-1]=0;
+	    cen+=1;
+	    current_element=createElements(cen);
+	    cen-=1;
+	    free(cen);
+	  }
+	  else{
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"NAME OUT %s\n",$1);
+	    fprintf(stderr,"(DATAOUTPUTS - %d) SET NAME OF current_element %s\n",__LINE__,$1);
+#endif
+	    if($1!=NULL){ 
+	      char *cen=zStrdup($1);
+	      cen[strlen(cen)-1]=0;
+#ifdef DEBUG
+	      fprintf(stderr,"tmp %s\n",cen);
+#endif
+	      cen+=1;
+	      setElementsName(&current_element,cen);
+	      cen-=1;
+	      free(cen);
+	    }
+	  }
+	wait_inputs=false;
+	wait_outputs=1;
+	//wait_outputs=true;
+      }
+  }
+ }
+ ;
+
+%%
+
+/**
+ * Print on stderr the message and the line number of the error which occurred.
+ * 
+ * @param s the error message
+ */
+void srerror(const char *s)
+{
+  if(debug)
+    fprintf(stderr,"\nligne %d : %s\n",srlineno,s);
+}
+
+/**
+ * Parse a ZCFG file and fill the service structure.
+ *
+ * @param conf the conf maps containing the main.cfg settings
+ * @param file the fullpath to the ZCFG file
+ * @param service the service structure to fill
+ * @return 0 on success, -1 on failure
+ */
+int getServiceFromFile(maps* conf,const char* file,service** service){
+  if(current_content!=NULL){
+    freeMap(&current_content);
+    free(current_content);
+    current_content=NULL;
+  }
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"(STARTING)FREE current_element %s\n",file);
+#endif
+  fflush(stderr);
+  fflush(stdout);
+  if(current_element!=NULL){
+    freeElements(&current_element);
+    free(current_element);
+    current_element=NULL;
+  }
+  my_service=NULL;
+
+  wait_maincontent=true;
+  wait_mainmetadata=false;
+  wait_metadata=false;
+  wait_mainap=false;
+  wait_ap=false;
+  wait_inputs=false;
+  wait_defaults=false;
+  wait_supporteds=false;
+  wait_outputs=-1;
+  wait_data=false;
+  wait_nested=false;
+//data=-1;
+  ::data=-1; // knut: add namespace to avoid ambiguous symbol
+  previous_data=1;
+  current_data=0;
+  
+  my_service=*service;
+
+  srin = fopen(file,"r");
+  if (srin==NULL){
+    setMapInMaps(conf,"lenv","message","file not found");
+    return -1;
+  }
+
+  int resultatYYParse = srparse() ;
+
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"RESULT: %d %d\n",resultatYYParse,wait_outputs);
+  dumpElements(current_element);
+#endif
+  if(wait_outputs && current_element!=NULL && current_element->name!=NULL){
+    if(current_content!=NULL){
+      addMapToMap(&current_element->content,current_content);
+    }
+    if(my_service->outputs==NULL){  
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"(DATAOUTPUTS - %d) DUP current_element\n",__LINE__);
+#endif
+      my_service->outputs=dupElements(current_element);
+      my_service->outputs->next=NULL;
+    }
+    else{
+#ifdef DEBUG_SERVICE_CONF
+      fprintf(stderr,"(DATAOUTPUTS - %d) COPY current_element\n",__LINE__);
+#endif
+      if(wait_nested){
+	elements* cursor=my_service->outputs;
+	while(cursor->next!=NULL)
+	  cursor=cursor->next;
+	if(nested_level>1){
+	  for(int j=0;j<nested_level-1;j++){
+	    cursor=cursor->child;
+	    while(cursor->next!=NULL)
+	      cursor=cursor->next;
+	  }
+	}
+	if(cursor->child==NULL){
+	  cursor->child=dupElements(current_element);
+	}else
+	  addToElements(&cursor->child,current_element);
+      }else
+	addToElements(&my_service->outputs,current_element);
+    }
+#ifdef DEBUG_SERVICE_CONF
+    fprintf(stderr,"(DATAOUTPUTS - %d) FREE current_element\n",__LINE__);
+#endif
+    freeElements(&current_element);
+    free(current_element);
+    current_element=NULL;
+#ifdef DEBUG_SERVICE_CONF
+    fprintf(stderr,"(DATAOUTPUTS - %d) FREE current_element\n",__LINE__);
+#endif
+  }
+  if(current_element!=NULL){
+    freeElements(&current_element);
+    free(current_element);
+    current_element=NULL;
+  }
+  int contentOnly=false;
+  if(current_content!=NULL){
+    if(my_service->content==NULL){
+      addMapToMap(&my_service->content,current_content);
+      contentOnly=true;
+      wait_maincontent=false;
+    }
+    freeMap(&current_content);
+    free(current_content);
+    current_content=NULL;
+  }
+  fclose(srin);
+#ifdef DEBUG_SERVICE_CONF
+  dumpService(my_service);
+#endif
+  if(wait_maincontent==true || (contentOnly==false && ((!wait_outputs && current_data==2 && my_service->outputs==NULL) || my_service==NULL || my_service->name==NULL || my_service->content==NULL))){
+    setMapInMaps(conf,"lenv","message",srlval.chaine);
+#ifndef WIN32
+    srlex_destroy();
+#endif
+    return -1;
+  }
+  else
+    *service=my_service;
+
+#ifndef WIN32
+  srlex_destroy();
+#endif
+  return resultatYYParse;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal.c	(revision 942)
@@ -0,0 +1,947 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2018 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define _LARGEFILE64_SOURCE 1
+#ifdef USE_MS
+#include "service_internal_ms.h"
+#else
+#include "cpl_vsi.h"
+#endif
+#include "service_internal.h"
+
+#ifdef WIN32
+// ref. https://docs.microsoft.com/en-us/windows/desktop/fileio/locking-and-unlocking-byte-ranges-in-files
+__inline int fcntl(int fd, int cmd, ...)
+{
+  va_list a;
+  va_start(a, cmd);
+  switch(cmd)
+    {
+    case F_SETLK:
+      {
+	HANDLE h = (HANDLE)_get_osfhandle(fd);
+	struct flock* l= va_arg(a, struct flock*);
+	OVERLAPPED sOverlapped;
+	sOverlapped.Offset = 0;
+	sOverlapped.OffsetHigh = 0;
+	switch(l->l_type)
+	  {
+	  case F_RDLCK:
+	    {
+	      if (!LockFileEx(h, LOCKFILE_FAIL_IMMEDIATELY, 0, l->l_len, 0, &sOverlapped)) 
+		{
+		  _set_errno(GetLastError() == ERROR_LOCK_VIOLATION ? EAGAIN : EBADF);
+		  return -1;
+		}
+	    }
+	    break;
+	  case F_WRLCK:
+	    {
+	      if (!LockFileEx(h, LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK, 0, l->l_len, 0, &sOverlapped))
+		{
+		  _set_errno(GetLastError() == ERROR_LOCK_VIOLATION ? EAGAIN : EBADF);
+		  return -1;
+		}
+	    }
+	    break;
+	  case F_UNLCK:
+	    {
+	      UnlockFileEx(h, 0, l->l_len, 0, &sOverlapped);
+	    }
+	    break;
+	  default:
+	    _set_errno(ENOTSUP);
+	    return -1;
+	  }
+      }
+      break;
+    default:
+      _set_errno(ENOTSUP);
+      return -1;
+    }
+  return 0;
+}
+#endif
+#define ERROR_MSG_MAX_LENGTH 1024
+
+/**
+ * Lock a file for read, write and upload.
+ * @param conf the main configuration maps
+ * @param filename the file to lock
+ * @param mode define access: 'r' for read, 'w' for write
+ * @return a new zooLock structure on sucess, NULL on failure 
+ */
+struct zooLock* lockFile(maps* conf,const char* filename,const char mode){
+  struct stat f_status;
+  int itn=0;
+  int s;
+  struct zooLock* myLock=(struct zooLock*)malloc(sizeof(struct flock)+sizeof(FILE*)+sizeof(char*));
+  int len=6;
+  char *myTemplate="%s.lock";
+  int res=-1;
+ retryLockFile:
+  myLock->filename=(char*)malloc((strlen(filename)+len)*sizeof(char));
+  sprintf(myLock->filename,myTemplate,filename);
+  s=stat(myLock->filename, &f_status);
+  if(s==0 && mode!='r'){
+    if(itn<ZOO_LOCK_MAX_RETRY){
+      itn++;
+#ifdef DEBUG
+      fprintf(stderr,"(%d) Wait for write lock on %s, tried %d times (sleep) ... \n",zGetpid(),myLock->filename,itn);
+      fflush(stderr);
+#endif
+      zSleep(5);
+      free(myLock->filename);
+      goto retryLockFile;
+    }else{
+      free(myLock->filename);
+      free(myLock);
+      return NULL;
+    }
+  }else{
+    char local_mode[3];
+    memset(local_mode,0,3);
+    if(mode=='w')
+      sprintf(local_mode,"%c+",mode);
+    else
+      sprintf(local_mode,"%c",mode);
+    myLock->lockfile=fopen(myLock->filename,local_mode);
+    char tmp[512];
+    sprintf(tmp,"%d",zGetpid());
+    if(myLock->lockfile==NULL){
+      myLock->lockfile=fopen(myLock->filename,"w+");
+      fwrite(tmp,sizeof(char),strlen(tmp),myLock->lockfile);
+      fflush(myLock->lockfile);
+      fclose(myLock->lockfile);
+      myLock->lockfile=fopen(myLock->filename,local_mode);
+    }/*else
+       fprintf(stderr,"%s %d %d\n",__FILE__,__LINE__,(myLock->lockfile==NULL));*/
+    if(mode!='r'){
+      fwrite(tmp,sizeof(char),strlen(tmp),myLock->lockfile);
+      fflush(myLock->lockfile);
+    }
+    int cnt=0;
+    if(mode=='r'){
+      myLock->lock.l_type = F_RDLCK;
+    }else
+      myLock->lock.l_type = F_WRLCK;
+    myLock->lock.l_whence = 0;
+    myLock->lock.l_start = 0;
+    myLock->lock.l_len = strlen(tmp)*sizeof(char);
+    while (true) {
+      if((res=fcntl(fileno(myLock->lockfile), F_SETLK, &(myLock->lock)))==-1 &&
+	 (errno==EAGAIN || errno==EACCES)){
+	  if(cnt >= ZOO_LOCK_MAX_RETRY){
+	    char message[51];	  
+	    sprintf(message,"Unable to get the lock after %d attempts.\n",cnt);
+	    setMapInMaps(conf,"lenv","message",message);
+	    fclose(myLock->lockfile);
+	    free(myLock->filename);
+	    free(myLock);
+	    return NULL;
+	  }
+#ifdef DEBUG
+	  fprintf(stderr,"(%d) Wait for lock on  %s, tried %d times ... \n",zGetpid(),myLock->filename,cnt);
+	  fflush(stderr);
+#endif
+	  zSleep(1);
+	  cnt++;
+	}else
+	   break;
+    }
+    if(res<0){
+      char *tmp;
+      if(errno==EBADF)
+	tmp="Either: the filedes argument is invalid; you requested a read lock but the filedes is not open for read access; or, you requested a write lock but the filedes is not open for write access.";
+      else
+	if(errno==EINVAL)
+	  tmp="Either the lockp argument doesn’t specify valid lock information, or the file associated with filedes doesn’t support locks.";
+	else
+	  tmp="The system has run out of file lock resources; there are already too many file locks in place.";
+#ifdef DEBUG
+      fprintf(stderr,"Unable to get the lock on %s due to the following error: %s\n",myLock->filename,tmp);
+#endif
+      return NULL;
+    }
+    return myLock;
+  }
+}
+
+/**
+ * Remove a lock.
+ * @param conf the main configuration maps
+ * @param s the zooLock structure
+ * @return 0 on success, -1 on failure.
+ */
+int unlockFile(maps* conf,struct zooLock* s){
+  int res=-1;
+  if(s!=NULL){
+    s->lock.l_type = F_UNLCK;
+    res=fcntl(fileno(s->lockfile), F_SETLK, &s->lock);
+    if(res==-1)
+      return res;
+    fclose(s->lockfile);
+#ifndef WIN32
+    // Check if there is any process locking a file and delete the lock if not.
+    s->lock.l_type = F_WRLCK;
+    if(fcntl(fileno(s->lockfile), F_GETLK, &s->lock)!=-1 && s->lock.l_type == F_UNLCK){
+#endif
+      zUnlink(s->filename);
+#ifndef WIN32
+    }
+#endif
+    free(s->filename);
+    free(s);
+  }
+  return res;
+}
+
+#ifndef RELY_ON_DB
+#include "dirent.h"
+
+/**
+ * Read the sid file attached of a service if any
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ * @return the reported status char* (temporary/final result)
+ */
+char* getStatusId(maps* conf,char* pid){
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  char* fbkpid =
+    (char *)
+    malloc ((strlen (r_inputs->value) + strlen (pid) + 7) * sizeof (char));
+  sprintf (fbkpid, "%s/%s.sid", r_inputs->value, pid);
+  FILE* f0 = fopen (fbkpid, "r");
+  if(f0!=NULL){
+    long flen;
+    char *fcontent;
+    fseek (f0, 0, SEEK_END);
+    flen = ftell (f0);
+    fseek (f0, 0, SEEK_SET);
+    fcontent = (char *) malloc ((flen + 1) * sizeof (char));
+    fread(fcontent,flen,1,f0);
+    fcontent[flen]=0;
+    fclose(f0);
+    return fcontent;
+  }else
+    return NULL;
+}
+
+/**
+ * Acquire the global lock
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @return a semid 
+ */
+semid acquireLock(maps* conf){
+  semid lockid;
+  int itn=0;
+ toRetry1:
+  lockid=getShmLockId(conf,1);
+  if(
+#ifdef WIN32
+     lockid==NULL
+#else
+     lockid<0
+#endif
+     ){
+#ifdef WIN32
+    return NULL;
+#else
+    return -1;
+#endif
+  }
+  if(lockShm(lockid)<0){
+#ifdef WIN32
+      return NULL;
+#else
+    if(itn<ZOO_LOCK_MAX_RETRY){
+      itn++;
+      goto toRetry1;
+    }else
+      return -1;
+#endif
+  }else
+    return lockid;
+}
+
+/**
+ * Read the cache file of a running service 
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ * @return the reported status char* (temporary/final result)
+ */
+char* _getStatusFile(maps* conf,char* pid){
+  map* tmpTmap = getMapFromMaps (conf, "main", "tmpPath");
+
+  struct dirent *dp;
+  DIR *dirp = opendir(tmpTmap->value);
+  char fileName[1024];
+  int hasFile=-1;
+  if(dirp!=NULL){
+    char tmp[128];
+    sprintf(tmp,"_%s.xml",pid);
+    while ((dp = readdir(dirp)) != NULL){
+#ifdef DEBUG
+      fprintf(stderr,"File : %s searched : %s\n",dp->d_name,tmp);
+#endif
+      if(strstr(dp->d_name,"final_")==0 && strstr(dp->d_name,tmp)!=0){
+	sprintf(fileName,"%s/%s",tmpTmap->value,dp->d_name);
+	hasFile=1;
+	break;
+      }
+    }
+  }
+  if(hasFile>0){
+    semid lockid;
+    char* stat=getStatusId(conf,pid);
+    if(stat!=NULL){
+      setMapInMaps(conf,"lenv","lid",stat);
+      lockid=acquireLock(conf);
+      if(lockid<0)
+	return NULL;
+    }
+
+    //FILE* f0 = fopen (fileName, "r");
+    // knut: open file in binary mode to avoid conversion of line endings (yielding extra bytes) on Windows platforms
+    FILE* f0 = fopen(fileName, "rb"); 
+    if(f0!=NULL){
+      fseek (f0, 0, SEEK_END);
+      long flen = ftell (f0);
+      fseek (f0, 0, SEEK_SET);
+      char *tmps1 = (char *) malloc ((flen + 1) * sizeof (char));
+      fread(tmps1,flen,1,f0);
+      tmps1[flen]=0;
+      fclose(f0);
+      if(stat!=NULL){
+	unlockShm(lockid);
+	free(stat);
+      }
+      return tmps1;
+    }
+    else{
+      if(stat!=NULL){
+	unlockShm(lockid);
+	free(stat);
+      }
+      return NULL;
+    }
+  }
+  else
+    return NULL;
+}
+
+/**
+ * Get the ongoing status of a running service 
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ * @return the reported status char* (MESSAGE|POURCENTAGE)
+ */
+char* _getStatus(maps* conf,char* lid){
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  char* fbkpid =
+    (char *)
+    malloc ((strlen (r_inputs->value) + strlen (lid) + 9) * sizeof (char));
+  sprintf (fbkpid, "%s/%s.status", r_inputs->value, lid);
+  FILE* f0 = fopen (fbkpid, "r");
+  if(f0!=NULL){    
+    semid lockid = NULL;
+    char* stat;
+    long flen;
+    stat=getStatusId(conf,lid);
+    if(stat!=NULL){
+      setMapInMaps(conf,"lenv","lid",stat);
+      lockid=acquireLock(conf);
+      if(lockid<0)
+	return NULL;
+    }
+    fseek (f0, 0, SEEK_END);
+    flen = ftell (f0);
+    if(flen>0){
+      char *fcontent;
+      fseek (f0, 0, SEEK_SET);
+      fcontent = (char *) malloc ((flen + 1) * sizeof (char));
+      fread(fcontent,flen,1,f0);
+      fcontent[flen]=0;
+      fclose(f0);
+      free(fbkpid);
+      if(stat!=NULL){
+#ifndef WIN32
+	removeShmLock(conf,1);
+#else
+	unlockShm(lockid);
+#endif
+	free(stat);
+      }
+      return fcontent;
+    }
+    fclose(f0);
+    free(fbkpid);
+    if(stat!=NULL){
+      removeShmLock(conf,1);
+      free(stat);
+    }
+    return NULL;
+  }else{
+    free(fbkpid);
+    char* stat=getStatusId(conf,lid);
+    setMapInMaps(conf,"lenv","lid",stat);
+    removeShmLock(conf,1);
+    return NULL;
+  }
+}
+
+/**
+ * Stop handling status repport.
+ *
+ * @param conf the map containing the setting of the main.cfg file
+ */
+void unhandleStatus(maps *conf){	
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  map* usid = getMapFromMaps (conf, "lenv", "usid");
+  char* fbkpid =
+    (char *) malloc ((strlen (r_inputs->value) + strlen (usid->value) + 9) 
+		     * sizeof (char));
+  sprintf (fbkpid, "%s/%s.status", r_inputs->value, usid->value);
+  zUnlink(fbkpid);
+  free(fbkpid);
+}
+
+/**
+ * Update the current status of the running service.
+ *
+ * @see acquireLock, lockShm
+ * @param conf the map containing the setting of the main.cfg file
+ * @return 0 on success, -2 if shmget failed, -1 if shmat failed
+ */
+int _updateStatus(maps *conf){
+	
+  map* r_inputs = getMapFromMaps (conf, "main", "tmpPath");
+  map* sid = getMapFromMaps (conf, "lenv", "usid");
+  
+  char* fbkpid =
+    (char *)
+    malloc ((strlen (r_inputs->value) + strlen (sid->value) + 9) * sizeof (char));
+  sprintf (fbkpid, "%s/%s.status", r_inputs->value, sid->value);
+  map* status=getMapFromMaps(conf,"lenv","status");
+  map* msg=getMapFromMaps(conf,"lenv","message");
+  if(status!=NULL && msg!=NULL &&
+     status->value!=NULL && msg->value!=NULL && 
+     strlen(status->value)>0 && strlen(msg->value)>1){    
+    semid lockid = NULL;
+	
+    char* stat=getStatusId(conf,sid->value);
+    if(stat!=NULL){
+      lockid=acquireLock(conf);
+      if(lockid<0){
+	dumpMap(status);
+	return ZOO_LOCK_ACQUIRE_FAILED;
+      }
+    }
+    FILE* fstatus=fopen(fbkpid,"w");
+    if(fstatus!=NULL){
+      fprintf(fstatus,"%s|%s",status->value,msg->value);
+      fflush(fstatus);
+      fclose(fstatus);
+    }
+    if(stat!=NULL){
+      unlockShm(lockid);
+      free(stat);
+    }
+  }
+
+  return 0;
+}
+
+#endif
+
+#ifdef WIN32
+
+#define SHMEMSIZE 4096
+
+size_t getKeyValue(maps* conf, char* key, size_t length){
+  if(conf==NULL) {
+    strncpy(key, "700666", length);
+    return strlen(key);
+  }
+  
+  map *tmpMap=getMapFromMaps(conf,"lenv","lid");
+  if(tmpMap==NULL)
+    tmpMap=getMapFromMaps(conf,"lenv","osid");
+
+  if(tmpMap!=NULL){
+    snprintf(key, length, "zoo_sem_%s", tmpMap->value);      
+  }
+  else {
+    strncpy(key, "-1", length);
+  }
+  return strlen(key);
+}
+
+
+semid getShmLockId(maps* conf, int nsems){
+  semid sem_id;
+  char key[MAX_PATH];
+  getKeyValue(conf, key, MAX_PATH);
+  
+  sem_id = CreateSemaphore( NULL, nsems, nsems+1, key);
+  if(sem_id==NULL){
+#ifdef DEBUG
+    fprintf(stderr,"Semaphore failed to create: %s\n", getLastErrorMessage());
+#endif
+    return NULL;
+  }
+#ifdef DEBUG
+  fprintf(stderr,"%s Accessed !\n",key);
+#endif
+  return sem_id;
+}
+
+int removeShmLock(maps* conf, int nsems){
+  semid sem_id=getShmLockId(conf,1);
+  if (CloseHandle(sem_id) == 0) {
+#ifdef DEBUG
+    fprintf(stderr,"Unable to remove semaphore: %s\n", getLastErrorMessage());
+#endif
+    return -1;
+  }
+#ifdef DEBUG
+  fprintf(stderr,"%d Removed !\n",sem_id);
+#endif
+  return 0;
+}
+
+int lockShm(semid id){
+  DWORD dwWaitResult=WaitForSingleObject(id,INFINITE);
+  switch (dwWaitResult){
+    case WAIT_OBJECT_0:
+      return 0;
+      break;
+    case WAIT_TIMEOUT:
+      return -1;
+      break;
+    default:
+      return -2;
+      break;
+  }
+  return 0;
+}
+
+int unlockShm(semid id){
+  if(!ReleaseSemaphore(id,1,NULL)){
+    return -1;
+  }
+  return 0;
+}
+
+static LPVOID lpvMemG = NULL;      // pointer to shared memory
+static HANDLE hMapObjectG = NULL;  // handle to file mapping
+
+
+char* getStatus(int pid){
+  char *lpszBuf=(char*) malloc(SHMEMSIZE*sizeof(char));
+  int i=0;
+  LPWSTR lpszTmp=NULL;
+  LPVOID lpvMem = NULL;
+  HANDLE hMapObject = NULL;
+  BOOL fIgnore,fInit;
+  char tmp[1024];
+  sprintf(tmp,"%d",pid);
+  if(hMapObject==NULL)
+    hMapObject = CreateFileMapping( 
+				   INVALID_HANDLE_VALUE,   // use paging file
+				   NULL,                   // default security attributes
+				   PAGE_READWRITE,         // read/write access
+				   0,                      // size: high 32-bits
+				   4096,                   // size: low 32-bits
+				   TEXT(tmp));   // name of map object
+  if (hMapObject == NULL){
+#ifdef DEBUG
+    fprintf(stderr,"ERROR on line %d\n",__LINE__);
+#endif
+    return "-1";
+  }
+  if((GetLastError() != ERROR_ALREADY_EXISTS)){
+#ifdef DEBUG
+    fprintf(stderr,"ERROR on line %d\n",__LINE__);
+    fprintf(stderr,"READING STRING S %s\n", getLastErrorMessage());
+#endif
+    fIgnore = UnmapViewOfFile(lpvMem); 
+    fIgnore = CloseHandle(hMapObject);
+    return "-1";
+  }
+  fInit=TRUE;
+  if(lpvMem==NULL)
+    lpvMem = MapViewOfFile( 
+			   hMapObject,     // object to map view of
+			   FILE_MAP_READ,  // read/write access
+			   0,              // high offset:  map from
+			   0,              // low offset:   beginning
+			   0);             // default: map entire file
+  if (lpvMem == NULL){
+#ifdef DEBUG
+    fprintf(stderr,"READING STRING S %d\n",__LINE__);
+    fprintf(stderr,"READING STRING S %s\n", getLastErrorMessage());
+#endif
+    return "-1"; 
+  }
+  lpszTmp = (LPWSTR) lpvMem;
+  while (*lpszTmp){
+    lpszBuf[i] = (char)*lpszTmp;
+    *lpszTmp++; 
+    lpszBuf[i+1] = '\0'; 
+    i++;
+  }
+  return (char*)lpszBuf;
+}
+
+#else
+/**
+ * Number of time to try to access a semaphores set
+ * @see getShmLockId
+ */
+#define MAX_RETRIES 10
+
+#ifndef __APPLE__
+/**
+ * arg for semctl system calls. 
+ */
+union semun {
+  int val; //!< value for SETVAL 
+  struct semid_ds *buf; //!< buffer for IPC_STAT & IPC_SET
+  ushort *array; //!< array for GETALL & SETALL
+};
+#endif
+
+/**
+ * Set in the pre-allocated key the zoo_sem_[OSID] string 
+ * where [OSID] is the lid (if any) or osid value from the [lenv] section.
+ *
+ * @param conf the map containing the setting of the main.cfg file
+ */
+int getKeyValue(maps* conf){
+  if(conf==NULL)
+     return 700666;
+  map *tmpMap=getMapFromMaps(conf,"lenv","lid");
+  if(tmpMap==NULL)
+    tmpMap=getMapFromMaps(conf,"lenv","osid");
+  int key=-1;
+  if(tmpMap!=NULL)
+    key=atoi(tmpMap->value);
+  return key;
+}
+
+/**
+ * Try to create or access a semaphore set.
+ *
+ * @see getKeyValue
+ * @param conf the map containing the setting of the main.cfg file
+ * @param nsems number of semaphores
+ * @return a semaphores set indentifier on success, -1 in other case
+ */
+int getShmLockId(maps* conf, int nsems){
+    int i;
+    union semun arg;
+    struct semid_ds buf;
+    struct sembuf sb;
+    semid sem_id;
+    int key=getKeyValue(conf);
+    
+    sem_id = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666);
+
+    if (sem_id >= 0) { /* we got it first */
+        sb.sem_op = 1; 
+	sb.sem_flg = 0;
+	arg.val=1;
+        for(sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++) { 
+            /* do a semop() to "free" the semaphores. */
+            /* this sets the sem_otime field, as needed below. */
+            if (semop(sem_id, &sb, 1) == -1) {
+                int e = errno;
+                semctl(sem_id, 0, IPC_RMID); /* clean up */
+                errno = e;
+                return -1; /* error, check errno */
+            }
+        }
+	setMapInMaps(conf,"lenv","semaphore","Created");
+    } else if (errno == EEXIST) { /* someone else got it first */
+        int ready = 0;
+
+        sem_id = semget(key, nsems, 0); /* get the id */
+        if (sem_id < 0) return sem_id; /* error, check errno */
+
+        /* wait for other process to initialize the semaphore: */
+        arg.buf = &buf;
+        for(i = 0; i < MAX_RETRIES && !ready; i++) {
+            semctl(sem_id, nsems-1, IPC_STAT, arg);
+            if (arg.buf->sem_otime != 0) {
+#ifdef DEBUG
+	      fprintf(stderr,"Semaphore acquired ...\n");
+#endif
+	      ready = 1;
+            } else {
+#ifdef DEBUG
+	      fprintf(stderr,"Retry to access the semaphore later ...\n");
+#endif
+	      zSleep(1000);
+            }
+        }
+	errno = ZOO_LOCK_ACQUIRE_FAILED;
+        if (!ready) {
+#ifdef DEBUG
+	  fprintf(stderr,"Unable to access the semaphore ...\n");
+#endif
+	  errno = ETIME;
+	  return -1;
+        }
+	setMapInMaps(conf,"lenv","semaphore","Acquired");
+    } else {
+        return sem_id; /* error, check errno */
+    }
+#ifdef DEBUG
+    fprintf(stderr,"%d Created !\n",sem_id);
+#endif
+    return sem_id;
+}
+
+/**
+ * Try to remove a semaphore set.
+ *
+ * @param conf the map containing the setting of the main.cfg file
+ * @param nsems number of semaphores
+ * @return 0 if the semaphore can be removed, -1 in other case.
+ */
+int removeShmLock(maps* conf, int nsems){
+  union semun arg;
+  int sem_id=getShmLockId(conf,nsems);
+  if (semctl(sem_id, 0, IPC_RMID, arg) == -1) {
+#ifdef DEBUG
+    perror("semctl remove");
+#endif
+    return -1;
+  }
+#ifdef DEBUG
+  fprintf(stderr,"Semaphore removed!\n");
+#endif
+  return 0;
+}
+
+/**
+ * Lock a semaphore set.
+ *
+ * @param id the semaphores set indetifier
+ * @return 0 if the semaphore can be locked, -1 in other case.
+ */
+int lockShm(int id){
+  struct sembuf sb;
+  sb.sem_num = 0;
+  sb.sem_op = -1;  /* set to allocate resource */
+  sb.sem_flg = SEM_UNDO;
+  if (semop(id, &sb, 1) == -1){
+#ifdef DEBUG
+    perror("semop lock");
+#endif
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * unLock a semaphore set.
+ *
+ * @param id the semaphores set indetifier
+ * @return 0 if the semaphore can be locked, -1 in other case.
+ */
+int unlockShm(int id){
+  struct sembuf sb;
+  sb.sem_num = 0;
+  sb.sem_op = 1;  /* free resource */
+  sb.sem_flg = SEM_UNDO;
+  if (semop(id, &sb, 1) == -1) {
+#ifdef DEBUG
+    perror("semop unlock");
+#endif
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * Get the current status of the running service.
+ *
+ * @see getKeyValue, getShmLockId, lockShm
+ * @param pid the semaphores 
+ * @return 0 on success, -2 if shmget failed, -1 if shmat failed
+ */
+char* getStatus(int pid){
+  int shmid;
+  key_t key;
+  void *shm;
+  key=pid;
+  if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
+#ifdef DEBUG
+    fprintf(stderr,"shmget failed in getStatus\n");
+#endif
+  }else{
+    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
+#ifdef DEBUG
+      fprintf(stderr,"shmat failed in getStatus\n");
+#endif
+    }else{
+      char *ret=strdup((char*)shm);
+      shmdt((void *)shm);
+      return ret;
+    }
+  }
+  return (char*)"-1";
+}
+
+#endif
+
+/**
+ * Update the status of an ongoing service 
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param percentCompleted percentage of completude of execution of the service
+ * @param message information about the current step executed
+ * @return the value of _updateStatus
+ * @see _updateStatus
+ */
+int updateStatus( maps* conf, const int percentCompleted, const char* message ){
+  char tmp[4];
+  snprintf(tmp,4,"%d",percentCompleted);
+  setMapInMaps( conf, "lenv", "status", tmp );
+  setMapInMaps( conf, "lenv", "message", message);
+  return _updateStatus( conf );
+}
+
+/**
+ * Access an input value 
+ *
+ * @param inputs the maps to search for the input value
+ * @param parameterName the input name to fetch the value
+ * @param numberOfBytes the resulting size of the value to add (for binary
+ *  values), -1 for basic char* data
+ * @return a pointer to the input value if found, NULL in other case.
+ */
+char* getInputValue( maps* inputs, const char* parameterName, size_t* numberOfBytes){
+  map* res=getMapFromMaps(inputs,parameterName,"value");
+  if(res!=NULL){
+    map* size=getMapFromMaps(inputs,parameterName,"size");
+    if(size!=NULL){
+      *numberOfBytes=(size_t)atoi(size->value);
+      return res->value;
+    }else{
+      *numberOfBytes=strlen(res->value);
+      return res->value;
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Read a file using the GDAL VSI API 
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param dataSource the datasource name to read
+ * @warning make sure to free resources returned by this function
+ */
+char *readVSIFile(maps* conf,const char* dataSource){
+    VSILFILE * fichier=VSIFOpenL(dataSource,"rb");
+    VSIStatBufL file_status;
+    int res=VSIStatL(dataSource, &file_status);
+    if(fichier==NULL || res<0){
+      char tmp[1024];
+      sprintf(tmp,"Failed to open file %s for reading purpose. File seems empty %ld.",
+	      dataSource,file_status.st_size);
+      setMapInMaps(conf,"lenv","message",tmp);
+      return NULL;
+    }
+    char *res1=(char *)malloc(file_status.st_size*sizeof(char));
+    VSIFReadL(res1,1,file_status.st_size*sizeof(char),fichier);
+    res1[file_status.st_size-1]=0;
+    VSIFCloseL(fichier);
+    VSIUnlink(dataSource);
+    return res1;
+}
+
+/**
+ * Set an output value 
+ *
+ * @param outputs the maps to define the output value
+ * @param parameterName the output name to set the value
+ * @param data the value to set
+ * @param numberOfBytes size of the value to add (for binary values), -1 for
+ *  basic char* data
+ * @return 0
+ */
+int  setOutputValue( maps* outputs, const char* parameterName, char* data, size_t numberOfBytes ){
+  if(numberOfBytes==-1){
+    setMapInMaps(outputs,parameterName,"value",data);
+  }else{
+    char size[1024];
+    map* tmp=getMapFromMaps(outputs,parameterName,"value");
+    if(tmp==NULL){
+      setMapInMaps(outputs,parameterName,"value","");
+      tmp=getMapFromMaps(outputs,parameterName,"value");
+    }
+    free(tmp->value);
+    tmp->value=(char*) malloc((numberOfBytes+1)*sizeof(char));
+    memcpy(tmp->value,data,numberOfBytes);
+    sprintf(size,"%lu",numberOfBytes);
+    setMapInMaps(outputs,parameterName,"size",size);
+  }
+  return 0;
+}
+
+/**
+ * Check if file exists in specified folder
+ *
+ * @param dir the folder in which to search for file
+ * @param name the name of the file (not full path) 
+ * @return a character string with the full path [dir/name], or NULL if the file does not exist
+ *
+ * @attention Caller is responsible for applying free() to the returned pointer
+ */
+char* file_exists(const char* dir, const char* name) {
+	const char* d = (dir != NULL ? dir : ".");
+	if (name != NULL) {
+		size_t length = strlen(d) + strlen(name) + 2; // including file separator and \0 character
+		char* path = (char*)calloc(length, sizeof(char));
+		snprintf(path, length, "%s/%s", d, name);
+
+		struct stat buffer;
+		if (stat(path, &buffer) != 0) {
+			free(path);
+			path = NULL;
+		}
+		return path;
+	}
+	else {
+		return NULL;
+	}
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal.h	(revision 942)
@@ -0,0 +1,169 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2013 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_H
+#define ZOO_SERVICE_INTERNAL_H 1
+
+#pragma once 
+
+/**
+ * The default service url (overriden by serverAddress)
+ */
+#define DEFAULT_SERVICE_URL "http://www.zoo-project.org/"
+/**
+ * The time size
+ */
+#define TIME_SIZE 40
+
+#include <libintl.h>
+#include <locale.h>
+/**
+ * ZOO-Kernel internal messages translation function
+ */
+#define _(String) dgettext ("zoo-kernel",String)
+/**
+ * ZOO-Services messages translation function
+ */
+#define _ss(String) dgettext ("zoo-services",String)
+
+/**
+ * ZOO-Kernel was unable to create a lock
+ */
+#define ZOO_LOCK_CREATE_FAILED -4
+/**
+ * ZOO-Kernel was unable to acquire a lock
+ */
+#define ZOO_LOCK_ACQUIRE_FAILED -5
+/**
+ * ZOO-Kernel was unable to release a lock
+ */
+#define ZOO_LOCK_RELEASE_FAILED -6
+/**
+ * Number of time the ZOO-Kernel will try to acquire lock
+ */
+#define ZOO_LOCK_MAX_RETRY 180
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#else
+#include <direct.h>
+#endif
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#ifndef USE_RUBY
+#include <unistd.h>
+#endif
+#ifndef WIN32
+#include <locale.h>
+#endif
+
+#include <fcntl.h>
+  
+#include "service.h"
+
+#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
+
+#include <CoreServices/CoreServices.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#endif
+
+#ifdef WIN32
+// fcntl flock definitions
+#define F_SETLK  8   // Non-Blocking set or clear a lock
+#define F_SETLKW 9   // Blocking set or clear a lock
+#define F_GETLK 10
+#define F_RDLCK  1   // read lock
+#define F_WRLCK  2   // write lock
+#define F_UNLCK  3   // remove lock
+struct flock {
+    short l_type;   // F_RDLCK, F_WRLCK, or F_UNLCK
+    short l_whence; // flag to choose starting offset, must be SEEK_SET
+    long  l_start;  // relative offset, in bytes, must be 0
+    long  l_len;    // length, in bytes; 0 means lock to EOF, must be 0
+    short l_pid;    // unused (returned with the unsupported F_GETLK)
+    short l_xxx;    // reserved for future use
+};
+#endif
+
+/**
+ * The lock structure used by the ZOO-Kernel to ensure atomicity of operations
+ *
+ */ 
+typedef struct zooLock{
+  struct flock lock; //!< The lock
+  FILE* lockfile;    //!< The pointer to the lock file
+  char* filename;    //!< The filename to lock
+} zooLock;
+
+static zooLock** zoo_file_locks=NULL;
+static int zoo_file_locks_cnt=0;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  
+  ZOO_DLL_EXPORT char *readVSIFile(maps*,const char*);
+  ZOO_DLL_EXPORT int  setOutputValue( maps*, const char*, char*, size_t);
+  ZOO_DLL_EXPORT char* getInputValue( maps*,const char*,size_t*);
+
+  ZOO_DLL_EXPORT struct zooLock* lockFile(maps*,const char*,const char);
+  ZOO_DLL_EXPORT int unlockFile(maps*,struct zooLock*);
+
+  ZOO_DLL_EXPORT void unhandleStatus(maps*);
+  ZOO_DLL_EXPORT int _updateStatus(maps*);
+  ZOO_DLL_EXPORT char* _getStatus(maps*,char*);
+  ZOO_DLL_EXPORT char* _getStatusFile(maps*,char*);
+  ZOO_DLL_EXPORT char* getStatus(int);
+  ZOO_DLL_EXPORT char* getStatusId(maps*,char*);
+
+  ZOO_DLL_EXPORT int updateStatus( maps*,const int,const char*);
+  ZOO_DLL_EXPORT int removeShmLock(maps*, int);
+  /**
+   * Cross platform type used for Lock identifier
+   */
+#ifndef WIN32
+#define semid int
+#else
+#include <windows.h>
+#define semid HANDLE
+#endif
+  ZOO_DLL_EXPORT semid acquireLock(maps*);
+  ZOO_DLL_EXPORT semid getShmLockId(maps*,int);
+  ZOO_DLL_EXPORT int lockShm(semid);
+  ZOO_DLL_EXPORT int unlockShm(semid);
+
+  ZOO_DLL_EXPORT char* file_exists(const char* dir, const char* name); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_hpc.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_hpc.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_hpc.c	(revision 942)
@@ -0,0 +1,1178 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2017 GeoLabs SARL
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "service_internal_hpc.h"
+#include "response_print.h"
+#include "server_internal.h"
+#include "service_callback.h"
+#include "mimetypes.h"
+#include <sys/un.h>
+
+typedef struct {
+  maps* conf;
+  char* local_file;
+  char* target_file;
+} local_params;
+
+/**
+ * Add nested outputs to every outputs that is geographic format 
+ * @see isGeographic
+ * @param s the service current definition
+ */ 
+void addNestedOutputs(service** s){
+  if((*s)==NULL){
+    return;
+  }    
+  if(*s==NULL || (*s)->outputs==NULL || (*s)->content==NULL){
+    return;
+  }
+  elements *out=(*s)->outputs;
+  elements* cur=out;
+  map* serviceType=getMap((*s)->content,"ServiceType");
+  if(strncmp(serviceType->value,"HPC",3)!=0)
+    return;
+  while(cur!=NULL && cur->defaults!=NULL){
+    map* mimeType=getMap(cur->defaults->content,"mimeType");
+    map* useMS=getMap(cur->defaults->content,"useMapserver");
+    if(mimeType!=NULL && useMS!=NULL && strncasecmp(useMS->value,"true",4)==0){
+      int geo=isGeographic(mimeType->value);
+      if(geo>0){
+	elements *tmp[3]={
+	  dupElements(cur),
+	  dupElements(cur),
+	  dupElements(cur)
+	};
+	const char *geoLink="wcs_link";
+	if(geo==2){
+	  geoLink="wfs_link";
+	}
+	int i=0;
+	for(;i<3;i++){
+	  if(tmp[i]->next!=NULL){
+	    freeElements(&tmp[i]->next);
+	    free(tmp[i]->next);
+	    tmp[i]->next=NULL;
+	  }
+	  free(tmp[i]->name);
+	  if(tmp[i]->format!=NULL)
+	    free(tmp[i]->format);
+	  tmp[i]->format=zStrdup("ComplexData");
+	  freeMap(&tmp[i]->content);
+	  free(tmp[i]->content);
+	  tmp[i]->content=NULL;
+	  switch(i){
+	  case 0:
+	    tmp[i]->name=zStrdup("download_link");
+	    tmp[i]->content=createMap("Title",_("Download link"));
+	    addToMap(tmp[i]->content,"Abstract",_("The download link"));
+	    addToMap(tmp[i]->defaults->content,"useMapserver","false");
+	    if(tmp[i]->supported!=NULL){
+	      freeIOType(&tmp[i]->supported);
+	      free(tmp[i]->supported);
+	      tmp[i]->supported=NULL;
+	    }
+	    break;
+	  case 1:
+	    tmp[i]->name=zStrdup("wms_link");
+	    tmp[i]->content=createMap("Title",_("WMS link"));
+	    addToMap(tmp[i]->content,"Abstract",_("The WMS link"));
+	    if(tmp[i]->supported!=NULL && tmp[i]->supported->next!=NULL){
+	      freeIOType(&tmp[i]->supported->next);
+	      free(tmp[i]->supported->next);
+	      tmp[i]->supported->next=NULL;
+	    }else{
+	      if(tmp[i]->supported!=NULL)
+		addToMap(tmp[i]->supported->content,"useMapserver","true");
+	      addToMap(tmp[i]->defaults->content,"useMapserver","true");
+	    }
+	    break;
+	  case 2:
+	    if(geo==2){
+	      tmp[i]->name=zStrdup("wfs_link");
+	      tmp[i]->content=createMap("Title",_("WFS link"));
+	      addToMap(tmp[i]->content,"Abstract",_("The WFS link"));
+	    }else{
+	      tmp[i]->name=zStrdup("wcs_link");
+	      tmp[i]->content=createMap("Title",_("WCS link"));
+	      addToMap(tmp[i]->content,"Abstract",_("The WCS link"));
+	    }
+	    if(tmp[i]->supported!=NULL && tmp[i]->supported->next!=NULL &&
+	       tmp[i]->supported->next->content!=NULL){
+	      freeIOType(&tmp[i]->supported);
+	      free(tmp[i]->supported);
+	      tmp[i]->supported=NULL;
+	      tmp[i]->supported=createIoType();
+	      iotype* cnext=cur->supported->next;
+	      tmp[i]->supported->content=createMap(cnext->content->name,cnext->content->value);
+	      addMapToMap(&tmp[i]->supported->content,cnext->content->next);
+	      addToMap(tmp[i]->supported->content,"useMapserver","true");
+	    }else
+	      addToMap(tmp[i]->defaults->content,"useMapserver","true");
+	    break;
+	  }
+	}
+	addToElements(&cur->child,tmp[0]);
+	addToElements(&cur->child,tmp[1]);
+	addToElements(&cur->child,tmp[2]);
+	free(cur->format);
+	cur->format=NULL;
+	if(cur->defaults!=NULL){
+	  freeIOType(&cur->defaults);
+	  free(cur->defaults);
+	  cur->defaults=NULL;
+	}
+	if(cur->supported!=NULL){
+	  freeIOType(&cur->supported);
+	  free(cur->supported);
+	  cur->supported=NULL;
+	}
+	freeElements(&tmp[2]);
+	free(tmp[2]);
+	freeElements(&tmp[1]);
+	free(tmp[1]);
+	freeElements(&tmp[0]);
+	free(tmp[0]);
+	//addToMap(cur->content,"internal","true");
+      }      
+    }else{
+      if(mimeType!=NULL){
+        elements *tmp=dupElements(cur);
+        tmp->name=zStrdup("download_link");
+        tmp->content=createMap("Title",_("Download link"));
+        addToMap(tmp->content,"Abstract",_("The download link"));
+        addToMap(tmp->defaults->content,"useMapserver","false");
+        if(tmp->supported!=NULL){
+          freeIOType(&tmp->supported);
+          free(tmp->supported);
+          tmp->supported=NULL;
+        }
+        addToElements(&cur->child,tmp);
+        free(cur->format);
+        cur->format=NULL;
+        if(cur->defaults!=NULL){
+          freeIOType(&cur->defaults);
+          free(cur->defaults);
+          cur->defaults=NULL;
+        }
+        if(cur->supported!=NULL){
+          freeIOType(&cur->supported);
+          free(cur->supported);
+          cur->supported=NULL;
+        }
+        freeElements(&tmp);
+        free(tmp);
+      }
+    }
+    cur=cur->next;
+  }
+  //dumpElements((*s)->outputs);
+}
+
+/**
+ * Acquire a read lock on every files used as input for executing a service.
+ * @param conf the main configuration file map
+ * @return 0 if every file can be locked, -1 if one lock has failed.
+ */
+int addReadLocks(maps** conf){
+  map* queueLengthMap=getMapFromMaps(*conf,"uploadQueue","length");
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  if(queueLengthMap!=NULL){
+    int cnt=atoi(queueLengthMap->value);
+    int i=0;
+    for(i=0;i<cnt;i++){
+      map* argv[2]={
+	getMapArray(queueMaps->content,"input",i),
+	getMapArray(queueMaps->content,"localPath",i)
+      };
+      zooLock* lck;
+      if((lck=lockFile(*conf,argv[1]->value,'r'))==NULL){
+	const char* templateStr=_("Unable to lock the file for %s in read mode.");
+	char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv[0]->value)+1)*sizeof(char));
+	sprintf(tmpMessage,templateStr,argv[0]->value);
+	setMapInMaps(*conf,"lenv","message",tmpMessage);
+	free(tmpMessage);
+	return -1;
+      }else{
+	if(zoo_file_locks_cnt==0){
+	  zoo_file_locks=(zooLock**)malloc(sizeof(zooLock*));
+	}
+	else{
+	  zoo_file_locks=(zooLock**)realloc(zoo_file_locks,(zoo_file_locks_cnt+1)*sizeof(zooLock*));
+	}
+	zoo_file_locks[zoo_file_locks_cnt]=lck;
+	zoo_file_locks_cnt++;
+      }
+    }
+  }
+  return 0;
+}
+
+/**
+ * Remove all read locks set for files used as input for executing the service.
+ * @param conf the main configuration maps pointer
+ * @return 0 in case of success, -1 if any error occured. In case of error, one
+ * can refer to the message map array from the lenv section.
+ */
+int removeReadLocks(maps** conf){
+  int res=0;
+  int nberr=0;
+  map* queueLengthMap=getMapFromMaps(*conf,"uploadQueue","length");
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  if(queueLengthMap!=NULL){
+    int cnt=atoi(queueLengthMap->value);
+    int i=0;
+    for(i=0;i<cnt;i++){
+      if(unlockFile(*conf,zoo_file_locks[i])<1){
+	map* argv=getMapArray(queueMaps->content,"input",i);
+	const char* templateStr=_("Unable to unlock the file for %s after execution.");
+	char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv->value)+1)*sizeof(char));
+	sprintf(tmpMessage,templateStr,argv->value);
+	maps* lenv=getMaps(*conf,"lenv");
+	setMapArray(lenv->content,"message",nberr,tmpMessage);
+	free(tmpMessage);
+	res=-1;
+	nberr++;
+      }
+    }
+  }
+  free(zoo_file_locks);
+  return res;
+}
+
+/**
+ * Get the section name depending on number of features and/or pixels of each
+ * inputs and the threshold defined in a section.
+ * It supposes that your inputs has been published using MapServer support, 
+ * implying that the number of features (nb_features), respectively pixels 
+ * (nb_pixels), are defined. The section, identified by confId, should contain
+ * preview_max_features and preview_max_pixels defining the threshold values.
+ * @param conf the main configuration file maps pointer
+ * @param inputs the inputs maps pointer
+ * @param confId the section identifier
+ * @return "preview_conf" in case the numbers are lower than the threshold,
+ * "fullres_conf" in other cases.
+ */
+char* getConfiguration(maps** conf,maps** inputs,const char* confId){
+  maps* input=*inputs;
+  map* max_pixels=getMapFromMaps(*conf,confId,"preview_max_pixels");
+  map* max_features=getMapFromMaps(*conf,confId,"preview_max_features");
+  int i_max_pixels=atoi(max_pixels->value);
+  int i_max_features=atoi(max_features->value);
+  while(input!=NULL && input->content!=NULL){
+    map* tmpMap=getMap(input->content,"geodatatype");
+    if(tmpMap!=NULL){
+      map* currentNb;
+      if(strcasecmp(tmpMap->value,"raster")==0 ){
+	currentNb=getMap(input->content,"nb_pixels");
+	if(atoi(currentNb->value)>i_max_pixels)
+	  return "fullres_conf";
+      }else{
+	if(strcasecmp(tmpMap->value,"vector")==0 ){
+	  currentNb=getMap(input->content,"nb_features");
+	  if(atoi(currentNb->value)>i_max_features)
+	    return "fullres_conf";
+	}
+      }
+    }
+    input=input->next;
+  }
+  return "preview_conf";
+}
+
+/**
+ * Load and run a HPC Application corresponding to the service.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ * @return SERVICE_SUCCEEDED in case of success, -1 or SERVICE_FAILED when failing.
+ */
+int zoo_hpc_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=tmp0->value;
+  map* tmp=NULL;
+  int res=-1;
+  // Get the configuration id depending on service type and defined thresholds
+  // then, set the configId key in the lenv section
+  char *serviceType;
+  map* mServiceType=getMap(s->content,"confId");
+  if(mServiceType!=NULL)
+    serviceType=mServiceType->value;
+  else
+    serviceType="HPC";
+  map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+  map* uuid=getMapFromMaps(*main_conf,"lenv","usid");
+  map* confMap=getMapFromMaps(*main_conf,serviceType,getConfiguration(main_conf,real_inputs,serviceType));
+  char * configurationId=confMap->value;
+  setMapInMaps(*main_conf,"lenv","configId",configurationId);
+  // Dump lenv maps again after having set the configId ...
+  char *flenv =
+    (char *)
+    malloc ((strlen (tmpPath->value) + 
+	     strlen (uuid->value) + 12) * sizeof (char));
+  sprintf (flenv, "%s/%s_lenv.cfg", tmpPath->value, uuid->value);
+  maps* lenvMaps=getMaps(m,"lenv");
+  dumpMapsToFile(lenvMaps,flenv,0);
+  free(flenv);
+
+  map* targetPathMap=getMapFromMaps(*main_conf,configurationId,"remote_data_path");
+  map* targetPersistentPathMap=getMapFromMaps(*main_conf,configurationId,"remote_persistent_data_path");
+  
+  pthread_t threads_pool[50];
+  // Force the HPC services to be called asynchronously
+  map* isAsync=getMapFromMaps(*main_conf,"lenv","async");
+  if(isAsync==NULL){
+    errorException(*main_conf,_("The synchronous mode is not supported by this type of service"),"NoSuchMode",s->name);
+    return -1;
+  }
+
+  maps* input=*real_inputs;
+  char **parameters=NULL;
+  int parameters_cnt=0;
+  while(input!=NULL && input->content!=NULL){
+    map* isInRequest=getMap(input->content,"inRequest");
+    map* minNb=getMap(input->content,"minOccurs");
+    if(getMaps(*real_outputs,input->name)==NULL &&
+       ( (isInRequest!=NULL && strncasecmp(isInRequest->value,"true",4)==0)
+	 || (minNb!=NULL && atoi(minNb->value)>0) ) ){
+      parameters_cnt+=1;
+      if(parameters_cnt==1)
+	parameters=(char**)malloc(parameters_cnt*sizeof(char*));
+      else
+	parameters=(char**)realloc(parameters,parameters_cnt*sizeof(char*));
+      if(getMap(input->content,"mimeType")!=NULL){
+	// Input is ComplexData
+	if(getMap(input->content,"cache_file")==NULL){
+	  // Input data has been passed by value
+	  // TODO: publish input through MapServer / use output publication
+	  dumpMapsValuesToFiles(main_conf,&input);
+	  addToMap(input->content,"toPublish","true");
+	  //addToMap(input->content,"useMapserver","true");
+	}
+	if(getMap(input->content,"cache_file")!=NULL){
+	  map* length=getMap(input->content,"length");
+	  if(length==NULL){
+	    addToMap(input->content,"length","1");
+	    length=getMap(input->content,"length");
+	  }
+	  int len=atoi(length->value);
+	  int i=0;
+	  for(i=0;i<len;i++){
+	    map* tmp=getMapArray(input->content,"cache_file",i);
+	    map* origin=getMapArray(input->content,"origin",i);
+	    char* targetName=strrchr(tmp->value,'/');
+	    char *targetPath;
+	    if(origin!=NULL && strcasecmp(origin->value,"SHARED")==0 && targetPersistentPathMap!=NULL){
+	      targetPath=(char*)malloc((strlen(targetPersistentPathMap->value)+strlen(targetName)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",targetPersistentPathMap->value,targetName);
+	    }
+	    else{
+	      targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+	    }
+	    setMapArray(input->content,"targetPath",i,targetPath);
+	    setMapArray(input->content,"localPath",i,tmp->value);
+	    map* tmp1=getMapArray(input->content,"value",i);
+	    if(tmp1!=NULL){
+	      free(tmp1->value);
+	      tmp1->value=strdup("empty");
+	    }
+	    if(i==0){
+	      parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+3)*sizeof(char));
+	      sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,targetPath);
+	    }else{
+	      fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	      fflush(stderr);
+	      char *tmpStr=zStrdup(parameters[parameters_cnt-1]);
+	      parameters[parameters_cnt-1]=(char*)realloc(parameters[parameters_cnt-1],(strlen(tmpStr)+strlen(targetPath)+2)*sizeof(char));
+	      sprintf(parameters[parameters_cnt-1],"%s %s",tmpStr,targetPath);
+	      free(tmpStr);
+	      fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	      fflush(stderr);
+	    }
+	    free(targetPath);
+	  }
+	  addToUploadQueue(main_conf,input);
+	}else{
+	  // ???
+	  fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	  fflush(stderr);
+	}
+      }else{
+	// LitteralData and BboxData 
+	if(getMap(input->content,"dataType")!=NULL){
+	  // For LitteralData, simply pass the value
+          map* length=getMap(input->content,"length");
+          if(length!=NULL){
+            char* value=NULL;
+            int len=atoi(length->value);
+            int i=0;
+            for(i=0;i<len;i++){
+              map* val=getMapArray(input->content,"value",i);
+              if(val!=NULL){
+                if(value==NULL){
+                  value=(char*)malloc((strlen(val->value)+3)*sizeof(char));
+                  sprintf(value,"\"%s\"",val->value);
+                }
+                else{
+                  value=(char*)realloc(value,(strlen(value)+strlen(val->value)+4)*sizeof(char));
+                  sprintf(value,"%s \"%s\"",value,val->value);
+                }
+              }
+            }
+            if(value!=NULL){
+              parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(value)+3)*sizeof(char));
+              sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,value);
+            }
+          }else{
+            map* val=getMap(input->content,"value");
+            parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(val->value)+5)*sizeof(char));
+            sprintf(parameters[parameters_cnt-1],"-%s \"%s\"",input->name,val->value);
+          }
+	}
+      }
+    }
+    input=input->next;
+  }
+
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,1,1);
+  invokeCallback(m,inputs,NULL,2,0);
+#endif  
+  if(getMapFromMaps(m,"lenv","mapError")!=NULL){
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,inputs,NULL,7,0);
+#endif
+    return -1;
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  dumpMaps(inputs);
+#endif
+
+  // Upload data on HPC
+  if(runUpload(main_conf)==false){
+    errorException (*main_conf, _("Unable to lock the file for upload!"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,inputs,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+    return -1;
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,2,1);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+
+  // Add the filename to generate for every output to parameters
+  input=*real_outputs;
+#ifdef HPC_DEBUG
+  dumpMaps(input);
+#endif
+  while(input!=NULL){
+    // Parse all outputs including inner outputs if required.
+    if(input->child==NULL){
+      // Name every files that should be produced by the service execution
+      map* mime=getMap(input->content,"mimeType");
+      char* targetName;
+      if(mime!=NULL){
+	bool hasExt=false;
+	map* fileExt=getFileExtensionMap(mime->value,&hasExt);
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+strlen(fileExt->value)+11)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.%s",s->name,input->name,uuid->value,fileExt->value);
+	freeMap(&fileExt);
+	free(fileExt);
+      }else{
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+14)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.tif",s->name,input->name,uuid->value);
+      }
+      char *targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+      map *tmpUrl=getMapFromMaps(*main_conf,"main","tmpUrl");
+      char *targetUrl=(char*)malloc((strlen(tmpUrl->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetUrl,"%s/%s",tmpUrl->value,targetName);
+      free(targetName);
+      setMapInMaps(*real_outputs,input->name,"generated_file",targetPath);
+      addToMap(input->content,"generated_url",targetUrl);
+      free(targetUrl);
+      {
+	parameters_cnt+=1;
+	if(parameters_cnt==1)
+	  parameters=(char**)malloc(parameters_cnt*sizeof(char*));
+	else
+	  parameters=(char**)realloc(parameters,parameters_cnt*sizeof(char*));
+	// We should verify if any optional tag for output is required
+	// (i.e. -out output.tiff *int8*), meaning that we should search
+	// for a corresponding inputs name.
+	map* inValue=getMapFromMaps(*real_inputs,input->name,"value");
+	if(inValue!=NULL){
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+strlen(inValue->value)+4)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s %s",input->name,targetPath,inValue->value);
+	}else{
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+3)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,targetPath);
+	}
+      }
+      free(targetPath);
+    }// In other case it means we need to return the cache_file as generated_file
+    else{
+      // Name every files that should be produced by the service execution
+      map* mime=getMap(input->child->content,"mimeType");
+      char* targetName;
+      if(mime!=NULL){
+	bool hasExt=false;
+	map* fileExt=getFileExtensionMap(mime->value,&hasExt);
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+strlen(fileExt->value)+11)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.%s",s->name,input->name,uuid->value,fileExt->value);
+	freeMap(&fileExt);
+	free(fileExt);
+      }else{
+	targetName=(char*)malloc((strlen(s->name)+strlen(input->name)+strlen(uuid->value)+14)*sizeof(char));
+	sprintf(targetName,"output_%s_%s_%s.tif",s->name,input->name,uuid->value);
+      }
+      char *targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+      map *tmpUrl=getMapFromMaps(*main_conf,"main","tmpUrl");
+      char *targetUrl=(char*)malloc((strlen(tmpUrl->value)+strlen(targetName)+2)*sizeof(char));
+      sprintf(targetUrl,"%s/%s",tmpUrl->value,targetName);
+      free(targetName);
+      addToMap(input->content,"generated_file",targetPath);
+      addToMap(input->content,"storage",targetPath);
+      addToMap(input->content,"generated_url",targetUrl);
+      free(targetUrl);
+      if(strcasecmp(input->name,"wms_link")!=0&&
+	 strcasecmp(input->name,"wcs_link")!=0 &&
+	 strcasecmp(input->name,"wfs_link")!=0){
+	parameters_cnt+=1;
+	if(parameters_cnt==1)
+	  parameters=(char**)malloc(parameters_cnt*sizeof(char*));
+	else
+	  parameters=(char**)realloc(parameters,parameters_cnt*sizeof(char*));
+	// We should verify if any optional tag for output is required
+	// (i.e. -out output.tiff *int8*), meaning that we should search
+	// for a corresponding inputs name.
+	map* inValue=getMapFromMaps(*real_inputs,input->name,"value");
+	if(inValue!=NULL){
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+strlen(inValue->value)+4)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s %s",input->name,targetPath,inValue->value);
+	}else{
+	  parameters[parameters_cnt-1]=(char*)malloc((strlen(input->name)+strlen(targetPath)+3)*sizeof(char));
+	  sprintf(parameters[parameters_cnt-1],"-%s %s",input->name,targetPath);
+	}
+      }
+      free(targetPath);
+    }
+    input=input->next;
+  }
+  // Produce the SBATCH File locally
+  char *scriptPath=(char*)malloc((strlen(s->name)+strlen(tmpPath->value)+strlen(uuid->value)+10)*sizeof(char));
+  sprintf(scriptPath,"%s/zoo_%s_%s.sh",tmpPath->value,s->name,uuid->value);
+  setMapInMaps(*main_conf,"lenv","local_script",scriptPath);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,3,0);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  FILE* scriptFile=fopen(scriptPath,"w+");
+  map* headerMap=getMapFromMaps(*main_conf,configurationId,"jobscript_header");
+  if(headerMap!=NULL){
+    // Use the header file if defined in the HPC section of the main.cfg file
+    struct stat f_status;
+    int s=stat(headerMap->value, &f_status);
+    if(s==0){
+      char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(headerMap->value,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+      fprintf(scriptFile,"%s\n### --- ZOO-Service HEADER end --- ###\n\n",fcontent);
+      free(fcontent);
+    }else
+      fprintf(scriptFile,"#!/bin/bash\n\n### *** Default ZOO-Service HEADER (no header found) *** ###\n\n");
+  }else
+    fprintf(scriptFile,"#!/bin/bash\n\n### *** Default ZOO-Service HEADER *** ###\n\n");
+  maps* hpc_opts=getMaps(*main_conf,configurationId);
+  if(hpc_opts!=NULL){
+    map* hpc_opts_content=hpc_opts->content;
+    while(hpc_opts_content!=NULL){
+      if(strncasecmp(hpc_opts_content->name,"sbatch_options_",15)==0)
+	fprintf(scriptFile,"#SBATCH --%s=%s\n",strstr(hpc_opts_content->name,"sbatch_options_")+15,hpc_opts_content->value);
+      hpc_opts_content=hpc_opts_content->next;
+    }
+  }
+  fprintf(scriptFile,"#SBATCH --job-name=ZOO-Project_%s_%s\n\n",uuid->value,s->name);
+  map* mods=getMap(s->content,"hpcModules");
+  if(mods!=NULL)
+    fprintf(scriptFile,"#SBATCH --export=MODULES=%s\n",mods->value);
+
+  map* bodyMap=getMapFromMaps(*main_conf,configurationId,"jobscript_body");
+  if(bodyMap!=NULL){
+    // Use the header file if defined in the HPC section of the main.cfg file
+    struct stat f_status;
+    int s=stat(bodyMap->value, &f_status);
+    if(s==0){
+      char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(bodyMap->value,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+      fprintf(scriptFile,"%s\n### --- ZOO-Service BODY end --- ###\n\n",fcontent);
+      free(fcontent);
+    }else
+      fprintf(scriptFile,"\n### *** Default ZOO-Service BODY (no body found) *** ###\n\n");
+  }else
+    fprintf(scriptFile,"\n### *** Default ZOO-Service BODY *** ###\n\n");
+
+  map* sp=getMap(s->content,"serviceProvider");
+  
+  // Require to produce the command line to be executed
+  fprintf(scriptFile,"\n\necho \"Job started at: $(date)\"\n");
+  fprintf(scriptFile,"echo \"Running service: [%s]\"\n",sp->value);
+  fprintf(scriptFile,"%s ",sp->value);
+  for(int i=0;i<parameters_cnt;i++){
+    fprintf(scriptFile," %s",parameters[i]);
+  }
+  for(int i=parameters_cnt-1;i>=0;i--){
+    free(parameters[i]);
+  }
+  free(parameters);
+  fprintf(scriptFile,"\n");
+  fprintf(scriptFile,"echo \"Job finished at: $(date)\"\n");
+  map* footerMap=getMapFromMaps(*main_conf,configurationId,"jobscript_footer");
+  if(footerMap!=NULL){
+    // Use the footer file if defined in the HPC section of the main.cfg file
+    struct stat f_status;
+    int s=stat(footerMap->value, &f_status);
+    if(s==0){
+      char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(footerMap->value,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+      char* ffcontent=(char*)malloc((strlen(fcontent)+(3*strlen(uuid->value))+1)*sizeof(char));
+      sprintf(ffcontent,fcontent,uuid->value,uuid->value,uuid->value);
+      fprintf(scriptFile,"%s\n### --- ZOO-Service FOOTER end --- ###\n\n",ffcontent);
+      free(fcontent);
+    }else
+      fprintf(scriptFile,"### *** Default ZOO-Service FOOTER (footer file failed to load) *** ###\n\n");
+  }else
+      fprintf(scriptFile,"### *** Default ZOO-Service FOOTER (no footer found) *** ###\n\n");
+  fflush(scriptFile);
+  fclose(scriptFile);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,3,1);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+
+  // Upload the SBATCH File to the remote host
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,inputs,NULL,4,0);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+#endif
+  targetPathMap=getMapFromMaps(*main_conf,configurationId,"remote_work_path");
+  if(targetPathMap==NULL){
+    setMapInMaps(*main_conf,"lenv","message",_("There is no remote_work_path defined in your section!"));
+    setMapInMaps(*main_conf,"lenv","status","failed");
+    errorException (*main_conf, _("There is no remote_work_path defined in your section!"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return SERVICE_FAILED;
+  }
+  char* targetName=strrchr(scriptPath,'/');
+  char *targetPath=(char*)malloc((strlen(targetPathMap->value)+strlen(targetName)+2)*sizeof(char));
+  sprintf(targetPath,"%s/%s",targetPathMap->value,targetName);
+  setMapInMaps(*main_conf,"lenv","remote_script",targetPath);
+  SSHCON *test=ssh_connect(*main_conf);
+  int copy0=ssh_copy(*main_conf,scriptPath,targetPath,ssh_get_cnt(*main_conf));
+  unlink(scriptPath);
+  free(scriptPath);
+  if(copy0!=true){
+    setMapInMaps(*main_conf,"lenv","message",_("Unable to upload the script"));
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    errorException(*main_conf,_("Unable to upload the script"),"NoApplicableCode",NULL);
+    return -1;
+  }
+  // Execute the SBATCH script remotely
+  addReadLocks(main_conf);
+  map* subStr=getMapFromMaps(*main_conf,configurationId,"sbatch_substr");
+  char *command=(char*)malloc((strlen(targetPath)+strlen(targetPathMap->value)+strlen(subStr->value)+strlen(uuid->value)+137)*sizeof(char));
+  sprintf(command,"sbatch %s 2> %s/error_%s.log | sed \"s:%s::g\"",targetPath,targetPathMap->value,uuid->value,subStr->value);
+  if(ssh_exec(*main_conf,command,ssh_get_cnt(m))<=0){
+    // The sbatch command has failed!
+    // Download the error log file from the HPC server
+    char tmpS[1024];
+    free(command);
+    command=(char*)malloc((strlen(targetPathMap->value)+strlen(uuid->value)+11)*sizeof(char));
+    sprintf(command,"%s/error_%s.log",targetPathMap->value,uuid->value);
+    targetName=strrchr(command,'/');
+    free(targetPath);
+    targetPath=(char*)malloc((strlen(tmpPath->value)+strlen(targetName)+2)*sizeof(char));
+    sprintf(targetPath,"%s/%s",tmpPath->value,targetName);
+    if(ssh_fetch(*main_conf,targetPath,command,ssh_get_cnt(m))==0){
+      struct stat f_status;
+      int ts=stat(targetPath, &f_status);
+      if(ts==0) {
+	char* fcontent = NULL;
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(targetPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	int fsize=f_status.st_size;
+	fcontent[fsize]=0;
+	fclose(f);
+	setMapInMaps(*main_conf,"lenv","message",fcontent);
+	free(fcontent);
+      }else
+	setMapInMaps(*main_conf,"lenv","message",_("No message provided"));
+    }else
+      setMapInMaps(*main_conf,"lenv","message",_("Unable to fetch the remote error log file"));
+    tmpPath=getMapFromMaps(m,"lenv","message");
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    sprintf(tmpS, "Cannot execute the HPC ZOO-Service %s using %s: %s", s->name, configurationId, tmpPath->value);
+    errorException(*main_conf,tmpS,"NoApplicableCode",NULL);
+    free(command);
+    free(targetPath);
+    ssh_close(*main_conf);
+    removeReadLocks(main_conf);
+    return -1;
+  }
+  free(targetPath);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+  invokeCallback(m,NULL,NULL,4,1);
+#endif
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  free(command);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+
+  struct sockaddr_un addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  int rc, cl, fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  char *sname=(char*)malloc((strlen(tmpPath->value)+strlen(uuid->value)+20));
+  sprintf(sname,"%s/.wait_socket_%s.sock",tmpPath->value,uuid->value);
+  strncpy(addr.sun_path, sname, sizeof(addr.sun_path)-1);
+  
+  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+    perror("bind error");
+    setMapInMaps(*main_conf,"lenv","message",_("Unable to bind socket!"));
+    errorException (*main_conf, _("Unable to bind socket!"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return -1;
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  if (listen(fd, 5) == -1) {
+    setMapInMaps(*main_conf,"lenv","message",_("Listen error"));
+    errorException (*main_conf, _("Listen error"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return -1;
+  }
+  if ( (cl = accept(fd, NULL, NULL)) == -1) {
+    setMapInMaps(*main_conf,"lenv","message",_("Accept error"));
+    errorException (*main_conf, _("Accept error"),
+		    "InternalError", NULL);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+    invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+    removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    return -1;
+  }else{
+#ifdef HPC_DEBUG
+    fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+    fflush(stderr);
+#endif
+    int hasPassed=-1;
+    char buf[11];
+    memset(&buf,0,11);
+    while ( (rc=read(cl,buf,10)) ) {	  
+      if(rc==0){
+	setMapInMaps(*main_conf,"lenv","message",_("Read closed"));
+	errorException (*main_conf, _("Read closed"),
+			"InternalError", NULL);
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+	removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+	return -1;
+      }else{
+	if(rc<0){
+	  setMapInMaps(*main_conf,"lenv","message",_("Read error"));
+	  errorException (*main_conf, _("Read error"),
+			  "InternalError", NULL);
+#ifdef HPC_DEBUG
+	  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	  fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	  invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+	  removeReadLocks(main_conf);
+#ifdef HPC_DEBUG
+	  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	  fflush(stderr);
+#endif
+	  return -1;
+	}
+      }
+      hasPassed=1;
+      res=atoi(buf);
+      unlink(sname);
+      free(sname);
+      removeReadLocks(main_conf);
+  
+      if(res==3){
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	invokeCallback(m,NULL,outputs,5,0);
+#endif
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+
+	// Read informations provided by FinalizeHPC as a configuration file
+	// then, remove the file.
+	map* jobid=getMapFromMaps(*main_conf,"lenv","usid");
+	map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+	char *filePath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+15)*sizeof(char));
+	sprintf(filePath,"%s/exec_status_%s",tmpPath->value,jobid->value);
+	maps* lm = (maps *) malloc (MAPS_SIZE);
+	lm->child=NULL;
+	lm->next=NULL;
+	int saved_stdout = dup (fileno (stdout));
+	dup2 (fileno (stderr), fileno (stdout));
+	conf_read(filePath,lm);
+	//dumpMaps(m);
+	fflush(stdout);
+	dup2 (saved_stdout, fileno (stdout));
+	close(saved_stdout);
+	unlink(filePath);
+	free(filePath);
+	addMapsToMaps(main_conf,lm);
+	freeMaps(&lm);
+	free(lm);
+
+	input=*real_outputs;
+	while(input!=NULL){
+	  if(input->child==NULL){
+	    map* generatedFile=getMap(input->content,"generated_file");
+	    if(generatedFile!=NULL){
+	      char* filename=strrchr(generatedFile->value,'/');
+	      char* targetPath=(char*)malloc((strlen(tmpPath->value)+strlen(filename)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",tmpPath->value,filename);
+	      test=ssh_connect(*main_conf);
+	      if(ssh_fetch(*main_conf,targetPath,generatedFile->value,ssh_get_cnt(m))==0){
+		setMapInMaps(*real_outputs,input->name,"generated_file",targetPath);
+		free(targetPath);
+	      }else{
+		map* hpcStdErr=getMapFromMaps(*main_conf,"henv","StdErr");
+		// Added for using sacct in place of scontrol
+		char *sourcePath=NULL;
+		if(hpcStdErr!=NULL){
+		  sourcePath=(char*)malloc((strlen(targetPathMap->value)+strlen(hpcStdErr->value)+2)*sizeof(char));
+		  sprintf(sourcePath,"%s/%s",targetPathMap->value,hpcStdErr->value);
+		}
+                if(hpcStdErr!=NULL && sourcePath!=NULL && ssh_fetch(*main_conf,targetPath,sourcePath,ssh_get_cnt(m))==0){
+		  free(sourcePath);
+		  struct stat f_status;
+		  int ts=stat(targetPath, &f_status);
+		  if(ts==0) {
+		    char* fcontent = NULL;
+		    fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+		    FILE* f=fopen(targetPath,"rb");
+		    fread(fcontent,f_status.st_size,1,f);
+		    int fsize=f_status.st_size;
+		    fcontent[fsize]=0;
+		    fclose(f);
+		    setMapInMaps(*main_conf,"lenv","message",fcontent);
+		    free(fcontent);
+		  }else{
+		    char *tmpStr=(char*)malloc((strlen(targetPath)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+		    sprintf(tmpStr,_("Unable to fetch the remote file for %s"),targetPath);
+		    setMapInMaps(*main_conf,"lenv","message",tmpStr);
+		    free(tmpStr);
+		  }
+                }else{
+                  char *tmpStr=(char*)malloc((strlen(filename)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+                  sprintf(tmpStr,_("Unable to fetch the remote file for %s"),filename);
+                  setMapInMaps(*main_conf,"lenv","message",tmpStr);
+                  free(tmpStr);
+                }
+#ifdef USE_CALLBACK
+		invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+		return SERVICE_FAILED;
+	      }
+	    }
+	  }else{
+	    map* generatedFile=getMap(input->content,"generated_file");
+	    map* generatedUrl=getMap(input->content,"generated_url");
+	    if(generatedFile!=NULL){
+	      char* filename=strrchr(generatedFile->value,'/');
+	      char* targetPath=(char*)malloc((strlen(tmpPath->value)+strlen(filename)+2)*sizeof(char));
+	      sprintf(targetPath,"%s/%s",tmpPath->value,filename);
+	      test=ssh_connect(*main_conf);
+	      if(ssh_fetch(*main_conf,targetPath,generatedFile->value,ssh_get_cnt(m))==0){
+		maps* tmp=getMaps(*real_outputs,input->name);
+		char serviceName[9];
+		freeMap(&tmp->content);
+		free(tmp->content);
+		tmp->content=NULL;
+		maps* output=getMaps(*real_outputs,input->name);
+		setMapInMaps(output->child,"download_link","generated_file",targetPath);
+		setMapInMaps(output->child,"download_link","generated_url",generatedUrl->value);
+		setMapInMaps(output->child,"download_link","storage",targetPath);
+		setMapInMaps(output->child,"download_link","useMapserver","false");
+		setMapInMaps(output->child,"download_link","replicateStorageNext","true");
+		setMapInMaps(output->child,"download_link","asReference","true");
+		setMapInMaps(output->child,"download_link","inRequest","true");
+		setMapInMaps(output->child,"wms_link","generated_file",targetPath);
+		setMapInMaps(output->child,"wms_link","storage",targetPath);
+		setMapInMaps(output->child,"wms_link","useMapserver","true");
+		setMapInMaps(output->child,"wms_link","msOgc","WMS");
+		setMapInMaps(output->child,"wms_link","requestedMimeType","image/png");
+		setMapInMaps(output->child,"wms_link","asReference","true");
+		if(getMaps(output->child,"wcs_link")!=NULL){
+		  sprintf(serviceName,"wcs_link");
+		  setMapInMaps(output->child,"wcs_link","msOgc","WCS");
+		}else{
+		  sprintf(serviceName,"wfs_link");
+		  setMapInMaps(output->child,"wfs_link","msOgc","WFS");
+                }
+		setMapInMaps(output->child,serviceName,"storage",targetPath);
+		setMapInMaps(output->child,serviceName,"generated_file",targetPath);
+		setMapInMaps(output->child,serviceName,"useMapserver","true");
+		setMapInMaps(output->child,serviceName,"asReference","true");
+	      }else{
+		map* hpcStdErr=getMapFromMaps(*main_conf,"henv","StdErr");
+		char *sourcePath=NULL;
+		if(hpcStdErr!=NULL){
+		  dumpMap(hpcStdErr);
+		  sourcePath=(char*)malloc((strlen(targetPathMap->value)+strlen(hpcStdErr->value)+2)*sizeof(char));
+		  sprintf(sourcePath,"%s/%s",targetPathMap->value,hpcStdErr->value);
+		}
+                if(hpcStdErr!=NULL && sourcePath!=NULL && ssh_fetch(*main_conf,targetPath,sourcePath,ssh_get_cnt(m))==0){
+		  free(sourcePath);
+		  struct stat f_status;
+		  int ts=stat(targetPath, &f_status);
+		  if(ts==0) {
+		    char* fcontent = NULL;
+		    fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+		    FILE* f=fopen(targetPath,"rb");
+		    fread(fcontent,f_status.st_size,1,f);
+		    int fsize=f_status.st_size;
+		    fcontent[fsize]=0;
+		    fclose(f);
+		    setMapInMaps(*main_conf,"lenv","message",fcontent);
+		    free(fcontent);
+		  }else{
+		    char *tmpStr=(char*)malloc((strlen(targetPath)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+		    sprintf(tmpStr,_("Unable to fetch the remote file for %s"),targetPath);
+		    setMapInMaps(*main_conf,"lenv","message",tmpStr);
+		    free(tmpStr);
+		  }
+		}else{
+		  char *tmpStr=(char*)malloc((strlen(sourcePath)+strlen(_("Unable to fetch the remote file for %s"))+1)*sizeof(char));
+		  sprintf(tmpStr,_("Unable to fetch the remote file for %s"),sourcePath);
+		  setMapInMaps(*main_conf,"lenv","message",tmpStr);
+		  free(tmpStr);
+		}
+#ifdef USE_CALLBACK
+                invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+                return SERVICE_FAILED;
+	      }
+	      free(targetPath);
+	    }
+	  }
+	  input=input->next;
+	}
+
+      }else{
+	// Try to access remotely to the log file and return a more relevant error message
+	setMapInMaps(*main_conf,"lenv","message",_("HPC Execution failed!"));
+	errorException (*main_conf, _("HPC Execution failed!"),
+			"InternalError", NULL);
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+	invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+	fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+	fflush(stderr);
+#endif
+      }
+    }
+    if(hasPassed<0){
+      perror("Failed to read");
+      setMapInMaps(*main_conf,"lenv","message",_("Unable to parse the value returned by remote execution"));
+      errorException (*main_conf, _("Unable to parse the value returned by remote execution"),
+		      "InternalError", NULL);
+#ifdef HPC_DEBUG
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+      fflush(stderr);
+#endif
+#ifdef USE_CALLBACK
+      invokeCallback(*main_conf,NULL,NULL,7,0);
+#endif
+#ifdef HPC_DEBUG
+      fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+      fflush(stderr);
+#endif
+      return SERVICE_FAILED;
+    }
+  }
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  ssh_close(*main_conf);
+#ifdef HPC_DEBUG
+  fprintf(stderr,"************************* %s %d \n\n",__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  return res;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_hpc.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_hpc.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_hpc.h	(revision 942)
@@ -0,0 +1,45 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2017 GeoLabs SARL
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_HPC_H
+#define ZOO_SERVICE_INTERNAL_HPC_H 1
+
+#pragma once 
+
+#include "service_internal.h"
+#include "service.h"
+#ifdef WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+#include "sshapi.h"
+
+void addNestedOutputs(service**);
+int zoo_hpc_support(maps**,map*,service*,maps**,maps**);
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_java.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_java.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_java.c	(revision 942)
@@ -0,0 +1,810 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2013 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_java.h"
+#include "response_print.h"
+
+/**
+ * Load a JAVA class then run the static public method corresponding to the 
+ * service by passing the conf, inputs and outputs parameters by reference.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_java_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* cwdMap=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=NULL;
+  if(cwdMap!=NULL)
+    ntmp=zStrdup(cwdMap->value);
+  map* tmp=getMap(request,"metapath");
+  char *classpath;
+  char *oclasspath;
+  int res=SERVICE_FAILED;
+  char *cclasspath=getenv("CLASSPATH");
+  if(tmp!=NULL){
+    if(cclasspath!=NULL){
+      classpath=(char*) malloc((strlen(ntmp)+strlen(tmp->value)+strlen(cclasspath)+4)*sizeof(char));
+      oclasspath=(char*) malloc((strlen(ntmp)+strlen(tmp->value)+strlen(cclasspath)+22)*sizeof(char));
+#ifndef WIN32
+      sprintf(classpath,"%s/%s/:%s",ntmp,tmp->value,cclasspath);
+#else
+      sprintf(classpath,"%s/%s/;%s",ntmp,tmp->value,cclasspath);
+#endif
+    }
+    else{
+      classpath=(char*) malloc((strlen(ntmp)+strlen(tmp->value)+3)*sizeof(char));
+      oclasspath=(char*) malloc((strlen(ntmp)+strlen(tmp->value)+21)*sizeof(char));
+      sprintf(classpath,"%s/%s/",ntmp,tmp->value);
+    }
+  }else{
+    if(cclasspath!=NULL){
+      classpath=(char*) malloc((strlen(ntmp)+strlen(cclasspath)+3)*sizeof(char));
+      oclasspath=(char*) malloc((strlen(ntmp)+strlen(cclasspath)+21)*sizeof(char));
+#ifndef WIN32
+      sprintf(classpath,"%s/:%s",ntmp,cclasspath);
+#else
+      sprintf(classpath,"%s/;%s",ntmp,cclasspath);
+#endif
+    }
+    else{
+      classpath=(char*) malloc((strlen(ntmp)+2)*sizeof(char));
+      oclasspath=(char*) malloc((strlen(ntmp)+20)*sizeof(char));
+      sprintf(classpath,"%s/",ntmp);
+    }
+  }
+  sprintf(oclasspath,"-Djava.class.path=%s",classpath);
+#ifdef DEBUG
+  fprintf(stderr,"CLASSPATH=%s\n",classpath);
+  fprintf(stderr,"(%s)\n",oclasspath);
+#endif
+#ifndef USE_JDB
+  int njdb=0;
+#else
+  int njdb=2;
+#endif
+#ifndef WIN32
+  int nb=2+njdb;
+#endif
+  int nbs[3]={0,0,0};
+  maps* javaMap=getMaps(*main_conf,"java");
+  if(javaMap!=NULL){
+    nbs[0]+=count(javaMap->content);
+  }
+  int nbc1=0;
+  maps* javaXMap=getMaps(*main_conf,"javax");
+  if(javaXMap!=NULL){
+    nbs[1]+=count(javaXMap->content);
+  }
+  int nbc0=0;
+  maps* javaXXMap=getMaps(*main_conf,"javaxx");
+  if(javaXXMap!=NULL){
+    nbs[2]+=count(javaXXMap->content);
+  }
+#ifdef WIN32
+  const int nb=2+nbs[1]+nbs[2]+nbs[0];
+  JavaVMOption *options=(JavaVMOption*)malloc(nb*sizeof(JavaVMOption));
+#else
+  JavaVMOption options[nb+nbs[1]+nbs[2]+nbs[0]+1];
+#endif
+  JavaVMInitArgs vm_args;
+  JavaVM *jvm;
+  JNIEnv *env;
+  long result;
+  jmethodID pmid;
+  jclass cls;
+#ifdef JAVA7
+  jobject cls_gr;
+#else
+  jclass cls_gr;
+#endif
+  int i,start;
+  options[0].optionString = oclasspath;
+  options[0].extraInfo=NULL;
+  options[1].optionString = "-server";
+  options[1].extraInfo=NULL;
+#ifdef USE_JDB
+  options[2].optionString = "-Xdebug";
+  options[2].extraInfo=NULL;
+  options[3].optionString = "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7896";
+  options[3].extraInfo=NULL;
+#endif
+#ifdef WIN32
+  start=2;
+  options[1].optionString = "-Xmx512m";
+#else
+  start=2+njdb;
+#endif
+  map *cursors[3]={NULL,NULL,NULL};
+  if(javaMap!=NULL)
+    cursors[0]=javaMap->content;
+  if(javaXMap!=NULL)
+    cursors[1]=javaXMap->content;
+  if(javaXXMap!=NULL)
+    cursors[2]=javaXXMap->content;
+  for(i=0;i<nbs[0];i++){
+    char *tmp=parseJVMOption(cursors[0]);
+    options[start+i].optionString = zStrdup(tmp);
+    options[start+i].extraInfo=NULL;
+    free(tmp);
+    cursors[0]=cursors[0]->next;
+  }
+  for(;i<nbs[0]+nbs[1];i++){
+    char *tmp=parseJVMXOption(cursors[1]);
+    options[start+i].optionString = zStrdup(tmp);
+    options[start+i].extraInfo=NULL;
+    free(tmp);
+    cursors[1]=cursors[1]->next;
+  }
+  for(;i<nbs[0]+nbs[2]+nbs[1];i++){
+    char *tmp=parseJVMXXOption(cursors[2]);
+    options[start+i].optionString = zStrdup(tmp);
+    options[start+i].extraInfo=NULL;
+    free(tmp);
+    cursors[2]=cursors[2]->next;
+  }
+
+  JNI_GetDefaultJavaVMInitArgs(&vm_args);
+  vm_args.version = JNI_VERSION_1_6;
+  vm_args.options = options;
+  vm_args.nOptions = start+nbs[0]+nbs[1]+nbs[2];
+  vm_args.ignoreUnrecognized = JNI_TRUE;
+
+  result = JNI_CreateJavaVM(&jvm,(void **)&env, &vm_args);
+  if(result == JNI_ERR ) {
+    fprintf(stderr,"Error invoking the JVM");
+    return -1;
+  }
+#ifdef DEBUG
+  else
+    fprintf(stderr,"JAVA VM Started\n");
+#endif
+
+  tmp=getMap(s->content,"serviceProvider");
+#ifdef JAVA7
+  cls = (*env).FindClass(tmp->value);
+#else
+  cls = (*env)->FindClass(env,tmp->value);
+#endif
+  if( cls == NULL ) {
+    displayStack(env,*main_conf);
+#ifdef JAVA7
+    (*jvm).DestroyJavaVM();
+#else
+    (*jvm)->DestroyJavaVM(jvm);
+#endif
+    return -1;
+  }
+#ifdef DEBUG
+  else{
+    fprintf(stderr,"%s loaded\n",tmp->value);
+  }
+#endif
+#ifdef JAVA7
+  cls_gr = (*env).NewGlobalRef(cls);
+#else
+  cls_gr = (*env)->NewGlobalRef(env, cls);
+#endif
+
+  if (cls != NULL) {
+#ifdef JAVA7
+    (*env).ExceptionClear();
+    pmid=(*env).GetStaticMethodID(cls, s->name, "(Ljava/util/HashMap;Ljava/util/HashMap;Ljava/util/HashMap;)I");
+#else
+    (*env)->ExceptionClear(env);
+    pmid=(*env)->GetStaticMethodID(env,cls_gr, s->name, "(Ljava/util/HashMap;Ljava/util/HashMap;Ljava/util/HashMap;)I");
+#endif
+    if (pmid!=0){
+#ifdef DEBUG
+      fprintf(stderr,"Function successfully loaded\n");
+#endif
+      jclass scHashMapClass,scHashMap_class;
+      jmethodID scHashMap_constructor;
+#ifdef JAVA7
+      scHashMapClass = (*env).FindClass("java/util/HashMap");
+      scHashMap_class = (jclass)(*env).NewGlobalRef(scHashMapClass);
+      scHashMap_constructor = (*env).GetMethodID(scHashMap_class, "<init>", "()V");
+#else
+      scHashMapClass = (*env)->FindClass(env, "java/util/HashMap");
+      scHashMap_class = (*env)->NewGlobalRef(env, scHashMapClass);
+      scHashMap_constructor = (*env)->GetMethodID(env, scHashMap_class, "<init>", "()V");
+#endif
+      /**
+       * The 3 standard parameter for each services
+       */
+      jobject arg1=HashMap_FromMaps(env,m,scHashMapClass,scHashMap_class,scHashMap_constructor);
+      jobject arg2=HashMap_FromMaps(env,inputs,scHashMapClass,scHashMap_class,scHashMap_constructor);
+      jobject arg3=HashMap_FromMaps(env,outputs,scHashMapClass,scHashMap_class,scHashMap_constructor);
+      jint pValue=0;
+
+#ifdef JAVA7
+      pValue=(*env).CallStaticIntMethod(cls,pmid,arg1,arg2,arg3);
+#else
+      pValue=(*env)->CallStaticIntMethod(env,cls,pmid,arg1,arg2,arg3);
+#endif
+      if (pValue != (jint)NULL){
+	res=pValue;
+	freeMaps(real_outputs);
+	free(*real_outputs);
+	freeMaps(main_conf);
+	free(*main_conf);
+	*main_conf=mapsFromHashMap(env,arg1,scHashMapClass);
+	*real_outputs=mapsFromHashMap(env,arg3,scHashMapClass);
+#ifdef DEBUG
+	fprintf(stderr,"Result of call: %i\n", pValue);
+	dumpMaps(inputs);
+	dumpMaps(outputs);
+#endif
+      }else{
+	displayStack(env,*main_conf);
+#ifdef JAVA7
+	(*jvm).DestroyJavaVM();
+#else
+	(*jvm)->DestroyJavaVM(jvm);
+#endif
+	return -1;
+      }
+    }
+    else{
+      displayStack(env,*main_conf);
+#ifdef JAVA7
+      (*env).ExceptionDescribe();
+      (*jvm).DestroyJavaVM();
+#else
+      (*jvm)->DestroyJavaVM(jvm);
+#endif
+      return -1;
+    }
+  }
+#ifdef JAVA7
+  (*jvm).DestroyJavaVM();
+#else
+  (*jvm)->DestroyJavaVM(jvm);
+#endif
+  for(i=0;i<nbs[2]+nbs[1]+nbs[0];i++){
+    free(options[start+i].optionString);
+  }
+#ifdef WIN32
+  free(options);
+#endif
+  return res;
+}
+
+/**
+ * Error handling: display stack trace in an ExceptionReport Document
+ *
+ * @param env the JNI environment pointer
+ * @param main_conf the conf maps containing the main.cfg settings
+ */
+void displayStack(JNIEnv *env,maps* main_conf){
+  map *tmpm=getMapFromMaps(main_conf,"main","tmpPath");
+  char tmps[1024];
+  sprintf(tmps,"%s/%d.ztmp",tmpm->value,getpid());
+  FILE* new_stdout=fopen(tmps,"wb+");
+  if(new_stdout==NULL){
+    map* err=createMap("text","Unable to run your service, no debug information can be provided (please verify privileges on tmpPath)");
+    addToMap(err,"code","InternalError");
+    printExceptionReportResponse(main_conf,err);
+    freeMap(&err);
+    free(err);
+    return;
+  }
+  fflush(stderr);
+  dup2(fileno(new_stdout),fileno(stderr));
+  fprintf(stderr,"Unable to run your java process properly: ");
+  fflush(stderr);
+#ifdef JAVA7
+  (*env).ExceptionDescribe();
+#else
+  (*env)->ExceptionDescribe(env);
+#endif
+  fflush(new_stdout);
+  fseek(new_stdout, 0, SEEK_END);
+  long flen=ftell(new_stdout);
+  fseek(new_stdout, 0, SEEK_SET);
+  char *tmps1=(char*)malloc((flen+1)*sizeof(char));
+  fread(tmps1,flen,1,new_stdout);
+  fclose(new_stdout);
+  tmps1[flen]=0;
+  map* err=createMap("text",tmps1);
+  addToMap(err,"code","InternalError");
+  printExceptionReportResponse(main_conf,err);
+  freeMap(&err);
+  free(err);
+}
+
+/**
+ * Create a string containing the JVM -D* options for a given map
+ * The result will be : -Dname=value
+ *
+ * @param m the map containing the option
+ * @return a char* containing the valide JVM option (-D*)
+ */
+char *parseJVMOption(map* m){
+  char *res=(char*)malloc((strlen(m->name)+strlen(m->value)+4)*sizeof(char));
+  sprintf(res,"-D%s=%s",m->name,m->value);
+  return res;
+}
+
+/**
+ * Create a string containing the JVM -XX:* option for a given map
+ * Depending on the map' name:
+ *  - in case the value is minus then the result will be : -XX:-name
+ *  - in case the value is plus then the result will be : -XX:+name
+ *  - in other cases the result will be : -XX:name=value
+ *
+ * @param m the map containing the option
+ * @return a char* containing the valide JVM option (-XX:*)
+ */
+char *parseJVMXXOption(map* m){
+  char *res=(char*)malloc((strlen(m->name)+strlen(m->value)+6)*sizeof(char));
+  if(strncasecmp(m->value,"minus",5)==0)
+    sprintf(res,"-XX:-%s",m->name);
+  else if(strncasecmp(m->value,"plus",4)==0)
+    sprintf(res,"-XX:+%s",m->name);
+  else
+    sprintf(res,"-XX:%s=%s",m->name,m->value);
+  return res;
+}
+
+/**
+ * Create a string containing the JVM -X** option for a given map.
+ * The result will be in the following format: -Xnamevalue
+ *
+ * @param m the map containing the option
+ * @return a char* containing the valide JVM option (-X**)
+ */
+char *parseJVMXOption(map* m){
+  char *res=(char*)malloc((strlen(m->name)+strlen(m->value)+5)*sizeof(char));
+  sprintf(res,"-X%s%s",m->name,m->value);
+  return res;
+}
+
+/**
+ * Convert a maps to a JAVA HashMap<String,HashMap<String,String>>
+ *
+ * @param env the JNI environment pointer
+ * @param t the maps to convert
+ * @param scHashMapClass the HashMap class
+ * @param scHashMap_class the HashMap class
+ * @param scHashMap_constructor the pointer to the hashMap constructor method
+ * @return a created JAVA HashMap containing the converted maps
+ * @warning make sure to free resources returned by this function
+ */
+jobject HashMap_FromMaps(JNIEnv *env,maps* t,jclass scHashMapClass,jclass scHashMap_class,jmethodID scHashMap_constructor){
+  jobject scObject,scObject1;
+  if(scHashMap_constructor!=NULL){
+#ifdef JAVA7
+    scObject = (*env).NewObject(scHashMap_class, scHashMap_constructor);
+#else
+    scObject = (*env)->NewObject(env, scHashMap_class, scHashMap_constructor);
+#endif
+    jmethodID put_mid = 0;
+
+#ifdef JAVA7
+    put_mid = (*env).GetMethodID(scHashMapClass, "put",
+				  "(Ljava/lang/Object;Ljava/lang/Object;)"
+				  "Ljava/lang/Object;");
+#else
+    put_mid = (*env)->GetMethodID(env,scHashMapClass, "put",
+				  "(Ljava/lang/Object;Ljava/lang/Object;)"
+				  "Ljava/lang/Object;");
+#endif
+    maps* tmp=t;
+    while(tmp!=NULL){
+      map* tmap=getMapType(tmp->content);
+      map* tmp1=tmp->content;
+#ifdef JAVA7
+      scObject1 = (*env).NewObject(scHashMap_class, scHashMap_constructor);
+#else
+      scObject1 = (*env)->NewObject(env, scHashMap_class, scHashMap_constructor);
+#endif
+      map* sizeV=getMap(tmp1,"size");
+      map* useFile=getMap(tmp1,"use_file");
+      map* cacheFile=getMap(tmp1,"cache_file");
+      map* isArray=getMap(tmp1,"isArray");
+      map* alen=getMap(tmp1,"length");
+      while(tmp1!=NULL){
+	if(strcmp(tmp1->name,"value")==0){
+	  if(isArray==NULL){
+	    if(sizeV!=NULL && strcmp(tmp1->name,"value")==0 && useFile==NULL){
+#ifdef JAVA7
+	      jbyteArray tmpData=(*env).NewByteArray(atoi(sizeV->value));
+	      (*env).SetByteArrayRegion(tmpData,0,atoi(sizeV->value),(const jbyte *)tmp1->value);
+	      (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF(tmp1->name), tmpData);
+#else
+	      jbyteArray tmpData=(*env)->NewByteArray(env,atoi(sizeV->value));
+	      (*env)->SetByteArrayRegion(env,tmpData,0,atoi(sizeV->value),(jbyte*) tmp1->value);
+	      (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,tmp1->name), tmpData);
+#endif
+	    }else
+#ifdef JAVA7
+	      (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF(tmp1->name), (*env).NewStringUTF(tmp1->value));
+#else
+	      (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,tmp1->name), (*env)->NewStringUTF(env,tmp1->value));
+#endif
+	      if(useFile!=NULL)
+#ifdef JAVA7
+		(*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF("cache_file"), (*env).NewStringUTF(cacheFile->value));
+#else
+	        (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,"cache_file"), (*env)->NewStringUTF(env,cacheFile->value));
+#endif
+	      
+	  }
+	  else{
+	    int alen1=atoi(alen->value);
+	    fprintf(stderr,"LENGTH %d \n",alen1);
+	    
+	    jclass scArrayListClass,scArrayList_class;
+	    jmethodID scArrayList_constructor;
+	    jobject scObject2,scObject3;
+#ifdef JAVA7
+	    scArrayListClass = (*env).FindClass("java/util/ArrayList");
+	    scArrayList_class = (jclass)(*env).NewGlobalRef(scArrayListClass);
+	    scArrayList_constructor = (*env).GetMethodID(scArrayList_class, "<init>", "()V");
+	    jmethodID add_mid = 0;
+	    scObject2 = (*env).NewObject(scArrayList_class, scArrayList_constructor);
+	    scObject3 = (*env).NewObject(scArrayList_class, scArrayList_constructor);
+
+	    add_mid = (*env).GetMethodID(scArrayListClass,
+					  "add","(Ljava/lang/Object;)Z");
+#else
+	    scArrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
+	    scArrayList_class = (*env)->NewGlobalRef(env, scArrayListClass);
+	    scArrayList_constructor = (*env)->GetMethodID(env, scArrayList_class, "<init>", "()V");
+	    jmethodID add_mid = 0;
+	    scObject2 = (*env)->NewObject(env, scArrayList_class, scArrayList_constructor);
+	    scObject3 = (*env)->NewObject(env, scArrayList_class, scArrayList_constructor);
+
+	    add_mid = (*env)->GetMethodID(env,scArrayListClass,
+					  "add","(Ljava/lang/Object;)Z");
+#endif	    
+	    int i;
+	    
+	    for(i=0;i<alen1;i++){
+	      map* cMap=getMapArray(tmp->content,"cache_file",i);
+	      map* uMap=getMapArray(tmp->content,"use_file",i);
+	      map* vMap=getMapArray(tmp->content,"value",i);
+	      map* sMap=getMapArray(tmp->content,"size",i);
+	      map* mMap=getMapArray(tmp->content,tmap->value,i);
+	      
+	      if(sMap!=NULL && vMap!=NULL && strncmp(vMap->name,"value",5)==0 && uMap==NULL){
+#ifdef JAVA7
+		jbyteArray tmpData=(*env).NewByteArray(atoi(sMap->value));
+		(*env).SetByteArrayRegion(tmpData,0,atoi(sMap->value),(const jbyte *)vMap->value);
+		(*env).CallObjectMethod(scObject2, add_mid, tmpData);
+#else
+		jbyteArray tmpData=(*env)->NewByteArray(env,atoi(sMap->value));
+		(*env)->SetByteArrayRegion(env,tmpData,0,atoi(sMap->value),vMap->value);
+		(*env)->CallObjectMethod(env,scObject2, add_mid, tmpData);
+#endif
+	      }else{
+#ifdef JAVA7
+		jobject tmpData=(*env).NewStringUTF(vMap->value);
+		(*env).CallObjectMethod(scObject2, add_mid, tmpData);
+#else
+		jobject tmpData=(*env)->NewStringUTF(env,vMap->value);
+		(*env)->CallObjectMethod(env,scObject2, add_mid, tmpData);
+#endif
+	      }
+
+	      if(cMap!=NULL){
+#ifdef JAVA7
+		jobject tmpData=(*env).NewStringUTF(cMap->value);
+		(*env).CallObjectMethod(scObject3, add_mid, tmpData);
+#else
+		jobject tmpData=(*env)->NewStringUTF(env,cMap->value);
+		(*env)->CallObjectMethod(env,scObject3, add_mid, tmpData);
+#endif
+
+	      }
+	    }
+
+#ifdef JAVA7
+	    (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF(tmp1->name), scObject2);
+	    (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF("cache_file"), scObject3);
+#else	    
+	    (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,tmp1->name), scObject2);
+	    (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,"cache_file"), scObject3);
+#endif
+
+	  }
+	}
+	else
+#ifdef JAVA7
+	  (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF(tmp1->name), (*env).NewStringUTF(tmp1->value));
+#else
+	  (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,tmp1->name), (*env)->NewStringUTF(env,tmp1->value));
+#endif
+	tmp1=tmp1->next;
+      }
+#ifdef JAVA7
+      (*env).CallObjectMethod(scObject, put_mid, (*env).NewStringUTF(tmp->name), scObject1);
+#else
+      (*env)->CallObjectMethod(env,scObject, put_mid, (*env)->NewStringUTF(env,tmp->name), scObject1);
+#endif
+      tmp=tmp->next;
+    }
+    return scObject;
+  }
+  else
+    return NULL;
+}
+
+/**
+ * Convert a JAVA HashMap<String,HashMap<String,String>> to a maps
+ *
+ * @param env the JNI environment pointer
+ * @param t the HashMap 
+ * @param scHashMapClass the hashMap class
+ * @return a created maps containing the converted HashMap
+ * @warning make sure to free resources returned by this function
+ */
+maps* mapsFromHashMap(JNIEnv *env,jobject t,jclass scHashMapClass){
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromHashMap start\n");
+#endif
+  /**
+   * What need to be done (in java).
+   * Set set = hm.entrySet();
+   * Iterator i = set.iterator();
+   * while(i.hasNext()){
+   *   Map.Entry me = (Map.Entry)i.next();
+   *   System.out.println(me.getKey() + " : " + me.getValue() );
+   * }
+   */
+  jclass scSetClass,scIteratorClass,scMapEntryClass;
+  jmethodID entrySet_mid,containsKey_mid,get_mid,iterator_mid,hasNext_mid,next_mid,getKey_mid,getValue_mid;
+  if(scHashMapClass==NULL){
+#ifdef DEBUG
+    fprintf(stderr,"Unable to load java.util.HashMap\n");
+#endif
+    return NULL;
+  }
+#ifdef JAVA7
+  entrySet_mid = (*env).GetMethodID(scHashMapClass, "entrySet", "()Ljava/util/Set;"); 
+  containsKey_mid = (*env).GetMethodID(scHashMapClass, "containsKey", "(Ljava/lang/Object;)Z");
+  get_mid = (*env).GetMethodID(scHashMapClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 
+#else
+  entrySet_mid = (*env)->GetMethodID(env, scHashMapClass, "entrySet", "()Ljava/util/Set;"); 
+  containsKey_mid = (*env)->GetMethodID(env, scHashMapClass, "containsKey", "(Ljava/lang/Object;)Z");
+  get_mid = (*env)->GetMethodID(env, scHashMapClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 
+#endif
+
+  if(containsKey_mid==0){
+#ifdef DEBUG
+    fprintf(stderr,"unable to load containsKey from HashMap object (%d) \n",entrySet_mid);
+#endif
+    return NULL;
+  }
+  if(get_mid==0){
+#ifdef DEBUG
+    fprintf(stderr,"unable to load get from HashMap object (%d) \n",entrySet_mid);
+#endif
+    return NULL;
+  }
+  if(entrySet_mid==0){
+#ifdef DEBUG
+    fprintf(stderr,"unable to load entrySet from HashMap object (%d) \n",entrySet_mid);
+#endif
+    return NULL;
+  }
+#ifdef DEBUG
+  else
+    fprintf(stderr,"entrySet loaded from HashMap object (%d) \n",entrySet_mid);
+#endif
+
+#ifdef JAVA7
+  scSetClass = (*env).FindClass("java/util/Set");
+  iterator_mid = (*env).GetMethodID(scSetClass, "iterator", "()Ljava/util/Iterator;"); 
+#else
+  scSetClass = (*env)->FindClass(env, "java/util/Set");
+  iterator_mid = (*env)->GetMethodID(env, scSetClass, "iterator", "()Ljava/util/Iterator;"); 
+#endif
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromHashMap 1 (%d) \n",iterator_mid);
+#endif
+
+#ifdef JAVA7
+  scIteratorClass = (*env).FindClass("java/util/Iterator");
+  hasNext_mid = (*env).GetMethodID(scIteratorClass, "hasNext", "()Z");
+#else
+  scIteratorClass = (*env)->FindClass(env, "java/util/Iterator");
+  hasNext_mid = (*env)->GetMethodID(env, scIteratorClass, "hasNext", "()Z");
+#endif
+
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromHashMap 2 (%d)\n",hasNext_mid);
+#endif
+
+#ifdef JAVA7
+  next_mid = (*env).GetMethodID(scIteratorClass, "next", "()Ljava/lang/Object;");
+#else
+  next_mid = (*env)->GetMethodID(env, scIteratorClass, "next", "()Ljava/lang/Object;");
+#endif
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromHashMap 3 (%d)\n",next_mid);
+#endif
+
+#ifdef JAVA7
+  scMapEntryClass = (*env).FindClass("java/util/Map$Entry");
+  getKey_mid = (*env).GetMethodID(scMapEntryClass, "getKey", "()Ljava/lang/Object;");
+#else
+  scMapEntryClass = (*env)->FindClass(env, "java/util/Map$Entry");
+  getKey_mid = (*env)->GetMethodID(env, scMapEntryClass, "getKey", "()Ljava/lang/Object;");
+#endif
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromHashMap 4 (%d)\n",getKey_mid);
+#endif
+#ifdef JAVA7
+  getValue_mid = (*env).GetMethodID(scMapEntryClass, "getValue", "()Ljava/lang/Object;");
+#else
+  getValue_mid = (*env)->GetMethodID(env, scMapEntryClass, "getValue", "()Ljava/lang/Object;");
+#endif
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromHashMap 5 (%d)\n",getValue_mid);
+#endif
+
+#ifdef JAVA7
+  jobject final_set=(*env).CallObjectMethod(t,entrySet_mid);
+  jobject final_iterator=(*env).CallObjectMethod(final_set,iterator_mid);
+#else
+  jobject final_set=(*env)->CallObjectMethod(env,t,entrySet_mid);
+  jobject final_iterator=(*env)->CallObjectMethod(env,final_set,iterator_mid);
+#endif
+
+  maps* final_res=NULL;
+  map* res=NULL;
+#ifdef JAVA7
+  while((*env).CallBooleanMethod(final_iterator,hasNext_mid)){
+    jobject tmp=(*env).CallObjectMethod(final_iterator,next_mid);
+
+    jobject imap=(*env).CallObjectMethod(tmp,getValue_mid);
+    jobject set=(*env).CallObjectMethod(imap,entrySet_mid);
+    jobject iterator=(*env).CallObjectMethod(set,iterator_mid);
+
+#else
+  while((*env)->CallBooleanMethod(env,final_iterator,hasNext_mid)){
+    jobject tmp=(*env)->CallObjectMethod(env,final_iterator,next_mid);
+
+    jobject imap=(*env)->CallObjectMethod(env,tmp,getValue_mid);
+    jobject set=(*env)->CallObjectMethod(env,imap,entrySet_mid);
+    jobject iterator=(*env)->CallObjectMethod(env,set,iterator_mid);
+
+#endif
+    int size=-1;
+#ifdef JAVA7
+    if((*env).CallBooleanMethod(imap,containsKey_mid,(*env).NewStringUTF("size"))){
+      jobject sizeV=(*env).CallObjectMethod(imap, get_mid,(*env).NewStringUTF("size"));
+      const char* sizeVS=(*env).GetStringUTFChars((jstring)sizeV, NULL);
+#else
+    if((*env)->CallBooleanMethod(env,imap,containsKey_mid,(*env)->NewStringUTF(env,"size"))){
+      jobject sizeV=(*env)->CallObjectMethod(env, imap, get_mid,(*env)->NewStringUTF(env,"size"));
+      const char* sizeVS=(*env)->GetStringUTFChars(env, sizeV, NULL);
+#endif
+      size=atoi(sizeVS);
+      fprintf(stderr,"SIZE : %s\n",sizeVS);
+#ifdef JAVA7
+      (*env).ReleaseStringUTFChars((jstring)sizeV, sizeVS);
+#else
+      (*env)->ReleaseStringUTFChars(env, sizeV, sizeVS);
+#endif
+    }
+    
+#ifdef JAVA7
+    while((*env).CallBooleanMethod(iterator,hasNext_mid)){
+      jobject tmp1=(*env).CallObjectMethod(iterator,next_mid);
+      jobject jk=(*env).CallObjectMethod(tmp1,getKey_mid);
+      jobject jv=(*env).CallObjectMethod(tmp1,getValue_mid);
+
+      const char* jkd=(*env).GetStringUTFChars((jstring)jk, NULL);
+#else
+    while((*env)->CallBooleanMethod(env,iterator,hasNext_mid)){
+      jobject tmp1=(*env)->CallObjectMethod(env,iterator,next_mid);
+      jobject jk=(*env)->CallObjectMethod(env,tmp1,getKey_mid);
+      jobject jv=(*env)->CallObjectMethod(env,tmp1,getValue_mid);
+
+      const char* jkd=(*env)->GetStringUTFChars(env, jk, NULL);
+#endif
+      if(size>=0 && strcmp(jkd,"value")==0){
+#ifdef JAVA7
+	jobject value=(jobject)(*env).GetByteArrayElements((jbyteArray)jv, NULL);
+#else
+	jobject value=(*env)->GetByteArrayElements(env, jv, NULL);
+#endif
+	if(res==NULL){
+	  res=createMap(jkd,"");
+	}else{
+	  addToMap(res,jkd,"");
+	}
+	map* tmpR=getMap(res,"value");
+	free(tmpR->value);
+	tmpR->value=(char*)malloc((size+1)*sizeof(char));
+	memmove(tmpR->value,value,size*sizeof(char));
+	tmpR->value[size]=0;
+	char tmp[128];
+	sprintf(tmp,"%d",size);
+	addToMap(res,"size",tmp);
+      }
+      else{
+#ifdef JAVA7
+	const char* jvd=(*env).GetStringUTFChars((jstring)jv, NULL);
+#else
+	const char* jvd=(*env)->GetStringUTFChars(env, jv, NULL);
+#endif
+	if(res==NULL){
+	  res=createMap(jkd,jvd);
+	}else{
+	  addToMap(res,jkd,jvd);
+	}
+#ifdef JAVA7
+	(*env).ReleaseStringUTFChars((jstring)jv, jvd);
+#else
+	(*env)->ReleaseStringUTFChars(env, jv, jvd);
+#endif
+      }
+
+#ifdef JAVA7
+      (*env).ReleaseStringUTFChars((jstring)jk, jkd);
+#else
+      (*env)->ReleaseStringUTFChars(env, jk, jkd);
+#endif
+
+    }
+#ifdef JAVA7
+    jobject jk=(*env).CallObjectMethod(tmp,getKey_mid);
+#else
+    jobject jk=(*env)->CallObjectMethod(env,tmp,getKey_mid);
+#endif
+    maps* cmap=createMaps(
+#ifdef JAVA7
+      (char*)(*env).GetStringUTFChars((jstring)jk, NULL)
+#else
+      (*env)->GetStringUTFChars(env, jk, NULL)
+#endif
+			  );
+#ifdef DEBUG
+    fprintf(stderr," / %s \n",cmap->name);
+#endif
+    cmap->content=res;
+    if(final_res==NULL)
+      final_res=dupMaps(&cmap);
+    else
+      addMapsToMaps(&final_res,cmap);
+    freeMaps(&cmap);
+    free(cmap);
+    cmap=NULL;
+    res=NULL;
+  }
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromHashMap end\n");
+#endif
+  return final_res;
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_java.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_java.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_java.h	(revision 942)
@@ -0,0 +1,54 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_JAVA_H
+#define ZOO_SERVICE_INTERNAL_JAVA_H 1
+
+#pragma once 
+
+#include "service.h"
+#include "service_internal.h"
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  jobject HashMap_FromMaps(JNIEnv*,maps*,jclass,jclass,jmethodID);
+  
+  maps* mapsFromHashMap(JNIEnv*,jobject,jclass);
+  
+  void displayStack(JNIEnv*,maps*);
+
+  char *parseJVMXXOption(map*);
+
+  char *parseJVMXOption(map*);
+
+  char *parseJVMOption(map*);
+
+  int zoo_java_support(maps**,map*,service*,maps**,maps**);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_js.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_js.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_js.c	(revision 942)
@@ -0,0 +1,1052 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2012 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_js.h"
+#include "response_print.h"
+
+#ifndef JSCLASS_GLOBAL_FLAGS
+#define JSCLSAS_GLOBAL_FLAGS 0
+#endif
+
+static char dbg[1024];
+
+/**
+ * The function used as alert from the JavaScript environment (ZOO-API)
+ *
+ * @param cx the JavaScript context
+ * @param argc the number of parameters
+ * @param argv1 the parameter values
+ * @return true
+ */
+JSBool
+JSAlert(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  int i=0;
+  JS_MaybeGC(cx);
+  for(i=0;i<argc;i++){
+    JSString* jsmsg = JS_ValueToString(cx,argv[i]);
+    char *tmp=JS_EncodeString(cx,jsmsg);
+    fprintf(stderr,"[ZOO-API:JS] %s\n",tmp);
+    free(tmp);
+  }
+  JS_MaybeGC(cx);
+  
+  return JS_TRUE;
+}
+
+/**
+ * The function used as importScript from the JavaScript environment (ZOO-API)
+ * 
+ * @param cx the JavaScript context
+ * @param argc the number of parameters
+ * @param argv1 the parameter values
+ * @return true
+ */
+JSBool 
+JSLoadScripts(JSContext *cx, uintN argc, jsval *argv1)
+{
+  JS_MaybeGC(cx);
+
+  jsval *argv = JS_ARGV(cx,argv1);
+  int i=0;
+  JS_MaybeGC(cx);
+  for(i=0;i<argc;i++){
+    char *filename = JSValToChar(cx,&argv[i]);
+#ifdef JS_DEBUG
+    fprintf(stderr,"Trying to load %s\n",api0);
+    fflush(stderr);
+#endif
+    JSObject *api_script1=loadZooApiFile(cx,JS_GetGlobalObject(cx),filename);
+  }
+  JS_MaybeGC(cx);
+  JS_SET_RVAL(cx, argv1, JSVAL_VOID);
+  
+  return JS_TRUE;
+}
+
+/**
+ * Load a JavaScript file then run the function corresponding to the service by
+ * passing the conf, inputs and outputs parameters by value as JavaScript
+ * Objects.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param inputs the maps containing the inputs
+ * @param outputs the maps containing the outputs
+ * @return SERVICE_SUCCEEDED or SERVICE_FAILED if the service run, -1 
+ *  if the service failed to load or throw error at runtime.
+ */
+int zoo_js_support(maps** main_conf,map* request,service* s,maps **inputs,maps **outputs)
+{
+  /*maps* main=*main_conf;
+  maps* _inputs=*inputs;
+  maps* _outputs=*outputs;*/
+
+  /* The class of the global object. */
+  JSClass global_class= {
+    "global", JSCLASS_GLOBAL_FLAGS,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+  };
+
+  /* JS variables. */
+  JSRuntime *rt;
+  JSContext *cx;
+  JSObject  *global;
+
+  /* Create a JS runtime. */
+  rt = JS_NewRuntime(8L * 1024L * 1024L);
+  if (rt == NULL)
+    return 1;
+  
+  /* Create a context. */
+  cx = JS_NewContext(rt,8192);
+  if (cx == NULL){
+    return 1;
+  }
+  JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
+  JS_SetVersion(cx, JSVERSION_LATEST);
+  JS_SetErrorReporter(cx, reportError);
+
+  /* Create the global object. */
+  global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
+
+  /* Populate the global object with the standard globals,
+     like Object and Array. */
+  if (!JS_InitStandardClasses(cx, global)){
+    return 1;
+  }
+
+  /* Define specific function and global variable to share with JS runtime
+   */
+  jsval tmp=INT_TO_JSVAL(3);
+  if (!JS_SetProperty(cx, global, "SERVICE_SUCCEEDED", &tmp))
+    return 1;
+  tmp=INT_TO_JSVAL(4);
+  if (!JS_SetProperty(cx, global, "SERVICE_FAILED", &tmp))
+    return 1;
+  if (!JS_DefineFunction(cx, global, "ZOORequest", JSRequest, 4, 0))
+    return 1;
+  if (!JS_DefineFunction(cx, global, "ZOOTranslate", JSTranslate, 4, 0))
+    return 1;
+  if (!JS_DefineFunction(cx, global, "ZOOUpdateStatus", JSUpdateStatus, 2, 0))
+    return 1;
+  if (!JS_DefineFunction(cx, global, "alert", JSAlert, 2, 0))
+    return 1;  
+  if (!JS_DefineFunction(cx, global, "sleep", JSSleep, 1, 0))
+    return 1;  
+  if (!JS_DefineFunction(cx, global, "importScripts", JSLoadScripts, 1, 0))
+    return 1;
+
+  /**
+   * Add private context object
+   */
+  void* cxPrivate = request;
+  JS_SetContextPrivate(cx,cxPrivate);
+
+  map* tmpm1=getMap(request,"metapath");
+  char ntmp[1024];
+  map* cwdMap=getMapFromMaps(*main_conf,"main","servicePath");
+  if(cwdMap!=NULL)
+    sprintf(ntmp,"%s",cwdMap->value);
+  else
+    getcwd(ntmp,1024);
+
+  /**
+   * Load the first part of the ZOO-API
+   */
+  char *api0=(char*)malloc((strlen(ntmp)+17)*sizeof(char));
+  sprintf(api0,"%s/ZOO-proj4js.js",ntmp);
+#ifdef JS_DEBUG
+  fprintf(stderr,"Trying to load %s\n",api0);
+#endif
+  JSObject *api_script1=loadZooApiFile(cx,global,api0);
+  free(api0);
+  fflush(stderr);
+
+  char *api1=(char*)malloc((strlen(ntmp)+13)*sizeof(char));
+  sprintf(api1,"%s/ZOO-api.js",ntmp);
+#ifdef JS_DEBUG
+  fprintf(stderr,"Trying to load %s\n",api1);
+#endif
+  JSObject *api_script2=loadZooApiFile(cx,global,api1);
+  free(api1);
+  fflush(stderr);
+
+  /* Your application code here. This may include JSAPI calls
+     to create your own custom JS objects and run scripts. */
+  //maps* out=*outputs;
+  int res=SERVICE_FAILED;
+  //maps* mc=*main_conf;
+  map* tmpm2=getMap(s->content,"serviceProvider");
+
+  char *filename=(char*)malloc(strlen(tmpm1->value)+strlen(tmpm2->value)+strlen(ntmp)+3);
+  sprintf(filename,"%s/%s/%s",ntmp,tmpm1->value,tmpm2->value);
+  filename[strlen(tmpm1->value)+strlen(tmpm2->value)+strlen(ntmp)+2]=0;
+#ifdef JS_DEBUG
+  fprintf(stderr,"FILENAME %s\n",filename);
+#endif
+  struct stat file_status;
+  stat(filename, &file_status);
+  //char *source=(char*)malloc(file_status.st_size);
+  //uint16 lineno;
+  jsval rval;
+  JSBool ok ;
+  JSObject *script = JS_CompileFile(cx, global, filename);
+  if(script!=NULL){
+    (void)JS_ExecuteScript(cx, global, script, &rval);
+  }
+  else{
+    char tmp1[1024];
+    sprintf(tmp1,"Unable to load JavaScript file %s",filename);
+    free(filename);
+    errorException(*main_conf,tmp1,"NoApplicableCode",NULL);
+    JS_MaybeGC(cx);
+    JS_DestroyContext(cx);
+    JS_DestroyRuntime(rt);
+    JS_ShutDown();
+    return -1;
+  }
+  
+
+  /* Call a function in obj's scope. */
+  jsval argv[3];
+  JSObject *jsargv1=JSObject_FromMaps(cx,*main_conf);
+  argv[0] = OBJECT_TO_JSVAL(jsargv1);
+  JSObject *jsargv2=JSObject_FromMaps(cx,*inputs);
+  argv[1] = OBJECT_TO_JSVAL(jsargv2);
+  JSObject *jsargv3=JSObject_FromMaps(cx,*outputs);
+  argv[2] = OBJECT_TO_JSVAL(jsargv3);
+  jsval rval1=JSVAL_NULL;
+#ifdef JS_DEBUG
+  fprintf(stderr, "object %p\n", (void *) argv[2]);
+#endif
+
+  ok = JS_CallFunctionName(cx, global, s->name, 3, argv, &rval1);
+
+#ifdef JS_DEBUG
+  fprintf(stderr, "object %p\n", (void *) argv[2]);
+#endif
+
+  JSObject *d;
+  if (ok==JS_TRUE && JSVAL_IS_OBJECT(rval1)==JS_TRUE) {
+#ifdef JS_DEBUG
+    fprintf(stderr,"Function run sucessfully !\n");
+#endif
+    /* Should get a number back from the service function call. */
+    ok = JS_ValueToObject(cx, rval1, &d);
+  }else{
+    /* Unable to run JS function */
+    char tmp1[1024];
+    if(strlen(dbg)==0)
+      sprintf(dbg,"No result was found after the function call");
+    sprintf(tmp1,"Unable to run %s from the JavaScript file %s : \n %s",s->name,filename,dbg);
+#ifdef JS_DEBUG
+    fprintf(stderr,"%s",tmp1);
+#endif
+    errorException(*main_conf,tmp1,"NoApplicableCode",NULL);
+    free(filename);
+    JS_MaybeGC(cx);
+    JS_DestroyContext(cx);
+    JS_DestroyRuntime(rt);
+    JS_ShutDown();
+    // Should return -1 here but the unallocation won't work from zoo_service_loader.c line 1847
+    return -1;
+  }
+
+  //jsval t=OBJECT_TO_JSVAL(d);
+  if(JS_IsArrayObject(cx,d)){
+#ifdef JS_DEBUG
+    fprintf(stderr,"An array was returned !\n");
+#endif
+    jsuint	 len;
+    if((JS_GetArrayLength(cx, d, &len)==JS_FALSE)){
+#ifdef JS_DEBUG
+      fprintf(stderr,"outputs array is empty\n");
+#endif
+    }
+    jsval tmp1;
+    JSBool hasResult=JS_GetElement(cx,d,0,&tmp1);
+    res=JSVAL_TO_INT(tmp1);
+#ifdef JS_DEBUG
+    fprintf(stderr," * %d * \n",res);
+#endif
+    if(res==SERVICE_SUCCEEDED){
+      jsval tmp2;
+      JSBool hasElement=JS_GetElement(cx,d,1,&tmp2);
+      if(hasElement==JS_TRUE){
+	freeMaps(outputs);
+	free(*outputs);
+	*outputs=mapsFromJSObject(cx,tmp2);
+      }
+    }else{
+      jsval tmp3;
+      JSBool hasConf=JS_GetElement(cx,d,1,&tmp3);
+      if(hasConf==JS_TRUE){
+	freeMaps(main_conf);
+	free(*main_conf);
+	*main_conf=mapsFromJSObject(cx,tmp3);
+      }
+    }
+
+  }
+  else{
+#ifdef JS_DEBUG
+    fprintf(stderr,"The service didn't return an array !\n");
+#endif
+    /**
+     * Extract result
+     */
+    jsval tmp1;
+    JSBool hasResult=JS_GetProperty(cx,d,"result",&tmp1);
+    res=JSVAL_TO_INT(tmp1);
+
+#ifdef JS_DEBUG
+    fprintf(stderr," * %d * \n",res);
+#endif
+    /**
+     * Extract outputs when available.
+     */
+    jsval tmp2;
+    JSBool hasElement=JS_GetProperty(cx,d,"outputs",&tmp2);
+    if(!JSVAL_IS_VOID(tmp2) && hasElement==JS_TRUE){
+      freeMaps(outputs);
+      free(*outputs);    
+      *outputs=mapsFromJSObject(cx,tmp2);
+    }
+    JS_MaybeGC(cx);
+#ifdef JS_DEBUG
+    if(JSVAL_IS_VOID(tmp2))
+      fprintf(stderr,"No outputs property returned\n");
+    else{
+      if(JS_IsArrayObject(cx,JSVAL_TO_OBJECT(tmp2)))
+	fprintf(stderr,"outputs is an array as expected\n");
+      else
+	fprintf(stderr,"outputs is not an array as expected\n");
+    }
+    JS_MaybeGC(cx);
+#endif
+
+    /**
+     * Extract conf when available.
+     */
+    jsval tmp3;
+    JSBool hasConf=JS_GetProperty(cx,d,"conf",&tmp3);
+    if(!JSVAL_IS_VOID(tmp3) && hasConf==JS_TRUE){
+      freeMaps(main_conf);
+      free(*main_conf);
+      *main_conf=mapsFromJSObject(cx,tmp3);
+    }
+    JS_MaybeGC(cx);
+
+#ifdef JS_DEBUG
+    dumpMaps(*outputs);
+#endif
+  }
+  /* Cleanup. */
+  JS_MaybeGC(cx);
+  JS_DestroyContext(cx);
+  JS_DestroyRuntime(rt);
+  JS_ShutDown();
+  free(filename);
+#ifdef JS_DEBUG
+  fprintf(stderr,"Returned value %d\n",res);
+#endif
+  return res;
+}
+
+/**
+ * Load a JavaScript file
+ *
+ * @param cx the JavaScript context
+ * @param global the global JavaScript object (not used)
+ * @param filename the file name to load
+ * @return a JavaScript Object on success, NULL if an errro occurred
+ */
+JSObject * loadZooApiFile(JSContext *cx,JSObject  *global, char* filename){
+  struct stat api_status;
+  int s=stat(filename, &api_status);
+  if(s==0){
+    jsval rval;
+    JSObject *script = JS_CompileFile(cx, JS_GetGlobalObject(cx), filename);
+    if(script!=NULL){
+      (void)JS_ExecuteScript(cx, JS_GetGlobalObject(cx), script, &rval);
+#ifdef JS_DEBUG
+      fprintf(stderr,"**************\n%s correctly loaded\n**************\n",filename);
+#endif
+      return script;
+    }
+#ifdef JS_DEBUG
+    else
+      fprintf(stderr,"\n**************\nUnable to run %s\n**************\n",filename);
+#endif
+  }
+#ifdef JS_DEBUG
+  else
+    fprintf(stderr,"\n**************\nUnable to load %s\n**************\n",filename);
+#endif
+  return NULL;
+}
+
+/**
+ * Convert a maps to a JavaScript Object
+ *
+ * @param cx the JavaScript context
+ * @param t the maps to convert
+ * @return a new JavaScript Object
+ */
+JSObject* JSObject_FromMaps(JSContext *cx,maps* t){
+  JSObject* res=JS_NewObject(cx, NULL, NULL, NULL);
+  if(res==NULL)
+    fprintf(stderr,"Array Object is NULL!\n");
+  maps* tmp=t;
+  while(tmp!=NULL){
+    JSObject *pval=JSObject_FromMap(cx,tmp->content);
+    if(tmp->child!=NULL){
+      JSObject *pvalc=JSObject_FromMaps(cx,tmp->child);
+      jsval pvaljc=OBJECT_TO_JSVAL(pvalc);
+      JS_SetProperty(cx, pval, "child", &pvaljc);
+    }
+    jsval pvalj=OBJECT_TO_JSVAL(pval);
+    JS_SetProperty(cx, res, tmp->name, &pvalj);
+#ifdef JS_DEBUG
+    fprintf(stderr,"Length of the Array %d, element : %s added \n",len,tmp->name);
+#endif
+    tmp=tmp->next;
+  }  
+  return res;
+}
+
+/**
+ * Convert a map to a JavaScript Object
+ *
+ * @param cx the JavaScript context
+ * @param t the map to convert
+ * @return a new JavaScript Object
+ */
+JSObject* JSObject_FromMap(JSContext *cx,map* t){
+  JSObject* res=JS_NewObject(cx, NULL, NULL, NULL);
+  map* tmpm=t;
+  map* isArray=getMap(t,"isArray");
+  map* isBinary=getMap(t,"size");
+  map* tmap=getMapType(t);
+#ifdef JS_DEBUG
+  if(tmap==NULL)
+    fprintf(stderr,"tmap is null !\n");
+  else
+    fprintf(stderr,"tmap is not null ! (%s = %s)\n",tmap->name,tmap->value);
+#endif
+  while(isArray==NULL && tmpm!=NULL){
+    jsval jsstr;
+    if(isBinary!=NULL && strncasecmp(tmpm->name,"value",5)==0)
+      jsstr = STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpm->value,atoi(isBinary->value)));
+    else
+      jsstr = STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpm->value,strlen(tmpm->value)));
+    JS_SetProperty(cx, res, tmpm->name,&jsstr);
+#ifdef JS_DEBUG
+    fprintf(stderr,"[JS] %s => %s\n",tmpm->name,tmpm->value);
+#endif
+    tmpm=tmpm->next;
+  }
+  if(isArray!=NULL){
+    map* len=getMap(t,"length");
+    int cnt=atoi(len->value);
+    JSObject* values=JS_NewArrayObject( cx, cnt, NULL );
+    JSObject* mvalues=JS_NewArrayObject( cx, cnt, NULL );
+    map *tmpm1,*tmpm2,*tmpm3;
+    int i=0;
+    for(i=0;i<cnt;i++){
+      tmpm1=getMapArray(t,"value",i);
+      tmpm2=getMapArray(t,tmap->name,i);
+      tmpm3=getMapArray(t,"size",i);
+      if(tmpm1!=NULL){
+	jsval jsstr;
+	if(tmpm3!=NULL)
+	  jsstr = STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpm1->value,atoi(tmpm3->value)));
+	else
+	  jsstr = STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpm1->value,strlen(tmpm1->value)));
+	JS_SetElement( cx, values, i, &jsstr );
+      }
+      if(tmpm2!=NULL){
+	jsval jsstr = STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpm2->value,strlen(tmpm2->value)));
+	JS_SetElement( cx, mvalues, i, &jsstr );
+      }
+    }
+    jsval jvalues=OBJECT_TO_JSVAL(values);
+    jsval jmvalues=OBJECT_TO_JSVAL(mvalues);
+    JS_SetProperty(cx, res,"value",&jvalues);
+    JS_SetProperty(cx, res,tmap->name,&jmvalues);
+    while(tmpm!=NULL){
+      if(strncasecmp(tmpm->name,"value",5)!=0 && strncasecmp(tmpm->name,"size",4)!=0 && strncasecmp(tmpm->name,tmap->name,strlen(tmap->name))!=0){
+	jsval jsstr = STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpm->value,strlen(tmpm->value)));
+	JS_SetProperty(cx, res, tmpm->name,&jsstr);
+      }
+#ifdef JS_DEBUG
+      fprintf(stderr,"[JS] %s => %s\n",tmpm->name,tmpm->value);
+#endif
+      tmpm=tmpm->next;
+    }
+  }
+  return res;
+}
+
+/**
+ * Convert a JavaScript Object to a maps
+ *
+ * @param cx the JavaScript context
+ * @param t the JavaScript Object to convert
+ * @return a new maps containing the JavaScript Object
+ */
+maps* mapsFromJSObject(JSContext *cx,jsval t){
+  maps *res=NULL;
+  maps *tres=NULL;
+  jsint oi=0;
+  JSObject* tt=JSVAL_TO_OBJECT(t);
+  if(JS_IsArrayObject(cx,tt)){
+#ifdef JS_DEBUG
+    fprintf(stderr,"Is finally an array !\n");
+#endif
+  }
+  else{
+#ifdef JS_DEBUG
+    fprintf(stderr,"Is not an array !\n");
+#endif
+    JSIdArray *idp=JS_Enumerate(cx,tt);
+    if(idp!=NULL) {
+      int index;
+      jsdouble argNum;
+#ifdef JS_DEBUG
+      fprintf(stderr,"Properties length :  %d \n",idp->length);
+#endif
+      
+      for (index=0,argNum=idp->length;index<argNum;index++) { 
+	jsval id = idp->vector[index];
+	jsval vp;
+	JS_IdToValue(cx,id,&vp);
+	char *tmp;
+	JSString *jsmsg;
+	size_t len1;
+	jsmsg = JS_ValueToString(cx,vp);
+	len1 = JS_GetStringLength(jsmsg);
+	
+	tmp=JS_EncodeString(cx,jsmsg);
+	tres=createMaps(tmp);
+
+	jsval nvp=JSVAL_NULL;
+	if((JS_GetProperty(cx, tt, tmp, &nvp)==JS_FALSE)){
+#ifdef JS_DEBUG
+	  fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,tmp);
+#endif
+	}
+	free(tmp);
+	JSObject *nvp1=JSVAL_TO_OBJECT(JSVAL_NULL);
+	JS_ValueToObject(cx,nvp,&nvp1);
+	jsval nvp1j=OBJECT_TO_JSVAL(nvp1);
+	if(JSVAL_IS_OBJECT(nvp1j)){
+	  tres->content=mapFromJSObject(cx,nvp1j);
+	}
+
+	jsval nvp0=JSVAL_NULL;
+	JSObject *nvp01=JSVAL_TO_OBJECT(JSVAL_NULL);
+	if((JS_GetProperty(cx, nvp1, "child", &nvp0)==JS_FALSE)){
+#ifdef JS_DEBUG
+	  fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,tmp);
+#endif
+	}
+	JS_ValueToObject(cx,nvp0,&nvp01);
+	jsval nvp01j=OBJECT_TO_JSVAL(nvp01);
+	if(!JSVAL_IS_NULL(nvp01j)){
+	  tres->child=mapsFromJSObject(cx,nvp01j);
+	}
+
+	if(res==NULL)
+	  res=dupMaps(&tres);
+	else
+	  addMapsToMaps(&res,tres);
+	freeMaps(&tres);
+	free(tres);
+	tres=NULL;
+      }
+      JS_DestroyIdArray(cx,idp);
+    }
+  }
+
+  jsuint len;
+  JSBool hasLen=JS_GetArrayLength(cx, tt, &len);
+#ifdef JS_DEBUG
+  if(hasLen==JS_FALSE){
+    fprintf(stderr,"outputs array is empty\n");
+  }
+  fprintf(stderr,"outputs array length : %d\n",len);
+#endif
+  for(oi=0;hasLen && oi < len;oi++){
+#ifdef JS_DEBUG
+    fprintf(stderr,"outputs array length : %d step %d \n",len,oi);
+#endif
+    jsval tmp1;
+    JSBool hasElement=JS_GetElement(cx,tt,oi,&tmp1);
+    JSObject *otmp1=JSVAL_TO_OBJECT(tmp1);
+    JSIdArray *idp=JS_Enumerate(cx,otmp1);
+    if(idp!=NULL) {
+      int index;
+      jsdouble argNum;
+#ifdef JS_DEBUG
+      fprintf(stderr,"Properties length :  %d \n",idp->length);
+#endif
+      tres=(maps*)malloc(MAPS_SIZE);
+      tres->name=NULL;
+      tres->content=NULL;
+      tres->next=NULL;
+
+      for (index=0,argNum=idp->length;index<argNum;index++) { 
+	jsval id = idp->vector[index];
+	jsval vp;
+	JS_IdToValue(cx,id,&vp);
+	char *tmp;
+	JSString *jsmsg;
+	size_t len1;
+	jsmsg = JS_ValueToString(cx,vp);
+	len1 = JS_GetStringLength(jsmsg);
+	tmp=JS_EncodeString(cx,jsmsg);
+#ifdef JS_DEBUG
+	fprintf(stderr,"Enumerate id : %d => %s\n",oi,tmp);
+#endif
+	jsval nvp=JSVAL_NULL;
+	if((JS_GetProperty(cx, JSVAL_TO_OBJECT(tmp1), tmp, &nvp)==JS_FALSE)){
+#ifdef JS_DEBUG
+	  fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,tmp);
+#endif
+	}
+	free(tmp);
+	if(JSVAL_IS_OBJECT(nvp)){
+#ifdef JS_DEBUG
+	  fprintf(stderr,"JSVAL NVP IS OBJECT\n");
+#endif
+	}
+
+	JSObject *nvp1=JSVAL_TO_OBJECT(JSVAL_NULL);
+	JS_ValueToObject(cx,nvp,&nvp1);
+	jsval nvp1j=OBJECT_TO_JSVAL(nvp1);
+	if(JSVAL_IS_OBJECT(nvp1j)){
+	  JSString *jsmsg1;
+	  char *tmp1, *tmp2;
+	  JSObject *nvp2=JSVAL_TO_OBJECT(JSVAL_NULL);
+	  jsmsg1 = JS_ValueToString(cx,nvp1j);
+	  len1 = JS_GetStringLength(jsmsg1);
+	  tmp1=JS_EncodeString(cx,jsmsg1);
+	  tmp2=JS_EncodeString(cx,jsmsg);
+#ifdef JS_DEBUG
+	  fprintf(stderr,"JSVAL NVP1J IS OBJECT %s = %s\n",JS_EncodeString(cx,jsmsg),tmp1);
+#endif
+	  if(strcasecmp(tmp1,"[object Object]")==0){
+	    tres->name=zStrdup(tmp2);
+	    tres->content=mapFromJSObject(cx,nvp1j);
+	  }
+	  else
+	    if(strcasecmp(tmp2,"name")==0){
+	      tres->name=zStrdup(tmp1);
+	    }
+	    else{
+	      if(tres->content==NULL)
+		tres->content=createMap(tmp2,tmp1);
+	      else
+		addToMap(tres->content,tmp2,tmp1);
+	    }
+	  free(tmp1);
+	  free(tmp2);
+	}
+#ifdef JS_DEBUG
+	else
+	  fprintf(stderr,"JSVAL NVP1J IS NOT OBJECT !!\n");
+#endif
+      }
+#ifdef JS_DEBUG
+      dumpMaps(tres);
+#endif
+      if(res==NULL)
+	res=dupMaps(&tres);
+      else
+	addMapsToMaps(&res,tres);
+      freeMaps(&tres);
+      free(tres);
+      tres=NULL;
+      JS_DestroyIdArray(cx,idp);
+    }
+  }
+#ifdef JS_DEBUG
+  dumpMaps(res);
+#endif
+  return res;
+}
+
+/**
+ * Convert a JavaScript Object to a map
+ *
+ * @param cx the JavaScript context
+ * @param t the JavaScript Object to convert
+ * @return a new map containing the JavaScript Object
+ */
+map* mapFromJSObject(JSContext *cx,jsval t){
+  map *res=NULL;
+  JSIdArray *idp=JS_Enumerate(cx,JSVAL_TO_OBJECT(t));
+#ifdef JS_DEBUG
+  fprintf(stderr,"Properties %p\n",(void*)t);
+#endif
+  if(idp!=NULL) {
+    int index;
+    jsdouble argNum;
+#ifdef JS_DEBUG
+    fprintf(stderr,"Properties length :  %d \n",idp->length);
+#endif
+    for (index=0,argNum=idp->length;index<argNum;index++) { 
+      jsval id = idp->vector[index];
+      jsval vp;
+      JS_IdToValue(cx,id,&vp);
+      char *tmp, *tmp1;
+      JSString *jsmsg,*jsmsg1;
+      size_t len,len1;
+      jsmsg = JS_ValueToString(cx,vp);
+      len = JS_GetStringLength(jsmsg);
+      jsval nvp;
+      tmp=JS_EncodeString(cx,jsmsg);
+      JS_GetProperty(cx, JSVAL_TO_OBJECT(t), tmp, &nvp);
+      jsmsg1 = JS_ValueToString(cx,nvp);
+      len1 = JS_GetStringLength(jsmsg1);
+      tmp1=JS_EncodeString(cx,jsmsg1);
+#ifdef JS_DEBUG
+      fprintf(stderr,"Enumerate id : %d [ %s => %s ]\n",index,tmp,tmp1);
+#endif
+      if(strcasecmp(tmp,"child")!=0){
+	if(res!=NULL){
+#ifdef JS_DEBUG
+	  fprintf(stderr,"%s - %s\n",tmp,tmp1);
+#endif
+	  addToMap(res,tmp,tmp1);
+	}
+	else{
+	  res=createMap(tmp,tmp1);
+	  res->next=NULL;
+	}
+      }
+      free(tmp);
+      free(tmp1);
+#ifdef JS_DEBUG
+      dumpMap(res);
+#endif
+    }
+    JS_DestroyIdArray(cx,idp);
+  }
+#ifdef JS_DEBUG
+  dumpMap(res);
+#endif
+  return res;
+}
+
+/**
+ * Print debug information messages on stderr
+ *
+ * @param cx the JavaScript context
+ * @param message the error message
+ * @param report the JavaScript Error Report
+ */
+void reportError(JSContext *cx, const char *message, JSErrorReport *report)
+{
+  sprintf(dbg,"%s:%u:%s\n",
+	  report->filename ? report->filename : "<no filename>",
+	  (unsigned int) report->lineno,
+	  message);
+#ifdef JS_DEBUG
+  fprintf(stderr,"%s",dbg);
+#endif
+  fflush(stderr);
+}
+
+/**
+ * Convert a JavaScript value to a char*
+ *
+ * @param context the JavaScript context
+ * @param arg the JavaScript value
+ * @return a new char*
+ * @warning be sure to free the resources returned by this function
+ */
+char* JSValToChar(JSContext* context, jsval* arg) {
+  char *c;
+  char *tmp;
+  JSString *jsmsg;
+  size_t len;
+  int i;
+  if(!JSVAL_IS_STRING(*arg)) {
+    return NULL;
+  }
+  jsmsg = JS_ValueToString(context,*arg);
+  len = JS_GetStringLength(jsmsg);
+  tmp = JS_EncodeString(context,jsmsg);
+  c = (char*)malloc((len+1)*sizeof(char));
+  c[len] = '\0';
+#ifdef ULINET_DEBUG
+  fprintf(stderr,"%d \n",len);
+#endif
+  for(i = 0;i < len;i++) {
+    c[i] = tmp[i];
+    c[i+1] = 0;
+  }
+#ifdef ULINET_DEBUG
+  fprintf(stderr,"%s \n",c);
+#endif
+  return c;
+}
+
+/**
+ * Set the HTTP header of a request
+ *
+ * @param handle the HINTERNET handle
+ * @param cx the JavaScript context
+ * @param header the JavaScript Array containing the headers to send
+ * @return the HINTERNET handle
+ */
+HINTERNET setHeader(HINTERNET* handle,JSContext *cx,JSObject *header){
+  jsuint length=0;
+  jsint i=0;
+  char *tmp1;
+#ifdef ULINET_DEBUG
+  fprintf(stderr,"setHeader\n");
+#endif
+  if(JS_IsArrayObject(cx,header)){
+#ifdef ULINET_DEBUG
+    fprintf(stderr,"header is an array\n");
+#endif
+    JS_GetArrayLength(cx,header,&length);
+#ifdef ULINET_DEBUG
+    fprintf(stderr,"header is an array of %d elements\n",length);
+#endif
+    handle->ihandle[handle->nb].header=NULL;
+    for(i=0;i<length;i++){
+      jsval tmp;
+      JS_GetElement(cx,header,i,&tmp);
+      tmp1=JSValToChar(cx,&tmp);
+#ifdef ULINET_DEBUG
+      curl_easy_setopt(handle->ihandle[handle->nb].handle,CURLOPT_VERBOSE,1);
+      fprintf(stderr,"Element of array n° %d, value : %s\n",i,tmp1);
+#endif
+      handle->ihandle[handle->nb].header=curl_slist_append(handle->ihandle[handle->nb].header, tmp1);
+      free(tmp1);
+    }
+  }
+  else{
+    fprintf(stderr,"not an array !!!!!!!\n");
+  }
+  return *handle;
+}
+
+/**
+ * The function used as ZOOTranslate from the JavaScript environment.
+ * Use the ZOO-Services messages translation function from the Python
+ * environment (ZOO-API)
+ *
+ * @param cx the JavaScript context
+ * @param argc the number of parameters
+ * @param argv1 the parameter values
+ * @return true
+ */
+JSBool
+JSTranslate(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  char *str=JSValToChar(cx,&argv[0]);
+  char *tmpValue=_ss(str);
+  JS_SET_RVAL(cx, argv1,STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpValue,strlen(tmpValue))));  
+  JS_MaybeGC(cx);
+  return JS_TRUE;
+}
+
+/**
+ * The function used as ZOORequest from the JavaScript environment (ZOO-API)
+ *
+ * @param cx the JavaScript context
+ * @param argc the number of parameters
+ * @param argv1 the parameter values
+ * @return true
+ * @see setHeader
+ */
+JSBool
+JSRequest(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  HINTERNET hInternet;
+  JSObject *header;
+  char *url;
+  char *method;
+  char* tmpValue;
+  size_t dwRead;
+  maps *tmpConf=createMaps("main");
+  tmpConf->content=createMap("memory","load");
+  JS_MaybeGC(cx);
+  hInternet=InternetOpen("ZooWPSClient\0",
+			 INTERNET_OPEN_TYPE_PRECONFIG,
+			 NULL,NULL, 0);
+  if(!CHECK_INET_HANDLE(hInternet))
+    return JS_FALSE;
+  if(argc>=2){
+    method=JSValToChar(cx,&argv[0]);
+    url=JSValToChar(cx,&argv[1]);
+  }
+  else{
+    method=zStrdup("GET");
+    url=JSValToChar(cx,argv);
+  }
+  hInternet.waitingRequests[hInternet.nb]=strdup(url);
+  if(argc==4){
+    char *body;
+    body=JSValToChar(cx,&argv[2]);
+    header=JSVAL_TO_OBJECT(argv[3]);
+#ifdef ULINET_DEBUG
+    fprintf(stderr,"URL (%s) \nBODY (%s)\n",url,body);
+#endif
+    if(JS_IsArrayObject(cx,header))
+      setHeader(&hInternet,cx,header);
+#ifdef ULINET_DEBUG
+    fprintf(stderr,"BODY (%s)\n",body);
+#endif
+    InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],body,strlen(body),
+		    INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);    
+    processDownloads(&hInternet);
+    free(body);
+  }else{
+    if(argc==3){
+      if(strncasecmp(method,"GET",3)==0){
+	header=JSVAL_TO_OBJECT(argv[2]);
+	if(JS_IsArrayObject(cx,header)){
+	  setHeader(&hInternet,cx,header);
+	}
+	InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],NULL,0,
+			INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);
+	processDownloads(&hInternet);
+      }else{
+	char *body=JSValToChar(cx,&argv[2]);
+	InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],body,strlen(body),
+			INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);
+	processDownloads(&hInternet);
+	free(body);
+      }
+    }else{
+      InternetOpenUrl(&hInternet,hInternet.waitingRequests[hInternet.nb],NULL,0,
+		      INTERNET_FLAG_NO_CACHE_WRITE,0,tmpConf);
+      processDownloads(&hInternet);
+    }
+  }
+  tmpValue=(char*)malloc((hInternet.ihandle[0].nDataLen+1)*sizeof(char));
+  InternetReadFile(hInternet.ihandle[0],(LPVOID)tmpValue,hInternet.ihandle[0].nDataLen,&dwRead);
+#ifdef ULINET_DEBUG
+  fprintf(stderr,"content downloaded (%d) (%s) \n",dwRead,tmpValue);
+#endif
+  if(dwRead==0){
+    JS_SET_RVAL(cx, argv1,STRING_TO_JSVAL(JS_NewStringCopyN(cx,"Unable to access the file.",strlen("Unable to access the file."))));
+    return JS_TRUE;
+  }
+
+#ifdef ULINET_DEBUG
+  fprintf(stderr,"content downloaded (%d) (%s) \n",dwRead,tmpValue);
+#endif
+  JS_SET_RVAL(cx, argv1,STRING_TO_JSVAL(JS_NewStringCopyN(cx,tmpValue,strlen(tmpValue))));
+  free(url);
+  if(argc>=2)
+    free(method);
+  freeMaps(&tmpConf);
+  free(tmpConf);
+  InternetCloseHandle(&hInternet);
+  JS_MaybeGC(cx);
+  return JS_TRUE;
+}
+
+/**
+ * The function used as ZOOUpdateStatus from the JavaScript environment
+ * (ZOO-API).
+ *
+ * @param cx the JavaScript context
+ * @param argc the number of parameters
+ * @param argv1 the parameter values
+ * @return true
+ * @see setHeader,_updateStatus
+ */
+JSBool
+JSUpdateStatus(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  JS_MaybeGC(cx);
+  int istatus=0;
+  char *status=NULL;
+  maps *conf;
+  if(argc>2){
+#ifdef JS_DEBUG
+    fprintf(stderr,"Number of arguments used to call the function : %i",argc);
+#endif
+    return JS_FALSE;
+  }
+  conf=mapsFromJSObject(cx,argv[0]);
+  if(JS_ValueToInt32(cx,argv[1],&istatus)==JS_TRUE){
+    char tmpStatus[4];
+    sprintf(tmpStatus,"%i",istatus);
+    tmpStatus[3]=0;
+    status=strdup(tmpStatus);
+  }
+  if(getMapFromMaps(conf,"lenv","status")!=NULL){
+    if(status!=NULL){
+      setMapInMaps(conf,"lenv","status",status);
+      free(status);
+    }
+    else
+      setMapInMaps(conf,"lenv","status","15");
+    _updateStatus(conf);
+  }
+  freeMaps(&conf);
+  free(conf);
+  JS_MaybeGC(cx);
+  return JS_TRUE;
+}
+
+/**
+ * The function used as sleep from the JavaScript environment
+ * (ZOO-API).
+ *
+ * @param cx the JavaScript context
+ * @param argc the number of parameters
+ * @param argv1 the parameter values
+ * @return true
+ */
+JSBool
+JSSleep(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  JS_MaybeGC(cx);
+  int isleep=0;
+  if(JS_ValueToInt32(cx,argv[0],&isleep)==JS_TRUE){
+    zSleep(isleep);
+  }
+  JS_MaybeGC(cx);
+  return JS_TRUE;
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_js.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_js.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_js.h	(revision 942)
@@ -0,0 +1,63 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_JS_H
+#define ZOO_SERVICE_INTERNAL_JS_H 1
+
+#pragma once 
+#ifdef WIN32
+#include <wchar.h>
+#endif
+#include "service.h"
+#include "service_internal.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "ulinet.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  char* JSValToChar(JSContext*, jsval*);
+  JSObject* JSObject_FromMaps(JSContext *,maps*);
+  JSObject* JSObject_FromMap(JSContext *,map*);
+  maps* mapsFromJSObject(JSContext *,jsval);
+  map* mapFromJSObject(JSContext *,jsval);
+  JSBool JSTranslate(JSContext*, uintN, jsval*);
+  JSBool JSRequest(JSContext*, uintN, jsval*);
+  JSBool JSUpdateStatus(JSContext*,uintN,jsval *);
+  JSBool JSSleep(JSContext*,uintN,jsval *);
+
+  void reportError(JSContext *cx, const char *message, JSErrorReport *report);
+  
+  int zoo_js_support(maps**,map*,service*,maps **,maps **);
+
+  JSObject *loadZooApiFile(JSContext*,JSObject*,char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_mono.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_mono.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_mono.c	(revision 942)
@@ -0,0 +1,438 @@
+/*
+ * Author : Gérald FENOY
+ * 
+ * ref. http://www.mono-project.com/docs/advanced/embedding/
+ *      http://www.mono-project.com/docs/advanced/pinvoke/
+ *      http://www.giorgosdimtsas.net/embedding-mono-in-your-c-application/
+ *
+ * Copyright (c) 2009-2013 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_mono.h"
+#include "response_print.h"
+
+MonoClass *iclasses[4];
+MonoMethod *imethods[10];
+
+/**
+ * Load a Mono dll then run the static public method corresponding to the 
+ * service by passing the conf, inputs and outputs parameters.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_mono_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  char *ntmp=NULL;
+  map* tmp=getMap(request,"metapath");
+  char *classpath;
+  char *oclasspath;
+  int res=SERVICE_FAILED;
+  MonoAssembly* assembly;
+  MonoImage* monoImage;
+
+  char* libPath="/usr/lib";
+  char* etcPath="/etc";
+  map* libPathMap=getMapFromMaps(*main_conf,"mono","lib");
+  map* etcPathMap=getMapFromMaps(*main_conf,"mono","etc");
+  if(libPathMap!=NULL)
+    libPath=libPathMap->value;
+  if(etcPathMap!=NULL)
+    etcPath=etcPathMap->value;
+  
+  mono_set_dirs(libPath,etcPath);
+
+  map* configMap=getMapFromMaps(*main_conf,"mono","config");
+  if(configMap!=NULL)
+    mono_config_parse(configMap->value);
+  else
+    mono_config_parse(NULL);
+
+  MonoDomain* monoDomain;
+  map* mono;
+  if (hasvalue(*main_conf, "mono", "version", &mono)) {	  
+	  monoDomain = mono_jit_init_version("ZOO_Embedded_Domain", mono->value);
+  }
+  else {	  
+	  monoDomain = mono_jit_init("ZOO_Embedded_Domain"); // use default framework version
+  }
+
+  //MonoDomain* monoDomain = mono_jit_init_version("ZOO_Embedded_Domain", "v4.0.30319"); 
+  //MonoDomain* monoDomain = mono_jit_init("ZOO_Embedded_Domain");  
+
+  char* ZMapsLib = "ZMaps.dll";
+  char *zooAssembly = NULL;
+  
+  map* config = NULL, *basedir = NULL;
+  if (hasvalue(*main_conf, "mono", "configdir", &basedir) && // knut: rename to e.g. "base_dir"?
+	  hasvalue(*main_conf, "mono", "configfile", &config)) {	  
+	  mono_domain_set_config(monoDomain, basedir->value, config->value); 
+	  zooAssembly = file_exists(basedir->value, ZMapsLib);
+  }
+  else {	  
+	  mono_domain_set_config(monoDomain, "./", "");
+  }    
+
+  map* cwdMap;
+  if (! hasvalue(*main_conf, "main", "servicePath", &cwdMap) &&
+	  ! hasvalue(*main_conf, "main", "libPath", &cwdMap) ) {
+	  cwdMap = getMapFromMaps(*main_conf, "lenv", "cwd");
+  }  
+
+  if (zooAssembly != NULL || (zooAssembly = file_exists(cwdMap->value, ZMapsLib)) != NULL) {
+	  assembly = mono_domain_assembly_open(monoDomain, zooAssembly);
+  }
+  else { 
+	  // try to load from default locations (GAC?)
+	  assembly = mono_domain_assembly_open(monoDomain, ZMapsLib);
+  }  
+  free(zooAssembly);
+
+  if (assembly == NULL) {
+	  setMapInMaps(*main_conf, "lenv", "message", _("The ZMaps.dll assembly cannot be found!"));
+	  return 4;
+  }
+
+  mono_add_internal_call ("ZOO_API::Translate", MonoTranslate);    
+  mono_add_internal_call("ZOO_API::UpdateStatus", MonoUpdateStatus);
+  
+  monoImage = mono_assembly_get_image(assembly);
+  MonoClass *KeysList = mono_class_from_name(monoImage, "ZooGenerics", "KeysList");
+  MonoClass *ZMapsClass = mono_class_from_name(monoImage, "ZooGenerics", "ZMaps");
+  MonoMethod *ZMapsAdd = mono_class_get_method_from_name(ZMapsClass, "addToMaps", 2);  
+  MonoMethod *ZMapsGetMaps = mono_class_get_method_from_name(ZMapsClass, "getMaps", 1);
+  MonoClass *_ZMapsClass = mono_class_from_name(monoImage, "ZooGenerics", "_ZMaps");
+  MonoMethod *_ZMapsSetContent = mono_class_get_method_from_name(_ZMapsClass, "setContent", 1);
+  MonoMethod *_ZMapsSetChild = mono_class_get_method_from_name(_ZMapsClass, "setChild", 1);
+  MonoMethod *_ZMapsGetContent = mono_class_get_method_from_name(_ZMapsClass, "getContent", 0);
+  MonoMethod *_ZMapsGetChild = mono_class_get_method_from_name(_ZMapsClass, "getChild", 0);
+  MonoClass *ZMapClass = mono_class_from_name(monoImage, "ZooGenerics", "ZMap");
+  MonoMethod *ZMapGetMap = mono_class_get_method_from_name(ZMapClass, "getMap", 1);
+  MonoMethod *ZMapAdd = mono_class_get_method_from_name(ZMapClass, "addToMap", 2);
+  MonoMethod *ZMapDisplay = mono_class_get_method_from_name(ZMapClass, "display", 1);
+  MonoObject *exc=NULL;
+
+  MonoClass *classes[3]={_ZMapsClass,ZMapsClass,ZMapClass};
+  MonoMethod *methods[5]={ZMapsAdd,_ZMapsSetContent,_ZMapsSetChild,ZMapAdd,ZMapDisplay};
+  
+  MonoMethod *ZMapsGetKeys = mono_class_get_method_from_name(ZMapsClass, "getKeys", 0);
+  
+  MonoMethod *ZMapsGetKeysCount = mono_class_get_method_from_name(ZMapsClass, "getKeysCount", 0);
+  MonoMethod *ZMapsGetKey = mono_class_get_method_from_name(ZMapsClass, "getKey", 1);
+  MonoMethod *ZMapGetKeys = mono_class_get_method_from_name(ZMapClass, "getKeys", 0);
+  MonoClassField *ZMapKeys = mono_class_get_field_from_name(ZMapClass, "Keys");
+  MonoMethod *ZMapGetKeysCount = mono_class_get_method_from_name(ZMapClass, "getKeysCount", 0);
+  MonoMethod *ZMapGetKey = mono_class_get_method_from_name(ZMapClass, "getKey", 1);
+  MonoMethod *ZMapGetSize = mono_class_get_method_from_name(ZMapClass, "getSize", 0);
+  MonoMethod *ZMapGetMapAsBytes = mono_class_get_method_from_name(ZMapClass, "getMapAsBytes", 0);
+  MonoClass *oclasses[4]={_ZMapsClass,ZMapsClass,ZMapClass,KeysList};
+  MonoMethod *omethods[10]={ZMapsGetMaps,ZMapsGetKeysCount,ZMapsGetKey,ZMapGetMap,ZMapGetKeysCount,ZMapGetKey,_ZMapsGetContent,_ZMapsGetChild,ZMapGetSize,ZMapGetMapAsBytes};
+  
+  for(int i=0;i<4;i++){
+    iclasses[i]=oclasses[i];
+    imethods[i]=omethods[i];
+  }
+  for(int i=4;i<10;i++)
+    imethods[i]=omethods[i];
+
+  void *args[3];
+
+  MonoObject * main=ZMapsFromMaps(monoDomain,classes,methods,&exc,m);
+
+  MonoObject * in=ZMapsFromMaps(monoDomain,classes,methods,&exc,inputs);
+
+  MonoObject * out=ZMapsFromMaps(monoDomain,classes,methods,&exc,outputs);
+  
+  args [0] = main;
+  args [1] = in;
+  args [2] = out;
+
+  char* sName = NULL;
+  MonoAssembly* serviceAssembly = NULL;
+  
+  tmp = getMap(s->content, "serviceProvider");  
+  char* test = file_exists(NULL, "log.txt");
+  if ( (sName = file_exists(cwdMap->value, tmp->value)) != NULL ||
+	   (sName = file_exists(".", tmp->value)) != NULL ||  // in case servicePath is defined but serviceProvider is in working directory
+	   (basedir != NULL && (sName = file_exists(basedir->value, tmp->value)) != NULL) ) {
+
+	   serviceAssembly = mono_domain_assembly_open(monoDomain, sName);
+  }
+  else {
+	  // try to open from default locations	  
+	  serviceAssembly = mono_domain_assembly_open(monoDomain, tmp->value);
+  }
+  free(sName);
+
+  //char *sName=(char*)malloc((strlen(tmp->value)+strlen(cwdMap->value)+2)*sizeof(char));
+  //sprintf(sName,"%s/%s",cwdMap->value,tmp->value);
+  //MonoAssembly* serviceAssembly = mono_domain_assembly_open(monoDomain,sName);
+  
+  if(serviceAssembly==NULL){
+    char *msg=(char*)malloc((strlen(_("Your service assembly: %s cannot be found!"))+strlen(tmp->value)+1)*sizeof(char));
+    sprintf(msg,_("Your service assembly %s cannot be found!"),tmp->value);
+    setMapInMaps(*main_conf,"lenv","message",msg);
+    free(msg);
+    return 4;
+  }
+  
+  MonoImage* serviceImage = mono_assembly_get_image(serviceAssembly);
+
+  map* tmp1=getMap(s->content,"serviceNameSpace");
+  
+  tmp=getMap(s->content,"serviceClass");
+  MonoClass *serviceClass = mono_class_from_name(serviceImage, tmp1->value, tmp->value);
+  if(serviceClass==NULL){
+    char *msg=(char*)malloc((strlen(_("Your service class method %s::%s cannot be found!"))+strlen(tmp1->value)+strlen(tmp->value)+1)*sizeof(char));
+    sprintf(msg,_("Your service class method %s::%s cannot be found!"),tmp1->value,tmp->value);
+    setMapInMaps(*main_conf,"lenv","message",msg);
+    free(msg);
+    return 4;
+  }
+  
+  MonoMethod *serviceFunction = mono_class_get_method_from_name(serviceClass, s->name, 3);
+  if(serviceFunction==NULL){
+    char *msg=(char*)malloc((strlen(_("Your service static method %s cannot be found!"))+strlen(s->name)+1)*sizeof(char));
+    sprintf(msg,_("Your service static method %s cannot be found!"),s->name);
+    setMapInMaps(*main_conf,"lenv","message",msg);
+    free(msg);
+    return 4;
+  }
+  
+  MonoObject *exception=NULL;
+  MonoObject *result = mono_runtime_invoke(serviceFunction,NULL,args,&exception);
+  
+  if (exception != NULL) { // knut: add exception handling
+	  MonoString* pMsg = mono_object_to_string(exception, NULL);	  
+	  setErrorMessage(*main_conf, s->name, NoApplicableCode, mono_string_to_utf8(pMsg));
+	  return 4;
+  }
+
+  res=*(int*)mono_object_unbox (result);
+  
+  if(res==3){
+    freeMaps(&outputs);
+    free(outputs);
+    outputs=mapsFromZMaps(monoDomain,oclasses,omethods,(MonoObject*)args[2]);
+    *real_outputs=outputs;
+  }
+  
+  freeMaps(&m);
+  free(m);
+  m=mapsFromZMaps(monoDomain,oclasses,omethods,(MonoObject*)args[0]);
+  *main_conf=m;
+  mono_jit_cleanup (monoDomain);  
+  return res;
+}
+
+/**
+ * Create ZMaps from maps
+ * @param domain the Mono Domain
+ * @param classes the Mono classes required to create (_ZMaps,ZMaps and ZMap)
+ * @param methods the Mono methods required (ZMapsAdd, _ZMapsSetContent, _ZMapsSetChild, ZMapAdd and ZMapDisplay)
+ * @param m the maps to use as source to create the corresponding ZMaps
+ * @return MonoObject* to a new ZMap
+ */
+MonoObject* ZMapsFromMaps(MonoDomain* domain,MonoClass **classes,MonoMethod **methods,MonoObject **exc,maps* m){
+  MonoObject *res=mono_object_new(domain,classes[1]);
+  MonoMethod* constructorMethod = mono_class_get_method_from_name(classes[1],
+								  ".ctor",
+								  0);
+  mono_runtime_invoke(constructorMethod, res, NULL, exc);
+  MonoMethod* constructorMethod1 = mono_class_get_method_from_name(classes[0],
+								   ".ctor",
+								   0);
+  
+  while(m!=NULL){
+    MonoObject *tmpRes=mono_object_new(domain,classes[0]);
+    mono_runtime_invoke(constructorMethod1, tmpRes, NULL, exc);
+    void *values0 [1];
+    MonoObject* content = ZMapFromMap (domain,classes[2],methods,exc,m->content);
+    values0 [0] = content;
+    MonoObject *exception=NULL;
+    mono_runtime_invoke(methods[1],tmpRes,values0,&exception);
+    if(exception!=NULL)
+      {
+	fprintf(stderr,"ERROR : %s\n", mono_string_to_utf8(mono_object_to_string(exception, NULL)));
+	fflush(stderr);
+	return res;
+      }
+    if(m->child!=NULL){
+      void *values [1];
+      values [0] = ZMapsFromMaps (domain,classes,methods,exc,m->child);
+      mono_runtime_invoke(methods[2],tmpRes,values,exc);
+    }
+    void *values [2];
+    values [0] = mono_string_new (domain, m->name);
+    values [1] = tmpRes;
+    mono_runtime_invoke(methods[0],res,values,exc);
+    m=m->next;
+  }
+  return res;
+}
+
+/**
+ * Create ZMap from map
+ * @param domain the Mono Domain
+ * @param classes the Mono classes required to create (_ZMaps,ZMaps and ZMap)
+ * @param methods the Mono methods required (ZMapsAdd, _ZMapsSetContent, _ZMapsSetChild, ZMapAdd and ZMapDisplay)
+ * @param exc the Mono exception object
+ * @param m the map to use as source to create a new ZMap
+ * @return MonoObject* to a new ZMap
+ */
+MonoObject* ZMapFromMap(MonoDomain* domain,MonoClass *ZMapClass,MonoMethod **methods,MonoObject **exc,map* m){
+  MonoObject *res=mono_object_new(domain,ZMapClass);
+  MonoMethod* constructorMethod = mono_class_get_method_from_name(ZMapClass,
+								  ".ctor",
+								  0);
+  mono_runtime_invoke(constructorMethod, res, NULL, exc);
+  map* sizeMap=getMap(m,"size");
+  while(m!=NULL){
+    void *values [2];
+    MonoString* name = mono_string_new(domain, m->name);
+    MonoString* value;
+    if(sizeMap!=NULL && strcasecmp(m->name,"value")==0)
+      value = mono_string_new_len(domain, m->value,atoi(sizeMap->value));
+    else
+      value = mono_string_new(domain, m->value);
+    values [0] = name;
+    values [1] = value;
+    mono_runtime_invoke(methods[3],res,values,exc);
+    m=m->next;
+  }
+  return res;
+}
+
+/**
+ * Create maps from ZMaps
+ * @param domain the Mono Domain
+ * @param classes the Mono classes required to create (_ZMapsClass,ZMapsClass,ZMapClass,KeysList)
+ * @param methods the Mono methods required (ZMapsGetMaps,ZMapsGetKeysCount,ZMapsGetKey,ZMapGetMap,ZMapGetKeysCount,ZMapGetKey,_ZMapsGetContent,_ZMapsGetChild)
+ * @param m the ZMaps to use as source to create a new maps
+ * @return MonoObject* to a new ZMaps
+ */
+maps* mapsFromZMaps(MonoDomain* domain,MonoClass **classes,MonoMethod **methods,MonoObject* m){
+  maps* res=NULL;
+  if(m!=NULL){
+    MonoObject *exc=NULL;
+    MonoObject *okeys = mono_runtime_invoke(methods[1],m,NULL,&exc);
+    if(exc!=NULL)
+      {
+	fprintf(stderr,"ERROR : %s\n", mono_string_to_utf8(mono_object_to_string(exc, NULL)));
+	fflush(stderr);
+	return res;
+      }
+
+    int keyCount=*(int*)mono_object_unbox (okeys);
+    for(int i=0;i<keyCount;i++){
+      void* values[1];
+      values[0]=&i;
+      exc=NULL;
+      MonoString *okey = (MonoString*) mono_runtime_invoke(methods[2],m,values,&exc);
+      char* key = mono_string_to_utf8(okey);
+      maps* tmp=createMaps(key);
+      values[0]=mono_string_new (domain, key);
+      MonoString *content_ZMaps = (MonoString*) mono_runtime_invoke(methods[0],m,values,&exc);
+      MonoObject *content = mono_runtime_invoke(methods[6],(MonoObject*)content_ZMaps,NULL,&exc);
+      tmp->content=mapFromZMap(domain,classes,methods,content);
+      MonoObject *childs = mono_runtime_invoke(methods[7],content_ZMaps,NULL,&exc);
+      tmp->child=mapsFromZMaps(domain,classes,methods,childs);
+      if(res==NULL){
+	res=dupMaps(&tmp);
+      }else
+	addMapsToMaps(&res,tmp);
+      freeMaps(&tmp);
+      free(tmp);
+      mono_free(key);
+    }
+  }
+  return res;
+}
+
+/**
+ * Create map from ZMap
+ * @param domain the Mono Domain
+ * @param classes the Mono classes required (_ZMapsClass,ZMapsClass,ZMapClass,KeysList)
+ * @param methods the Mono methods required (ZMapsGetMaps,ZMapsGetKeysCount,ZMapsGetKey,ZMapGetMap,ZMapGetKeysCount,ZMapGetKey,_ZMapsGetContent,_ZMapsGetChild,ZMapGetSize)
+ * @param m the ZMap to use as source to create a new map
+ * @return MonoObject* to a new ZMap
+ */
+map* mapFromZMap(MonoDomain* domain,MonoClass **classes,MonoMethod **methods,MonoObject* m){
+  map* res=NULL;
+  if(m!=NULL){
+    MonoObject *exc = NULL;
+    MonoObject *okeys = mono_runtime_invoke(methods[4],m,NULL,&exc);
+    int keyCount=*(int*)mono_object_unbox (okeys);
+    MonoObject *osize = mono_runtime_invoke(methods[8],m,NULL,&exc);
+    int size=*(int*)mono_object_unbox (osize);
+    for(int i=0;i<keyCount;i++){
+      void* values[1];
+      values[0]=&i;
+      exc=NULL;
+      MonoString *okey = (MonoString*) mono_runtime_invoke(methods[5],m,values,&exc);
+      char* key = mono_string_to_utf8(okey);
+      values[0]=mono_string_new (domain, key);
+      exc=NULL;
+      MonoString *ovalue = (MonoString*) mono_runtime_invoke(methods[3],m,values,&exc);
+      char* value = mono_string_to_utf8(ovalue);
+      if(res==NULL)
+	res=createMap(key,value);
+      else
+	addToMap(res,key,value);
+    }
+  }
+  return res;
+}
+
+/**
+ * The translate function to search in zoo-services gettext domain for translating a string.
+ * @param str the string to be translated
+ * @return the translated string
+ */
+static MonoString* MonoTranslate(MonoString *str){
+  return mono_string_new (mono_domain_get(), _(mono_string_to_utf8(str)));
+}
+
+/**
+ * The updateStatus function to update the ongoing status of a ZOO-Service.
+ * @param m the main.cfg map
+ * @param str the message for the current step 
+ * @param p the percentage of the 
+ * @return the translated string
+ */
+static void MonoUpdateStatus(MonoObject* obj, MonoString *str, int p) {	
+	MonoDomain* domain = mono_object_get_domain(obj);	
+	maps *confMaps = mapsFromZMaps(domain, iclasses, imethods, obj);	
+	setMapInMaps(confMaps, "lenv", "message", mono_string_to_utf8(str));	
+	int tmp = p > 100 || p < 0 ? -1 : p;	
+	char tmpStatus[5];
+	snprintf(tmpStatus, 4, "%d", tmp);	
+	setMapInMaps(confMaps, "lenv", "status", (char*)tmpStatus);	
+	_updateStatus(confMaps);	
+	freeMaps(&confMaps);	
+	free(confMaps);
+	return;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_mono.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_mono.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_mono.h	(revision 942)
@@ -0,0 +1,55 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_CSHARP_H
+#define ZOO_SERVICE_INTERNAL_CSHARP_H 1
+
+#pragma once 
+
+#include "service.h"
+#include "service_internal.h"
+#include <mono/jit/jit.h>
+#include <mono/metadata/mono-config.h>
+#include <mono/metadata/assembly.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  int zoo_mono_support(maps**,map*,service*,maps**,maps**);
+  MonoObject* ZMapsFromMaps(MonoDomain*,MonoClass**,MonoMethod**,MonoObject**,maps*);
+  MonoObject* ZMapFromMap(MonoDomain*,MonoClass*,MonoMethod**,MonoObject**,map*);
+  maps* mapsFromZMaps(MonoDomain*,MonoClass**,MonoMethod**,MonoObject*);
+  map* mapFromZMap(MonoDomain*,MonoClass**,MonoMethod**,MonoObject*);
+  static MonoString* MonoTranslate(MonoString*);
+  //static void MonoUpdateStatus(MonoObject*,MonoString*,int*);
+  static void MonoUpdateStatus(MonoObject*, MonoString*, int);
+  //MonoClass *iclasses[4]; // knut: move declarations to service_internal_mono.c
+  //MonoMethod *imethods[10];
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ms.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ms.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ms.c	(revision 942)
@@ -0,0 +1,1552 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2010-2011 Fondazione Edmund Mach. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Cross platform definition of layerObj->class
+ */
+#ifndef WIN32
+#define CLASS class
+#else
+#define CLASS _class
+#endif
+#include "service_internal_ms.h"
+#include "server_internal.h"
+#include "response_print.h"
+#include "caching.h"
+
+/**
+ * Get a list of configuration keys having a corresponding mandatory ows_*.
+ * Map composed by a main.cfg maps name as key and the corresponding 
+ * MapServer Mafile Metadata name to use
+ * see doc from here :
+ *  - http://mapserver.org/ogc/wms_server.html
+ *  - http://mapserver.org/ogc/wfs_server.html
+ *  - http://mapserver.org/ogc/wcs_server.html
+ *
+ * @return a new map containing a table linking a name of a configuration key
+ * to a corresponding mandatory ows_* keyword (ie. "fees" => "ows_fees").
+ */
+map* getCorrespondance(){
+  map* res=createMap("encoding","ows_encoding");
+  addToMap(res,"abstract","ows_abstract");
+  addToMap(res,"title","ows_title");
+  addToMap(res,"keywords","ows_keywordlist");
+  addToMap(res,"fees","ows_fees");
+  addToMap(res,"accessConstraints","ows_accessconstraints");
+  addToMap(res,"providerName","ows_attribution_title");
+  addToMap(res,"providerSite","ows_service_onlineresource");
+  addToMap(res,"individualName","ows_contactperson");
+  addToMap(res,"positionName","ows_contactposition");
+  addToMap(res,"providerName","ows_contactorganization");
+  addToMap(res,"role","ows_role");
+  addToMap(res,"addressType","ows_addresstype");
+  addToMap(res,"addressCity","ows_city");
+  addToMap(res,"addressDeliveryPoint","ows_address");
+  addToMap(res,"addressPostalCode","ows_postcode");
+  addToMap(res,"addressAdministrativeArea","ows_stateorprovince");
+  addToMap(res,"addressCountry","ows_country");
+  addToMap(res,"phoneVoice","ows_contactvoicetelephone");
+  addToMap(res,"phoneFacsimile","ows_contactfacsimiletelephone");
+  addToMap(res,"addressElectronicMailAddress","ows_contactelectronicmailaddress");
+  // Missing Madatory Informations
+  addToMap(res,"hoursOfService","ows_hoursofservice");
+  addToMap(res,"contactInstructions","ows_contactinstructions");
+  return res;
+}
+
+/**
+ * Return the current publish_id value
+ * @param elem and maps pointer on which the search occur
+ * @return the integer value of the publish_id field, if any, 0 otherwise
+ */ 
+int getPublishedId(maps* elem){
+  if(elem!=NULL && elem->content!=NULL){
+    map* myIndex=getMap(elem->content,"published_id");
+    if(myIndex!=NULL){
+      return atoi(myIndex->value);
+    }
+  }
+  return 0;
+}
+
+/**
+ * Add width and height keys to an output maps containing the maximum width
+ * and height for displaying the full data extent.
+ * Restriction to an image having a size of 640x480 (width * height)
+ *
+ * @param output 
+ * @param minx the lower left x coordinate
+ * @param miny the lower left y coordinate
+ * @param maxx the upper right x coordinate
+ * @param maxy the upper right y coordinate
+ */
+void setMapSize(maps* output,double minx,double miny,double maxx,double maxy){
+  int imyIndex=getPublishedId(output);
+  double maxWidth=640;
+  double maxHeight=480;
+  double deltaX=maxx-minx;
+  double deltaY=maxy-miny;
+  double qWidth;
+  qWidth=maxWidth/deltaX;
+  double qHeight;
+  qHeight=maxHeight/deltaY;
+#ifdef DEBUGMS
+  fprintf(stderr,"deltaX : %.15f \ndeltaY : %.15f\n",deltaX,deltaY);
+  fprintf(stderr,"qWidth : %.15f \nqHeight : %.15f\n",qWidth,qHeight);
+#endif
+
+  double width=deltaX*qWidth;
+  double height=height=deltaY*qWidth;
+  if(deltaX<deltaY){
+    width=deltaX*qHeight;
+    height=deltaY*qHeight;
+  }
+  if(height<0)
+    height=-height;
+  if(width<0)
+    width=-width;
+  char sWidth[1024];
+  char sHeight[1024];
+  sprintf(sWidth,"%.3f",width);
+  sprintf(sHeight,"%.3f",height);
+#ifdef DEBUGMS
+  fprintf(stderr,"sWidth : %.15f \nsHeight : %.15f\n",sWidth,sHeight);
+#endif
+  if(output!=NULL){
+    setMapArray(output->content,"width",imyIndex,sWidth);
+    setMapArray(output->content,"height",imyIndex,sHeight);
+  }
+}
+
+/**
+ * Add a Reference key to an output containing the WMFS/WFS/WCS request for
+ * accessing service result
+ * 
+ * @param m the conf maps containing the main.cfg settings
+ * @param tmpI the specific output maps to add the Reference key
+ */
+void setReferenceUrl(maps* m,maps* tmpI){
+  int imyIndex=getPublishedId(tmpI);
+  if(getMapArray(tmpI->content,"ref_wms_link",imyIndex)!=NULL)
+    return;
+  outputMapfile(m,tmpI);
+  map *msUrl=getMapFromMaps(m,"main","mapserverAddress");
+  if(msUrl==NULL){
+    errorException (m, _("Unable to find any mapserverAddress defined in the main.cfg file"),
+		    "InternalError", NULL);
+    exit(-1);
+  }
+  if(getMapArray(tmpI->content,"ref_wms_link",imyIndex)!=NULL)
+    return;
+  int finalProto=-1;
+  map *msOgcVersion=getMapFromMaps(m,"main","msOgcVersion");
+  map *dataPath=getMapFromMaps(m,"main","dataPath");
+  map *sid=getMapFromMaps(m,"lenv","usid");
+  map* format=getMapArray(tmpI->content,"mimeType",imyIndex);
+  map* rformat=getMapArray(tmpI->content,"requestedMimeType",imyIndex);
+  map* width=getMapArray(tmpI->content,"width",imyIndex);
+  map* height=getMapArray(tmpI->content,"height",imyIndex);
+  map* protoMap=getMapArray(tmpI->content,"msOgc",imyIndex);
+  map* versionMap=getMapArray(tmpI->content,"msOgcVersion",imyIndex);
+  map* datatype=getMapArray(tmpI->content,"geodatatype",imyIndex);
+  map* layerName=getMapArray(tmpI->content,"msLayer",imyIndex);
+  char options[4][5][25]={
+    {"WMS","1.3.0","GetMap","layers=%s","wms_extent"},
+    {"WFS","1.0.0","GetFeature","typename=%s","wcs_extent"},
+    {"WCS","2.0.0","GetCoverage","coverageid=%s","wcs_extent"},
+    {"WCS","1.0.0","GetCoverage","coverage=%s","wcs_extent"}
+  };
+  map *nbElements=getMapArray(tmpI->content,"nb_features",imyIndex);
+  if(nbElements==NULL)
+    nbElements=getMapArray(tmpI->content,"nb_pixels",imyIndex);
+  if(datatype==NULL || strncmp(datatype->value,"other",5)==0 || (nbElements!=NULL && atoi(nbElements->value)==0)){
+    map* minNb=getMap(tmpI->content,"minoccurs");
+    map* useMs=getMap(tmpI->content,"useMapserver");
+    if((minNb==NULL || atoi(minNb->value)>=1) && useMs!=NULL && strncasecmp(useMs->value,"true",4)==0){
+      int lIndex=0;
+      maps* lenv=getMaps(m,"lenv");
+      if(getMapFromMaps(m,"lenv","mapErrorNb")==NULL)
+	setMapInMaps(m,"lenv","mapErrorNb","0");
+      else{
+	map* tmpV=getMapFromMaps(m,"lenv","mapErrorNb");
+	lIndex=atoi(tmpV->value)+1;
+	addIntToMap(lenv->content,"mapErrorNb",lIndex);
+      }
+      setMapInMaps(m,"lenv","mapError","true");
+      setMapArray(lenv->content,"locator",lIndex,tmpI->name);
+      if(nbElements==NULL)
+	setMapArray(lenv->content,"message",lIndex,_("The ZOO-Kernel was able to retrieve the data but could not read it as geographic data."));
+      else
+	setMapArray(lenv->content,"message",lIndex,_("The ZOO-Kernel was able to retrieve the data but could not access any feature or pixel in te resulting file."));
+      if(getMapFromMaps(m,"lenv","state")==NULL)
+	errorException (m, _("Unable to find any geographic data"), "WrongInputData", tmpI->name);
+    }
+    return;
+  }
+  int proto=0;
+  if(rformat==NULL){
+    rformat=getMapArray(tmpI->content,"mimeType",imyIndex);
+  }
+  if(strncasecmp(rformat->value,"text/xml",8)==0)
+    proto=1;
+  if(strncasecmp(rformat->value,"image/tiff",10)==0 ||
+     strncasecmp(rformat->value,"image/geotiff",10)==0)
+    proto=2;
+  int hasFormat=-1;
+  if(protoMap!=NULL){
+    hasFormat=1;
+    if(strncasecmp(protoMap->value,"WMS",3)==0){
+      proto=0;
+      rformat=createMap("value","image/png");
+    }
+    else{
+      if(strncasecmp(protoMap->value,"WFS",3)==0){
+	proto=1;
+	rformat=createMap("value","text/xml");
+      }
+      else {
+	proto=2;
+	rformat=createMap("value","image/tiff");
+      }
+    }
+  }
+  char *protoVersion=options[proto][1];
+  if(proto==1){
+    if(msOgcVersion!=NULL)
+      protoVersion=msOgcVersion->value;
+    if(versionMap!=NULL)
+      protoVersion=versionMap->value;
+  }
+
+
+  map* extent=getMapArray(tmpI->content,options[proto][4],imyIndex);
+  map* crs=getMapArray(tmpI->content,"crs",imyIndex);
+  int hasCRS=1;
+  if(crs==NULL){
+    crs=getMapFromMaps(m,"main","crs");
+    if(crs==NULL){
+      crs=createMap("crs","epsg:4326");
+      hasCRS=0;
+    }
+  }
+  char layers[128];
+  if(layerName==NULL)
+    sprintf(layers,options[proto][3],tmpI->name);
+  else
+    sprintf(layers,options[proto][3],layerName->value);
+
+  if(format==NULL || width==NULL || height==NULL || extent==NULL){
+    char tmpStr[1024];
+    sprintf(tmpStr,_("Unable to create the mapfile for %s because of missing values."),tmpI->name);
+    errorException (m, tmpStr,
+		    "InternalError", NULL);
+    exit(-1);
+    return;
+  }
+
+  if(proto==0){
+    hasFormat=1;
+    rformat=createMap("mimeType","image/png");
+  }else{
+    if(proto==1){
+      rformat=createMap("mimeType","text/xml");
+      hasFormat=1;
+    }
+    else
+      if(proto==2){
+        rformat=createMap("mimeType","image/tiff");
+	hasFormat=1;
+	finalProto=1;
+      }
+  }
+  
+  char* webService_url=(char*)malloc((strlen(msUrl->value)+strlen(rformat->value)+strlen(tmpI->name)+strlen(width->value)+strlen(height->value)+strlen(extent->value)+256)*sizeof(char));
+
+
+  if(proto>0){
+    if(proto==2)
+      finalProto=1;
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    if(datatype!=NULL && strncasecmp(datatype->value,"raster",6)==0){
+      setMapArray(tmpI->content,"ref_wcs_link",imyIndex,webService_url);
+    }
+    else{
+      setMapArray(tmpI->content,"ref_wfs_link",imyIndex,webService_url);
+    }
+    proto=0;
+    freeMap(&rformat);
+    free(rformat);
+    rformat=createMap("mimeType","image/png");
+  }
+  else{
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&width=%s&height=%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    width->value,
+	    height->value,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    setMapArray(tmpI->content,"ref_wms_link",imyIndex,webService_url);
+    if(datatype!=NULL && strncasecmp(datatype->value,"raster",6)==0){
+      proto=2;
+      freeMap(&rformat);
+      free(rformat);
+      rformat=createMap("mimeType","image/tiff");
+    }
+    else{
+      proto=1;
+      freeMap(&rformat);
+      free(rformat);
+      rformat=createMap("mimeType","text/xml");
+    }
+  }
+  setMapArray(tmpI->content,"Reference",imyIndex,webService_url);
+  memset(layers,0,128);
+  sprintf(layers,options[proto][3],tmpI->name);
+  protoVersion=options[proto][1];
+  extent=getMapArray(tmpI->content,options[proto][4],imyIndex);
+  memset(webService_url,0,strlen(webService_url));
+  if(proto>0){
+    if(proto==2)
+      finalProto=1;
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    if(datatype!=NULL && strncasecmp(datatype->value,"raster",6)==0){
+      setMapArray(tmpI->content,"ref_wcs_link",imyIndex,webService_url);
+    }
+    else{
+      setMapArray(tmpI->content,"ref_wfs_link",imyIndex,webService_url);
+    }
+  }else{
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&width=%s&height=%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    width->value,
+	    height->value,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    setMapArray(tmpI->content,"ref_wms_link",imyIndex,webService_url);
+  }
+  if(finalProto>0){
+    proto=3;
+    memset(layers,0,128);
+    sprintf(layers,options[proto][3],tmpI->name);
+    protoVersion=options[proto][1];
+    extent=getMapArray(tmpI->content,options[proto][4],imyIndex);
+    memset(webService_url,0,strlen(webService_url));
+     freeMap(&rformat);
+    free(rformat);
+    rformat=createMap("value","image/tiff");
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%d_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    imyIndex,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+    setMapArray(tmpI->content,"ref_wcs_preview_link",imyIndex,webService_url);
+  }
+  if(hasCRS==0){
+    freeMap(&crs);
+    free(crs);
+  }
+  freeMap(&rformat);
+  free(rformat);
+  free(webService_url);
+}
+
+/**
+ * Set projection for a layer in a MAPFILE using Authority Code and Name if
+ * available or fallback to proj4 definition if available or fallback to
+ * default EPSG:4326
+ *
+ * @param output the output maps
+ * @param m the opened mapObj
+ * @param myLayer the layerObj
+ * @param pszProjection a char* containing the SRS definition in WKT format
+ */
+void setSrsInformations(maps* output,mapObj* m,layerObj* myLayer,
+			char* pszProjection){
+  OGRSpatialReferenceH  hSRS;
+  map* msSrs=NULL;
+  int imyIndex=getPublishedId(output);
+  hSRS = OSRNewSpatialReference(NULL);
+  if( pszProjection!=NULL && strlen(pszProjection)>1){
+    if(OSRImportFromWkt( hSRS, &pszProjection ) == CE_None ){
+      char *proj4Str=NULL;
+      if(OSRGetAuthorityName(hSRS,NULL)!=NULL && 
+	 OSRGetAuthorityCode(hSRS,NULL)!=NULL){
+	char tmpSrs[20];
+	sprintf(tmpSrs,"%s:%s",
+		OSRGetAuthorityName(hSRS,NULL),OSRGetAuthorityCode(hSRS,NULL));
+	msLoadProjectionStringEPSG(&m->projection,tmpSrs);
+	msLoadProjectionStringEPSG(&myLayer->projection,tmpSrs);
+	
+	char tmpSrss[256];
+	sprintf(tmpSrss,"EPSG:4326 EPSG:900913 EPSG:3857 %s",tmpSrs);
+	
+	msInsertHashTable(&(m->web.metadata), "ows_srs", tmpSrss);
+	msInsertHashTable(&(myLayer->metadata), "ows_srs", tmpSrss);
+	
+#ifdef DEBUGMS
+	fprintf(stderr,"isGeo %b\n\n",OSRIsGeographic(hSRS)==TRUE);
+#endif
+	if(output!=NULL){
+	  if(OSRIsGeographic(hSRS)==TRUE)
+	    setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
+	  else
+	    setMapArray(output->content,"crs_isGeographic",imyIndex,"false");
+	  setMapArray(output->content,"crs",imyIndex,tmpSrs);
+	}
+      }
+      else{
+	OSRExportToProj4(hSRS,&proj4Str);
+	if(proj4Str!=NULL && strlen(proj4Str)>0){
+#ifdef DEBUGMS
+	  fprintf(stderr,"PROJ (%s)\n",proj4Str);
+#endif
+	  msLoadProjectionString(&(m->projection),proj4Str);
+	  msLoadProjectionString(&(myLayer->projection),proj4Str);
+	  if(output!=NULL){ 
+	    if(OSRIsGeographic(hSRS)==TRUE)
+	      setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
+	    else
+	      setMapArray(output->content,"crs_isGeographic",imyIndex,"false");
+	  }
+	  free(proj4Str);
+	}
+	else{
+	  msLoadProjectionStringEPSG(&m->projection,"EPSG:4326");
+	  msLoadProjectionStringEPSG(&myLayer->projection,"EPSG:4326");
+	  if(output!=NULL){
+	    setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
+	  }
+	}
+	if(output!=NULL){
+	  setMapArray(output->content,"crs",imyIndex,"EPSG:4326");
+	  setMapArray(output->content,"real_extent",imyIndex,"true");
+	}
+	msInsertHashTable(&(m->web.metadata),"ows_srs", "EPSG:4326 EPSG:900913 EPSG:3857");
+	msInsertHashTable(&(myLayer->metadata),"ows_srs","EPSG:4326 EPSG:900913 EPSG:3857");
+      }
+    }
+  }
+  else{
+    if(output!=NULL){
+      msSrs=getMapArray(output->content,"msSrs",imyIndex);
+    }
+    if(msSrs!=NULL){
+      msLoadProjectionStringEPSG(&m->projection,msSrs->value);
+      msLoadProjectionStringEPSG(&myLayer->projection,msSrs->value);
+      char tmpSrs[128];
+      sprintf(tmpSrs,"%s EPSG:4326 EPSG:900913 EPSG:3857",msSrs->value);
+      msInsertHashTable(&(m->web.metadata),"ows_srs",tmpSrs);
+      msInsertHashTable(&(myLayer->metadata),"ows_srs",tmpSrs);
+    }else{
+      msLoadProjectionStringEPSG(&m->projection,"EPSG:4326");
+      msLoadProjectionStringEPSG(&myLayer->projection,"EPSG:4326");
+      msInsertHashTable(&(m->web.metadata),"ows_srs","EPSG:4326 EPSG:900913 EPSG:3857");
+      msInsertHashTable(&(myLayer->metadata),"ows_srs","EPSG:4326 EPSG:900913 EPSG:3857");
+    }
+    if(output!=NULL){
+      setMapArray(output->content,"crs",imyIndex,msSrs->value);
+      setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
+    }
+  }
+
+  OSRDestroySpatialReference( hSRS );
+}
+
+/**
+ * Set the MAPFILE extent, the the ows_extent for the layer, add wms_extent and
+ * wfs_extent to the output maps and call setMapSize.
+ *
+ * @param output the specific output
+ * @param m the mapObj
+ * @param myLayer the layerObj
+ * @param minX the lower left x coordinate
+ * @param minY the lower left y coordinate
+ * @param maxX the upper right x coordinate
+ * @param maxY the upper right y coordinate
+ * @see setMapSize
+ */
+void setMsExtent(maps* output,mapObj* m,layerObj* myLayer,
+		 double minX,double minY,double maxX,double maxY){
+  int imyIndex=getPublishedId(output);
+  msMapSetExtent(m,minX,minY,maxX,maxY);
+  //m->maxsize=4096;
+#ifdef DEBUGMS
+  fprintf(stderr,"Extent %.15f %.15f %.15f %.15f\n",minX,minY,maxX,maxY);
+#endif
+  char tmpExtent[1024];
+  sprintf(tmpExtent,"%.15f %.15f %.15f %.15f",minX,minY,maxX,maxY);
+#ifdef DEBUGMS
+  fprintf(stderr,"Extent %s\n",tmpExtent);
+#endif
+  msInsertHashTable(&(myLayer->metadata), "ows_extent", tmpExtent);
+  
+  if(output!=NULL){
+    map* test=getMapArray(output->content,"real_extent",imyIndex);
+    pointObj min, max;
+    projectionObj tempSrs;
+    min.x = m->extent.minx;
+    min.y = m->extent.miny;
+    max.x = m->extent.maxx;
+    max.y = m->extent.maxy;
+    char tmpSrsStr[1024];
+    msInitProjection(&tempSrs);
+    msLoadProjectionStringEPSG(&tempSrs,"EPSG:4326");
+
+    msProjectPoint(&(myLayer->projection),&tempSrs,&min);
+    msProjectPoint(&myLayer->projection,&tempSrs,&max);
+  
+    if(test!=NULL){
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.y,min.x,max.y,max.x);
+      map* isGeo=getMapArray(output->content,"crs_isGeographic",imyIndex);
+#ifdef DEBUGMS
+      fprintf(stderr,"isGeo = %s\n",isGeo->value);
+#endif
+      if(isGeo!=NULL && strcasecmp("true",isGeo->value)==0){
+	sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.y,min.x,max.y,max.x);
+	setMapArray(output->content,"wgs84_extent",imyIndex,tmpExtent);
+        sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f", minY,minX, maxY, maxX);
+      }else{
+	sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.x,min.y,max.x,max.y);
+	setMapArray(output->content,"wgs84_extent",imyIndex,tmpExtent);
+      }
+      setMapArray(output->content,"wms_extent",imyIndex,tmpExtent);
+      sprintf(tmpSrsStr,"%.15f,%.15f,%.15f,%.15f",min.x,min.y,max.x,max.y);
+      setMapArray(output->content,"wcs_extent",imyIndex,tmpExtent);
+    }else{
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",min.x,min.y,max.x,max.y);
+      setMapArray(output->content,"wgs84_extent",imyIndex,tmpExtent);
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",minX, minY, maxX, maxY);
+      map* isGeo=getMapArray(output->content,"crs_isGeographic",imyIndex);
+      if(isGeo!=NULL){
+#ifdef DEBUGMS
+	fprintf(stderr,"isGeo = %s\n",isGeo->value);
+#endif
+	if(isGeo!=NULL && strcasecmp("true",isGeo->value)==0)
+	  sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f", minY,minX, maxY, maxX);
+      }
+      setMapArray(output->content,"wms_extent",imyIndex,tmpExtent); 
+      sprintf(tmpExtent,"%.15f,%.15f,%.15f,%.15f",minX,minY,maxX,maxY);
+      setMapArray(output->content,"wcs_extent",imyIndex,tmpExtent);
+    }
+  }
+
+  setMapSize(output,minX,minY,maxX,maxY);
+}
+
+/**
+ * Try to open a vector output and define the corresponding layer in the MAPFILE
+ *
+ * @param conf the conf maps containing the main.cfg settings
+ * @param output the specific output maps
+ * @param m the mapObj
+ */
+int tryOgr(maps* conf,maps* output,mapObj* m){
+  int imyIndex=getPublishedId(output);
+  map* tmpMap=getMapArray(output->content,"storage",imyIndex);
+  char *pszDataSource=tmpMap->value;
+
+  /**
+   * Try to open the DataSource using OGR
+   */
+  OGRRegisterAll();
+  /**
+   * Try to load the file as ZIP
+   *
+  OGRDataSourceH poDS1 = NULL;
+  OGRSFDriverH *poDriver1 = NULL;
+  char *dsName=(char*)malloc((8+strlen(pszDataSource)+1)*sizeof(char));
+  char *odsName=zStrdup(pszDataSource);
+  char *sdsName=zStrdup(pszDataSource);
+  char *demo=".data";
+  sdsName[strlen(sdsName)-(strlen(demo)-1)]='d';
+  sdsName[strlen(sdsName)-(strlen(demo)-2)]='i';
+  sdsName[strlen(sdsName)-(strlen(demo)-3)]='r';
+  sdsName[strlen(sdsName)-(strlen(demo)-4)]=0;
+
+  odsName[strlen(odsName)-(strlen(demo)-1)]='z';
+  odsName[strlen(odsName)-(strlen(demo)-2)]='i';
+  odsName[strlen(odsName)-(strlen(demo)-3)]='p';
+  odsName[strlen(odsName)-(strlen(demo)-4)]=0;
+  sprintf(dsName,"/vsizip/%s",odsName);
+
+#ifdef DEBUGMS
+  fprintf(stderr,"Try loading %s, %s, %s\n",dsName,odsName,dsName);
+#endif
+
+  FILE* file = fopen(pszDataSource, "rb");
+  FILE* fileZ = fopen(odsName, "wb");
+  free(odsName);
+  fseek(file, 0, SEEK_END);
+  unsigned long fileLen=ftell(file);
+  fseek(file, 0, SEEK_SET);
+  char *buffer=(char *)malloc(fileLen+1);
+  fread(buffer, fileLen, 1, file);
+  fwrite(buffer,fileLen, 1, fileZ);
+  fclose(file);
+  fclose(fileZ);
+  free(buffer);
+#ifdef DEBUGMS
+  fprintf(stderr,"Try loading %s",dsName);
+#endif
+  poDS1 = OGROpen( dsName, FALSE, poDriver1 );
+  if( poDS1 == NULL ){
+    fprintf(stderr,"Unable to access the DataSource as ZIP File\n");
+    setMapInMaps(conf,"lenv","message","Unable to open datasource in read only mode");
+    fprintf(stderr,"Remove ZIP File!\n");
+    unlink(odsName);
+    //OGR_DS_Destroy(poDS1);
+  }else{
+#ifdef DEBUGMS
+    fprintf(stderr,"The DataSource is a  ZIP File\n");
+#endif
+    char** demo=VSIReadDir(dsName);
+    int i=0;
+    zMkdir(sdsName
+#ifndef WIN32
+		,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH 
+#endif
+		);
+    while(demo[i]!=NULL){
+#ifdef DEBUGMS
+      fprintf(stderr,"ZIP File content : %s\n",demo[i]);
+#endif
+      char *tmpDs=(char*)malloc((strlen(dsName)+strlen(demo[i])+2)*sizeof(char));
+      sprintf(tmpDs,"%s/%s",dsName,demo[i]);
+      fprintf(stderr,"read : %s\n",tmpDs);
+      
+      VSILFILE* vsif=VSIFOpenL(tmpDs,"rb");
+#ifdef DEBUGMS
+      fprintf(stderr,"open : %s\n",tmpDs);
+#endif
+      VSIFSeekL(vsif,0,SEEK_END);
+      vsi_l_offset size=VSIFTellL(vsif);
+#ifdef DEBUGMS
+      fprintf(stderr,"size : %d\n",size);
+#endif
+      VSIFSeekL(vsif,0,SEEK_SET);
+      char *vsifcontent=(char*) malloc(((int)size+1)*sizeof(char));
+      VSIFReadL(vsifcontent,1,(size_t)size,vsif);
+      char *fpath=(char*) malloc((strlen(sdsName)+strlen(demo[1])+2)*sizeof(char));
+      sprintf(fpath,"%s/%s",sdsName,demo[i]);
+      int f=zOpen(fpath,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+      zWrite(f,vsifcontent,(int)size);
+      close(f);
+      chmod(fpath,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH);
+      char* tmpP=strstr(fpath,".shp");
+      if(tmpP==NULL)
+	tmpP=strstr(fpath,".SHP");
+      if(tmpP!=NULL){
+#ifdef DEBUGMS
+	fprintf(stderr,"*** DEBUG %s\n",strstr(tmpP,"."));
+#endif
+	if( strcmp(tmpP,".shp")==0 || strcmp(tmpP,".SHP")==0 ){
+	  tmpMap=getMap(output->content,"storage");
+	  free(tmpMap->value);
+	  tmpMap->value=(char*) malloc((strlen(fpath)+1)*sizeof(char));
+	  sprintf(tmpMap->value,"%s",fpath);
+	  pszDataSource=tmpMap->value;
+#ifdef DEBUGMS
+	  fprintf(stderr,"*** DEBUG %s\n",pszDataSource);
+#endif
+	}
+      }
+      VSIFCloseL(vsif);
+      i++;
+    }
+    OGR_DS_Destroy(poDS1);
+    }
+  free(sdsName);
+  free(dsName);*/
+  
+  OGRDataSourceH poDS = NULL;
+  OGRSFDriverH *poDriver = NULL;
+  poDS = OGROpen( pszDataSource, FALSE, poDriver );
+  if( poDS == NULL ){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to access the DataSource %s\n",pszDataSource);
+#endif
+    setMapInMaps(conf,"lenv","message","Unable to open datasource in read only mode");
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to access the DataSource, exit! \n"); 
+#endif
+    return -1;
+  }
+
+  setMapArray(output->content,"gdalType",imyIndex,OGR_Dr_GetName(OGR_DS_GetDriver(poDS)));  
+  setMapArray(output->content,"geodatatype",imyIndex,"vector");
+  int iLayer = 0;
+  for( iLayer=0; iLayer < OGR_DS_GetLayerCount(poDS); iLayer++ ){
+    OGRLayerH poLayer = OGR_DS_GetLayer(poDS,iLayer);
+
+    if( poLayer == NULL ){
+#ifdef DEBUGMS
+      fprintf(stderr,"Unable to access the DataSource Layer \n");
+#endif
+      setMapInMaps(conf,"lenv","message","Unable to open datasource in read only mode");
+      return -1;
+    }
+
+    /**
+     * Add a new layer set name, data
+     */
+    layerObj* myLayer=NULL;
+    if(getMapArray(output->content,"msInclude",imyIndex)==NULL){
+      if(msGrowMapLayers(m)==NULL){
+	return -1;
+      }
+      if(initLayer((m->layers[m->numlayers]), m) == -1){
+	return -1;
+      }
+      myLayer=m->layers[m->numlayers];
+    }else{
+      myLayer=m->layers[m->numlayers-1];
+    }
+    
+#ifdef DEBUGMS
+    dumpMaps(output);
+#endif
+    myLayer->name = zStrdup(output->name);
+    myLayer->tileitem=NULL;
+    myLayer->data = zStrdup(OGR_L_GetName(poLayer));
+    myLayer->connection = zStrdup(pszDataSource);
+    myLayer->index = m->numlayers;
+    myLayer->dump = MS_TRUE;
+    myLayer->status = MS_ON;
+    msConnectLayer(myLayer,MS_OGR,pszDataSource);
+
+    addIntToMapArray(output->content,"nb_features",imyIndex,OGR_L_GetFeatureCount(poLayer,1));
+
+    /**
+     * Detect the Geometry Type or use Polygon
+     */
+    if(OGR_L_GetGeomType(poLayer) != wkbUnknown){
+      switch(OGR_L_GetGeomType(poLayer)){
+      case wkbPoint:
+      case wkbMultiPoint:
+      case wkbPoint25D:
+      case wkbMultiPoint25D:
+#ifdef DEBUGMS
+	fprintf(stderr,"POINT DataSource Layer \n");
+#endif
+	myLayer->type = MS_LAYER_POINT;
+	break;
+      case wkbLineString :
+      case wkbMultiLineString :
+      case wkbLineString25D:
+      case wkbMultiLineString25D:
+#ifdef DEBUGMS
+	fprintf(stderr,"LINE DataSource Layer \n");
+#endif
+	myLayer->type = MS_LAYER_LINE;
+	break;
+      case wkbPolygon:
+      case wkbMultiPolygon:
+      case wkbPolygon25D:
+      case wkbMultiPolygon25D:
+#ifdef DEBUGMS
+	fprintf(stderr,"POLYGON DataSource Layer \n");
+#endif
+	myLayer->type = MS_LAYER_POLYGON;
+	break;
+      default:
+	myLayer->type = MS_LAYER_POLYGON;
+	break;
+      }
+    }else
+      myLayer->type = MS_LAYER_POLYGON;
+
+    /**
+     * Detect spatial reference or use WGS84
+     */
+    OGRSpatialReferenceH srs=OGR_L_GetSpatialRef(poLayer);
+    if(srs!=NULL){
+      char *wkt=NULL;
+      OSRExportToWkt(srs,&wkt);
+      setSrsInformations(output,m,myLayer,wkt);
+      free(wkt);
+    }
+    else{
+      setMapArray(output->content,"crs",imyIndex,"EPSG:4326");
+      setMapArray(output->content,"crs_isGeographic",imyIndex,"true");
+      msLoadProjectionStringEPSG(&m->projection,"EPSG:4326");
+      msInsertHashTable(&(m->web.metadata), "ows_srs", "EPSG:4326 EPSG:900913 EPSG:3857");
+      msInsertHashTable(&(myLayer->metadata), "ows_srs", "EPSG:4326 EPSG:900913 EPSG:3857");
+    }
+
+    OGREnvelope oExt;
+    if (OGR_L_GetExtent(poLayer,&oExt, TRUE) == OGRERR_NONE){
+      setMsExtent(output,m,myLayer,oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY);
+      char extent[1024];
+      memset(&extent,0,1024);
+      sprintf(extent,"%f,%f,%f,%f",oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY);
+      setMapArray(output->content,"boundingbox",imyIndex,extent);
+    }
+  
+    /**
+     * Detect the FID column or use the first attribute field as FID
+     */
+    char *fid=(char*)OGR_L_GetFIDColumn(poLayer);
+    if(strlen(fid)==0){
+      OGRFeatureDefnH def=OGR_L_GetLayerDefn(poLayer);
+      int fIndex=0;
+      for(fIndex=0;fIndex<OGR_FD_GetFieldCount(def);fIndex++){
+	OGRFieldDefnH fdef=OGR_FD_GetFieldDefn(def,fIndex);
+	fid=(char*)OGR_Fld_GetNameRef(fdef);
+	break;
+      }
+    }
+    msInsertHashTable(&(myLayer->metadata), "gml_featureid", fid);
+    msInsertHashTable(&(myLayer->metadata), "gml_include_items", "all");
+    msInsertHashTable(&(myLayer->metadata), "ows_name", output->name);
+    map* tmpMap=getMapArray(output->content,"title",imyIndex);
+    if(tmpMap!=NULL)
+      msInsertHashTable(&(myLayer->metadata), "ows_title", tmpMap->value);
+    else
+      msInsertHashTable(&(myLayer->metadata), "ows_title", "Default Title");
+
+    if(getMapArray(output->content,"msInclude",imyIndex)==NULL){
+      if(msGrowLayerClasses(myLayer) == NULL)
+	return -1;
+      if(initClass((myLayer->CLASS[myLayer->numclasses])) == -1)
+	return -1;
+      if(msGrowClassStyles(myLayer->CLASS[myLayer->numclasses]) == NULL)
+	return -1;
+      if(initStyle(myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]) == -1)
+	return -1;
+      /**
+       * Apply msStyle else fallback to the default style
+       */
+      tmpMap=getMap(output->content,"msStyle");
+      if(tmpMap==NULL){
+        switch(myLayer->type){
+	case MS_LAYER_POLYGON:
+	  tmpMap=getMapFromMaps(conf,"main","msStylePoly");
+	  break;
+	case MS_LAYER_LINE:
+	  tmpMap=getMapFromMaps(conf,"main","msStyleLine");
+	  break;
+	default:
+	  tmpMap=getMapFromMaps(conf,"main","msStylePoint");
+	  break;
+        }
+      }
+      if(tmpMap!=NULL)
+	msUpdateStyleFromString(myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles],tmpMap->value,0);
+      else{
+	/**
+	 * Set style
+	 */
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.red=125;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.green=125;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.blue=255;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.red=80;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.green=80;
+	myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinecolor.blue=80;
+	
+	/**
+	 * Set specific style depending on type
+	 */
+	if(myLayer->type == MS_LAYER_POLYGON)
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->width=3;
+	if(myLayer->type == MS_LAYER_LINE){
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->width=3;
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->outlinewidth=1.5;
+	}
+	if(myLayer->type == MS_LAYER_POINT){
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->symbol=1;
+	  myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->size=15;
+	}
+	
+      }
+      myLayer->CLASS[myLayer->numclasses]->numstyles++;
+      myLayer->numclasses++;
+    
+      m->layerorder[m->numlayers] = m->numlayers;
+      m->numlayers++;
+
+    }
+  }
+  OGR_DS_Destroy(poDS);
+  //OGRCleanupAll();
+
+  return 1;
+}
+
+/**
+ * Try to open a raster output and define the corresponding layer in the MAPFILE
+ *
+ * @param conf the conf maps containing the main.cfg settings
+ * @param output the specific output maps
+ * @param m the mapObj
+ */
+int tryGdal(maps* conf,maps* output,mapObj* m){
+  int imyIndex=getPublishedId(output);
+  map* tmpMap=getMapArray(output->content,"storage",imyIndex);
+  map* styleMap=getMap(output->content,"msStyle");
+  char *pszFilename=tmpMap->value;
+  GDALDatasetH hDataset;
+  GDALRasterBandH hBand;
+  double adfGeoTransform[6];
+  int i, iBand;
+  
+  /**
+   * Try to open the DataSource using GDAL
+   */
+  GDALAllRegister();
+  hDataset = GDALOpen( pszFilename, GA_Update ); /*GA_ReadOnly*/
+  if( hDataset == NULL ){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to access the DataSource %s \n",pszFilename);
+#endif
+    setMapArray(output->content,"geodatatype",imyIndex,"other");
+    setMapInMaps(conf,"lenv","message","gdalinfo failed - unable to open");
+    GDALDestroyDriverManager();
+    return -1;
+  }
+#ifdef DEBUGMS
+  fprintf(stderr,"Accessing the DataSource %s %d\n",pszFilename,__LINE__);
+#endif
+
+  setMapArray(output->content,"geodatatype",imyIndex,"raster");
+  /**
+   * Add a new layer set name, data
+   */
+  if(msGrowMapLayers(m)==NULL){
+    return -1;
+  }
+  if(initLayer((m->layers[m->numlayers]), m) == -1){
+    return -1;
+  }
+  m->layers[m->numlayers]->index=m->numlayers;
+
+  layerObj* myLayer=m->layers[m->numlayers];
+  myLayer->name = zStrdup(output->name);
+  myLayer->tileitem=NULL;
+  myLayer->data = zStrdup(pszFilename);
+  myLayer->index = m->numlayers;
+  myLayer->dump = MS_TRUE;
+  myLayer->status = MS_ON;
+  myLayer->type = MS_LAYER_RASTER;
+
+  char *title=output->name;
+  tmpMap=getMapArray(output->content,"title",imyIndex);
+  if(tmpMap!=NULL)
+    title=tmpMap->value;
+  char *abstract=output->name;
+  tmpMap=getMapArray(output->content,"abstract",imyIndex);
+  if(tmpMap!=NULL)
+    abstract=tmpMap->value;
+
+  msInsertHashTable(&(myLayer->metadata), "ows_label", title);
+  msInsertHashTable(&(myLayer->metadata), "ows_title", title);
+  msInsertHashTable(&(myLayer->metadata), "ows_abstract", abstract);
+  msInsertHashTable(&(myLayer->metadata), "ows_rangeset_name", output->name);
+  msInsertHashTable(&(myLayer->metadata), "ows_rangeset_label", title);
+
+  /**
+   * Set Map Size to the raster size
+   */
+  m->width=GDALGetRasterXSize( hDataset );
+  m->height=GDALGetRasterYSize( hDataset );
+  if(m->width>4096 || m->height>4096){
+    if(m->width>m->height)
+      m->maxsize=m->width;
+    else  
+      m->maxsize=m->height;
+  }else
+    m->maxsize=4096;
+  addIntToMapArray(output->content,"nb_pixels",imyIndex,GDALGetRasterXSize( hDataset )*GDALGetRasterYSize( hDataset ));
+  int pixel_type=GDALGetRasterDataType( hDataset );
+  addIntToMapArray(output->content,"pixel_data_type",imyIndex,pixel_type);
+
+  int outputIndex=msGetOutputFormatIndex(m,"tiff");
+  if(outputIndex>=0){
+    m->outputformatlist[outputIndex]->imagemode=((pixel_type==GDT_Byte)?MS_IMAGEMODE_BYTE:((pixel_type==GDT_Int16 || pixel_type==GDT_UInt16)?MS_IMAGEMODE_INT16:((pixel_type!=GDT_Float32)?MS_IMAGEMODE_FLOAT32:MS_IMAGEMODE_BYTE)));
+    outputIndex=msGetOutputFormatIndex(m,"geotiff");
+    if(outputIndex>=0)
+      m->outputformatlist[outputIndex]->imagemode=((pixel_type==GDT_Byte)?MS_IMAGEMODE_BYTE:((pixel_type==GDT_Int16 || pixel_type==GDT_UInt16)?MS_IMAGEMODE_INT16:((pixel_type!=GDT_Float32)?MS_IMAGEMODE_FLOAT32:MS_IMAGEMODE_BYTE)));
+  }
+  //
+    
+  /**
+   * Set projection using Authority Code and Name if available or fallback to 
+   * proj4 definition if available or fallback to default EPSG:4326
+   */
+  const char *tRef=GDALGetProjectionRef( hDataset );
+  if( tRef != NULL && strlen(tRef)>0 ){
+    char *pszProjection;
+    pszProjection = (char *) GDALGetProjectionRef( hDataset );
+#ifdef DEBUGMS
+    fprintf(stderr,"Accessing the DataSource %s\n",GDALGetProjectionRef( hDataset ));
+#endif
+    setSrsInformations(output,m,myLayer,pszProjection);
+  }else{
+    fprintf(stderr,"NO SRS FOUND %s %d ! %s\n",__FILE__,__LINE__,GDALGetProjectionRef( hDataset ));
+    fflush(stderr);
+    CPLErr sp=GDALSetProjection( hDataset , "+init=epsg:4326" );
+    if(sp!=CE_None){
+      fprintf(stderr,"NO SRS SET ! %s\n",CPLGetLastErrorMsg());
+    }
+  }
+
+  /**
+   * Set extent
+   */
+  if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None ){
+    if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0 ){
+
+      double minX = adfGeoTransform[0]
+	+ adfGeoTransform[2] * GDALGetRasterYSize(hDataset);
+      double minY = adfGeoTransform[3]
+	+ adfGeoTransform[5] * GDALGetRasterYSize(hDataset);
+
+      double maxX = adfGeoTransform[0]
+	+ adfGeoTransform[1] * GDALGetRasterXSize(hDataset);
+      double maxY = adfGeoTransform[3]
+	+ adfGeoTransform[4] * GDALGetRasterXSize(hDataset);
+
+      setMsExtent(output,m,myLayer,minX,minY,maxX,maxY);
+      char extent[1024];
+      memset(&extent,0,1024);
+      sprintf(extent,"%f,%f,%f,%f",minX,minY,maxX,maxY);
+      setMapArray(output->content,"boundingbox",imyIndex,extent);
+    }
+  }else{
+    int scale=1;
+    if(m->width>2048){
+      addIntToMapArray(output->content,"width",imyIndex,2048);
+      scale=2048/m->width;
+    }else
+      addIntToMapArray(output->content,"width",imyIndex,m->width);
+    addIntToMapArray(output->content,"height",imyIndex,m->height*scale);
+  }
+
+  /**
+   * Extract information about available bands to set the bandcount and the
+   * processing directive
+   */
+  char nBands[3];
+  memset(&nBands,0,3);
+  int nBandsI=GDALGetRasterCount( hDataset );
+  if(nBandsI<100){
+    sprintf(nBands,"%d",GDALGetRasterCount( hDataset ));
+    msInsertHashTable(&(myLayer->metadata), "ows_bandcount", nBands);
+  }
+  if(styleMap==NULL || strstr(styleMap->value,"BANDS=")==NULL){
+    if(nBandsI>=3)
+      if(nBandsI==4)
+	msLayerAddProcessing(myLayer,"BANDS=1,2,3,4");
+      else
+	msLayerAddProcessing(myLayer,"BANDS=1,2,3");
+    else if(nBandsI>=2)
+      msLayerAddProcessing(myLayer,"BANDS=1,2");
+    else
+      msLayerAddProcessing(myLayer,"BANDS=1");
+  }
+
+  /**
+   * Name available Bands
+   */
+  char lBands[7];
+  char *nameBands=NULL;
+  for( iBand = 0; iBand < nBandsI; iBand++ ){
+    memset(&lBands,0,7);
+    sprintf(lBands,"Band%d",iBand+1);    
+    if(nameBands==NULL){
+      nameBands=(char*)malloc((strlen(lBands)+1)*sizeof(char));
+      sprintf(nameBands,"%s",lBands);
+    }else{
+      /*if(iBand<4)*/{
+	char *tmpS=zStrdup(nameBands);
+	nameBands=(char*)realloc(nameBands,(strlen(tmpS)+strlen(lBands)+2)*sizeof(char));
+	sprintf(nameBands,"%s %s",tmpS,lBands);
+	free(tmpS);
+      }
+    }
+  }
+  if(nameBands!=NULL){
+    msInsertHashTable(&(myLayer->metadata), "ows_bandnames", nameBands);
+    free(nameBands);
+  }
+
+  /**
+   * Loops over metadata information to setup specific information
+   */
+  for( iBand = 0; iBand < nBandsI; iBand++ ){
+    double      pdfMin, pdfMax, pdfMean, pdfStdDev;
+    hBand = GDALGetRasterBand( hDataset, iBand+1 );
+
+    CPLErrorReset();
+    GDALGetRasterStatistics( hBand, TRUE, TRUE, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev);
+    char tmpN[21];
+    sprintf(tmpN,"Band%d",iBand+1);
+    if (CPLGetLastErrorType() == CE_None){
+      char tmpMm[100],tmpMp[100],tmpNb[3];
+      sprintf(tmpMm,"%.3f %.3f",pdfMin,pdfMax);
+      if(pdfMin!=pdfMax && (styleMap==NULL || strstr(styleMap->value,"SCALE_")==NULL)){
+        sprintf(tmpNb,"%d",iBand+1);
+        if(styleMap==NULL || strstr(styleMap->value,"BANDS=")==NULL || strstr(strstr(styleMap->value,"BANDS="),tmpNb)!=NULL){ 
+	  if(pdfMean-(2*pdfStdDev)<0)
+	    sprintf(tmpMp,"SCALE_%d=%.3f,%.3f",iBand+1,0.0,pdfMean+(2*pdfStdDev));
+	  else
+	    sprintf(tmpMp,"SCALE_%d=%.3f,%.3f",iBand+1,pdfMean-(2*pdfStdDev),pdfMean+(2*pdfStdDev));
+	  msLayerAddProcessing(myLayer,tmpMp);
+        }
+      }
+      char tmpI[31];      
+      sprintf(tmpI,"%s_interval",tmpN);
+      msInsertHashTable(&(myLayer->metadata), tmpI, tmpMm);
+      map* test=getMap(output->content,"msClassify");
+      if(test!=NULL && strncasecmp(test->value,"true",4)==0){
+	/**
+	 * Classify one band raster pixel value using regular interval
+	 */
+	int _tmpColors[10][3]={
+	  {102,153,204},
+	  {51,102,153},
+	  {102,102,204},
+	  {51,204,0},
+	  {153,255,102},
+	  {204,255,102},
+	  {102,204,153},
+	  {255,69,64},
+	  {255,192,115},
+	  {255,201,115}
+	};
+	  
+	if(nBandsI==1){
+	  double delta=pdfMax-pdfMin;
+	  double interval=delta/10;
+	  double cstep=pdfMin;
+	  for(i=0;i<10;i++){
+	    /**
+	     * Create a new class
+	     */
+	    if(msGrowLayerClasses(myLayer) == NULL)
+	      return -1;
+	    if(initClass((myLayer->CLASS[myLayer->numclasses])) == -1)
+	      return -1;
+	    if(msGrowClassStyles(myLayer->CLASS[myLayer->numclasses]) == NULL)
+	      return -1;
+	    if(initStyle(myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]) == -1)
+	      return -1;
+	    
+	    /**
+	     * Set class name
+	     */
+	    char className[7];
+	    sprintf(className,"class%d",i);
+	    myLayer->CLASS[myLayer->numclasses]->name=zStrdup(className);
+	    
+	    /**
+	     * Set expression
+	     */
+	    char expression[1024];
+	    if(i+1<10)
+	      sprintf(expression,"([pixel]>=%.3f AND [pixel]<%.3f)",cstep,cstep+interval);
+	    else
+	      sprintf(expression,"([pixel]>=%.3f AND [pixel]<=%.3f)",cstep,cstep+interval);
+	    msLoadExpressionString(&myLayer->CLASS[myLayer->numclasses]->expression,expression);
+	    
+	    /**
+	     * Set color
+	     */
+	    myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.red=_tmpColors[i][0];
+	    myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.green=_tmpColors[i][1];
+	    myLayer->CLASS[myLayer->numclasses]->styles[myLayer->CLASS[myLayer->numclasses]->numstyles]->color.blue=_tmpColors[i][2];
+	    cstep+=interval;
+	    myLayer->CLASS[myLayer->numclasses]->numstyles++;
+	    myLayer->numclasses++;
+	    
+	  }
+	  
+	  char tmpMm[100];
+	  sprintf(tmpMm,"%.3f %.3f",pdfMin,pdfMax);
+	  
+	}
+      }
+      else{
+	if(nBandsI==1){
+	  myLayer->offsite.red=0;
+	  myLayer->offsite.green=0;
+	  myLayer->offsite.blue=0;
+	}
+      }
+    }
+    if( strlen(GDALGetRasterUnitType(hBand)) > 0 ){
+      char tmpU[31];
+      sprintf(tmpU,"%s_band_uom",tmpN);
+      msInsertHashTable(&(myLayer->metadata), tmpU, GDALGetRasterUnitType(hBand));
+    }
+
+  }
+  if(styleMap==NULL || strstr(styleMap->value,"RESAMPLE")==NULL)
+    msLayerAddProcessing(myLayer,"RESAMPLE=BILINEAR");
+  
+  if(styleMap!=NULL && strlen(styleMap->value)>9){
+    msUpdateLayerFromString(myLayer,styleMap->value,MS_FALSE);
+  }
+  
+  m->layerorder[m->numlayers] = m->numlayers;
+  m->numlayers++;
+  GDALClose( hDataset );
+  GDALDestroyDriverManager();
+  CPLCleanupTLS();
+  storeMd5(pszFilename);
+  return 1;
+}
+
+/**
+ * Create a MapFile for WMS, WFS or WCS Service output
+ *
+ * @param conf the conf maps containing the main.cfg settings
+ * @param outputs a specific output maps
+ */
+void outputMapfile(maps* conf,maps* outputs){
+  /**
+   * First store the value on disk
+   */
+  int imyIndex=getPublishedId(outputs);
+  map* mime=getMapArray(outputs->content,"mimeType",imyIndex);
+  map* msUrl=getMapFromMaps(conf,"main","mapserverAddress");
+  map* dataPath=getMapFromMaps(conf,"main","dataPath");
+  char *ext="data";
+  if(mime!=NULL)
+    if(strncasecmp(mime->value,"application/json",16)==0)
+      ext="json";
+
+  map* storage=getMapArray(outputs->content,"storage",imyIndex);
+  if(storage==NULL){
+    map* tmpMap=getMapFromMaps(conf,"main","dataPath");
+    map* sidMap=getMapFromMaps(conf,"lenv","usid");
+    char *pszDataSource=(char*)malloc((strlen(tmpMap->value)+strlen(sidMap->value)+strlen(outputs->name)+17)*sizeof(char));
+    sprintf(pszDataSource,"%s/ZOO_DATA_%d_%s_%s.%s",tmpMap->value,imyIndex,outputs->name,sidMap->value,ext);
+    int f=zOpen(pszDataSource,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+    map *gfile=getMapArray(outputs->content,"generated_file",imyIndex);
+    if(gfile!=NULL){
+      readGeneratedFile(conf,outputs->content,gfile->value);	    
+    }
+    map* sizeMap=getMapArray(outputs->content,"size",imyIndex);
+    map* vData=getMapArray(outputs->content,"value",imyIndex);
+    if(sizeMap!=NULL){
+      zWrite(f,vData->value,atoi(sizeMap->value)*sizeof(char));
+    }
+    else{
+      zWrite(f,vData->value,(strlen(vData->value)+1)*sizeof(char));
+    }
+    close(f);
+    setMapArray(outputs->content,"storage",imyIndex,pszDataSource);
+    free(pszDataSource);
+  }
+
+  /*
+   * Create an empty map, set name, default size and extent
+   */
+  map* mapfileTemplate=getMapArray(outputs->content,"msInclude",imyIndex);
+  mapObj *myMap=NULL;
+  if(mapfileTemplate==NULL){
+    myMap=msNewMapObj();
+  }
+  else{
+    map* dataPath=getMapFromMaps(conf,"main","dataPath");
+    map* sid=getMapFromMaps(conf,"lenv","sid");
+    char *mapfileTemplatePath=(char*)malloc(((strlen(dataPath->value)+strlen(sid->value)+strlen(outputs->name)+10)*sizeof(char)));
+    sprintf(mapfileTemplatePath,"%s/%s_%s.map",dataPath->value,outputs->name,sid->value);
+    myMap=msLoadMap(mapfileTemplate->value,mapfileTemplatePath);
+    if(myMap==NULL){
+      setMapInMaps(conf,"lenv","message",_("Unable to open your template mapfile!"));
+      return ;
+    }
+  }
+  free(myMap->name);
+  myMap->name=zStrdup("ZOO-Project_WXS_Server");
+  msMapSetSize(myMap,2048,2048);
+  msMapSetExtent(myMap,-1,-1,1,1);
+  
+  /*
+   * Set imagepath and imageurl using tmpPath and tmpUrl from main.cfg
+   */
+  map *tmp1=getMapFromMaps(conf,"main","tmpPath");
+  myMap->web.imagepath=zStrdup(tmp1->value);
+  tmp1=getMapFromMaps(conf,"main","tmpUrl");
+  myMap->web.imageurl=zStrdup(tmp1->value);
+  
+  /*
+   * Define supported output formats
+   */
+  outputFormatObj *o1=msCreateDefaultOutputFormat(NULL,"AGG/PNG","png");
+  o1->imagemode=MS_IMAGEMODE_RGBA;
+  o1->transparent=MS_TRUE;
+  o1->inmapfile=MS_TRUE;
+  msAppendOutputFormat(myMap,msCloneOutputFormat(o1));
+  msFreeOutputFormat(o1);
+
+#ifdef USE_KML
+  outputFormatObj *o2=msCreateDefaultOutputFormat(NULL,"KML","kml");
+  if(!o2){
+    perror("Unable to initialize KML driver");
+    fprintf(stderr,"Unable to initialize KML driver !\n");
+  }else{
+    o2->inmapfile=MS_TRUE;  
+    msAppendOutputFormat(myMap,msCloneOutputFormat(o2));
+    msFreeOutputFormat(o2);
+  }
+#endif
+
+  outputFormatObj *o3=msCreateDefaultOutputFormat(NULL,"GDAL/GTiff","tiff");
+  if(!o3)
+    fprintf(stderr,"Unable to initialize GDAL driver !\n");
+  else{
+    o3->imagemode=MS_IMAGEMODE_INT16;
+    o3->inmapfile=MS_TRUE;  
+    msAppendOutputFormat(myMap,msCloneOutputFormat(o3));
+    msFreeOutputFormat(o3);
+  }
+
+  outputFormatObj *o4=msCreateDefaultOutputFormat(NULL,"GDAL/AAIGRID","grd");
+  if(!o4)
+    fprintf(stderr,"Unable to initialize GDAL driver !\n");
+  else{
+    o4->imagemode=MS_IMAGEMODE_BYTE;
+    o4->inmapfile=MS_TRUE;  
+    msAppendOutputFormat(myMap,msCloneOutputFormat(o4));
+    msFreeOutputFormat(o4);
+  }
+
+#ifdef USE_CAIRO
+  outputFormatObj *o5=msCreateDefaultOutputFormat(NULL,"CAIRO/PNG","cairopng");
+  if(!o5)
+    fprintf(stderr,"Unable to initialize CAIRO driver !\n");
+  else{
+    o5->imagemode=MS_IMAGEMODE_RGBA;
+    o5->transparent=MS_TRUE;
+    o5->inmapfile=MS_TRUE;
+    msAppendOutputFormat(myMap,msCloneOutputFormat(o5));
+    msFreeOutputFormat(o5);
+  }
+#endif
+
+  
+  outputFormatObj *o6=msCreateDefaultOutputFormat(NULL,"GDAL/GTiff","geotiff");
+  if(!o6)
+    fprintf(stderr,"Unable to initialize GDAL driver !\n");
+  else{
+    o6->imagemode=MS_IMAGEMODE_BYTE;
+    o6->mimetype=strdup("image/geotiff");
+    o6->inmapfile=MS_TRUE;
+    msAppendOutputFormat(myMap,msCloneOutputFormat(o6));
+    msFreeOutputFormat(o6);
+  }
+
+  
+  /*
+   * Set default projection to EPSG:4326
+   */
+  msLoadProjectionStringEPSG(&myMap->projection,"EPSG:4326");
+  myMap->transparent=1;
+
+  /*
+   * Set mapserver PROJ_LIB/GDAL_DATA or any other config parameter from 
+   * the main.cfg [mapserver] section if any
+   */
+  maps *tmp3=getMaps(conf,"mapserver");
+  if(tmp3!=NULL){
+    map* tmp4=tmp3->content;
+    while(tmp4!=NULL){
+      msSetConfigOption(myMap,tmp4->name,tmp4->value);
+      tmp4=tmp4->next;
+    }
+  }
+
+  /**
+   * Set a ows_rootlayer_title,  
+   */
+  if (msInsertHashTable(&(myMap->web.metadata), "ows_rootlayer_name", "ZOO_Project_Layer") == NULL){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to add metadata");
+#endif
+    return;
+  }
+  if (msInsertHashTable(&(myMap->web.metadata), "ows_rootlayer_title", "ZOO_Project_Layer") == NULL){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to add metadata");
+#endif
+    return;
+  }
+
+  /**
+   * Enable all the WXS requests using ows_enable_request
+   * see http://mapserver.org/trunk/development/rfc/ms-rfc-67.html
+   */
+  if (msInsertHashTable(&(myMap->web.metadata), "ows_enable_request", "*") == NULL){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to add metadata");
+#endif
+    return;
+  }
+  msInsertHashTable(&(myMap->web.metadata), "ows_srs", "EPSG:4326");
+
+  /**
+   * Set metadata extracted from main.cfg file maps
+   */
+  maps* cursor=conf;
+  map* correspondance=getCorrespondance();
+  while(cursor!=NULL){
+    if(strstr(cursor->name,"_help")==NULL){
+      map* _cursor=cursor->content;
+      map* vMap;
+      while(_cursor!=NULL){
+	if((vMap=getMap(correspondance,_cursor->name))!=NULL){
+	  if (msInsertHashTable(&(myMap->web.metadata), vMap->value, _cursor->value) == NULL){
+#ifdef DEBUGMS
+	    fprintf(stderr,"Unable to add metadata");
+#endif
+	    freeMap(&correspondance);
+	    free(correspondance);
+	    return;
+	  }
+	}
+	_cursor=_cursor->next;
+      }
+    }
+    cursor=cursor->next;
+  }
+  freeMap(&correspondance);
+  free(correspondance);
+
+  map* sid=getMapFromMaps(conf,"lenv","usid");
+  char *mapPath=
+    (char*)malloc((14+strlen(sid->value)+strlen(outputs->name)+strlen(dataPath->value))*sizeof(char));
+  sprintf(mapPath,"%s/%s_%d_%s.map",dataPath->value,outputs->name,imyIndex,sid->value);
+  char *mapUrl=
+    (char*)malloc((6+strlen(mapPath)+strlen(msUrl->value))*sizeof(char));
+  sprintf(mapUrl,"%s?map=%s",msUrl->value,mapPath);
+
+  if (msInsertHashTable(&(myMap->web.metadata), "ows_onlineresource", mapUrl) == NULL){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to add metadata");
+#endif
+    return;
+  }
+
+  if(tryOgr(conf,outputs,myMap)<0)
+    if(tryGdal(conf,outputs,myMap)<0)
+      return ;
+
+  char *tmpPath=(char*)malloc((13+strlen(dataPath->value))*sizeof(char));
+  sprintf(tmpPath,"%s/symbols.sym",dataPath->value);
+  msInitSymbolSet(&myMap->symbolset);
+  myMap->symbolset.filename=zStrdup(tmpPath);
+  free(tmpPath);
+
+  msSaveMap(myMap,mapPath);
+  saveMapNames(conf,outputs,mapPath);
+  free(mapPath);
+  //free(myMap->symbolset.filename);
+  //msFreeSymbolSet(&myMap->symbolset);
+  msFreeMap(myMap);
+  //msFree(myMap);
+  msGDALCleanup();
+}
+
+/**
+ * Save the map fullpath in a text file (.maps)
+ * @param conf the main configuration map pointer
+ * @param output the current output for which a mapfile has been generated
+ * @param mapfile the mapfile saved to store in the text file
+ */
+void saveMapNames(maps* conf,maps* output,char* mapfile){
+  map* storage=getMap(output->content,"storage");
+  char *tmp=zStrdup(storage->value);
+  tmp[strlen(tmp)-strlen(strrchr(tmp,'.'))]=0;
+  char* mapName=(char*)malloc((strlen(tmp)+6)*sizeof(char*));
+  sprintf(mapName,"%s.maps",tmp);
+  FILE* myMaps=fopen(mapName,"a");
+  if(myMaps!=NULL){
+    fprintf(myMaps,"%s\n",mapfile);
+    fclose(myMaps);
+  }
+  free(mapName);
+  free(tmp);
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ms.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ms.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ms.h	(revision 942)
@@ -0,0 +1,63 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2010  Fondazione Edmund Mach. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef ZOO_SERVICE_INTERNAL_MS_H
+#define ZOO_SERVICE_INTERNAL_MS_H 1
+
+#include <sys/stat.h>
+#include "service.h"
+#include "cpl_conv.h"
+#include "cpl_multiproc.h"
+#include "ogr_api.h"
+#include "gdal.h"
+#include "ogr_srs_api.h"
+#ifdef WIN32
+#include <unistd.h>
+#endif
+
+
+#include <mapserver.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  map* getCorrespondance();
+  void setMapSize(maps* output,double minx,double miny,double maxy,double maxx);
+  void setReferenceUrl(maps* m,maps* tmpI);
+
+  void setSrsInformations(maps* output,mapObj* m,layerObj* myLayer, char* pszProjection);
+  
+  void setMsExtent(maps* output,mapObj* m,layerObj* myLayer,
+		   double minX,double minY,double maxX,double maxY);
+  int tryOgr(maps* conf,maps* output,mapObj* m);
+  
+  int tryGdal(maps* conf,maps* output,mapObj* m);
+  void outputMapfile(maps* conf,maps* outputs);
+  void saveMapNames(maps*,maps*,char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+ 
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_otb.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_otb.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_otb.c	(revision 942)
@@ -0,0 +1,483 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * See Ref: http://hg.orfeo-toolbox.org/OTB/ Copyright
+ * Some parts of this code are derived from ITK. See ITKCopyright.txt for 
+ * details.
+ */
+
+#include "service_internal_otb.h"
+#include "response_print.h"
+#include "server_internal.h"
+
+using namespace otb::Wrapper;
+
+/**
+ * Global OTB counter 
+ */
+int otbCounter=0;
+
+/**
+ * The ZooWatcher list
+ */
+WatcherListType m_WatcherList;
+/**
+ * A pointer to the conf maps containing the main.cfg settings
+ */
+maps* m_Conf;
+
+/**
+ * The command to create a ZooWatcher and add it to the global m_WatcherList
+ */
+class MyCommand : public itk::Command
+{
+ public:
+  itkNewMacro( MyCommand );
+ public:
+
+  /**
+   * The method that defines the action to be taken by the command. 
+   *
+   * @param caller an itk::Object pointer
+   * @param event an itk::EventObject pointer
+   */
+  void Execute(itk::Object *caller, const itk::EventObject & event)
+  {
+    Execute( (const itk::Object *)caller, event);
+  }
+ 
+  /**
+   * The method that defines the action to be taken by the command. 
+   * Create a new ZooWatcher instance then add it to the m_WatcherList.
+   *
+   * @param caller a const itk::Object pointer
+   * @param event an itk::EventObject pointer
+   * @see ZooWatcher,ZooWatcher::SetConf
+   */
+  void Execute(const itk::Object *caller, const itk::EventObject & event)
+  {
+    const AddProcessToWatchEvent* eventToWatch = dynamic_cast< const AddProcessToWatchEvent*> ( &event );
+    std::string m_CurrentDescription = eventToWatch->GetProcessDescription();
+    ZooWatcher * watch = new ZooWatcher(eventToWatch->GetProcess(),
+					eventToWatch->GetProcessDescription());
+    watch->SetConf(&m_Conf);
+    m_WatcherList.push_back(watch);
+  }
+
+};
+
+/**
+ * Replace all occurence of from by to in a str string
+ *
+ * @param str the string to transform
+ * @param from the string to replace
+ * @param to the string used as replacement
+ * @return the resulting string 
+ */
+std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
+    size_t start_pos = 0;
+    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
+        str.replace(start_pos, from.length(), to);
+        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
+    }
+    return str;
+}
+
+/**
+ * Load and run an OTB Application corresponding to the service by using inputs parameters.
+ * Define the m_Conf 
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_otb_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=tmp0->value;
+  map* tmp=NULL;
+  int res=-1;
+  std::vector<std::string> list = ApplicationRegistry::GetAvailableApplications();
+  if (list.size() == 0){
+    map* tmps=createMap("text","No OTB Application found.");
+    addToMap(tmps,"code","InternalError");
+    printExceptionReportResponse(m,tmps);
+    freeMap(&tmps);
+    free(tmps);
+    res=-1;
+    return res;
+  }
+  else{
+    dumpMapsValuesToFiles(main_conf,real_inputs);
+    for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it){
+      if(s->name==*it){
+	Application::Pointer m_Application=ApplicationRegistry::CreateApplication(*it);
+	if (m_Application.IsNull()){
+	  char tmpS[1024];
+	  sprintf(tmpS, "The OTB Application %s cannot be loaded.", (*it).c_str());
+	  map* tmps=createMap("text",tmpS);
+	  addToMap(tmps,"code","InternalError");
+	  printExceptionReportResponse(m,tmps);
+	  freeMap(&tmps);
+	  free(tmps);
+	  res=-1;
+	}else{
+	  // Create Observer on AddProcessToWatchEvent
+	  m_Conf=m;
+	  MyCommand::Pointer myCommand = MyCommand::New();
+	  m_Application->AddObserver(AddProcessToWatchEvent(), myCommand);
+	  char tmpS[1024];
+	  const std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
+	  for (unsigned int i = 0; i < appKeyList.size(); i++){
+	    const std::string paramKey(appKeyList[i]);
+	    Parameter::Pointer param = m_Application->GetParameterByKey(paramKey);
+	    ParameterType type = m_Application->GetParameterType(paramKey);
+	    if (type != ParameterType_Group && paramKey!="inxml" && paramKey!="outxml"){
+	      map* test=getMapFromMaps(inputs,paramKey.c_str(),"cache_file");
+	      if(test==NULL){
+		test=getMapFromMaps(inputs,paramKey.c_str(),"inRequest");
+		map* tmpPath=getMapFromMaps(m,"main","tmpPath");
+		map* tmpSid=getMapFromMaps(m,"lenv","usid");
+		char tmp[1024];
+		map* tmpVal=getMapFromMaps(outputs,paramKey.c_str(),"mimeType");
+		maps* tmpMaps=getMaps(outputs,paramKey.c_str());
+		if(tmpMaps!=NULL && test!=NULL && test->value!=NULL && strncasecmp(test->value,"true",4)==0){
+		  test=getMapFromMaps(inputs,paramKey.c_str(),"value");
+		  if(type == ParameterType_OutputImage){
+		    ImagePixelType outPixType = ImagePixelType_float;
+		    if (strncasecmp(test->value,"uint8",5)==0)
+		      outPixType = ImagePixelType_uint8;
+		    else if (strncasecmp(test->value,"int16",5)==0)
+		      outPixType = ImagePixelType_int16;
+		    else if (strncasecmp(test->value,"uint16",6)==0)
+		      outPixType = ImagePixelType_uint16;
+		    else if (strncasecmp(test->value,"int32",5)==0)
+		      outPixType = ImagePixelType_int32;
+		    else if (strncasecmp(test->value,"uint32",6)==0)
+		      outPixType = ImagePixelType_uint32;
+		    else if (strncasecmp(test->value,"double",6)==0)
+		      outPixType = ImagePixelType_double;
+		    const char* ext="tiff";
+		    if(tmpVal!=NULL){
+		      if(strncasecmp(tmpVal->value,"image/jp2",9)==0)
+			 ext="j2k";
+		      else
+			if(strncasecmp(tmpVal->value,"image/png",9)==0)
+			 ext="png";
+			else
+			  if(strncasecmp(tmpVal->value,"image/jpeg",10)==0)
+			    ext="jpeg";
+		    }
+		    sprintf(tmp,"%s/%s_%d_%s.%s",tmpPath->value,s->name,otbCounter,tmpSid->value,ext);
+		    otbCounter++;
+		    m_Application->SetParameterString(paramKey, tmp);
+		    setMapInMaps(inputs,paramKey.c_str(),"generated_file",tmp);
+		    dynamic_cast<OutputImageParameter *> (param.GetPointer())->SetPixelType(outPixType);
+		  }
+		  else{   	 	 
+		    if(test!=NULL && test->value!=NULL)  	 	 
+		      m_Application->SetParameterString(paramKey, test->value);  	 	 
+		  } 
+		}else{
+		  if(type == ParameterType_OutputVectorData){
+		      char* ext="json";
+		      if(tmpVal!=NULL){
+			if(strncasecmp(tmpVal->value,"text/xml",8)==0)
+			ext="gml";
+		      else
+			if(strncasecmp(tmpVal->value,"applicaton/json",15)==0)
+			  ext="json";
+			else
+			  if(strncasecmp(tmpVal->value,"application/zip",14)==0)
+			    ext="shp";
+			  else
+			    if(strncasecmp(tmpVal->value,"application/vnd.google-earth.kml+xml",36)==0)
+			      ext="kml";
+		      }
+		      sprintf(tmp,"%s/%s_%d_%s.%s",tmpPath->value,s->name,otbCounter,tmpSid->value,ext);
+		      otbCounter++;
+		      m_Application->SetParameterString(paramKey, tmp);
+		      setMapInMaps(inputs,paramKey.c_str(),"generated_file",tmp);
+		  }
+		  else
+		    if(type == ParameterType_OutputFilename){
+		      char* ext="txt";
+		      if(tmpVal!=NULL){
+			if(strncasecmp(tmpVal->value,"text/xml",8)==0)
+			  ext="xml";
+			else
+			  if(strncasecmp(tmpVal->value,"text/csv",15)==0)
+			    ext="csv";
+			  else
+			    if(strncasecmp(tmpVal->value,"application/zip",14)==0)
+			      ext="shp";
+			    else
+			      if(strncasecmp(tmpVal->value,"application/vnd.google-earth.kml+xml",36)==0)
+				ext="kml";
+			      else
+				if(strncasecmp(tmpVal->value,"application/vnd.google-earth.kmz",32)==0){
+				  ext="kmz";
+				  sprintf(tmp,"%s/%s_%d_%sxt.%s",tmpPath->value,s->name,otbCounter,tmpSid->value,ext);
+				  m_Application->SetParameterString(paramKey, tmp);
+				  setMapInMaps(outputs,paramKey.c_str(),"expected_generated_file",tmp);
+				}
+
+		      }
+		      sprintf(tmp,"%s/%s_%d_%s.%s",tmpPath->value,s->name,otbCounter,tmpSid->value,ext);
+		      otbCounter++;
+		      m_Application->SetParameterString(paramKey, tmp);
+		      setMapInMaps(inputs,paramKey.c_str(),"generated_file",tmp);
+		    }
+		    else{
+		      test=getMapFromMaps(inputs,paramKey.c_str(),"value");
+		      if(test!=NULL && type!=ParameterType_ListView){
+			m_Application->SetParameterString(paramKey, test->value);
+		      }
+		      else
+			if(type==ParameterType_ListView){
+			  std::vector<std::string> values;
+			  values.push_back(test->value);
+			  map* tmpLength=getMapFromMaps(inputs,paramKey.c_str(),"length");
+			  if(tmpLength!=NULL){
+			    int len=atoi(tmpLength->value);
+			    for(int k=1;k<len;k++){
+			      char tmp[15];
+			      sprintf(tmp,"cache_file_%d",k);
+			      map* tmpVal=getMapFromMaps(inputs,paramKey.c_str(),tmp);
+			      if(tmpVal!=NULL){
+				values.push_back(tmpVal->value);
+			      }
+			    }
+			  }
+			  dynamic_cast<ListViewParameter *> (param.GetPointer())->SetSelectedItems(values);
+			}
+		    }
+		}
+	      }else{
+		if(type == ParameterType_InputImageList){
+		  std::vector<std::string> values;
+		  values.push_back(test->value);
+		  map* tmpPath=getMapFromMaps(inputs,paramKey.c_str(),"length");
+		  if(tmpPath!=NULL){
+		    int len=atoi(tmpPath->value);
+		    for(int k=1;k<len;k++){
+		      char tmp[15];
+		      sprintf(tmp,"cache_file_%d",k);
+		      map* tmpVal=getMapFromMaps(inputs,paramKey.c_str(),tmp);
+		      if(tmpVal!=NULL){
+			values.push_back(tmpVal->value);
+		      }
+		    }
+		  }
+		  dynamic_cast<InputImageListParameter *> (param.GetPointer())->SetListFromFileName(values);
+		}
+		else
+		  if(type == ParameterType_InputVectorData || type == ParameterType_InputFilename){
+		    map* tmpPath=getMapFromMaps(m,"main","tmpPath");
+		    map* tmpSid=getMapFromMaps(m,"lenv","sid");
+		    char tmp[1024];
+		    map* tmpVal=getMapFromMaps(inputs,paramKey.c_str(),"mimeType");
+		    char* ext="json";
+		    if(tmpVal!=NULL){
+		      if(strncasecmp(tmpVal->value,"application/zip",14)==0){
+			char *tmpName=(char*)malloc((strlen(test->value)+9)*sizeof(char));
+			std::string test0(test->value);
+			if(test0.find(".zca")!=std::string::npos){
+			  symlink(test->value,ReplaceAll(test->value,".zca",".zip").c_str());
+			  sprintf(tmpName,"/vsizip/%s",ReplaceAll(test->value,".zca",".zip").c_str());
+			}else
+			  sprintf(tmpName,"/vsizip/%s",test->value);
+			char **files=VSIReadDir(tmpName);
+			int nFiles = CSLCount( files );
+			char *tmpSSName=(char*)malloc((strlen(tmpPath->value)+strlen(paramKey.c_str())+strlen(tmpSid->value)+9)*sizeof(char));
+			sprintf(tmpSSName,"%s/Input_%s_%s",tmpPath->value,paramKey.c_str(),tmpSid->value);
+			mkdir(tmpSSName,0777);
+			    
+			for(int kk=0;kk<nFiles;kk++){
+			  char *tmpSName=(char*)malloc((strlen(tmpName)+strlen(files[kk])+2)*sizeof(char));
+			  sprintf(tmpSName,"%s/%s",tmpName,files[kk]);
+			  VSILFILE* fmain=VSIFOpenL(tmpSName, "rb");
+			  if(fmain!=NULL){
+			    VSIFSeekL(fmain,0,SEEK_END);
+			    long count=VSIFTellL(fmain);
+			    VSIRewindL(fmain);
+
+			    char *content=(char*) malloc((count+1)*sizeof(char));  
+			    VSIFReadL(content,1,count*sizeof(char),fmain);
+			  
+			    char *tmpSSSName=(char*)malloc((strlen(tmpSSName)+strlen(files[kk])+2)*sizeof(char));
+			    sprintf(tmpSSSName,"%s/%s",tmpSSName,files[kk]);
+			    
+			    FILE* fx=fopen(tmpSSSName, "wb");
+			    fwrite(content,1,count,fx);
+			    fclose(fx);
+			    VSIFCloseL(fmain);
+			    free(content);
+			    std::string test1(tmpSSSName);
+			    if(test1.find(".shp")!=std::string::npos){
+			      setMapInMaps(inputs,paramKey.c_str(),"cache_file",tmpSSSName);
+			      test=getMapFromMaps(inputs,paramKey.c_str(),"cache_file");
+			    }
+			    free(tmpSSSName);
+			  }
+			  free(tmpSName);
+			}
+			free(tmpSSName);
+			free(tmpName);
+		      }
+		    }
+		    
+		    m_Application->SetParameterString(paramKey, test->value);
+		  }
+		  else
+		    if(type == ParameterType_InputImage
+		       || type == ParameterType_ComplexInputImage || type == ParameterType_InputVectorData
+		       || type == ParameterType_InputFilename){
+		      m_Application->SetParameterString(paramKey, test->value);
+		  }
+	      }
+	    }
+	    param->SetUserValue(true);
+	    m_Application->UpdateParameters();
+	  }
+
+	  try{
+	    if( m_Application->ExecuteAndWriteOutput() == 0 ){
+	      std::vector< std::pair<std::string, std::string> > paramList;
+	      paramList = m_Application->GetOutputParametersSumUp();
+	      if(paramList.size()>0)
+		for( unsigned int i=0; i<paramList.size(); i++){
+		  setMapInMaps(outputs,paramList[i].first.c_str(),"value",paramList[i].second.c_str());
+		}
+	      else{
+		const std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
+		for (unsigned int i = 0; i < appKeyList.size(); i++){
+		  const std::string paramKey(appKeyList[i]);
+		  std::vector<std::string> values;
+		  Parameter::Pointer param = m_Application->GetParameterByKey(paramKey);
+		  ParameterType type = m_Application->GetParameterType(paramKey);
+		  if (type != ParameterType_Group && paramKey!="inxml" && paramKey!="outxml"
+		      && (type == ParameterType_OutputImage || type == ParameterType_OutputFilename
+			  || type == ParameterType_OutputVectorData ) ){
+		    if(type == ParameterType_OutputImage || type == ParameterType_OutputFilename || type == ParameterType_OutputVectorData){
+		      map* test=getMapFromMaps(outputs,paramKey.c_str(),"mimeType");
+		      if(test!=NULL && strncasecmp(test->value,"application/zip",15)==0){
+			
+			test=getMapFromMaps(inputs,paramKey.c_str(),"generated_file");
+			char tmpName[1024];
+			sprintf(tmpName,"/vsizip/%s",ReplaceAll(test->value,".shp",".zip").c_str());
+			VSILFILE* fmain=VSIFOpenL(tmpName, "w");
+			FILE * file;
+			char *tmp;
+			char tmpSName[1024];
+			long count;
+			
+			char *exts[4];
+			exts[0]=".shp";
+			exts[1]=".shx";
+			exts[2]=".dbf";
+			exts[3]=".prj";
+			for(int c=0;c<4;c++){
+			  sprintf(tmpSName,"%s/result%s",tmpName,exts[c]);
+			  
+			  file=fopen(ReplaceAll(test->value,".shp",exts[c]).c_str(),"rb");
+			  if(file!=NULL){
+			    fseek(file, 0, SEEK_END);
+			    count = ftell(file);
+			    rewind(file);
+			    
+			    tmp=(char*) malloc((count+1)*sizeof(char));  
+			    fread(tmp,1,count*sizeof(char),file);
+			    
+			    VSILFILE* fx=VSIFOpenL(tmpSName, "wb");
+			    VSIFWriteL(tmp,1,count,fx);
+			    VSIFCloseL(fx);
+			    fclose(file);
+			    free(tmp);
+			  }
+			}
+			
+			VSIFCloseL(fmain);
+			
+			FILE* file1=fopen(ReplaceAll(test->value,".shp",".zip").c_str(), "rb");
+			fseek(file1, 0, SEEK_END);
+			count=ftell(file1);
+			rewind(file1);
+			
+			tmp=(char*) malloc((count+1)*sizeof(char));  
+			fread(tmp,1,count*sizeof(char),file1);
+			
+			file=fopen(ReplaceAll(test->value,".shp",".zip").c_str(),"wb");
+			fwrite(tmp,1,count,file);
+			fclose(file);
+			free(tmp);
+			fclose(file1);
+			setMapInMaps(inputs,paramKey.c_str(),"generated_file",ReplaceAll(test->value,".shp",".zip").c_str());
+		      }
+		      test=getMapFromMaps(inputs,paramKey.c_str(),"generated_file");
+
+		      if(test!=NULL){
+			setMapInMaps(outputs,paramKey.c_str(),"generated_file",test->value);
+		      }
+
+		    }
+		  }
+		}
+	      }
+	      res=3;
+	      break;
+	    }
+	    else{
+	      sprintf(tmpS, "The OTB Application %s cannot be run.", s->name);
+	      setMapInMaps(m,"lenv","message",tmpS);
+	      res=SERVICE_FAILED;
+	    }
+	  }
+	  catch(std::exception& err){
+	    setMapInMaps(m,"lenv","message",err.what());
+	    return SERVICE_FAILED;
+	    
+	  }
+	  catch(...){
+	    setMapInMaps(m,"lenv","message","An unknown exception has been raised during application execution");
+	    res=SERVICE_FAILED;
+	  }
+	  break;
+	}
+      }
+    }
+  }
+
+  for (unsigned int i = 0; i < m_WatcherList.size(); i++){
+    m_WatcherList[i]->FreeConf();
+    delete m_WatcherList[i];
+    m_WatcherList[i] = NULL;
+  }
+  m_WatcherList.clear();
+
+  return res;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_otb.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_otb.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_otb.h	(revision 942)
@@ -0,0 +1,53 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_OTB_H
+#define ZOO_SERVICE_INTERNAL_OTB_H 1
+
+#pragma once 
+
+#include "otbWrapperApplication.h"
+#include "otbWrapperApplicationRegistry.h"
+#include "otbWrapperInputImageListParameter.h"
+#include "otbWrapperListViewParameter.h"
+#include "otbWrapperAddProcessToWatchEvent.h"
+#include "otbZooWatcher.h"
+#include "service_internal.h"
+#include "service.h"
+#include "cgic.h"
+#ifdef WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+#include <vector>
+#include <string>
+
+/**
+ * A vector to store the ZooWatcher
+ */
+typedef std::vector<ZooWatcher *> WatcherListType;
+
+int zoo_otb_support(maps**,map*,service*,maps**,maps**);
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_perl.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_perl.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_perl.c	(revision 942)
@@ -0,0 +1,201 @@
+/**
+ * Author : David SAGGIORATO
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_perl.h"
+
+
+static PerlInterpreter *my_perl;
+
+
+void xs_init(pTHX)
+{
+	char *file = __FILE__;
+	dXSUB_SYS;
+	
+	/* DynaLoader is a special case */
+	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+}
+
+
+
+int map_to_hash(map * m, HV ** hash_map) {
+	HV * tmp = *hash_map;
+	map * tmp_m = m;
+	do {
+		//printf("map name %s  value %s \n",m->name,m->value);
+
+		if ( NULL == hv_store( tmp, tmp_m->name, strlen(tmp_m->name), sv_2mortal(newSVpv(tmp_m->value, strlen(tmp_m->value))), 0) ) {
+			return 1;
+			}
+		tmp_m = tmp_m->next;
+		}
+	while (tmp_m != NULL);
+	return 0;
+}
+
+int maps_to_hash( maps* m, HV ** hash_maps){
+	HV * tmp = *hash_maps;
+	if (m != NULL) {
+		//printf("maps name %s \n",m->name);
+		HV* hash_m = (HV *)sv_2mortal((SV *)newHV());
+		if (map_to_hash(m->content,&hash_m) != 0){
+			return 1;
+		}
+		
+		if ( NULL == hv_store( tmp, m->name, strlen(m->name),sv_2mortal(newRV_inc((SV *)hash_m)), 0) ) {
+			return 1;
+		}	
+		return maps_to_hash(m->next,hash_maps);
+	}
+	return 0;
+}
+
+int hash_to_map(HV * hh,map ** m){
+	hv_iterinit(hh);
+	*m = (map *)malloc(MAP_SIZE);
+	if (*m == NULL){
+		// erreur d'allocation memoire
+		return 1;
+	}
+	map * tmp = *m;
+	HE * he = hv_iternext(hh);
+	while (he != NULL){
+		//fprintf(stderr,"key : %s  value : %s \n",HeKEY(he),(char *)SvRV(HeVAL(he)));
+		tmp->name = HeKEY(he);
+		tmp->value = (char *)SvRV(HeVAL(he));
+		he = hv_iternext(hh);
+		if(he != NULL){
+			tmp->next = (map *)malloc(MAP_SIZE);
+			if (tmp->next == NULL){
+				//erreur allocation memoire
+				return 1;
+			}
+			tmp=tmp->next;
+		}
+		else {
+			tmp->next = NULL;
+		}
+
+	}
+
+	return 1;
+}
+	
+int hash_to_maps(HV * hh,maps** m){
+	hv_iterinit(hh);
+	maps * tmp = *m;
+	HE * he = hv_iternext(hh);
+	map *mm;
+	while (he != NULL) {
+		//fprintf(stderr,"key ===> %s \n",HeKEY(he));
+		tmp=createMaps(HeKEY(he));
+		hash_to_map((HV *) SvRV(HeVAL(he)),&mm);
+		tmp->content = mm;
+		if(*m==NULL)
+		  *m=tmp;
+		he = hv_iternext(hh);
+		if (he != NULL){
+			tmp= tmp->next;
+		}
+		else {
+			tmp->next = NULL;
+		}		
+	}
+	return 1;
+}
+	
+int zoo_perl_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+	maps* m=*main_conf;
+ 	maps* inputs=*real_inputs;
+	maps* outputs=*real_outputs;
+  	int res=SERVICE_FAILED;
+  	map * tmp=getMap(s->content,"serviceProvide");
+
+	char *my_argv[] = { "", tmp->value };
+	if ((my_perl = perl_alloc()) == NULL){
+		fprintf(stderr,"no memmory");
+		exit(1);
+	}
+	perl_construct( my_perl );
+	perl_parse(my_perl, xs_init, 2, my_argv, (char **)NULL);
+	perl_run(my_perl);
+	
+
+	HV* h_main_conf = (HV *)sv_2mortal((SV *)newHV());
+	HV* h_real_inputs = (HV *)sv_2mortal((SV *)newHV());
+	HV* h_real_outputs = (HV *)sv_2mortal((SV *)newHV());
+	maps_to_hash(m,&h_main_conf);
+	maps_to_hash(inputs,&h_real_inputs);
+	maps_to_hash(outputs,&h_real_outputs);
+	dSP;
+    	ENTER;
+    	SAVETMPS;
+    	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newRV_inc((SV *)h_main_conf)));
+	XPUSHs(sv_2mortal(newRV_inc((SV *)h_real_inputs)));
+	XPUSHs(sv_2mortal(newRV_inc((SV *)h_real_outputs)));
+	PUTBACK;
+	call_pv(s->name, G_SCALAR);
+	SPAGAIN;
+	res = POPi;
+	hash_to_maps(h_real_outputs,real_outputs);
+	//dumpMaps(*real_outputs);
+	PUTBACK;
+    	FREETMPS;
+    	LEAVE;
+	return SERVICE_SUCCEEDED;
+}
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_perl.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_perl.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_perl.h	(revision 942)
@@ -0,0 +1,64 @@
+/**
+ * Author : David SAGGIORATO
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_PERL_H
+#define ZOO_SERVICE_INTERNAL_PERL_H 1
+
+#pragma once 
+
+#include "service.h"
+#include "service_internal.h"
+#include <stdio.h>
+#include <EXTERN.h>
+#include <perl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void xs_init (pTHX);
+
+void boot_DynaLoader (pTHX_ CV*);
+
+int map_to_hash(map*, HV** );
+
+int maps_to_hash(maps *, HV ** );
+
+int hash_to_map(HV* ,map**);
+
+int hash_to_maps(HV* ,maps** );
+
+int zoo_perl_support(maps**,map*,service*,maps**,maps**);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
+
+
+
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php.c	(revision 942)
@@ -0,0 +1,452 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef WIN32
+  #define NO_FCGI_DEFINES
+#endif
+
+#ifndef ZEND_DEBUG
+  #define ZEND_DEBUG 0
+#endif  
+
+#include <sapi/embed/php_embed.h>
+#include <zend_stream.h>
+
+#include "service_internal_php.h"
+#include "response_print.h"
+
+zval *php_Array_from_maps(maps* t);
+zval*  php_Array_from_map(map*);
+maps* php_maps_from_Array(HashTable* t);
+map* php_map_from_HasTable(HashTable* t);
+
+#ifdef ZTS
+void ***tsrm_ls;
+#endif
+
+ZEND_BEGIN_MODULE_GLOBALS(zoo)
+long _SERVICE_SUCCEEDED;
+long _SERVICE_FAILED;
+ZEND_END_MODULE_GLOBALS(zoo)
+
+#ifdef ZTS
+#define ZOO_G(v) TSRMG(zoo_globals_id, zend_zoo_globals *, v)
+#else
+#define ZOO_G(v) (zoo_globals.v)
+#endif
+
+#define PHP_ZOO_VERSION "1.0"
+#define PHP_ZOO_EXTNAME "ZOO"
+
+PHP_MINIT_FUNCTION(zoo);
+PHP_MSHUTDOWN_FUNCTION(zoo);
+PHP_RINIT_FUNCTION(zoo);
+
+PHP_FUNCTION(zoo_Translate);
+PHP_FUNCTION(zoo_UpdateStatus);
+PHP_FUNCTION(zoo_SERVICE_SUCCEEDED);
+PHP_FUNCTION(zoo_SERVICE_FAILED);
+
+extern zend_module_entry zoo_module_entry;
+#define phpext_zoo_ptr &zoo_entry
+
+ZEND_DECLARE_MODULE_GLOBALS(zoo)
+
+static zend_function_entry zoo_functions[] = {
+  PHP_FE(zoo_Translate, NULL)
+  PHP_FE(zoo_UpdateStatus, NULL)
+  PHP_FE(zoo_SERVICE_SUCCEEDED, NULL)
+  PHP_FE(zoo_SERVICE_FAILED, NULL)
+  {NULL, NULL, NULL}
+};
+
+zend_module_entry zoo_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+    STANDARD_MODULE_HEADER,
+#endif
+    PHP_ZOO_EXTNAME,
+    zoo_functions,
+    PHP_MINIT(zoo),
+    PHP_MSHUTDOWN(zoo),
+    PHP_RINIT(zoo),
+    NULL,
+    NULL,
+#if ZEND_MODULE_API_NO >= 20010901
+    PHP_ZOO_VERSION,
+#endif
+    STANDARD_MODULE_PROPERTIES
+};
+
+ZEND_GET_MODULE(zoo)
+
+PHP_INI_BEGIN()
+PHP_INI_END()
+
+static void
+php_zoo_init_globals(zend_zoo_globals *zoo_globals)
+{
+  zoo_globals->_SERVICE_SUCCEEDED=3;
+  zoo_globals->_SERVICE_FAILED=4;
+}
+
+PHP_RINIT_FUNCTION(zoo)
+{
+  return SUCCESS;
+}
+
+PHP_MINIT_FUNCTION(zoo)
+{
+  ZEND_INIT_MODULE_GLOBALS(zoo, php_zoo_init_globals,NULL);
+  REGISTER_INI_ENTRIES();
+  return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(zoo)
+{
+  UNREGISTER_INI_ENTRIES();
+  return SUCCESS;
+}
+
+PHP_FUNCTION(zoo_Translate)
+{
+  char *value;
+  int value_len;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &value, &value_len) == FAILURE) {
+    RETURN_NULL();
+  }
+  RETURN_STRING(_ss(value), 1);
+}
+
+PHP_FUNCTION(zoo_UpdateStatus)
+{
+  zval *arr;
+  char *message;
+  int message_len;
+  long pourcent;
+  char *status=(char*)malloc(4*sizeof(char));
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "asl", &arr, &message, &message_len,&pourcent) == FAILURE) {
+    RETURN_NULL();
+  }
+  HashTable* t=HASH_OF(arr);
+  maps* conf=php_maps_from_Array(t);
+  setMapInMaps(conf,"lenv","message",message);
+  sprintf(status,"%d",pourcent);
+  setMapInMaps(conf,"lenv","status",status);
+  _updateStatus(conf);
+  freeMaps(&conf);
+  free(conf);
+  free(status);
+  RETURN_NULL();
+}
+
+PHP_FUNCTION(zoo_SERVICE_SUCCEEDED)
+{
+  RETURN_LONG(ZOO_G(_SERVICE_SUCCEEDED));
+}
+
+PHP_FUNCTION(zoo_SERVICE_FAILED)
+{
+  RETURN_LONG(ZOO_G(_SERVICE_FAILED));
+}
+
+/**
+ * Load a PHP script then run the function corresponding to the service by
+ * passing the conf, inputs and outputs parameters by reference.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_php_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){	
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+    
+  map* libp = getMapFromMaps(m, "main", "libPath");  
+  int res=SERVICE_FAILED;
+
+  map* tmp=getMap(s->content,"serviceProvider");
+  if (tmp == NULL || tmp->value == NULL) {
+	  return errorException(m, "Missing serviceProvider (library file)", "NoApplicableCode", NULL);
+  }
+  
+  map* cwd=getMapFromMaps(m,"lenv","cwd");
+#ifdef IGNORE_METAPATH
+  map* mp = createMap("metapath", "");
+#else  
+  map* mp = getMap(request, "metapath");
+#endif
+  char *scriptName;
+  
+  if (libp != NULL && libp->value != NULL) {
+	scriptName = (char*) malloc((strlen(libp->value) + strlen(tmp->value) + 2)*sizeof(char));
+    sprintf (scriptName, "%s/%s", libp->value, tmp->value);	
+  }
+  else {	
+    if(mp!=NULL && strlen(mp->value)>0){
+      scriptName=(char*)malloc((strlen(cwd->value)+strlen(mp->value)+strlen(tmp->value)+3)*sizeof(char));
+      sprintf(scriptName,"%s/%s/%s",cwd->value,mp->value,tmp->value);
+    }else{
+      scriptName=(char*)malloc((strlen(cwd->value)+strlen(tmp->value)+2)*sizeof(char));
+      sprintf(scriptName,"%s/%s",cwd->value,tmp->value);
+    }
+  } 
+  zend_file_handle iscript;
+  iscript.type=ZEND_HANDLE_FD;
+  iscript.opened_path=NULL;
+  iscript.filename=tmp->value;
+  iscript.free_filename=0;
+  FILE* temp=fopen(scriptName,"rb");
+  if(temp==NULL){
+    char tmp1[1024];
+    sprintf(tmp1,_("Unable to load the PHP file %s"),tmp->value);
+    free(scriptName);
+    return errorException(m,tmp1,"NoApplicableCode",NULL);
+  }
+  iscript.handle.fd=fileno(temp);
+
+  php_embed_init(0,NULL PTSRMLS_CC);
+   
+  zend_try {
+    zend_startup_module(&zoo_module_entry);
+    php_execute_script(&iscript TSRMLS_CC);
+    zval *iargs[3];
+    zval iret, ifunc,ifile;
+      
+    ZVAL_STRING(&ifunc, s->name, 0);
+    iargs[0] = php_Array_from_maps(*main_conf);
+    iargs[1] = php_Array_from_maps(*real_inputs);
+    iargs[2] = php_Array_from_maps(*real_outputs);
+      
+    if((res=call_user_function(EG(function_table), NULL, &ifunc, &iret, 3, iargs TSRMLS_CC))==SUCCESS){
+      
+      HashTable* t=HASH_OF(iargs[2]);
+      HashTable* t1=HASH_OF(iargs[0]);
+      freeMaps(real_outputs);
+      free(*real_outputs);
+      freeMaps(main_conf);
+      free(*main_conf);
+      *real_outputs=php_maps_from_Array(t);
+      *main_conf=php_maps_from_Array(t1);
+
+      res=Z_LVAL(iret);
+    }else{
+      free(scriptName);
+      fclose(temp);
+      return errorException(m,"Unable to process.","NoApplicableCode",NULL);;
+    }
+  } zend_catch { 
+    free(scriptName);
+    fclose(temp);
+    return errorException(m,"Unable to process.","NoApplicableCode",NULL);;
+  } zend_end_try();
+  free(scriptName);
+  fclose(temp);
+  php_embed_shutdown(TSRMLS_C);
+
+  return res;
+}
+
+/**
+ * Convert a maps to a php Array
+ *
+ * @param t the maps to convert
+ * @return the php Array
+ */
+zval *php_Array_from_maps(maps* t){
+  zval *mapArray;
+  zval *mapArrayTmp;
+  maps* tmp=t;
+  int tres=0;
+  MAKE_STD_ZVAL(mapArray);
+  tres=array_init(mapArray);
+  while(tmp!=NULL){
+    add_assoc_zval(mapArray,tmp->name,php_Array_from_map(tmp->content));
+    tmp=tmp->next;
+  }
+  return mapArray;
+}
+
+/**
+ * Convert a map to a php Array
+ *
+ * @param t the map to convert
+ * @return the php Array
+ */
+zval *php_Array_from_map(map* t){
+  zval *mapArray;
+  zval *mapArrayTmp;
+  map* tmp=t;
+  int tres=0;
+  MAKE_STD_ZVAL(mapArray);
+  tres=array_init(mapArray);
+  while(tmp!=NULL){
+    map* sMap=getMapArray(tmp,"size",0);    
+    if(strncmp(tmp->name,"value",5)==0 && sMap!=NULL && tmp->value != NULL){
+      tres=add_assoc_stringl(mapArray,tmp->name,tmp->value,atoi(sMap->value),1);
+    } 
+    else if (tmp->value != NULL) {
+      tres=add_assoc_string(mapArray,tmp->name,tmp->value,1);
+    }
+    tmp=tmp->next;
+  }
+  return mapArray;
+}
+
+/**
+ * Convert a php Array to a maps
+ *
+ * @param t the php Array to convert
+ * @return the created maps
+ */
+maps* php_maps_from_Array(HashTable *t){
+  maps* final_res=NULL;
+  maps* cursor=final_res;
+  char key[1024];
+  for(zend_hash_internal_pointer_reset(t); 
+      zend_hash_has_more_elements(t) == SUCCESS; 
+      zend_hash_move_forward(t)) { 
+    char *key; 
+    uint keylen; 
+    ulong idx; 
+    int type; 
+    zval **ppzval, tmpcopy; 
+    type = zend_hash_get_current_key_ex(t, &key, &keylen, &idx, 0, NULL); 
+    if (zend_hash_get_current_data(t, (void**)&ppzval) == FAILURE) { 
+      /**
+       * Should never actually fail since the key is known to exist.
+       */
+      continue; 
+    }
+    /**
+     * Duplicate the zval so that * the orignal’s contents are not destroyed
+     */
+    tmpcopy = **ppzval;
+#ifdef DEBUG
+    fprintf(stderr,"key : %s\n",key);
+#endif
+    zval_copy_ctor(&tmpcopy); 
+#ifdef DEBUG
+    fprintf(stderr,"key : %s\n",key);
+#endif
+    /**
+     * Reset refcount & Convert
+     */
+    INIT_PZVAL(&tmpcopy); 
+    //convert_to_string(&tmpcopy); 
+    if (type == HASH_KEY_IS_STRING) { 
+      /**
+       * String Key / Associative
+       */
+      cursor=createMaps(key);
+#ifdef DEBUG	
+      fprintf(stderr,"key : %s\n",key);
+#endif	
+      HashTable* t=HASH_OF(*ppzval);
+#ifdef DEBUG
+      fprintf(stderr,"key : %s\n",key);
+#endif
+      cursor->content=php_map_from_HasTable(t);
+      cursor->next=NULL;
+      if(final_res==NULL)
+	final_res=dupMaps(&cursor);
+      else{
+	addMapsToMaps(&final_res,cursor);
+      }
+      freeMaps(&cursor);
+      free(cursor);
+    }
+#ifdef DEBUG
+    fprintf(stderr,"key : %s\n",key);
+#endif
+    /**
+     * Toss out old copy
+     */
+    zval_dtor(&tmpcopy);
+  }
+  return final_res;
+}
+
+/**
+ * Convert a php Array to a map
+ *
+ * @param t the php Array to convert
+ * @return the created map
+ */
+map* php_map_from_HasTable(HashTable* t){
+#ifdef DEBUG
+  fprintf(stderr,"mapsFromPHPArray start\n");
+#endif
+  map* final_res=(map*)malloc(MAP_SIZE);
+  final_res=NULL;
+  char key[1024];
+  for(zend_hash_internal_pointer_reset(t);
+      zend_hash_has_more_elements(t) == SUCCESS;
+      zend_hash_move_forward(t)) {
+    char *key;
+    uint keylen;
+    ulong idx;
+    int type;
+    int len;
+    zval **ppzval, tmpcopy;
+    type = zend_hash_get_current_key_ex(t, &key, &keylen, &idx, 0, NULL); 
+    if (zend_hash_get_current_data(t, (void**)&ppzval) == FAILURE) { 
+      /* Should never actually fail * since the key is known to exist. */ 
+      continue; 
+    }
+    /**
+     * Duplicate the zval so that * the orignal’s contents are not destroyed 
+     */ 
+    tmpcopy = **ppzval; 
+    zval_copy_ctor(&tmpcopy); 
+    /**
+     * Reset refcount & Convert 
+     */ 
+    INIT_PZVAL(&tmpcopy); 
+    convert_to_string(&tmpcopy);
+    if(strncmp(key,"value",5)==0){
+      len=Z_STRLEN_P(&tmpcopy);      
+	  final_res = addToMapWithSize(final_res,key,Z_STRVAL_P(&tmpcopy),len);
+    }
+    else{
+      if(final_res==NULL){
+#ifdef DEBUG
+	fprintf(stderr,"%s => %s\n",key,Z_STRVAL(tmpcopy));
+#endif
+	final_res=createMap(key,Z_STRVAL(tmpcopy));
+      }
+      else{
+#ifdef DEBUG
+	fprintf(stderr,"%s => %s\n",key,Z_STRVAL(tmpcopy));
+#endif
+	addToMap(final_res,key,Z_STRVAL(tmpcopy));
+      }
+    }
+    /* Toss out old copy */ 
+    zval_dtor(&tmpcopy); 
+  }
+  return final_res;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php.h	(revision 942)
@@ -0,0 +1,43 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_PHP_H
+#define ZOO_SERVICE_INTERNAL_PHP_H 1
+
+#pragma once
+
+#include "service.h"
+#include "service_internal.h"
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  int zoo_php_support(maps**,map*,service*,maps**,maps**);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php7.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php7.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_php7.c	(revision 942)
@@ -0,0 +1,413 @@
+/*
+ * Author : Gérald FENOY, Knut LANDMARK
+ *
+ * Copyright (c) 2009-2016 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef WIN32
+  #define NO_FCGI_DEFINES
+  #define ZEND_WIN32_KEEP_INLINE
+#endif
+
+#ifndef ZEND_DEBUG
+  #define ZEND_DEBUG 0
+#endif  
+
+#include <sapi/embed/php_embed.h>
+#include <zend_stream.h>
+
+#include "service_internal_php.h"
+#include "response_print.h"
+
+map* php_hashtable_to_map(HashTable* tab);
+maps* php_array_to_maps(HashTable* arr);
+void php_map_to_array(map* src, zval* arr);
+void php_maps_to_array(maps* src, zval* arr);
+
+#define zval_make_ref_array(zv,len) for (int elem = 0; elem < len; elem++) ZVAL_MAKE_REF(&zv[elem]);
+#define zval_unref_array(zv,len)    for (int elem = 0; elem < len; elem++) ZVAL_UNREF(&zv[elem]);	
+
+#ifdef ZTS
+void ***tsrm_ls;
+#endif
+
+ZEND_BEGIN_MODULE_GLOBALS(zoo)
+long _SERVICE_SUCCEEDED;
+long _SERVICE_FAILED;
+ZEND_END_MODULE_GLOBALS(zoo)
+
+#ifdef ZTS
+#define ZOO_G(v) TSRMG(zoo_globals_id, zend_zoo_globals *, v)
+#else
+#define ZOO_G(v) (zoo_globals.v)
+#endif
+
+#define PHP_ZOO_VERSION "1.0"
+#define PHP_ZOO_EXTNAME "ZOO"
+
+PHP_MINIT_FUNCTION(zoo);
+PHP_MSHUTDOWN_FUNCTION(zoo);
+PHP_RINIT_FUNCTION(zoo);
+
+PHP_FUNCTION(zoo_Translate);
+PHP_FUNCTION(zoo_UpdateStatus);
+PHP_FUNCTION(zoo_SERVICE_SUCCEEDED);
+PHP_FUNCTION(zoo_SERVICE_FAILED);
+
+extern zend_module_entry zoo_module_entry;
+#define phpext_zoo_ptr &zoo_entry
+
+ZEND_DECLARE_MODULE_GLOBALS(zoo)
+
+static zend_function_entry zoo_functions[] = {
+  PHP_FE(zoo_Translate, NULL)
+  PHP_FE(zoo_UpdateStatus, NULL)
+  PHP_FE(zoo_SERVICE_SUCCEEDED, NULL)
+  PHP_FE(zoo_SERVICE_FAILED, NULL)
+  {NULL, NULL, NULL}
+};
+
+zend_module_entry zoo_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+    STANDARD_MODULE_HEADER,
+#endif
+    PHP_ZOO_EXTNAME,
+    zoo_functions,
+    PHP_MINIT(zoo),
+    PHP_MSHUTDOWN(zoo),
+    PHP_RINIT(zoo),
+    NULL,
+    NULL,
+#if ZEND_MODULE_API_NO >= 20010901
+    PHP_ZOO_VERSION,
+#endif
+    STANDARD_MODULE_PROPERTIES
+};
+
+ZEND_GET_MODULE(zoo)
+
+PHP_INI_BEGIN()
+PHP_INI_END()
+
+static void
+php_zoo_init_globals(zend_zoo_globals *zoo_globals)
+{
+  zoo_globals->_SERVICE_SUCCEEDED=3;
+  zoo_globals->_SERVICE_FAILED=4;
+}
+
+PHP_RINIT_FUNCTION(zoo)
+{
+  return SUCCESS;
+}
+
+PHP_MINIT_FUNCTION(zoo)
+{
+  ZEND_INIT_MODULE_GLOBALS(zoo, php_zoo_init_globals,NULL);
+  REGISTER_INI_ENTRIES();
+  return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(zoo)
+{
+  UNREGISTER_INI_ENTRIES();
+  return SUCCESS;
+}
+
+PHP_FUNCTION(zoo_Translate)
+{
+  char *value;
+  size_t value_len;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &value, &value_len) == FAILURE) {
+    RETURN_NULL();
+  }
+  //RETURN_STRING(_ss(value), 1);
+  RETURN_STRINGL(_ss(value), 1);
+}
+
+PHP_FUNCTION(zoo_UpdateStatus)
+{
+  zval *arr;
+  char *message;
+  size_t message_len;
+  zend_long pourcent;
+  char *status=(char*)malloc(4*sizeof(char));
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "asl", &arr, &message, &message_len,&pourcent) == FAILURE) {
+    RETURN_NULL();
+  }
+  HashTable* t=HASH_OF(arr);
+  maps* conf = php_array_to_maps(t);
+    
+  setMapInMaps(conf,"lenv","message",message);
+  sprintf(status,"%d",pourcent);
+  setMapInMaps(conf,"lenv","status",status);  
+  _updateStatus(conf); 
+  freeMaps(&conf); 
+  free(conf);
+  free(status);
+  
+  RETURN_NULL();
+}
+
+PHP_FUNCTION(zoo_SERVICE_SUCCEEDED)
+{
+  RETURN_LONG(ZOO_G(_SERVICE_SUCCEEDED));
+}
+
+PHP_FUNCTION(zoo_SERVICE_FAILED)
+{
+  RETURN_LONG(ZOO_G(_SERVICE_FAILED));
+}
+
+/**
+ * Load a PHP script then run the function corresponding to the service by
+ * passing the conf, inputs and outputs parameters by reference.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_php_support(maps** main_conf, map* request, service* s, maps **real_inputs, maps **real_outputs) {	
+  maps* m = *main_conf;
+  maps* inputs = *real_inputs;
+  maps* outputs = *real_outputs;
+    
+  map* libp = getMapFromMaps(m, "main", "libPath");  
+  int res=SERVICE_FAILED;
+
+  map* tmp = getMap(s->content, "serviceProvider");
+  if (tmp == NULL || tmp->value == NULL) {
+    return errorException(m, "Missing serviceProvider (library file)", "NoApplicableCode", NULL);
+  }  
+  
+  #ifdef IGNORE_METAPATH
+  map* mp = createMap("metapath", "");
+  #else  
+  map* mp = getMap(request, "metapath");
+  #endif
+  
+  map* cwd = getMapFromMaps(m,"lenv","cwd");
+  char *scriptName;
+  
+  if (libp != NULL && libp->value != NULL) {
+    scriptName = (char*) malloc((strlen(libp->value) + strlen(tmp->value) + 2)*sizeof(char));
+    sprintf (scriptName, "%s/%s", libp->value, tmp->value);	
+  }
+  else {	
+    if(mp != NULL && strlen(mp->value) > 0) {
+      scriptName = (char*) malloc((strlen(cwd->value)+strlen(mp->value)+strlen(tmp->value)+3)*sizeof(char));
+      sprintf(scriptName, "%s/%s/%s", cwd->value, mp->value, tmp->value);
+    } 
+	  else {
+      scriptName = (char*) malloc((strlen(cwd->value)+strlen(tmp->value)+2)*sizeof(char));
+      sprintf(scriptName, "%s/%s", cwd->value, tmp->value);
+    }
+  }
+  
+  zend_file_handle iscript;
+  iscript.type = ZEND_HANDLE_FD;
+  iscript.opened_path = NULL;
+  iscript.filename = tmp->value;
+  iscript.free_filename = 0;
+  
+  FILE* temp = fopen(scriptName, "rb");
+  if(temp == NULL) {
+    char tmp1[1024];
+    sprintf(tmp1, _("Unable to load the PHP file %s"), tmp->value);
+    free(scriptName);
+    return errorException(m, tmp1, "NoApplicableCode", NULL);
+  }
+  iscript.handle.fd = fileno(temp);
+
+  php_embed_init(0, NULL);
+
+  zend_try {
+    zend_startup_module(&zoo_module_entry);
+    php_execute_script(&iscript TSRMLS_CC);
+
+	  zval iargs[3];
+    zval iret, ifunc;	
+		      
+	  ZVAL_STRING(&ifunc, s->name);
+	
+	  php_maps_to_array(*main_conf, iargs);    
+    php_maps_to_array(*real_inputs, iargs+1);    
+    php_maps_to_array(*real_outputs, iargs+2);
+    zval_make_ref_array(iargs,3);
+    
+    if((res = call_user_function(EG(function_table), NULL, &ifunc, &iret, 3, iargs)) == SUCCESS) {	
+		
+	    zval_unref_array(iargs,3);	  	  
+	    zend_string_release(Z_STR_P(&ifunc));
+      
+      HashTable* t = HASH_OF(iargs+2);
+      HashTable* t1 = HASH_OF(iargs);
+      freeMaps(real_outputs);
+      free(*real_outputs);
+      freeMaps(main_conf);
+      free(*main_conf);
+      
+      *real_outputs = php_array_to_maps(t);	  
+      *main_conf = php_array_to_maps(t1);
+
+      res = Z_LVAL(iret);
+    }
+    else {
+      free(scriptName);
+      fclose(temp);
+      return errorException(m, "Unable to process.", "NoApplicableCode", NULL);;
+    }
+  } 
+  zend_catch { 
+    free(scriptName);
+    fclose(temp);
+    return errorException(m, "Unable to process.", "NoApplicableCode", NULL);;
+  } 
+  zend_end_try();
+  
+  free(scriptName);
+  fclose(temp);
+  php_embed_shutdown(TSRMLS_C);
+
+  return res;
+}
+
+/**
+ * Convert a Zoo struct maps to a php array
+ *
+ * @param src the struct maps* to convert (source data structure)
+ * @param arr pointer to zval that is to hold the php array
+ */
+void php_maps_to_array(maps* src, zval* arr) {
+	
+  int tres = array_init(arr);
+  maps* pm = src;
+		
+  while (pm != NULL) {
+    zval zv; // allocate on heap??
+    php_map_to_array(pm->content, &zv);
+    add_assoc_zval(arr, pm->name, &zv);	
+    pm = pm->next;
+	}
+}
+
+/**
+ * Convert a Zoo map to a php array
+ *
+ * @param src the struct map* to convert (source data structure)
+ * @param arr pointer to zval that is to hold the php array
+ */
+void php_map_to_array(map* src, zval* arr) {
+	
+  int tres = array_init(arr);
+  map* pm = src;
+	
+  while(pm != NULL) {
+    map* sMap = getMapArray(pm, "size", 0);
+		
+    if (pm->value != NULL && strncmp(pm->name, "value", 5) == 0 && sMap != NULL) {			 
+      tres = add_assoc_stringl(arr, pm->name, pm->value, atoi(sMap->value));
+		}
+    else {
+      tres = add_assoc_string(arr, pm->name, pm->value);			
+		}						
+    pm = pm->next;			
+  }	
+}
+
+/**
+ * Convert a php hashtable (array) to a Zoo maps
+ *
+ * @param arr the php hashtable to convert
+ * @return the created struct maps*
+ */
+maps* php_array_to_maps(HashTable* arr) {
+
+  maps* res = NULL;
+  zval* data;
+  zend_string* key = NULL;
+  ulong num_key;	
+	
+  ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, key, data)
+    if (!key) { // HASH_KEY_IS_LONG			
+      key = strpprintf(64, "%lu", num_key);
+	  }	
+    zval copy;
+    ZVAL_DUP(&copy, data);
+    HashTable* tab = HASH_OF(&copy);
+		
+    maps* node = createMaps(ZSTR_VAL(key));					
+    node->content = php_hashtable_to_map(tab);
+		
+    if(res == NULL) {
+      res = node;
+    }
+    else {
+      addMapsToMaps(&res, node);
+      freeMaps(&node);
+      free(node);
+    }
+    zval_dtor(&copy);		
+  ZEND_HASH_FOREACH_END();
+	
+  return res;
+}
+
+/**
+ * Convert a php hashtable (array) to a Zoo map
+ *
+ * @param tab the php hashtable to convert
+ * @return the created struct map*
+ */
+map* php_hashtable_to_map(HashTable* tab) {
+
+  map* res = NULL;
+  zval* data;
+  zend_string* key = NULL;
+  ulong num_key;
+	
+  ZEND_HASH_FOREACH_KEY_VAL(tab, num_key, key, data)
+    if (!key) { // HASH_KEY_IS_LONG			
+      key = strpprintf(64, "%lu", num_key);
+    }
+    zval copy;
+    ZVAL_DUP(&copy, data);
+    convert_to_string(&copy);
+		
+    if(strncmp(ZSTR_VAL(key), "value", 5) == 0) {			
+      size_t len = Z_STRLEN(copy);      			
+      res = addToMapWithSize(res, ZSTR_VAL(key), Z_STRVAL(copy), len);
+    }
+    else {
+      if (res == NULL) {				
+        res = createMap(ZSTR_VAL(key), Z_STRVAL(copy));
+			}
+      else {				
+        addToMap(res, ZSTR_VAL(key), Z_STRVAL(copy));
+      }
+    }				
+    zval_dtor(&copy); 			
+  ZEND_HASH_FOREACH_END();
+	
+  return res;	
+}	
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_python.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_python.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_python.c	(revision 942)
@@ -0,0 +1,890 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2014 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_python.h"
+
+/**
+ * The state for the zoo Python module
+ */
+struct module_state {
+   PyObject *error;
+};
+
+#if PY_MAJOR_VERSION >= 3
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
+#define PyInt_FromLong PyLong_FromLong
+#define PyInt_AsLong PyLong_AsLong
+#define PyString_FromString PyUnicode_FromString
+#define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+#define PyString_Check PyUnicode_Check
+#define	PyString_AsString _PyUnicode_AsString
+#define	PyString_Size PyUnicode_GetSize
+#else
+#define GETSTATE(m) (&_state)
+static struct module_state _state;
+#endif
+
+/**
+ * The exception for the zoo Python module
+ */
+static PyObject* ZooError;
+
+/**
+ * Function definitions for the zoo Python Module
+ *
+ * Define the following functions available from a service loaded and running
+ * from the ZOO-Kernel Python environment:
+ *  - "_" corresponding to the PythonTranslate function
+ *  - "update_status" corresponding to the PythonUpdateStatus function
+ * @see PythonTranslate, PythonUpdateStatus
+ */
+PyMethodDef zooMethods[] = {
+  {"_", PythonTranslate, METH_VARARGS, "Translate a string using the zoo-services textdomain."},
+  {"update_status", PythonUpdateStatus, METH_VARARGS, "Update status percentage of a running process."},
+  {NULL, NULL, 0, NULL} /* tempt not the blade, all fear the sentinel */
+};
+
+#if PY_MAJOR_VERSION >= 3
+
+static int myextension_traverse(PyObject *m, visitproc visit, void *arg) {
+  Py_VISIT(GETSTATE(m)->error);
+  return 0;
+}
+
+static int myextension_clear(PyObject *m) {
+  Py_CLEAR(GETSTATE(m)->error);
+  return 0;
+}
+
+static struct PyModuleDef moduledef = {
+  PyModuleDef_HEAD_INIT,
+  "zoo",
+  NULL,
+  sizeof(struct module_state),
+  zooMethods,
+  NULL,
+  myextension_traverse,
+  myextension_clear,
+  NULL
+};
+#endif
+
+/**
+ * Function to create and initialize the zoo Python module
+ *
+ * @return the Python module (for Python versions < 3, nothing for version >=3)
+ */
+PyMODINIT_FUNC init_zoo(){
+  PyObject *tmp,*d;
+  PyObject *module = 
+#if PY_MAJOR_VERSION >= 3
+    PyModule_Create(&moduledef);
+#else
+    Py_InitModule("zoo", zooMethods);
+#endif
+  if (module == NULL){
+#if PY_MAJOR_VERSION >= 3
+    return NULL;
+#else
+    return;
+#endif
+  }
+
+  struct module_state *st = GETSTATE(module);
+
+  d = PyModule_GetDict(module);
+  tmp = PyInt_FromLong(3);
+  PyDict_SetItemString(d, "SERVICE_SUCCEEDED", tmp);
+  Py_DECREF(tmp);
+
+  tmp = PyInt_FromLong(4);
+  PyDict_SetItemString(d, "SERVICE_FAILED", tmp);
+  Py_DECREF(tmp);
+
+  tmp = PyString_FromString(ZOO_VERSION);
+  PyDict_SetItemString(d, "VERSION", tmp);
+  Py_DECREF(tmp);
+
+  ZooError = PyErr_NewException((char*)"zoo.error", NULL, NULL);
+  Py_INCREF(ZooError);
+  PyModule_AddObject(module, "error", ZooError);
+#if PY_MAJOR_VERSION >= 3
+  return module;
+#endif
+}
+
+/**
+ * Load a Python module then run the function corresponding to the service
+ * by passing the conf, inputs and outputs parameters by reference. 
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_python_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+
+  char *pythonpath;
+  char *python_path;
+
+#ifdef WIN32
+  const char* os_pathsep = ";";
+#else
+  const char* os_pathsep = ":";
+#endif
+
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=tmp0->value;  
+  map* tmp=NULL;
+  int hasToClean=0;
+  tmp=getMapFromMaps(*main_conf,"env","PYTHONPATH"); 
+
+  map* kvp = NULL;
+  char* libPath = NULL;
+  if (hasvalue(*main_conf, "main", "libPath", &kvp)) {
+	  libPath = kvp->value;
+  }
+  else {
+	  libPath = "";
+  }
+
+#ifdef DEBUG
+  fprintf(stderr,"PYTHON SUPPORT \n");
+#endif
+  if(tmp!=NULL){
+#ifdef DEBUG
+    fprintf(stderr,"PYTHON SUPPORT (%i)\n",strlen(tmp->value));
+#endif
+    python_path=(char*)malloc((strlen(tmp->value)+1)*sizeof(char));
+    sprintf(python_path,"%s",tmp->value);
+    hasToClean=1;
+  }
+  else{
+    map* cwdMap=getMapFromMaps(*main_conf,"main","servicePath");
+    if(cwdMap!=NULL)
+      python_path=cwdMap->value;
+    else
+      python_path=(char*)".";	
+  }
+  tmp=NULL;
+  tmp=getMap(request,"metapath");
+  if(tmp!=NULL && strcmp(tmp->value,"")!=0){
+    //pythonpath=(char*)malloc((4+strlen(python_path)+strlen(ntmp)+strlen(tmp->value))*sizeof(char));
+	  pythonpath = (char*)malloc((5 + strlen(python_path) + strlen(ntmp) + strlen(tmp->value) + strlen(libPath)) * sizeof(char));
+#ifdef WIN32
+  //sprintf(pythonpath,"%s/%s/;%s",ntmp,tmp->value,python_path);
+	sprintf(pythonpath, "%s/%s/;%s;%s", ntmp, tmp->value, python_path, libPath);
+#else
+  //sprintf(pythonpath,"%s/%s/:%s",ntmp,tmp->value,python_path);
+  sprintf(pythonpath, "%s/%s/:%s:%s", ntmp, tmp->value, python_path, libPath);  
+#endif
+  }
+  else{
+    //pythonpath=(char*)malloc((2+strlen(python_path)+strlen(ntmp))*sizeof(char));
+	  pythonpath = (char*)malloc((3 + strlen(python_path) + strlen(ntmp) + strlen(libPath)) * sizeof(char));
+#ifdef WIN32
+    //sprintf(pythonpath,"%s;%s",ntmp,python_path);
+	sprintf(pythonpath, "%s;%s;%s", ntmp, python_path, libPath);
+#else
+    //sprintf(pythonpath,"%s:%s",ntmp,python_path);
+	sprintf(pythonpath, "%s:%s:%s", ntmp, python_path, libPath);
+#endif	
+  }
+#ifdef DEBUG
+    fprintf(stderr,"PYTHONPATH=%s\n",pythonpath);
+#endif
+	map* home = NULL;
+// knut: also set PYTHONHOME environment variable so that Python can load standard modules
+#ifndef WIN32	
+  setenv("PYTHONPATH",pythonpath,1);  
+  //= getMapFromMaps(*main_conf, "env", "PYTHONHOME"); 
+  if (hasvalue(*main_conf, "env", "PYTHONHOME", &home)) {
+	  setenv("PYTHONHOME", home->value, 1); // overwrite
+  }
+#else	
+  SetEnvironmentVariable("PYTHONPATH",pythonpath);
+  char* toto=(char*)malloc((strlen(pythonpath)+12)*sizeof(char));
+  sprintf(toto,"PYTHONPATH=%s",pythonpath);
+  _putenv(toto);
+  free(toto);
+  if (hasvalue(*main_conf, "env", "PYTHONHOME", &home)) { 
+	  SetEnvironmentVariable("PYTHONHOME", home->value);
+  }
+  char buffer[128];        
+#endif  
+  if(hasToClean>0)
+    free(python_path);
+  free(pythonpath);
+
+  PyThreadState *mainstate;
+#if PY_MAJOR_VERSION >= 3  
+  PyImport_AppendInittab("zoo", init_zoo);  
+#else
+  PyEval_InitThreads();
+#endif  
+  Py_Initialize();  
+#if PY_MAJOR_VERSION >= 3  
+  PyEval_InitThreads();
+  PyImport_ImportModule("zoo");  
+#else
+  init_zoo();
+#endif  
+  mainstate = PyThreadState_Swap(NULL);
+  PyEval_ReleaseLock();
+  PyGILState_STATE gstate;
+  gstate = PyGILState_Ensure();
+  PyObject *pName, *pModule, *pFunc;
+  tmp=getMap(s->content,"serviceProvider");
+  map* mp=getMap(request,"metapath");
+  if(tmp!=NULL){
+    if(mp!=NULL && strlen(mp->value)>0){
+      char *mps=zStrdup(mp->value);
+      int i,len=strlen(mps);
+      int j=0;
+      for(i=0;i<len;i++){
+	if(mps[i]=='/'){
+	  mps[i]='.';
+	}
+      }
+      char *mn=(char*)malloc((strlen(mps)+strlen(tmp->value)+2)*sizeof(char));
+      sprintf(mn,"%s.%s",mps,tmp->value);
+      pName = PyString_FromString(mn);	  
+      free(mn);
+      free(mps);
+    }
+    else{
+      pName = PyString_FromString(tmp->value);
+    }
+  }
+  else{
+    errorException (m, "Unable to parse serviceProvider please check your zcfg file.", "NoApplicableCode", NULL);
+    exit(-1);
+  }  
+  pModule = PyImport_Import(pName);    
+  int res=SERVICE_FAILED;
+  if (pModule != NULL) {
+    pFunc=PyObject_GetAttrString(pModule,s->name);
+    if (pFunc && PyCallable_Check(pFunc)){
+      PyObject *pValue;
+      PyDictObject* arg1=PyDict_FromMaps(m);
+      PyDictObject* arg2=PyDict_FromMaps(inputs);
+      PyDictObject* arg3=PyDict_FromMaps(outputs);
+      PyObject *pArgs=PyTuple_New(3);
+      if (!pArgs)
+	return -1;
+      PyTuple_SetItem(pArgs, 0, (PyObject *)arg1);
+      PyTuple_SetItem(pArgs, 1, (PyObject *)arg2);
+      PyTuple_SetItem(pArgs, 2, (PyObject *)arg3);
+      pValue = PyObject_CallObject(pFunc, pArgs);	  
+      if (pValue != NULL) {
+	res=PyInt_AsLong(pValue);
+	freeMaps(real_outputs);
+	free(*real_outputs);
+	freeMaps(main_conf);
+	free(*main_conf);
+	*main_conf=mapsFromPyDict(arg1);
+	*real_outputs=mapsFromPyDict(arg3);	
+#ifdef DEBUG
+	fprintf(stderr,"Result of call: %i\n", PyInt_AsLong(pValue));
+	dumpMaps(inputs);
+	dumpMaps(*real_outputs);
+#endif
+      }else{
+	PythonZooReport(m,tmp->value,0);
+	res=-1;
+      }
+    }
+    else{
+      char tmpS[1024];
+      sprintf(tmpS, "Cannot find the %s function in the %s file.\n", s->name, tmp->value);
+      errorException(m,tmpS,"NoApplicableCode",NULL);
+      res=-1;
+    }
+  } else{
+    PythonZooReport(m,tmp->value,1);
+    res=-1;
+  } 
+#if PY_MAJOR_VERSION < 3
+  PyGILState_Release(gstate);
+  PyEval_AcquireLock();
+#endif
+  PyThreadState_Swap(mainstate);
+  Py_Finalize();  
+  return res;
+}
+
+/**
+ * Report Python error which may occur on loading the Python module or at 
+ * runtime.
+ * 
+ * @param m the conf maps containing the main.cfg settings
+ * @param module the service name
+ * @param load 1 if the Python module was not loaded yet
+ */
+void PythonZooReport(maps* m,const char* module,int load){
+  PyObject *pName, *pModule, *pFunc;
+  PyObject *ptype, *pvalue, *ptraceback,*pValue,*pArgs;
+  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+#if PY_MAJOR_VERSION >= 3  
+  const
+#endif
+    char *pStrErrorMessage = PyString_AsString(pvalue);
+  const char *tmp0=_("Python module %s cannot be loaded. Message: %s\n");
+  
+  PyObject *trace=PyObject_Str(pvalue);
+  char *pbt=NULL;
+  if(PyString_Check(trace)){
+    pbt=(char*)malloc((8+strlen(PyString_AsString(trace)))*sizeof(char));
+    sprintf(pbt,"TRACE: %s",PyString_AsString(trace));
+  }
+  else
+    fprintf(stderr,"EMPTY TRACE ?");
+
+  trace=NULL;
+  
+  trace=PyObject_Str(ptype);
+  if(PyString_Check(trace)){
+    char *tpbt=zStrdup(pbt);
+    if(pbt!=NULL)
+      free(pbt);
+    pbt=(char*)malloc((1+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));
+    sprintf(pbt,"%s\n%s",tpbt,PyString_AsString(trace));
+    free(tpbt);
+  }
+  else
+    fprintf(stderr,"EMPTY TRACE ?");
+  
+  if(ptraceback!=NULL){
+    char *tpbt=zStrdup(pbt);
+    pName = PyString_FromString("traceback");
+    pModule = PyImport_Import(pName);
+    pArgs = PyTuple_New(1);
+    PyTuple_SetItem(pArgs, 0, ptraceback);
+    pFunc = PyObject_GetAttrString(pModule,"format_tb");
+    pValue = PyObject_CallObject(pFunc, pArgs);
+    trace=NULL;
+    trace=PyObject_Str(pValue);
+    if(PyString_Check(trace)){
+      if(pbt!=NULL)
+	free(pbt);
+      const char* format=_("%s\nUnable to run your python process properly. Please check the following messages : %s");
+      pbt=(char*)malloc((strlen(format)+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));
+      sprintf(pbt,format,tpbt,PyString_AsString(trace));
+    }
+    else{
+      if(pbt!=NULL)
+	free(pbt);
+      const char* format=_("%s \n Unable to run your python process properly. Unable to provide any further information.");
+      pbt=(char*)malloc((strlen(format)+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));
+      sprintf(pbt,format,tpbt);
+    }
+    free(tpbt);
+  }
+  if(load>0){
+    char *tmpS=(char*)malloc((strlen(tmp0)+strlen(module)+strlen(pbt)+1)*sizeof(char));
+    sprintf(tmpS,tmp0,module,pbt);
+    errorException(m,tmpS,"NoApplicableCode",NULL);
+    free(tmpS);
+  }else
+    errorException(m,pbt,"NoApplicableCode",NULL);
+  free(pbt);
+}
+
+/**
+ * Convert a maps to a Python dictionary
+ *
+ * @param t the maps to convert
+ * @return a new PyDictObject containing the converted maps
+ * @see PyDict_FromMap
+ * @warning make sure to free resources returned by this function
+ */
+PyDictObject* PyDict_FromMaps(maps* t){
+  PyObject* res=PyDict_New( );
+  maps* tmp=t;
+  while(tmp!=NULL){
+    PyObject* value=(PyObject*)PyDict_FromMap(tmp->content);
+    if(tmp->child!=NULL){
+      PyObject* cname=PyString_FromString("child");
+      PyObject* childs=(PyObject*)PyDict_FromMaps(tmp->child);
+      if(PyDict_SetItem(value,cname,childs)<0){
+	fprintf(stderr,"Unable to set map value ...");
+	return NULL;
+      } 
+      Py_DECREF(cname);
+    }
+    PyObject* name=PyString_FromString(tmp->name);
+    if(PyDict_SetItem(res,name,value)<0){
+      fprintf(stderr,"Unable to set map value ...");
+      return NULL;
+    }
+    Py_DECREF(name);
+    tmp=tmp->next;
+  }  
+  return (PyDictObject*) res;
+}
+
+/**
+ * Convert a map to a Python dictionary
+ *
+ * @param t the map to convert
+ * @return a new PyDictObject containing the converted maps
+ * @warning make sure to free resources returned by this function
+ */
+PyDictObject* PyDict_FromMap(map* t){
+  PyObject* res=PyDict_New( );
+  map* tmp=t;
+  int hasSize=0;
+  map* isArray=getMap(tmp,"isArray");
+  map* size=getMap(tmp,"size");
+  map* useFile=getMap(tmp,"use_file");
+  map* cacheFile=getMap(tmp,"cache_file");
+  map* tmap=getMapType(tmp);
+  while(tmp!=NULL){
+    PyObject* name=PyString_FromString(tmp->name);
+    if(strcasecmp(tmp->name,"value")==0) {
+      if(isArray!=NULL){
+	map* len=getMap(tmp,"length");
+	int cnt=atoi(len->value);
+	PyObject* value=PyList_New(cnt);
+	PyObject* mvalue=PyList_New(cnt);
+	PyObject* svalue=PyList_New(cnt);
+	PyObject* cvalue=PyList_New(cnt);
+
+	for(int i=0;i<cnt;i++){
+	  
+	  map* vMap=getMapArray(t,"value",i);
+	  map* uMap=getMapArray(t,"use_file",i);
+	  map* sMap=getMapArray(t,"size",i);
+	  map* cMap=getMapArray(t,"cache_file",i);
+
+	  if(vMap!=NULL){
+	    
+	    PyObject* lvalue;
+	    PyObject* lsvalue;
+	    PyObject* lcvalue;
+	    if(sMap==NULL || uMap!=NULL){
+	      lvalue=PyString_FromString(vMap->value);
+	    }
+	    else{    
+	      lvalue=PyString_FromStringAndSize(vMap->value,atoi(sMap->value));
+	    }
+	    if(sMap!=NULL){
+	      lsvalue=PyString_FromString(sMap->value);
+	      hasSize=1;
+	    }
+	    else
+	      lsvalue=Py_None;
+	    if(uMap!=NULL){
+	      lcvalue=PyString_FromString(cMap->value);;
+	    }else
+	      lcvalue=Py_None;
+
+	    if(PyList_SetItem(value,i,lvalue)<0){
+	      fprintf(stderr,"Unable to set key value pair...");
+	      return NULL;
+	    } 
+	    if(PyList_SetItem(svalue,i,lsvalue)<0){
+	      fprintf(stderr,"Unable to set key value pair...");
+	      return NULL;
+	    } 
+	    if(PyList_SetItem(cvalue,i,lcvalue)<0){
+	      fprintf(stderr,"Unable to set key value pair...");
+	      return NULL;
+	    }
+	  }
+	  
+	  PyObject* lmvalue;
+	  map* mMap=getMapArray(tmp,tmap->name,i);
+	  if(mMap!=NULL){
+	    lmvalue=PyString_FromString(mMap->value);
+	  }else
+	    lmvalue=Py_None;
+	  
+	  if(PyList_SetItem(mvalue,i,lmvalue)<0){
+	      fprintf(stderr,"Unable to set key value pair...");
+	      return NULL;
+	  } 
+	  
+	}
+
+	if(PyDict_SetItem(res,name,value)<0){
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+	if(PyDict_SetItem(res,PyString_FromString(tmap->name),mvalue)<0){
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+	if(PyDict_SetItem(res,PyString_FromString("cache_file"),cvalue)<0){
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+	if(hasSize>0)
+	  if(PyDict_SetItem(res,PyString_FromString("size"),svalue)<0){
+	    fprintf(stderr,"Unable to set key value pair...");
+	    return NULL;
+	  }
+      }
+      else if(size!=NULL && useFile==NULL){
+	PyObject* value=PyString_FromStringAndSize(tmp->value,atoi(size->value));
+	if(PyDict_SetItem(res,name,value)<0){
+	  Py_DECREF(value);
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+	Py_DECREF(value);
+      }
+      else{
+	PyObject* value=PyString_FromString(tmp->value);
+	if(PyDict_SetItem(res,name,value)<0){
+	  Py_DECREF(value);
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+	Py_DECREF(value);
+      }
+    }
+    else{
+      if(PyDict_GetItem(res,name)==NULL){
+	PyObject* value=PyString_FromString(tmp->value);
+	if(PyDict_SetItem(res,name,value)<0){
+	  Py_DECREF(value);
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+	Py_DECREF(value);
+      }
+    }
+    Py_DECREF(name);
+    tmp=tmp->next;
+  }
+  return (PyDictObject*) res;
+}
+
+/**
+ * Convert a Python dictionary to a maps 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new maps containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+maps* mapsFromPyDict(PyDictObject* t){
+  maps* res=NULL;
+  maps* cursor=NULL;
+  PyObject* list=PyDict_Keys((PyObject*)t);
+  int nb=PyList_Size(list);
+  int i;
+  PyObject* key;
+  PyObject* value;
+  for(i=0;i<nb;i++){
+#ifdef DEBUG
+    fprintf(stderr,">> parsing maps %d\n",i);
+#endif
+    key=PyList_GetItem(list,i);
+    value=PyDict_GetItem((PyObject*)t,key);
+#ifdef DEBUG
+    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
+	    PyString_AsString(key),PyString_AsString(value));
+#endif
+    cursor=createMaps(PyString_AsString(key));
+    cursor->content=mapFromPyDict((PyDictObject*)value);
+    PyObject* cname=PyString_FromString("child");
+    PyObject* childs=PyDict_GetItem((PyObject*)value,cname);
+    if(childs!=NULL)
+      cursor->child=mapsFromPyDict((PyDictObject*)childs);
+    Py_DECREF(cname);
+#ifdef DEBUG
+    dumpMap(cursor->content);
+#endif
+    cursor->next=NULL;
+    if(res==NULL)
+      res=dupMaps(&cursor);
+    else
+      addMapsToMaps(&res,cursor);
+    freeMap(&cursor->content);
+    free(cursor->content);
+    free(cursor);
+#ifdef DEBUG
+    dumpMaps(res);
+    fprintf(stderr,">> parsed maps %d\n",i);
+#endif
+  }
+  Py_DECREF(list);
+  return res;
+}
+
+/**
+ * Convert a Python dictionary to a maps 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new maps containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+maps* _mapsFromPyDict(PyDictObject* t){
+	
+	PyObject* list = PyDict_Keys((PyObject*)t); // new ref	
+	int nb = PyList_Size(list);	
+	
+	if (nb < 1) {
+		Py_DECREF(list);
+		return NULL;
+	}
+
+	maps* ptr = (maps*) malloc(MAPS_SIZE);
+	maps* res = ptr;	
+	
+	PyObject* key;
+	PyObject* value;
+	
+	for(int i = 0; i < nb; i++) {
+		
+		key = PyList_GetItem(list,i); // borrowed ref
+		value = PyDict_GetItem((PyObject*) t, key); // borrowed ref
+		
+		ptr->name = zStrdup(PyString_AsString(key));
+		ptr->content = mapFromPyDict((PyDictObject*) value);
+		
+		ptr->next = i < nb - 1 ? (maps*) malloc(MAPS_SIZE) : NULL;
+		ptr = ptr->next;
+	}
+	Py_DECREF(list);
+
+	return res;
+} // mapsFromPyDict
+
+/**
+ * Convert a Python dictionary to a map 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new map containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+map* mapFromPyDict(PyDictObject* t){
+  map* res=NULL;
+  PyObject* list=PyDict_Keys((PyObject*)t);
+  int nb=PyList_Size(list);
+  int i;
+  PyObject* key;
+  PyObject* value;
+  for(i=0;i<nb;i++){
+    key=PyList_GetItem(list,i);
+    value=PyDict_GetItem((PyObject*)t,key);
+#ifdef DEBUG
+    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
+	    PyString_AsString(key),PyString_AsString(value));
+#endif
+    if(strncmp(PyString_AsString(key),"child",5)!=0){
+      if(strncmp(PyString_AsString(key),"value",5)==0){
+#if PY_MAJOR_VERSION >= 3  
+	const
+#endif
+	  char *buffer=NULL;
+	Py_ssize_t size;
+#if PY_MAJOR_VERSION >= 3
+	if(PyBytes_Check(value)){
+	  size=PyBytes_Size(value);
+	  buffer=PyBytes_AsString(value);
+	}
+	else
+	  if(PyUnicode_Check(value) && PyUnicode_READY(value) == 0){
+	    buffer=PyUnicode_AsUTF8AndSize(value,&size);
+	  }
+	  else{
+#ifdef DEBUG
+	    fprintf(stderr,"Unsupported return value.");
+#endif
+	    return NULL;
+	  }
+#else
+	PyString_AsStringAndSize(value,&buffer,&size);
+#endif      
+	res = addToMapWithSize(res,PyString_AsString(key),buffer,size);
+      }else{
+#if PY_MAJOR_VERSION >= 3  
+	const
+#endif
+	  char* lkey=PyString_AsString(key);
+#if PY_MAJOR_VERSION >= 3  
+	const
+#endif
+	  char* lvalue=PyString_AsString(value);
+	if(res!=NULL){
+	  if(PyString_Size(value)>0)
+	    addToMap(res,lkey,lvalue);
+	}
+	else{
+	  if(PyString_Size(value)>0)
+	    res=createMap(lkey,lvalue);
+	}
+      }
+    }
+  }
+  Py_DECREF(list);
+  return res;
+}
+
+/**
+ * Convert a Python dictionary to a map 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new map containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+map* _mapFromPyDict(PyDictObject* t) {
+	
+  PyObject* list = PyDict_Keys((PyObject*) t); // new ref
+  int nb = PyList_Size(list);
+	
+  if (nb < 1) {
+    Py_DECREF(list);
+    return NULL;
+  }	
+	
+  map* ptr = (map*) malloc(MAP_SIZE);
+  map* res = ptr;
+	
+  PyObject* key;
+  PyObject* value;
+#if PY_MAJOR_VERSION >= 3  
+  const
+#endif
+    char *buffer = NULL;
+  Py_ssize_t size;
+  for(int i = 0; i < nb; i++) {
+		
+    key = PyList_GetItem(list, i); // borrowed ref
+    value = PyDict_GetItem((PyObject*) t, key); // borrowed ref		
+				
+    ptr->name = zStrdup(PyString_AsString(key));		
+    map* msize = NULL;
+		
+#if PY_MAJOR_VERSION >= 3
+    if (PyBytes_Check(value)) {
+      // value is byte array
+      size = PyBytes_Size(value);				
+      buffer = PyBytes_AsString(value); // pointer to internal buffer
+      char sz[32];
+      sprintf(sz, "%d", (int) size);	
+      msize = createMap("size", sz);			
+    }
+    else if (PyUnicode_Check(value) && PyUnicode_READY(value) == 0) {
+      // value is string object		
+      buffer = PyUnicode_AsUTF8AndSize(value, &size);
+      size++;
+    }
+    else {
+      printf("Type not recognized\n");
+      // error handling
+      // ...
+    }
+#else	
+    PyString_AsStringAndSize(value, &buffer, &size);
+    size++;
+    // to do: handle byte arrays
+#endif
+		
+    ptr->value = (char*) malloc(size); // check for NULL pointer
+    memmove(ptr->value, buffer, size);
+			
+    if (msize != NULL) {
+      ptr->next = msize;
+      ptr = ptr->next;
+    }						
+		
+    ptr->next = i < nb - 1 ? (map*) malloc(MAP_SIZE) : NULL;
+    ptr = ptr->next;
+  }	
+  Py_DECREF(list);
+			
+  return res;
+} // mapFromPyDict
+
+/**
+ * Use the ZOO-Services messages translation function from the Python
+ * environment
+ *
+ * @param self the Python object on which we can run the method
+ * @param args the Python arguments given from the Python environment
+ * @return a new Python string containing the translated value
+ * @see _ss
+ */
+PyObject*
+PythonTranslate(PyObject* self, PyObject* args)
+{
+  char *str;
+  if (!PyArg_ParseTuple(args, "s", &str)){
+#ifdef DEBUG
+    fprintf(stderr,"Incorrect arguments to update status function");
+#endif
+    return NULL;
+  }
+  return PyString_FromString(_ss(str));
+}
+
+/**
+ * Update the ongoing status of a running service from the Python environment
+ *
+ * @param self the Python object on which we can run the method
+ * @param args the Python arguments given from the Python environment
+ * @return None to the Python environment
+ * @see _updateStatus
+ */
+PyObject*
+PythonUpdateStatus(PyObject* self, PyObject* args)
+{
+  maps* conf;
+  PyObject* confdict;
+  int istatus;
+  char* status=NULL;
+  if (!PyArg_ParseTuple(args, "O!i", &PyDict_Type, &confdict, &istatus)){
+#ifdef DEBUG
+    fprintf(stderr,"Incorrect arguments to update status function");
+#endif
+    Py_RETURN_NONE;
+  }
+  if (istatus < 0 || istatus > 100){
+     PyErr_SetString(ZooError, "Status must be a percentage.");
+     Py_RETURN_NONE;
+  }else{
+     char tmpStatus[4];
+     snprintf(tmpStatus, 4, "%i", istatus);
+     status = zStrdup(tmpStatus);
+  }
+  // create a local copy and update the lenv map
+  conf = mapsFromPyDict((PyDictObject*)confdict);
+  if(status!=NULL){
+    setMapInMaps(conf,"lenv","status",status);
+    free(status);
+  }
+  else
+    setMapInMaps(conf,"lenv","status","15");
+  _updateStatus(conf);
+  freeMaps(&conf);
+  free(conf);
+  Py_RETURN_NONE;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_python.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_python.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_python.h	(revision 942)
@@ -0,0 +1,51 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2019 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_PYTHON_H
+#define ZOO_SERVICE_INTERNAL_PYTHON_H 1
+
+#pragma once 
+
+#include <Python.h>
+#include "service_internal.h"
+#include "response_print.h"
+#ifdef WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+
+PyDictObject* PyDict_FromMaps(maps* t);
+PyDictObject* PyDict_FromMap(map* t);
+
+maps* mapsFromPyDict(PyDictObject* t);
+map* mapFromPyDict(PyDictObject* t);
+
+int zoo_python_support(maps**,map*,service*,maps**,maps**);
+
+void PythonZooReport(maps*,const char*,int);
+
+PyObject* PythonTranslate(PyObject*, PyObject*);
+PyObject* PythonUpdateStatus(PyObject*, PyObject*);
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_r.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_r.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_r.c	(revision 942)
@@ -0,0 +1,394 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2018 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_r.h"
+
+void jump_to_toplevel(void){
+  fprintf(stderr,"Error occured\n");
+  fprintf(stderr,"%s %d \n",__FILE__,__LINE__);
+  fflush(stderr);
+  //resetStack(1);
+  fprintf(stderr,"%s %d \n",__FILE__,__LINE__);
+  fflush(stderr);
+}
+
+void init_zoo(SEXP conf,SEXP outputs){
+  const char* names[]={
+    "SERVICE_SUCCEEDEED",
+    "SERVICE_FAILED",
+    "conf",
+    "outputs",
+    ""
+  };
+  SEXP res = PROTECT(mkNamed(VECSXP, names));
+  SET_VECTOR_ELT(res, 0, Rf_ScalarInteger(3));
+  SET_VECTOR_ELT(res, 1, Rf_ScalarInteger(4));
+  SET_VECTOR_ELT(res, 2, conf);
+  SET_VECTOR_ELT(res, 3, outputs);
+  defineVar(install("zoo"),res, R_GlobalEnv);
+
+  static const R_CallMethodDef callMethods[]  = {
+    {"ZOOTranslate", (DL_FUNC) &RTranslate, 1},
+    {"ZOOUpdateStatus", (DL_FUNC) &RUpdateStatus, 2},
+    {NULL, NULL, 0}
+  };
+  
+  static R_NativePrimitiveArgType RTranslate_t[] = {
+    STRSXP
+  };
+  static R_NativePrimitiveArgType RUpdateStatus_t[] = {
+    VECSXP,STRSXP
+  };
+  
+  static const R_CMethodDef cMethods[] = {
+   {"ZOOTranslate", (DL_FUNC) &RTranslate, 1, RTranslate_t},
+   {"ZOOUpdateStatus", (DL_FUNC) &RUpdateStatus, 2, RUpdateStatus_t},
+   {NULL, NULL, 0, NULL}
+  };
+  
+  DllInfo *info = R_getEmbeddingDllInfo();
+  R_registerRoutines(info, cMethods, callMethods, NULL, NULL);
+}
+
+/**
+ * Load a R script then run the function corresponding to the service
+ * by passing the conf, inputs and outputs parameters by reference. 
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ */
+int zoo_r_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  SEXP pName;
+  int result=0;
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=tmp0->value;
+  map* tmp=NULL;
+  int hasToClean=0;
+  char *r_path, *rpath;
+  map* cwdMap=getMapFromMaps(*main_conf,"main","servicePath");
+  int r_argc = 3;
+  char *r_argv[] = { "R", "--no-save", "--silent" };
+  Rf_initEmbeddedR(r_argc, r_argv);
+  if(cwdMap!=NULL)
+    r_path=cwdMap->value;
+  else{
+    if(tmp0!=NULL)
+      r_path=tmp0->value;
+    else
+      r_path=(char*)".";
+  }
+
+  tmp=getMap(s->content,"serviceProvider");
+  map* mp=getMap(request,"metapath");
+  if(tmp!=NULL){
+    if(mp!=NULL && strlen(mp->value)>0){
+      char *mn=(char*)malloc((strlen(mp->value)+strlen(tmp->value)+2)*sizeof(char));
+      sprintf(mn,"%s/%s",mp->value,tmp->value);
+      pName = mkString(mn);
+      free(mn);
+    }
+    else{
+      char *tmpStr=(char*)malloc((strlen(r_path)+strlen(tmp->value)+2)*sizeof(char));
+      sprintf(tmpStr,"%s/%s",r_path,tmp->value);
+      pName = mkString(tmpStr);
+      free(tmpStr);
+    }
+  }
+  else{
+    errorException (m, "Unable to parse serviceProvider please check your zcfg file.", "NoApplicableCode", NULL);
+    return -1;
+  }
+  SEXP e;
+  int errorOccurred;
+  PROTECT(e = lang2(install("source"), pName));
+  R_tryEval(e, R_GlobalEnv, &errorOccurred);
+  UNPROTECT(1);
+  if (errorOccurred){
+    setMapInMaps(*main_conf,"lenv","message",_("Unable to load your R file"));
+    return SERVICE_FAILED;
+  }else{
+    result=SERVICE_FAILED;
+    {
+      SEXP pValue;
+      SEXP  arg1=RList_FromMaps(m);
+      SEXP  arg2=RList_FromMaps(*real_inputs);
+      SEXP  arg3=RList_FromMaps(*real_outputs);
+      SEXP r_call;
+      init_zoo(arg1,arg3);
+      PROTECT(r_call = lang4(install(s->name), arg1,arg2,arg3));
+      int errorOccurred;
+      
+      SEXP ret = R_tryEval(r_call, R_GlobalEnv, &errorOccurred);
+      if (!errorOccurred) {
+	int *val = INTEGER(ret);
+        for (int i = 0; i < LENGTH(ret); i++)
+	  if(i==0){
+	      result=val[i];
+	      SEXP zooEnv = findVar(install("zoo"), R_GlobalEnv);
+	      if(zooEnv!=NULL){
+		SEXP names = Rf_getAttrib(zooEnv, R_NamesSymbol);
+		int nbKeys=nrows(names);
+		int i;
+		for(i=0;i<nbKeys;i++){
+		  if(i==2){
+		    freeMaps(main_conf);
+		    free(*main_conf);
+		    SEXP confList=VECTOR_ELT(zooEnv,i);
+		    *main_conf=mapsFromRList(confList);
+		  }
+		  if(i==3){
+		    freeMaps(real_outputs);
+		    free(*real_outputs);
+		    SEXP outList=VECTOR_ELT(zooEnv,i);
+		    *real_outputs=mapsFromRList(outList);
+		  }
+		}
+	      }
+	      return result;
+	    }
+      }else{
+	const char* tmpStr=R_curErrorBuf();
+	setMapInMaps(*main_conf,"lenv","message",tmpStr);
+	char* finalStr=(char*)malloc((strlen(tmpStr)+strlen(_("Unable to run your R service: "))+2)*sizeof(char));
+	sprintf(finalStr,"%s %s",_("Unable to run your R service: "),tmpStr);
+	errorException(*main_conf,finalStr,"NoApplicableCode",NULL);
+	free(finalStr);
+	result=-1;
+      }
+    }
+  }
+  Rf_endEmbeddedR(0);
+  return result;
+}
+
+char** listMapsKeys(maps* m){
+  char** res=NULL;
+  maps* tmp=m;
+  int i=0;
+  while(tmp!=NULL){
+    if(i==0)
+      res=(char**)malloc(2*sizeof(char*));
+    else
+      res=(char**)realloc(res,(i+2)*sizeof(char*));
+    res[i]=zStrdup(tmp->name);
+    res[i+1]="";
+    i++;
+    tmp=tmp->next;
+  }
+  return res;
+}
+
+char** listMapKeys(map* m){
+  char** res=NULL;
+  map* tmp=m;
+  int i=0;
+  while(tmp!=NULL){
+    if(i==0)
+      res=(char**)malloc(2*sizeof(char*));
+    else
+      res=(char**)realloc(res,(i+2)*sizeof(char*));
+    res[i]=zStrdup(tmp->name);
+    res[i+1]="";
+    i++;
+    tmp=tmp->next;
+  }
+  return res;
+}
+
+/**
+ * Convert a maps to a R List
+ *
+ * @param t the maps to convert
+ * @return a new SEXP containing the converted maps
+ * @see RList_FromMap
+ * @warning make sure to free resources returned by this function
+ */
+SEXP RList_FromMaps(maps* t){
+  maps* tmp=t;
+  char** keys=listMapsKeys(t);
+  SEXP res = PROTECT(mkNamed(VECSXP,(const char**) keys));
+  free(keys);
+  int cnt=0;
+  while(tmp!=NULL){
+    SEXP input = RList_FromMap(tmp->content);
+    SET_VECTOR_ELT(res,cnt,input);
+    cnt++;
+    tmp=tmp->next;
+  } 
+  UNPROTECT(1);
+  return res;
+}
+
+/**
+ * Convert a map to a R List
+ *
+ * @param t the map to convert
+ * @return a new SEXP containing the converted maps
+ * @warning make sure to free resources returned by this function
+ */
+SEXP RList_FromMap(map* t){
+  map* tmp=t;
+  int hasSize=0;
+  char** keys=listMapKeys(t);
+  SEXP res = PROTECT(mkNamed(VECSXP, (const char**)keys));
+  free(keys);
+  int cnt=0;
+  while(tmp!=NULL){
+    SEXP value=mkString(tmp->value);
+    SET_VECTOR_ELT(res,cnt,value);
+    cnt++;
+    tmp=tmp->next;
+  }
+  UNPROTECT(1);
+  return res;
+}
+
+/**
+ * Convert a R List to a maps 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new maps containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+maps* mapsFromRList(SEXP t){
+  maps* res=NULL;
+  maps* cursor=NULL;
+  SEXP names = Rf_getAttrib(t, R_NamesSymbol);
+  int nbKeys=nrows(names);
+  int i;
+  for(i=0;i<nbKeys;i++){
+    SEXP key=STRING_ELT(names,i);
+    SEXP value=VECTOR_ELT(t,i);
+    cursor=createMaps(R_CHAR(key));
+    cursor->content=mapFromRList(value);
+    cursor->next=NULL;
+    if(res==NULL)
+      res=dupMaps(&cursor);
+    else
+      addMapsToMaps(&res,cursor);
+    freeMap(&cursor->content);
+    free(cursor->content);
+    free(cursor);
+  }
+  return res;
+}
+
+/**
+ * Convert a R List to a map 
+ *
+ * @param t the PyDictObject to convert
+ * @return a new map containing the converted PyDictObject
+ * @warning make sure to free resources returned by this function
+ */
+map* mapFromRList(SEXP t){
+  map* res=NULL;
+  SEXP names = Rf_getAttrib(t, R_NamesSymbol);
+  int nbKeys=nrows(names);
+  int i;
+  for(i=0;i<nbKeys;i++){
+    SEXP key=STRING_ELT(names,i);
+    SEXP value=VECTOR_ELT(t,i);
+    if(strncmp(R_CHAR(key),"child",5)!=0){
+      {
+	const char* lkey=R_CHAR(key);
+	const char* lvalue=CHAR(STRING_ELT(value,0));
+	if(res!=NULL){
+	  addToMap(res,lkey,lvalue);
+	}
+	else{
+	  res=createMap(lkey,lvalue);
+	}
+      }
+    }
+  }
+  return res;
+}
+
+/**
+ * Use the ZOO-Services messages translation function from the R
+ * environment
+ *
+ * @param str the R string passed from the R environment
+ * @return a new R string containing the translated value
+ * @see _ss
+ */
+SEXP
+RTranslate(SEXP str)
+{
+  if (!isString(str) || !TYPEOF(STRING_ELT( str, 0 )) == CHARSXP){
+#ifdef DEBUG
+    fprintf(stderr,"Incorrect arguments to update status function");
+#endif
+    return R_NilValue;
+  }
+  const char* tmpStr=CHAR(STRING_ELT(str,0));
+  return mkString(_ss(tmpStr));
+}
+
+/**
+ * Update the ongoing status of a running service from the R environment
+ *
+ * @param confdict the R arguments passed from the R environment
+ * @param status the R arguments passed from the R environment
+ * @return Nil to the Python environment
+ * @see _updateStatus
+ */
+SEXP
+RUpdateStatus(SEXP confdict,SEXP status)
+{
+  maps* conf;
+  int istatus;
+  char* cstatus=NULL;
+  if (!isInteger(status) && !isReal(status)){
+#ifdef DEBUG
+    fprintf(stderr,"Incorrect arguments to update status function");
+#endif
+    return R_NilValue;
+  }
+  if(isInteger(status))
+    istatus=asInteger(status);
+  else
+    istatus=asReal(status);
+  if (istatus < 0 || istatus > 100){
+    return R_NilValue;
+  }
+  // create a local copy and update the lenv map
+  conf = mapsFromRList(confdict);
+  if(status!=NULL){
+    maps* tmpMaps=getMaps(conf,"lenv");
+    addIntToMap(tmpMaps->content,"status",istatus);
+  }
+  else
+    setMapInMaps(conf,"lenv","status","15");
+  _updateStatus(conf);
+  freeMaps(&conf);
+  free(conf);
+  return R_NilValue;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_r.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_r.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_r.h	(revision 942)
@@ -0,0 +1,47 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_R_H
+#define ZOO_SERVICE_INTERNAL_R_H 1
+
+#pragma once 
+
+#include <Rinternals.h>
+#include <Rembedded.h>
+#include "service_internal.h"
+#include "response_print.h"
+#include "cgic.h"
+
+SEXP RList_FromMaps(maps* t);
+SEXP RList_FromMap(map* t);
+
+maps* mapsFromRList(SEXP t);
+map* mapFromRList(SEXP t);
+
+int zoo_r_support(maps**,map*,service*,maps**,maps**);
+
+SEXP RTranslate(SEXP);
+SEXP RUpdateStatus(SEXP,SEXP);
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ruby.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ruby.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ruby.c	(revision 942)
@@ -0,0 +1,498 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2014 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_internal_ruby.h"
+
+#if RUBY_API_VERSION_MAJOR >= 2 || RUBY_API_VERSION_MINOR == 9 
+int argc=0;
+char **argv=NULL;
+#endif
+
+/**
+ * Load a Ruby file then run the function corresponding to the service by
+ * passing the conf, inputs and outputs parameters by refernce as Ruby Hash.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param real_inputs the maps containing the inputs
+ * @param real_outputs the maps containing the outputs
+ * @return SERVICE_SUCCEEDED or SERVICE_FAILED if the service run, -1 
+ *  if the service failed to load or throw error at runtime.
+ */
+int zoo_ruby_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+#if RUBY_API_VERSION_MAJOR >= 2 || RUBY_API_VERSION_MINOR == 9
+  ruby_sysinit(&argc,&argv);
+  RUBY_INIT_STACK;
+#endif
+  ruby_init();
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
+  char *ntmp=tmp0->value;
+  map* tmp=NULL;
+  ruby_init_loadpath();
+  ruby_script("ZOO_EMBEDDED_ENV");
+  
+  VALUE klass=rb_define_module("Zoo");
+  rb_define_const(klass,"SERVICE_SUCCEEDED",INT2FIX(3));
+  rb_define_const(klass,"SERVICE_FAILED",INT2FIX(4));
+  typedef VALUE (*HOOK)(...);
+  rb_define_module_function(klass,"Translate",reinterpret_cast<HOOK>(RubyTranslate),-1);
+  rb_define_module_function(klass,"UpdateStatus",reinterpret_cast<HOOK>(RubyUpdateStatus),-1);
+
+  int error = 0;
+		
+  ID rFunc=Qnil;
+  tmp=getMap(s->content,"serviceProvider");
+  if(tmp!=NULL){
+#if RUBY_VERSION_MINOR == 8
+    const char* script = ruby_sourcefile = rb_source_filename(tmp->value);
+    rb_protect(LoadWrap, reinterpret_cast<VALUE>(script), &error);
+#else
+    rb_load_protect(rb_str_new2(tmp->value), 0, &error);
+#endif
+    if(error) {
+      ruby_trace_error(m);
+      return -1;
+    }
+#if RUBY_VERSION_MINOR == 8
+    ruby_exec();
+#else
+    ruby_exec_node(NULL);
+#endif
+  }
+  else{
+    map* err=createMap("text","Unable to parse serviceProvider please check your zcfg file.");
+    addToMap(err,"code","NoApplicableCode");
+    printExceptionReportResponse(m,err);
+    return -1;
+  }
+  int res=SERVICE_FAILED;
+  rFunc=rb_intern(s->name);
+  if(rFunc!=Qnil){
+    VALUE arg1=RubyHash_FromMaps(m);
+    VALUE arg2=RubyHash_FromMaps(inputs);
+    VALUE arg3=RubyHash_FromMaps(outputs);
+    VALUE rArgs[3]={arg1,arg2,arg3};
+    if (!rArgs)
+      return -1;
+    struct my_callback data;
+    data.obj=Qnil;
+    data.method_id=rFunc;
+    data.nargs=3;
+    data.args[0]=rArgs[0];
+    data.args[1]=rArgs[1];
+    data.args[2]=rArgs[2];
+    typedef VALUE (*HOOK)(VALUE);
+    VALUE tres=rb_protect(reinterpret_cast<HOOK>(FunCallWrap),(VALUE)(&data),&error);
+    if (TYPE(tres) == T_FIXNUM) {
+      res=FIX2INT(tres);
+      freeMaps(real_outputs);
+      free(*real_outputs);
+      freeMaps(main_conf);
+      free(*main_conf);
+      *main_conf=mapsFromRubyHash(arg1);
+      *real_outputs=mapsFromRubyHash(arg3);
+#ifdef DEBUG
+      dumpMaps(*main_conf);
+      dumpMaps(*real_outputs);
+#endif
+    }else{
+      ruby_trace_error(m);
+      res=-1;
+    }
+  }
+  else{
+    char tmpS[1024];
+    sprintf(tmpS, "Cannot find the %s function in the %s file.\n", s->name, tmp->value);
+    map* tmps=createMap("text",tmpS);
+    printExceptionReportResponse(m,tmps);
+    res=-1;
+  }
+  ruby_finalize();
+  return res;
+}
+
+/**
+ * Load a ruby file
+ *
+ * @arg the file to load
+ * @return Qnil
+ */
+VALUE LoadWrap(VALUE arg) {
+  const char *filename = reinterpret_cast<const char*>(arg);
+  rb_load_file(filename);
+  return Qnil;
+}
+
+/**
+ * Call a ruby function with parameters
+ *
+ * @arg the callback structure
+ * @return the value returned the called ruby function
+ */
+VALUE FunCallWrap(VALUE rdata) {
+  struct my_callback* data = (struct my_callback*) rdata;
+  return rb_funcall2(data->obj,data->method_id,data->nargs,data->args);
+}
+
+/**
+ * Print the Ruby Stack Trace in an ows:ExceptionReport XML Document
+ *
+ * @param m the conf maps containing the main.cfg settings
+ * @see printExceptionReportResponse
+ */
+void ruby_trace_error(maps* m){
+#if RUBY_VERSION_MINOR == 8
+  VALUE lasterr = rb_gv_get("$!");
+#else
+  VALUE lasterr = rb_errinfo();
+  VALUE ruby_errinfo = lasterr;
+#endif
+  VALUE message = rb_obj_as_string(lasterr);
+  VALUE lklass = rb_class_path(CLASS_OF(lasterr));
+#if RUBY_VERSION_MINOR == 8
+  char *trace=(char*)malloc((strlen(RSTRING(lklass)->ptr)+strlen(RSTRING(message)->ptr)+3)*sizeof(char));
+  sprintf(trace,"%s: %s",RSTRING_PTR(lklass),RSTRING_PTR(message));
+#else
+  char *trace=(char*)malloc((strlen(RSTRING_PTR(lklass))+strlen(RSTRING_PTR(message))+3)*sizeof(char));
+  sprintf(trace,"%s: %s",RSTRING_PTR(lklass),RSTRING_PTR(message));
+#endif
+  if(!NIL_P(ruby_errinfo))
+    {
+      VALUE ary = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0);
+      int c;
+      for (c=0; c<RARRAY_LEN(ary); c++) {
+	int len=strlen(trace);
+	char *tmp0=zStrdup(trace);
+#if RUBY_VERSION_MINOR == 8
+	trace=(char *) realloc(trace,(len+strlen(RSTRING(RARRAY(ary)->ptr[c])->ptr)+2)*sizeof(char));
+	sprintf(trace,"%s\n%s",tmp0,RSTRING(RARRAY(ary)->ptr[c])->ptr);
+#else
+	trace=(char *) realloc(trace,(len+strlen(RSTRING_PTR(RARRAY_PTR(ary)[c]))+2)*sizeof(char));
+	sprintf(trace,"%s\n%s",tmp0,RSTRING_PTR(RARRAY_PTR(ary)[c]));
+#endif
+	free(tmp0);
+      }
+    }
+  map* err=createMap("text",trace);
+  addToMap(err,"code","NoApplicableCode");
+  printExceptionReportResponse(m,err);
+}
+
+/**
+ * Convert a maps to a Ruby Hash
+ *
+ * @param t the maps to convert
+ * @return a new Ruby Hash
+ */
+VALUE RubyHash_FromMaps(maps* t){
+  VALUE res=rb_hash_new();
+  maps* tmp=t;
+  while(tmp!=NULL){
+    VALUE value=RubyHash_FromMap(tmp->content);
+    VALUE name=rb_str_new2(tmp->name);
+    rb_hash_aset(res,name,value);
+    tmp=tmp->next;
+  }  
+  return res;
+}
+
+/**
+ * Push the key on the array
+ *
+ * @param key the key to push
+ * @param value not used
+ * @param ary the Array
+ * @return ST_CONTINUE
+ */
+int
+keys_i(VALUE key,VALUE value,VALUE ary)
+{
+  if (key == Qundef) return ST_CONTINUE;
+  rb_ary_push(ary, key);
+  return ST_CONTINUE;
+}
+
+/**
+ * Return the size of a Ruby Hash
+ * 
+ * @param hash the input Hash
+ */
+VALUE
+rb_hash_size(VALUE hash)
+{
+    return INT2FIX(RHASH_TBL(hash)->num_entries);
+}
+
+/**
+ * Convert a map to a Ruby Hash
+ *
+ * @param t the map to convert
+ * @return a new Ruby Hash
+ */
+VALUE RubyHash_FromMap(map* t){
+  VALUE res=rb_hash_new( );
+  map* tmp=t;
+  int hasSize=0;
+  map* isArray=getMap(tmp,"isArray");
+  map* useFile=getMap(tmp,"use_file");
+  map* size=getMap(tmp,"size");
+  map* tmap=getMapType(tmp);
+  while(tmp!=NULL){
+    VALUE name= rb_str_new2(tmp->name);
+    if(strcasecmp(tmp->name,"value")==0) {
+      if(isArray!=NULL){
+	map* len=getMap(tmp,"length");
+	int cnt=atoi(len->value);
+	VALUE value=rb_ary_new2(cnt);
+	VALUE mvalue=rb_ary_new2(cnt);
+	VALUE svalue=rb_ary_new2(cnt);
+	VALUE cvalue=rb_ary_new2(cnt);
+
+	for(int i=0;i<cnt;i++){
+	  
+	  map* vMap=getMapArray(tmp,"value",i);	    
+	  map* sMap=getMapArray(tmp,"size",i);
+	  map* uMap=getMapArray(tmp,"use_file",i);
+	  map* cMap=getMapArray(tmp,"cache_file",i);
+
+	  if(vMap!=NULL){
+	    
+	    VALUE lvalue;
+	    VALUE lsvalue;
+	    VALUE lcvalue;
+	    if(sMap==NULL || uMap==NULL){
+	      lvalue=rb_str_new2(vMap->value);
+	      if(sMap==NULL)
+		lsvalue=Qnil;
+	      else
+		lsvalue=rb_str_new2(sMap->value);
+	    }
+	    else{
+	      lvalue=rb_str_new(vMap->value,atoi(sMap->value));
+	      lsvalue=rb_str_new2(sMap->value);
+	      hasSize=1;
+	    }
+	    if(uMap!=NULL)
+	      lcvalue=rb_str_new2(cMap->value);
+	    else
+	      lcvalue=Qnil;
+
+	    rb_ary_push(value,lvalue);
+	    rb_ary_push(svalue,lsvalue);
+	    rb_ary_push(cvalue,lcvalue);
+	  }
+	  
+	  map* mMap=getMapArray(tmp,tmap->name,i);
+
+	  VALUE lmvalue;
+	  if(mMap!=NULL){
+	    lmvalue=rb_str_new2(mMap->value);
+	  }else
+	    lmvalue=Qnil;
+	  rb_ary_push(mvalue,lmvalue);
+	  
+	}
+
+	rb_hash_aset(res, name, mvalue);
+	rb_hash_aset(res, rb_str_new2(tmap->name), mvalue);
+	VALUE lname0=rb_str_new2("cache_size");
+	rb_hash_aset(res, lname0, value);
+      
+	if(hasSize>0){
+	  VALUE lname=rb_str_new2("size");
+	  rb_hash_aset(res, lname, value);
+	}
+      }
+      else if(size!=NULL){
+	VALUE value=rb_str_new(tmp->value,atoi(size->value));
+	rb_hash_aset(res, name, value);
+      }
+      else{
+	VALUE value=rb_str_new2(tmp->value);
+	rb_hash_aset(res, name, value);
+      }
+    }
+    else{
+      VALUE value=rb_str_new2(tmp->value);
+      rb_hash_aset(res, name, value);
+    }
+    tmp=tmp->next;
+  }
+  return res;
+}
+
+/**
+ * Convert a Ruby Hash to a maps
+ *
+ * @param t the Ruby Hash to convert
+ * @return a new maps
+ */
+maps* mapsFromRubyHash(VALUE t){
+  maps* res=NULL;
+  maps* cursor=res;
+  VALUE list;
+  list = rb_ary_new();
+  typedef int (*HOOK)(...);
+  rb_hash_foreach(t, reinterpret_cast<HOOK>(keys_i), list);
+  int nb=rb_hash_size(t);
+  int i;
+  for(i=0;i<FIX2INT(nb);i++){
+    VALUE key=rb_ary_pop(list);
+    VALUE value=rb_hash_aref(t,key);
+#ifdef DEBUG
+    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
+	    StringValueCStr(key),StringValueCStr(value));
+#endif
+    cursor=createMaps(StringValueCStr(key));
+    cursor->content=mapFromRubyHash(value);
+    if(res==NULL)
+      res=dupMaps(&cursor);
+    else
+      addMapsToMaps(&res,cursor);
+    freeMaps(&cursor);
+    free(cursor);
+  }
+  return res;
+}
+
+/**
+ * Convert a Ruby Hash to a map
+ *
+ * @param t the Ruby Hash to convert
+ * @return a new map
+ */
+map* mapFromRubyHash(VALUE t){
+  map* res=NULL;
+  VALUE list;
+  list = rb_ary_new();
+  typedef int (*HOOK)(...);
+  rb_hash_foreach(t,reinterpret_cast<HOOK>(keys_i), list);
+  int nb=RHASH_TBL(t)->num_entries;
+  int i;
+  for(i=0;i<nb;i++){
+    VALUE key=rb_ary_pop(list);
+    VALUE value=rb_hash_aref(t,key);
+#ifdef DEBUG
+    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
+	    StringValueCStr(key),StringValueCStr(value));
+#endif
+    if(strcmp(StringValueCStr(key),"value")==0){
+      char *buffer=NULL;
+      int size=RSTRING_LEN(value);
+      buffer=StringValueCStr(value);
+      if(res!=NULL){
+	addToMap(res,StringValueCStr(key),"");
+      }else{
+	res=createMap(StringValueCStr(key),"");
+      }
+      map* tmpR=getMap(res,"value");
+      free(tmpR->value);
+      tmpR->value=(char*)malloc((size+1)*sizeof(char));
+      memmove(tmpR->value,buffer,size*sizeof(char));
+      tmpR->value[size]=0;
+      char sin[1024];
+      sprintf(sin,"%d",size);
+      addToMap(res,"size",sin);
+    }else{
+      if(res!=NULL){
+	addToMap(res,StringValueCStr(key),StringValueCStr(value));
+      }
+      else{
+	res=
+	  createMap(StringValueCStr(key),StringValueCStr(value));
+      }
+    }
+  }
+  return res;
+}
+
+/**
+ * Use the ZOO-Services messages translation function from the Ruby
+ * environment (ZOO-API)
+ *
+ * @param argc the number of parameters
+ * @param argv the parameter values given from the Ruby environment
+ * @param obj the Ruby object on which we run the method
+ * @return a new Ruby string containing the translated value
+ * @see _ss
+ */
+VALUE
+RubyTranslate(int argc, VALUE *argv, VALUE obj)
+{
+  return rb_str_new2(_ss(StringValueCStr(argv[0])));
+}
+
+/**
+ * Update the ongoing status of a running service from the Ruby environment
+ * (ZOO-API)
+ *
+ * @param argc the number of parameters
+ * @param argv the parameter values given from the Ruby environment
+ * @param obj the Ruby object on which we run the method
+ * @return a new Ruby string containing the translated value
+ * @see _updateStatus
+ */
+VALUE
+RubyUpdateStatus(int argc, VALUE *argv, VALUE obj)
+{
+  maps* conf;
+  VALUE confdict=argv[0];
+  int istatus=argv[1];
+  char* status;
+  if (istatus < 0 || istatus > 100){
+    fprintf(stderr,"Status must be a percentage.");
+    return Qnil;
+  }else{
+     char tmpStatus[4];
+     snprintf(tmpStatus, 4, "%i", istatus);
+     status = zStrdup(tmpStatus);
+  }
+  /* now update the map */
+  {
+    VALUE lenv = rb_hash_aref(confdict,rb_str_new2("lenv"));
+    if(TYPE(lenv)!=T_NIL){
+      VALUE valobj=rb_str_new2(status);
+      rb_hash_aset(lenv,rb_str_new2("status"),valobj);
+    }
+  }
+  conf = mapsFromRubyHash(confdict);
+  if (getMapFromMaps(conf,"lenv","status") != NULL){
+    fprintf(stderr,"STATUS RETURNED : %s\n",status);
+    if(status!=NULL){
+      setMapInMaps(conf,"lenv","status",status);
+      free(status);
+    }
+    else
+      setMapInMaps(conf,"lenv","status","15");
+    _updateStatus(conf);
+  }
+  freeMaps(&conf);
+  free(conf);
+  return Qnil;
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ruby.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ruby.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_ruby.h	(revision 942)
@@ -0,0 +1,78 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2014 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_RUBY_H
+#define ZOO_SERVICE_INTERNAL_RUBY_H 1
+
+#pragma once 
+
+#define RUBY_GLOBAL_SETUP
+#undef NEED_STRLCAT
+#undef NEED_STRLCPY
+#include "service.h"
+#include "service_internal.h"
+#undef RUBY_EXPORT
+#undef STRCASECMP
+#undef STRNCASECMP
+#undef _
+#include <ruby.h>
+#if ZRUBY_VERSION < 2
+#include <version.h>
+#else
+#include <ruby/version.h>
+#endif
+#if RUBY_VERSION_MINOR==8
+#include <st.h>
+#else
+#include <ruby/st.h>
+#endif
+
+#define MAX_ARGS 3
+/**
+ * The Ruby method pointer
+ */
+struct my_callback {
+  VALUE obj; //!< Object used to call a method
+  ID method_id; //!< The method to call
+  int nargs; //!< The arguments number
+  VALUE args[MAX_ARGS]; //!< The arguments values
+};
+
+void ruby_trace_error(maps*);
+VALUE FunCallWrap(VALUE);
+VALUE LoadWrap(VALUE);
+
+VALUE RubyHash_FromMaps(maps*);
+VALUE RubyHash_FromMap(map*);
+
+maps* mapsFromRubyHash(VALUE);
+void createMapsFromRubyHash(maps**,VALUE);
+map* mapFromRubyHash(VALUE);
+
+int zoo_ruby_support(maps**,map*,service*,maps**,maps**);
+
+VALUE RubyTranslate(int,VALUE*,VALUE);
+VALUE RubyUpdateStatus(int,VALUE*,VALUE);
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_saga.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_saga.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_saga.c	(revision 942)
@@ -0,0 +1,1242 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <locale.h>
+#include <wx/string.h>
+#include <wx/app.h>
+#include <api_core.h>
+#include <data_manager.h>
+#include <saga_api.h>
+#define _ZOO_SAGA
+#include "service_internal_saga.h"
+#include "server_internal.h"
+#include "mimetypes.h"
+
+/**
+ * Global SAGA-GIS output counter 
+ */
+int sagaOutputCounter=0;
+
+/**
+ * Observer used to access the ongoing status of a running OTB Application
+ */
+class SagaWatcher
+{
+ public:
+  static int Callback(TSG_UI_Callback_ID ID, CSG_UI_Parameter &Param_1, CSG_UI_Parameter &Param_2);
+  /** 
+   * Define the message value
+   *
+   * @param conf the maps pointer to copy
+   */
+  static void SetMessage(const char *mess)
+  {
+    FreeMessage();
+    message=zStrdup(mess);
+  }
+  /** 
+   * Free the message value
+   *
+   */
+  static void FreeMessage()
+  {
+    if(message!=NULL)
+      free(message);
+    message=NULL;
+  }
+  /** 
+   * Copy the original conf in the m_conf property
+   *
+   * @param conf the maps pointer to copy
+   */
+  void SetConf(maps **conf)
+  {
+    m_conf=dupMaps(conf);
+  }
+  /**  
+   * Get Configuration maps (m_conf)
+   * @return the m_conf property
+   */
+  const maps& GetConf()
+  {
+    return *m_conf;
+  }
+  /**  
+   * Free Configuration maps (m_Conf)
+   */
+  void FreeConf(){
+    freeMaps(&m_conf);
+    free(m_conf);
+  }
+ private:
+  /** Main conf maps */
+  static maps* m_conf;
+  /** Status */
+  static int status;
+  /** Message */
+  static char* message;
+};
+
+maps* SagaWatcher::m_conf;
+char* SagaWatcher::message=zStrdup("No message left");
+int SagaWatcher::status=1;
+
+/**
+ * The callback function called at any SAGA-GIS module step
+ *
+ * @param id a TSG_UI_Callback_ID as defined in api_core.h (line 1290)
+ * @param param1 
+ * @param param2
+ */
+int
+SagaWatcher::
+Callback(TSG_UI_Callback_ID id, CSG_UI_Parameter &param1, CSG_UI_Parameter &param2)
+{
+
+  int res = 1;
+  switch( id )
+    {
+    default:
+      return 0;
+      break;
+
+    case CALLBACK_DLG_ERROR:
+      return 1;
+      break;
+
+    case CALLBACK_DLG_PARAMETERS:
+    case CALLBACK_PROCESS_SET_OKAY:
+    case CALLBACK_DATAOBJECT_COLORS_GET:
+    case CALLBACK_DATAOBJECT_COLORS_SET:
+    case CALLBACK_DATAOBJECT_PARAMS_GET:
+    case CALLBACK_DATAOBJECT_PARAMS_SET:
+    case CALLBACK_DATAOBJECT_UPDATE:
+    case CALLBACK_DATAOBJECT_SHOW:
+    case CALLBACK_DLG_CONTINUE:
+    case CALLBACK_PROCESS_SET_READY:
+    case CALLBACK_PROCESS_GET_OKAY:
+      return res;
+      break;
+
+    case CALLBACK_PROCESS_SET_PROGRESS:
+      {
+	int cPercent= param2.Number != 0.0 ? 1 + (int)(100.0 * param1.Number / param2.Number) : 100 ;
+	if( cPercent != status ){
+	  status=cPercent;
+	}else
+	  return res;
+      }
+      break;
+
+    case CALLBACK_PROCESS_SET_TEXT:
+      SetMessage(param1.String.b_str());
+      break;
+
+    case CALLBACK_MESSAGE_ADD:
+      SetMessage(param1.String.b_str());
+      break;
+
+    case CALLBACK_MESSAGE_ADD_ERROR:
+      SetMessage(param1.String.b_str());
+      break;
+
+    case CALLBACK_MESSAGE_ADD_EXECUTION:
+      SetMessage(param1.String.b_str());
+      break;
+
+    case CALLBACK_DLG_MESSAGE:
+      SetMessage((param2.String + ": " + param1.String).b_str());
+      break;
+
+    case CALLBACK_DATAOBJECT_ADD:
+      if(SG_Get_Data_Manager().Add((CSG_Data_Object *)param1.Pointer))
+	res = 1 ;
+      else
+	res = 0;
+      return res;
+      break;
+
+    }
+  updateStatus(m_conf,status,message);
+  return( res );
+}
+
+TSG_PFNC_UI_Callback Get_Callback (SagaWatcher watcher){
+  return( &(watcher.Callback) );
+}
+
+
+/**
+ * Get the default file extension for SAGA-GIS parameter type.
+ * Extensions are the following:
+ *  - sgrd for grid and data_object
+ *  - shp for shapes and tin
+ *  - csv for tables
+ *  - spc for points
+ *
+ * @param param a SAGA-GIS Parameter
+ */ 
+const char* sagaGetDefaultExt(CSG_Parameter* param){
+  if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("grid"))
+     || CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("data_object"))){
+    return "sgrd";
+  }
+  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes")) ||
+	  CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
+    return "shp";
+  }
+  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
+    return "csv";
+  }
+  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("points"))){
+    return "spc";
+  }
+  return "unknown";
+}
+
+/**
+ * Load a datasource in the SAGA-GIS Data Manager.
+ *
+ * @param param a SAGA-GIS Parameter
+ * @param arg the arguments map passed to a SAGA-GIS module
+ * @return false on failure, true in case of success
+ */
+bool sagaLoadInput(CSG_Parameter* param,map* arg){
+  if(!param->is_Input() || !param->is_Enabled()){
+    return true;
+  }
+  map* carg=getMap(arg,CSG_String(param->Get_Identifier()).b_str());
+  if(carg!=NULL){
+    wxString fileName(carg->value);
+    if(param->is_DataObject()){
+      // In case it there is a single datasource
+      if(!SG_Get_Data_Manager().Find(&fileName) && !SG_Get_Data_Manager().Add(&fileName) && !param->is_Optional() ){
+	return false;
+      }
+      fprintf(stderr,"%s %s\n",carg->name,carg->value);
+      fflush(stderr);
+      return( param->Set_Value(SG_Get_Data_Manager().Find(&fileName,false)) );
+    }
+    else
+      if(param->is_DataObject_List()){
+	// In case there are multiple datasources
+	param->asList()->Del_Items();
+	wxString fileNames(fileName);
+	while( fileNames.Length() > 0 ){
+	  fileName = fileNames.BeforeFirst(';').Trim(false);
+	  fileNames = fileNames.AfterFirst (';');	    
+	  if( !SG_Get_Data_Manager().Find(&fileName) ){
+	    SG_Get_Data_Manager().Add(&fileName);
+	  }
+	  param->asList()->Add_Item(SG_Get_Data_Manager().Find(&fileName,false));
+	}
+      }
+  }
+  return true;
+}
+
+/**
+ * Extract all SAGA-GIS parameters from a parameters list and set its values to
+ * the one defined in the map.
+ *
+ * @parap params the parameters list
+ * @parap argument the argument map containing the value to use
+ * @return true in success, false in other case
+ */
+bool sagaSetParameters(CSG_Parameters *params,map* argument){
+
+  int pc=params->Get_Count();
+  params->Restore_Defaults();
+
+  for(int k=0;k<pc;k++){
+    CSG_Parameter * param=params->Get_Parameter(k);
+    if( param->is_Output() ){
+      map* omap=getMap(argument,CSG_String(param->Get_Identifier()).b_str());
+      if( param->is_DataObject() && param->is_Optional() && !param->asDataObject() && omap!=NULL){
+	param->Set_Value(DATAOBJECT_CREATE);
+      }
+    }
+    else
+      if( param->is_Option() && !param->is_Information() ){
+	map* inmap=getMap(argument,CSG_String(param->Get_Identifier()).b_str());
+	if(inmap!=NULL){
+	    switch( param->Get_Type() ){
+	    case PARAMETER_TYPE_Bool:
+	      if(strncasecmp(inmap->value,"true",4)==0 || strncasecmp(inmap->value,"1",1)==0){
+		param->Set_Value(1);
+	      }else
+		param->Set_Value(0);
+	      break;
+	    case PARAMETER_TYPE_Parameters:
+	      // TODO: nested inputs gesture
+	      break;
+	    case PARAMETER_TYPE_Int:
+	      param->Set_Value((int)strtol(inmap->value,NULL,10));
+	      break;
+	    case PARAMETER_TYPE_Double:
+	    case PARAMETER_TYPE_Degree:
+	      param->Set_Value((double)strtod(inmap->value,NULL));
+	      break;
+	    case PARAMETER_TYPE_String:
+	      param->Set_Value(CSG_String(inmap->value));
+	      break;
+	    case PARAMETER_TYPE_FilePath:
+	      param->Set_Value(CSG_String(inmap->value));
+	      break;
+	    case PARAMETER_TYPE_FixedTable:
+	      {
+		CSG_Table Table(inmap->value);
+		param->asTable()->Assign_Values(&Table);
+	      }
+	      break;
+	    case PARAMETER_TYPE_Choice:
+	      {
+		int val=(int)strtol(inmap->value,(char**)NULL,10);
+		if(val==0 && strncasecmp(inmap->value,"0",1)!=0)
+		  param->Set_Value(CSG_String(inmap->value));
+		else
+		  param->Set_Value(val);
+	      }
+	      break;
+	    default:
+	      break;
+	    }
+	}else{
+	  if(param->Get_Type()==PARAMETER_TYPE_Range){
+	    inmap=getMap(argument,(CSG_String(param->Get_Identifier())+"_MIN").b_str());
+	    if(inmap!=NULL)
+#if SAGA_MAJOR_VERSION == 2	      
+	      param->asRange()->Set_LoVal(strtod(inmap->value,NULL));
+#else
+	      param->asRange()->Set_Min(strtod(inmap->value,NULL));
+#endif	    
+	    inmap=getMap(argument,(CSG_String(param->Get_Identifier())+"_MAX").b_str());
+	    if(inmap!=NULL)
+#if SAGA_MAJOR_VERSION == 2	      
+	      param->asRange()->Set_HiVal(strtod(inmap->value,NULL));	    
+#else
+	      param->asRange()->Set_Max(strtod(inmap->value,NULL));
+#endif	    
+	  }
+	  if(inmap==NULL){
+	    param->Restore_Default();
+	  }
+	}
+      }
+  }
+
+  for(int k=0;k<pc;k++){
+    CSG_Parameter * param=params->Get_Parameter(k);
+    if( param->is_Input() )
+      if(!sagaLoadInput(param,argument)){
+	fprintf(stderr,"%s %d \n",__FILE__,__LINE__);
+	return false;
+      }
+  }
+  return true;
+}
+
+/**
+ * Save all values outputed by a SAGA-GIS module invocation to files
+ *
+ * @param params the parameters list
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param outputs the maps to set the generated_file for each output
+ */
+bool sagaSaveOutputs(CSG_Parameters *params,maps* main_conf,maps** outputs)
+{
+  for(int j=0; j<params->Get_Count(); j++)
+    {
+      CSG_Parameter *param = params->Get_Parameter(j);
+      maps* cMaps=getMaps(*outputs,CSG_String(param->Get_Identifier()).b_str());
+      // Specific TIN case
+      if(cMaps==NULL && CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin")))
+	cMaps=getMaps(*outputs,(CSG_String(param->Get_Identifier())+"_POINTS").b_str());
+      if(cMaps!=NULL){
+	map* tmpPath=getMapFromMaps(main_conf,"main","tmpPath");
+	map* sid=getMapFromMaps(main_conf,"lenv","usid");
+	const char *file_ext=sagaGetDefaultExt(param);
+
+	if( param->is_Input() )
+	  {
+	    if( param->is_DataObject() )
+	      {
+		CSG_Data_Object *pObject = param->asDataObject();
+		
+		if( pObject && pObject->is_Modified() && SG_File_Exists(pObject->Get_File_Name()) )
+		  {
+		    pObject->Save(pObject->Get_File_Name());
+		    addToMap(cMaps->content,"generated_file",CSG_String(pObject->Get_File_Name()).b_str());
+		  }
+	      }
+	    
+	    else if( param->is_DataObject_List() )
+	      {
+		for(int i=0; i<
+#if SAGA_MAJOR_VERSION == 2
+		      param->asList()->Get_Count()
+#else
+		      param->asList()->Get_Data_Count()
+#endif		      
+		      ; i++)
+		  {
+		    CSG_Data_Object *pObject =
+#if SAGA_MAJOR_VERSION == 2		      
+		      param->asList()->asDataObject(i)
+#else
+		      param->asList()->Get_Data(i)
+#endif		      
+		      ;
+		    
+		    if( pObject->is_Modified() && SG_File_Exists(pObject->Get_File_Name()) )
+		      {
+			pObject->Save(pObject->Get_File_Name());
+			setMapArray(cMaps->content,"generated_file",i,CSG_String(pObject->Get_File_Name()).b_str());
+		      }
+		  }
+	      }
+	  }
+	else
+	  if( param->is_Output() )
+	    {
+	      char *realFileName=(char*)malloc((strlen(file_ext)+strlen(sid->value)+strlen(cMaps->name)+14)*sizeof(char));
+	      char *fullFileName=(char*)malloc((strlen(file_ext)+strlen(sid->value)+strlen(cMaps->name)+strlen(tmpPath->value)+16)*sizeof(char));
+	      sprintf(realFileName,"Output_%s_%s_%d",cMaps->name,sid->value,sagaOutputCounter);
+	      sprintf(fullFileName,"%s/Output_%s_%s_%d.%s",tmpPath->value,cMaps->name,sid->value,sagaOutputCounter,file_ext);
+	      sagaOutputCounter+=1;
+	      wxString fileName(fullFileName);
+	      addToMap(cMaps->content,"generated_name",realFileName);
+	      free(realFileName);
+	      free(fullFileName);
+
+	      if( param->is_DataObject() )
+		{
+		  if( param->asDataObject() )
+		    {
+		      param->asDataObject()->Save(&fileName);
+		      addToMap(cMaps->content,"generated_file",CSG_String(param->asDataObject()->Get_File_Name()).b_str());
+		    }
+		}
+	    
+	      else if( param->is_DataObject_List() )
+		{
+		  CSG_Strings	fileNames;
+		
+		  while( fileName.Length() > 0 )
+		    {
+		      CSG_String current_file(&fileName);
+		      current_file = current_file.BeforeFirst(';');
+		      if( current_file.Length() > 0 )
+			{
+			  fileNames += current_file;
+			  fileName = fileName.AfterFirst(';');
+			}
+		      else
+			{
+			  fileNames += &fileName;
+			  fileName.Clear();
+			}
+		    }
+#if SAGA_MAJOR_VERSION == 2		  
+		  int nFileNames = param->asList()->Get_Count() <= fileNames.Get_Count() ? fileNames.Get_Count() : fileNames.Get_Count() - 1;
+		  for(int i=0; i<param->asList()->Get_Count(); i++)
+		    {
+		      if( i < nFileNames )
+			{
+			  param->asList()->asDataObject(i)->Save(fileNames[i]);
+			}
+		      else
+			{
+			  param->asList()->asDataObject(i)->Save(CSG_String::Format(SG_T("%s_%0*d"),
+										    fileNames[fileNames.Get_Count() - 1].c_str(),
+										    SG_Get_Digit_Count(param->asList()->Get_Count()),
+										    1 + i - nFileNames
+										    ));
+			}
+		      setMapArray(cMaps->content,"generated_file",i,
+				  CSG_String(param->asList()->asDataObject(i)->Get_File_Name()).b_str());
+		    }
+#else
+		  int nFileNames = param->asList()->Get_Data_Count() <= fileNames.Get_Count() ? fileNames.Get_Count() : fileNames.Get_Count() - 1;
+		  for(int i=0; i<param->asList()->Get_Data_Count(); i++)
+		    {
+		      if( i < nFileNames )
+			{
+			  param->asList()->Get_Data(i)->Save(fileNames[i]);
+			}
+		      else
+			{
+			  param->asList()->Get_Data(i)->Save(CSG_String::Format(SG_T("%s_%0*d"),
+										    fileNames[fileNames.Get_Count() - 1].c_str(),
+										    SG_Get_Digit_Count(param->asList()->Get_Data_Count()),
+										    1 + i - nFileNames
+										    ));
+			}
+		      setMapArray(cMaps->content,"generated_file",i,
+				  CSG_String(param->asList()->Get_Data(i)->Get_File_Name()).b_str());
+		    }
+		  
+#endif		  
+		}
+	    }
+      }
+    }
+  return( true );
+}
+
+/**
+ * Invoke the execution of a SAGA-GIS module.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param lib_name the SAGA-GIS library name
+ * @param module_name the SAGA-GIS module name
+ * @param arguments the map containing the arguments to pass to the module
+ * @param outputs default to NULL, contains the maps to fill with the result
+ */
+int sagaExecuteCmd(maps** main_conf,const char* lib_name,const char* module_name,map* arguments,maps** outputs=NULL){
+  int res=SERVICE_FAILED;
+
+#if SAGA_MAJOR_VERSION == 2  
+  CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(CSG_String(lib_name),true);
+#else
+  CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(CSG_String(lib_name),true);
+#endif  
+  if( library == NULL){
+    char tmp[255];
+    sprintf(tmp,"Counld not load the %s SAGA library",lib_name);
+    setMapInMaps(*main_conf,"lenv","message",tmp);
+    res=SERVICE_FAILED;
+    return res;
+  }
+
+#if SAGA_MAJOR_VERSION == 2  
+  CSG_Module * module=library->Get_Module(atoi(module_name));
+#else
+  CSG_Tool * module=library->Get_Tool(atoi(module_name));
+#endif  
+  if(module == NULL){
+    char tmp[255];
+    sprintf(tmp,"Counld not load the %s module from the %s SAGA library",module_name,lib_name);
+    setMapInMaps(*main_conf,"lenv","message",tmp);
+    res=SERVICE_FAILED;
+    return res;
+  }
+
+  CSG_Parameters * params=module->Get_Parameters();
+  if(!params){
+    char tmp[255];
+    sprintf(tmp,"Counld not find any param for the %s module from the %s SAGA library",module_name,lib_name);
+    setMapInMaps(*main_conf,"lenv","message",tmp);
+    res=SERVICE_FAILED;
+    return res;
+  }
+  
+  sagaSetParameters(params,arguments);
+
+  module->Update_Parameter_States();
+
+  bool retval=false;
+  if(module->On_Before_Execution()){
+    retval=module->Execute();
+    module->On_After_Execution();
+  }
+  
+  if(retval && outputs!=NULL){
+    sagaSaveOutputs(module->Get_Parameters(),*main_conf,outputs);
+    SG_Get_Data_Manager().Delete_Unsaved();
+    return SERVICE_SUCCEEDED;
+  }
+
+  return SERVICE_FAILED;
+
+}
+
+/**
+ * Export a SAGA-GIS Shapes to a file in a specific format (GML,KML,GeoJSON).
+ * saga_cmd io_gdal 4 -FILE my.format -SHAPES my.shp -FORMAT XXX
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param in the output maps to fill with the resulting file
+ */
+int sagaExportOGR(maps** conf, maps** in){
+  map* mtype=getMap((*in)->content,"mimeType");
+  map* gfile=getMap((*in)->content,"generated_file");
+  char* fext=NULL;
+  map* arg=NULL;
+  if(strncasecmp(mtype->value,"text/xml",8)==0){
+    fext=zStrdup("xml");
+  }
+  else if(strncasecmp(mtype->value,"application/json",16)==0){
+    fext=zStrdup("json");
+  }
+  else{
+    fext=zStrdup("kml");
+  }
+  char* tmpName=(char*)malloc((strlen(gfile->value)+2)*sizeof(char));
+  strncpy(tmpName,gfile->value,(strlen(gfile->value)-3)*sizeof(char));
+  strncpy(&tmpName[0]+(strlen(gfile->value)-3),fext,(strlen(fext))*sizeof(char));
+  tmpName[strlen(fext)+(strlen(gfile->value)-3)]=0;
+  arg=createMap("SHAPES",gfile->value);
+  addToMap(arg,"FILE",tmpName);
+  if(strncasecmp(mtype->value,"text/xml",8)==0){
+    addToMap(arg,"FORMAT","GML");
+  }
+  else if(strncasecmp(mtype->value,"application/json",16)==0){
+    addToMap(arg,"FORMAT","GeoJSON");
+  }
+  else{
+#ifdef HAVE_LIBKML
+    addToMap(arg,"FORMAT","LIBKML");
+#else
+    addToMap(arg,"FORMAT","KML");
+#endif
+  }
+  free(fext);
+  free(gfile->value);
+  gfile->value=zStrdup(tmpName);
+  free(tmpName);
+  
+  sagaExecuteCmd(conf,"io_gdal","4",arg);
+  freeMap(&arg);
+  free(arg);
+}
+
+/**
+ * Export a SAGA-GIS pointcloud to a las file.
+ * saga_cmd io_shapes_las 0 -POINTS my.spc -FILE my.las
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param in the output maps to fill with the resulting file
+ */
+void sagaExportPC(maps** conf, maps** in){
+  map* mtype=getMap((*in)->content,"mimeType");
+  map* gfile=getMap((*in)->content,"generated_file");
+  char* fext="las";
+  map* arg=NULL;
+  char* tmpName=(char*)malloc((strlen(gfile->value)+2)*sizeof(char));
+  strncpy(tmpName,gfile->value,(strlen(gfile->value)-3)*sizeof(char));
+  strncpy(&tmpName[0]+(strlen(gfile->value)-3),fext,(strlen(fext))*sizeof(char));
+  tmpName[strlen(fext)+(strlen(gfile->value)-3)]=0;
+  arg=createMap("POINTS",gfile->value);
+  addToMap(arg,"FILE",tmpName);
+  free(gfile->value);
+  gfile->value=zStrdup(tmpName);
+  sagaExecuteCmd(conf,"io_shapes_las","0",arg);
+  freeMap(&arg);
+  free(arg);
+  free(tmpName);
+}
+
+/**
+ * Export a SAGA-GIS Grid to a file in a specific format (tiff,hdr,aa).
+ * saga_cmd io_gdal 1 -FILE my.format -GRIDS my.sgrd -FORMAT XXX
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param in the output maps to fill with the resulting file
+ */
+int sagaExportGDAL(maps** conf, maps** in/*,CSG_Parameter* param*/){
+  map* mtype=getMap((*in)->content,"extension");
+  map* gfile=getMap((*in)->content,"generated_file");
+  char* fext=NULL;
+  map* arg;
+
+  if(mtype!=NULL)
+    fext=zStrdup(mtype->value);
+  else{
+    fext=zStrdup("tiff");
+  }
+
+  mtype=getMap((*in)->content,"mimeType");
+  if(strncasecmp(mtype->value,"image/tiff",10)==0){
+    arg=createMap("FORMAT","1");
+  }
+  else if(strncasecmp(mtype->value,"application/x-ogc-envi",22)==0){
+    arg=createMap("FORMAT","ENVI .hdr Labelled");
+  }
+  else{
+    arg=createMap("FORMAT","ARC Digitized Raster Graphics");
+  }
+
+  if(gfile!=NULL){
+    char* tmpName=(char*)malloc((strlen(gfile->value)+1)*sizeof(char));
+    strncpy(tmpName,gfile->value,(strlen(gfile->value)-4)*sizeof(char));
+    strncpy(&tmpName[0]+(strlen(gfile->value)-4),fext,(strlen(fext))*sizeof(char));
+    tmpName[strlen(fext)+(strlen(gfile->value)-4)]=0;
+    addToMap(arg,"FILE",tmpName);
+    addToMap(arg,"GRIDS",gfile->value);
+    free(tmpName);
+    free(fext);
+    free(gfile->value);
+    map* tmp=getMap(arg,"FILE");
+    gfile->value=zStrdup(tmp->value);
+    sagaExecuteCmd(conf,"io_gdal","1",arg);
+  }
+  else{
+    // Empty result
+    return true;
+  }
+  freeMap(&arg);
+  free(arg);
+}
+
+/**
+ * Export a SAGA-GIS TIN to a file in a specific format (GML,KML,GeoJSON).
+ * Exporting TIN produce 5 separated files (POINTS, CENTER, EDGES, TRIANGLES 
+ * and POLYGONS). Even if a client can choose which result it want to have,
+ * SAGA-GIS module will be invoked in a way that it will produce in any case
+ * each possible outputs. The selection of a specific output is made in the 
+ * ZOO-Kernel itself and not specifically at this level.
+ * saga_cmd tin_tools 3 -TIN my.shp -POINTS p.shp ...
+ *
+ * @param conf the conf maps containing the main.cfg settings
+ * @param in the output maps to fill with the resulting file
+ * @see sagaExportOGR
+ */
+int sagaExportTIN(maps** conf, maps** in,const char* tname/*,CSG_Parameter* param*/){
+  map* mtype=getMap((*in)->content,"mimeType");
+  map* gfile=getMap((*in)->content,"generated_file");
+  char* fext="shp";
+  map* arg=createMap("TIN",gfile->value);
+
+  char* tinOut[5]={
+    "POINTS",
+    "CENTER",
+    "EDGES",
+    "TRIANGLES",
+    "POLYGONS"
+  };
+  maps* resouts=NULL;
+
+  int i=0;
+  for(i=0;i<5;i++){
+    char* tmpName=(char*)malloc((strlen(gfile->value)+strlen(tinOut[i])+4)*sizeof(char));
+    strncpy(tmpName,gfile->value,(strlen(gfile->value)-3)*sizeof(char));
+    char *tmpSubName=(char*) malloc((strlen(tinOut[i])+3)*sizeof(char));
+    sprintf(tmpSubName,"_%s.",tinOut[i]);
+    strncpy(&tmpName[0]+(strlen(gfile->value)-4),tmpSubName,(strlen(tmpSubName))*sizeof(char));
+    strncpy(&tmpName[0]+(strlen(gfile->value)+strlen(tmpSubName)-4),fext,(strlen(fext))*sizeof(char));
+    tmpName[strlen(fext)+(strlen(gfile->value)+strlen(tmpSubName)-4)]=0;
+
+    maps* louts=createMaps(tinOut[i]);
+    louts->content=createMap("mimeType","UNKOWN");
+    
+    addToMap(arg,tinOut[i],tmpName);
+    
+    free(tmpName);
+    if(resouts==NULL)
+      resouts=dupMaps(&louts);
+    else
+      addMapsToMaps(&resouts,louts);
+    freeMaps(&louts);
+    free(louts);
+  }
+  
+  sagaExecuteCmd(conf,"tin_tools","3",arg,&resouts);
+
+  for(i=0;i<5;i++){
+    map* generatedFile=getMapFromMaps(resouts,tinOut[i],"generated_file");
+    setMapInMaps(*in,(CSG_String(tname)+"_"+tinOut[i]).b_str(),"generated_file",generatedFile->value);
+    maps* cout=getMaps(*in,(CSG_String(tname)+"_"+tinOut[i]).b_str());
+    sagaExportOGR(conf,&cout);
+  }
+  return true;
+}
+
+/**
+ * Import GDAL Datasource into SAGA-GIS.
+ * saga_cmd io_gdal 0 -TRANSFORM 0 -FILES my.format -GRIDS /tmpPath/MyGridXXX.sgrd
+ * 
+ * @param conf the conf maps containing the main.cfg settings
+ * @param in in the inputs maps
+ */
+int sagaImportGDAL(maps** conf, maps** in){
+  map* l=getMap((*in)->content,"length");
+  bool shouldClean=false;
+  if(l==NULL){
+    l=createMap("length","1");
+    shouldClean=true;
+  }
+  int len=strtol(l->value,NULL,10);
+  int i=0;
+  for(i=0;i<len;i++){
+    map* arg=createMap("TRANSFORM","0");
+    addToMap(arg,"INTERPOL","4");
+    map* v=getMapArray((*in)->content,"cache_file",i);
+    if(v!=NULL)
+      addToMap(arg,"FILES",v->value);
+    addToMap(arg,"GRIDS","");
+
+    maps* louts=createMaps("GRIDS");
+    louts->content=createMap("mimeType","UNKOWN");
+
+    sagaExecuteCmd(conf,"io_gdal","0",arg,&louts);
+
+    map* tmp=getMapFromMaps(louts,"GRIDS","generated_file");
+    setMapArray((*in)->content,"saga_value",i,tmp->value);
+
+    freeMaps(&louts);
+    free(louts);
+    freeMap(&arg);
+    free(arg);
+  }
+  if(shouldClean){
+    freeMap(&l);
+    free(l);
+  }
+}
+
+/**
+ * Import OGR Datasource into SAGA-GIS.
+ * saga_cmd io_gdal 3 -SHAPES my.shp -FILES my.format
+ * 
+ * @param conf the conf maps containing the main.cfg settings
+ * @param in in the inputs maps
+ */
+int sagaImportOGR(maps** conf, maps** in){
+  char *ext;
+  map* arg;
+  map* l=getMap((*in)->content,"length");
+  bool shouldClean=false;
+  if(l==NULL){
+    l=createMap("length","1");
+    shouldClean=true;
+  }
+  int len=strtol(l->value,NULL,10);
+  int i=0;
+  for(i=0;i<len;i++){
+    map* v=getMapArray((*in)->content,"cache_file",i);
+    arg=createMap("SHAPES","");
+    if(v!=NULL)
+      addToMap(arg,"FILES",v->value);
+
+    maps* louts=createMaps("SHAPES");
+    louts->content=createMap("mimeType","UNKOWN");
+
+    sagaExecuteCmd(conf,"io_gdal","3",arg,&louts);
+
+    map* tmp=getMapFromMaps(louts,"SHAPES","generated_file");
+    setMapArray((*in)->content,"saga_value",i,tmp->value);
+
+    freeMaps(&louts);
+    free(louts);
+    freeMap(&arg);
+    free(arg);
+  }
+  if(shouldClean){
+    freeMap(&l);
+    free(l);
+  }
+}
+
+/**
+ * Import TIN into SAGA-GIS. Calling this function suppose that sagaImportOGR
+ * was called first.
+ * saga_cmd tin_tools 2 -SHAPES myShapes.shp -TIN myTin.shp
+ * 
+ * @param conf the conf maps containing the main.cfg settings
+ * @param in in the inputs maps
+ * @see sagaImportOGR
+ */
+bool sagaImportTIN(maps** conf, maps** in){
+  char *ext;
+  map* arg;
+  map* l=getMap((*in)->content,"length");
+  bool shouldClean=false;
+  if(l==NULL){
+    l=createMap("length","1");
+    shouldClean=true;
+  }
+  int len=strtol(l->value,NULL,10);
+  int i=0;
+  for(i=0;i<len;i++){
+    map* v=getMapArray((*in)->content,"saga_value",i);
+    arg=createMap("TIN","");
+    if(v!=NULL)
+      addToMap(arg,"SHAPES",v->value);
+    maps* louts=createMaps("TIN");
+    louts->content=createMap("mimeType","UNKOWN");
+    sagaExecuteCmd(conf,"tin_tools","2",arg,&louts);
+    map* tmp=getMapFromMaps(louts,"TIN","generated_file");
+    v=getMapArray((*in)->content,"saga_value",i);
+    if(tmp!=NULL){
+      if(v!=NULL){
+	free(v->value);
+	v->value=zStrdup(tmp->value);
+      }
+      else
+	setMapArray((*in)->content,"saga_value",i,tmp->value);
+    }
+    freeMaps(&louts);
+    free(louts);
+    freeMap(&arg);
+    free(arg);
+  }
+  if(shouldClean){
+    freeMap(&l);
+    free(l);
+  }
+  return true;
+}
+
+/**
+ * Import table into SAGA-GIS. 
+ * saga_cmd io_table 1 -TABLE myTable -FILENAME myFile -SEPARATOR 2
+ * 
+ * @param conf the conf maps containing the main.cfg settings
+ * @param in in the inputs maps
+ */
+int sagaImportTable(maps** conf, maps** in){
+  char *ext;
+  map* arg;
+  map* l=getMap((*in)->content,"length");
+  bool shouldClean=false;
+  if(l==NULL){
+    l=createMap("length","1");
+    shouldClean=true;
+  }
+  int len=strtol(l->value,NULL,10);
+  int i=0;
+  for(i=0;i<len;i++){
+
+    // Create and fill arg map
+    arg=createMap("SEPARATOR","2");
+    addToMap(arg,"TABLE","");
+    map* v=getMapArray((*in)->content,"cache_file",i);
+    if(v!=NULL)
+      addToMap(arg,"FILENAME",v->value);
+
+    // Create the output maps
+    maps* louts=createMaps("TABLE");
+    louts->content=createMap("mimeType","UNKOWN");
+
+    // Execute the saga command
+    sagaExecuteCmd(conf,"io_table","1",arg,&louts);
+
+    // Fetch result and add it to the original map as saga_value
+    map* tmp=getMapFromMaps(louts,"TABLE","generated_file");
+    setMapArray((*in)->content,"saga_value",i,tmp->value);
+
+    // Cleanup
+    freeMaps(&louts);
+    free(louts);
+    freeMap(&arg);
+    free(arg);
+
+  }
+  // Cleanup if required
+  if(shouldClean){
+    freeMap(&l);
+    free(l);
+  }
+}
+
+/**
+ * Import las file as pointcloud into SAGA-GIS. 
+ * saga_cmd io_shapes_las 1 -POINTS my.spc -FILENAME my.las
+ * 
+ * @param conf the conf maps containing the main.cfg settings
+ * @param in in the inputs maps
+ */
+int sagaImportPC(maps** conf, maps** in){
+  char *ext;
+  map* arg;
+  map* l=getMap((*in)->content,"length");
+  bool shouldClean=false;
+  if(l==NULL){
+    l=createMap("length","1");
+    shouldClean=true;
+  }
+  int len=strtol(l->value,NULL,10);
+  int i=0;
+  for(i=0;i<len;i++){
+
+    // Create and fill arg map
+    arg=createMap("POINTS","");
+    map* v=getMapArray((*in)->content,"cache_file",i);
+    if(v!=NULL)
+      addToMap(arg,"FILES",v->value);
+
+    // Create the output maps
+    maps* louts=createMaps("POINTS");
+    louts->content=createMap("mimeType","UNKOWN");
+
+    // Execute the saga command
+    sagaExecuteCmd(conf,"io_shapes_las","1",arg,&louts);
+
+    // Fetch result and add it to the original map as saga_value
+    map* tmp=getMapFromMaps(louts,"POINTS","generated_file");
+    setMapArray((*in)->content,"saga_value",i,tmp->value);
+
+    // Cleanup
+    freeMaps(&louts);
+    free(louts);
+    freeMap(&arg);
+    free(arg);
+
+  }
+  // Cleanup if required
+  if(shouldClean){
+    freeMap(&l);
+    free(l);
+  }
+}
+
+/**
+ * Load and invoke a SAGA-GIS module defined in a service metadata definitions.
+ * Load all the input data into SAGA-GIS using io_gdal, io_tables and 
+ * io_shapes_las for SAGA grids/shapes, tables and pointcloud respectively. 
+ * Load and run the module from its library and invoke it using the data 
+ * imported in SAGA-GIS at first stage. After the execution, export the outputs
+ * to files using io_gdal and io_shapes_las for grids/shapes and pointcloud 
+ * respectively.
+ *
+ * @param main_conf the conf maps containing the main.cfg settings
+ * @param request the map containing the HTTP request
+ * @param s the service structure
+ * @param inputs the maps containing the inputs
+ * @param outputs the maps containing the outputs
+ */
+int zoo_saga_support(maps** main_conf,map* request,service* s,maps** inputs,maps** outputs){
+  int res=SERVICE_FAILED;
+  if( !wxInitialize() ){
+    fprintf(stderr,"initialisation failed");
+    return SERVICE_FAILED;
+  }
+  setlocale(LC_NUMERIC, "C");
+  static bool g_bShow_Messages = false;
+
+  dumpMapsValuesToFiles(main_conf,inputs);
+
+  SagaWatcher watcher=SagaWatcher();
+  watcher.SetConf(main_conf);
+
+  SG_Set_UI_Callback(Get_Callback(watcher));
+
+#if SAGA_MAJOR_VERSION == 2  
+  int n = SG_Get_Module_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
+  if( SG_Get_Module_Library_Manager().Get_Count() <= 0 )
+#else
+  int n = SG_Get_Tool_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
+  if( SG_Get_Tool_Library_Manager().Get_Count() <= 0 )
+#endif
+  {
+    setMapInMaps(*main_conf,"lenv","message","Could not load any SAGA tool library");
+    res=SERVICE_FAILED;
+    return res;
+  }
+
+  map* serviceProvider=getMap(s->content,"serviceProvider");
+
+  // Load the SAGA-GIS library corresponding to the serviceProvider
+#if SAGA_MAJOR_VERSION == 2  
+  CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(CSG_String(serviceProvider->value),true);
+#else
+  CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(CSG_String(serviceProvider->value),true);
+#endif
+  if( library == NULL){
+    char tmp[255];
+    sprintf(tmp,"Counld not load the %s SAGA library",serviceProvider->value);
+    setMapInMaps(*main_conf,"lenv","message",tmp);
+    res=SERVICE_FAILED;
+    return res;
+  }
+  
+  // Load the SAGA-GIS module corresponding to the service name from the library
+#if SAGA_MAJOR_VERSION == 2  
+  CSG_Module * module=library->Get_Module(atoi(s->name));
+#else
+  CSG_Tool * module=library->Get_Tool(atoi(s->name));
+#endif
+  if(module == NULL){
+    char tmp[255];
+    sprintf(tmp,"Counld not load the %s module from the %s SAGA library",
+	    s->name,serviceProvider->value);
+    setMapInMaps(*main_conf,"lenv","message",tmp);
+    res=SERVICE_FAILED;
+    return res;
+  }
+
+  // Load all the parameters defined for the module
+  CSG_Parameters * params=module->Get_Parameters();
+  if(!params){
+    char tmp[255];
+    sprintf(tmp,"Counld not find any param for the %s module from the %s SAGA library",
+	    s->name,serviceProvider->value);
+    setMapInMaps(*main_conf,"lenv","message",tmp);
+    res=SERVICE_FAILED;
+    return res;
+  }
+  int pc=params->Get_Count();
+
+  // Loop over each inputs to transform raster files to grid when needed, 
+  // import tables, shapes or point clouds
+  for(int k=0;k<pc;k++){
+    CSG_Parameter * param=params->Get_Parameter(k);
+    if(param!=NULL && !param->is_Output()){
+      maps* inmap=getMaps(*inputs,CSG_String(param->Get_Identifier()).b_str());
+      if(inmap!=NULL){
+	map* tmp=getMap(inmap->content,"value");
+	if(tmp==NULL || strncasecmp(tmp->value,"NULL",4)!=0){
+	  if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("grid"))){
+	    sagaImportGDAL(main_conf,&inmap);
+	  }
+	  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
+	    sagaImportOGR(main_conf,&inmap);
+	    sagaImportTIN(main_conf,&inmap);
+	  }
+	  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes"))){
+	    sagaImportOGR(main_conf,&inmap);
+	  }
+	  else{
+	    if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
+	      sagaImportTable(main_conf,&inmap);
+	    }
+	    else
+	      if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("points"))){
+		sagaImportPC(main_conf,&inmap);
+	      }
+	  }
+	}
+      }
+    }
+  }
+
+  // Create a map conraining arguments to pass to the SAGA-GIS module
+  // Fetch all input value (specifically for data imported into SAGA-GIS)
+  maps* inp=*inputs;
+  int k=0;
+  map* cParams=NULL;
+  while(inp!=NULL){
+    map* len=getMap(inp->content,"length");
+    bool shouldClean=false;
+    if(len==NULL){
+      len=createMap("length","1");
+      shouldClean=true;
+    }
+    int len0=strtol(len->value,NULL,10);
+    int i=0;
+    char *cinput=NULL;
+    int clen=0;
+    for(i=0;i<len0;i++){
+      map* val=getMapArray(inp->content,"saga_value",i);
+      if(val==NULL)
+	val=getMapArray(inp->content,"value",i);
+      if(val!=NULL && strncasecmp(val->value,"NULL",4)!=0){
+	if(cinput==NULL){
+	  cinput=zStrdup(val->value);
+	}
+	else{
+	  cinput=(char*)realloc(cinput,(clen+strlen(val->value)+1)*sizeof(char));
+	  strncpy(&cinput[0]+clen,";",1);
+	  strncpy(&cinput[0]+(clen+1),val->value,strlen(val->value));
+	  clen+=1;
+	}
+	clen+=strlen(val->value);
+	cinput[clen]=0;
+      }
+    }
+    if(cinput!=NULL && strncasecmp(cinput,"NULL",4)!=0){
+      if(cParams==NULL)
+	cParams=createMap(inp->name,cinput);
+      else
+	addToMap(cParams,inp->name,cinput);
+      free(cinput);
+    }
+    inp=inp->next;
+  }
+
+  // Fetch all output and define a resulting filename
+  inp=*outputs;
+  map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+  map* sid=getMapFromMaps(*main_conf,"lenv","usid");
+  while(inp!=NULL){
+    for(int k=0;k<pc;k++){
+      CSG_Parameter * param=params->Get_Parameter(k);
+      if(CSG_String(param->Get_Identifier()).Cmp(inp->name)==0){
+	const char *file_ext=sagaGetDefaultExt(param);
+	char *fileName=(char*)malloc((strlen(file_ext)+strlen(sid->value)+strlen(inp->name)+strlen(tmpPath->value)+11)*sizeof(char));
+	sprintf(fileName,"%s/Output_%s_%s.%s",tmpPath->value,inp->name,sid->value,file_ext);
+	if(cParams==NULL)
+	  cParams=createMap(inp->name,fileName);
+	else
+	  addToMap(cParams,inp->name,fileName);
+      }
+    }
+    inp=inp->next;
+  }
+
+  sagaSetParameters(params,cParams);
+
+  module->Update_Parameter_States();
+  
+  bool retval=false;
+  if(module->On_Before_Execution()){
+    retval=module->Execute();
+    module->On_After_Execution();
+  }
+
+  sagaSaveOutputs(params,*main_conf,outputs);
+
+  // Loop over each outputs to transform grid to raster file when needed, 
+  // export tables, shapes or point clouds
+  for(int k=0;k<pc;k++){
+    CSG_Parameter * param=params->Get_Parameter(k);
+    if(param!=NULL && param->is_Output()){
+      maps* inmap=getMaps(*outputs,CSG_String(param->Get_Identifier()).b_str());
+      if(inmap!=NULL){
+	if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("grid"))
+	   || CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("data_object"))){
+	  sagaExportGDAL(main_conf,&inmap);
+	}else{
+	  if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes"))){
+	    sagaExportOGR(main_conf,&inmap);
+	  }
+	  else{
+	    if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
+	    }
+	    else{
+	      if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
+		sagaExportTIN(main_conf,&inmap,"TIN");
+	      }
+	      else
+		if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("points"))){
+		  sagaExportPC(main_conf,&inmap);
+	      }
+	    }
+	  }
+	}
+      }
+      else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
+	sagaExportTIN(main_conf,outputs,CSG_String(param->Get_Identifier()).b_str());
+      }
+	      
+    }
+  }
+
+  wxUninitialize();
+
+  return SERVICE_SUCCEEDED;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_saga.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_saga.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_internal_saga.h	(revision 942)
@@ -0,0 +1,35 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2015 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SERVICE_INTERNAL_SAGA_H
+#define ZOO_SERVICE_INTERNAL_SAGA_H 1
+
+#pragma once 
+
+#include "service.h"
+#include "service_internal.h"
+
+int zoo_saga_support(maps**,map*,service*,maps**,maps**);
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_json.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_json.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_json.c	(revision 942)
@@ -0,0 +1,143 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service_json.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  json_object* mapToJson(map* myMap){
+    json_object *res=json_object_new_object();
+    map* cursor=myMap;
+    map* sizeMap=getMap(myMap,"size");
+    map* length=getMap(myMap,"length");
+    while(cursor!=NULL){
+      json_object *val=NULL;
+      if(length==NULL && sizeMap==NULL)
+	val=json_object_new_string(cursor->value);
+      else{
+	if(length==NULL && sizeMap!=NULL){
+	  if(strncasecmp(cursor->name,"value",5)==0)
+	    val=json_object_new_string_len(cursor->value,atoi(sizeMap->value));
+	  else
+	    val=json_object_new_string(cursor->value);
+	}
+	else{
+	  // In other case we should consider array with potential sizes
+	  int limit=atoi(length->value);
+	  int i=0;
+	  val=json_object_new_array();
+	  for(i=0;i<limit;i++){
+	    map* lsizeMap=getMapArray(myMap,"size",i);
+	    if(lsizeMap!=NULL && strncasecmp(cursor->name,"value",5)==0){
+	      json_object_array_add(val,json_object_new_string_len(cursor->value,atoi(sizeMap->value)));
+	    }else{
+	      json_object_array_add(val,json_object_new_string(cursor->value));
+	    }
+	  }
+	}
+      }
+      if(val!=NULL)
+	json_object_object_add(res,cursor->name,val);
+      cursor=cursor->next;
+    }
+    return res;
+  }
+
+  json_object* mapsToJson(maps* myMap){
+    json_object *res=json_object_new_object();
+    maps* cursor=myMap;
+    while(cursor!=NULL){
+      json_object *obj=NULL;
+      if(cursor->content!=NULL){
+	//json_object *content=NULL;
+	obj=mapToJson(cursor->content);
+	//json_object_object_add(obj,"content",content);
+      }else
+	obj=json_object_new_object();
+      if(cursor->child!=NULL){
+	json_object *child=NULL;
+	child=mapsToJson(cursor->child);
+	json_object_object_add(obj,"child",child);
+      }
+      json_object_object_add(res,cursor->name,obj);
+      cursor=cursor->next;
+    }
+    return res;
+  }
+
+  json_object* elementsToJson(elements* myElements){
+    json_object *res=json_object_new_object();
+    elements* cur=myElements;
+    while(cur!=NULL){
+      json_object *cres=json_object_new_object();
+      json_object_object_add(cres,"content",mapToJson(cur->content));
+      json_object_object_add(cres,"metadata",mapToJson(cur->metadata));
+      json_object_object_add(cres,"additional_parameters",mapToJson(cur->additional_parameters));
+      if(cur->format!=NULL){
+	json_object_object_add(cres,"format",json_object_new_string(cur->format));
+      }
+      if(cur->child==NULL){
+	if(cur->defaults!=NULL)
+	  json_object_object_add(cres,"defaults",mapToJson(cur->defaults->content));
+	else
+	  json_object_object_add(cres,"defaults",mapToJson(NULL));
+	iotype* scur=cur->supported;
+	json_object *resi=json_object_new_array();
+	while(scur!=NULL){
+	  json_object_array_add(resi,mapToJson(scur->content));
+	  scur=scur->next;
+	}
+	json_object_object_add(cres,"supported",resi);
+	fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+	fflush(stderr);
+      }
+      
+      dumpElements(cur->child);
+      json_object_object_add(cres,"child",elementsToJson(cur->child));
+      fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+      fflush(stderr);
+
+      json_object_object_add(res,cur->name,cres);
+      cur=cur->next;
+    }
+    return res;
+  }
+  
+  json_object* serviceToJson(service* myService){
+    json_object *res=json_object_new_object();
+    json_object_object_add(res,"name",json_object_new_string(myService->name));
+    json_object_object_add(res,"content",mapToJson(myService->content));
+    json_object_object_add(res,"metadata",mapToJson(myService->metadata));
+    json_object_object_add(res,"additional_parameters",mapToJson(myService->additional_parameters));
+    json_object_object_add(res,"inputs",elementsToJson(myService->inputs));
+    json_object_object_add(res,"outputs",elementsToJson(myService->outputs));
+    return res;
+  }
+  
+  
+#ifdef __cplusplus
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_json.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_json.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_json.h	(revision 942)
@@ -0,0 +1,44 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2014 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_JSON_H
+#define ZOO_JSON_H 1
+
+#pragma once
+
+#include <stdio.h>
+#include <ctype.h>
+#include <service.h>
+#include <json_object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  json_object* mapToJson(map*);
+  json_object* mapsToJson(maps*);
+  json_object* serviceToJson(service*);
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_loader.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_loader.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_loader.c	(revision 942)
@@ -0,0 +1,272 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2009-2010 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Environment variables definitions.
+ * All the following fixed values should be extracted from a configuration main
+ * configuration file for all the potential services.
+ */
+/**
+ * END "Environment variables definitions"
+ */
+#define length(x) (sizeof(x) / sizeof(x[0]))
+
+extern "C" int yylex();
+extern "C" int crlex();
+
+#include <string.h>
+
+#include "service.h"
+#include "service_internal.h"
+#include "service_internal_python.h"
+
+#include <dirent.h>
+#include <signal.h>
+#include <unistd.h>
+#ifndef WIN32
+#include <dlfcn.h>
+#include <libgen.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <stdarg.h>
+
+void sigint_handler(int sig){
+    printf("Not this time!\n");
+}
+
+int main(int argc, char *argv[])
+{
+  if (argc < 4){
+    printf( "Usage: %s <servicename> <directory>|<definition_file> <REQUEST> [<functionname> <param_1>[...<param_n>]]\n", basename(argv[0]) );
+    return 1;
+  }
+ 
+  map* outputs=NULL;
+  /**
+   * Parsing inputs (need a loop over all files in the service path !!)
+   */
+  maps* m;
+  m=(maps*)malloc(MAP_SIZE);
+  conf_read("main.cfg",m);
+  map* tmpm=getMapFromMaps(m,"main","serverAddress");
+  int toto=count(tmpm);
+  //printf(" - %i \n",toto);
+
+  if(tmpm!=NULL)
+    SERVICE_URL=strdup(tmpm->value);
+  else
+    SERVICE_URL=DEFAULT_SERVICE_URL;
+
+  service* s[100];
+  service* s1;
+  int scount=0;
+
+  if(strcmp(argv[3],"GetCapabilities")==0){
+    int i=0;
+    struct dirent *dp;
+    DIR *dirp = opendir(argv[1]);
+    int t;
+    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
+    xmlNodePtr n = printGetCapabilitiesHeader(doc,argv[2],m);
+    
+    int saved_stdout = dup(fileno(stdout));
+    stdout = freopen("/dev/null" , "w" , stdout);
+    while ((dp = readdir(dirp)) != NULL)
+      if(strstr(dp->d_name,".zcfg")!=0){
+	char toto1[1024];
+	sprintf(toto1,"%s%s",argv[1],dp->d_name);
+	char *toto=toto1;
+	s1=(service*)malloc(sizeof(char*)+(MAP_SIZE*2)+(2*ELEMENTS_SIZE));
+	//s[scount]=(service*)malloc(sizeof(service*));
+	//#ifdef DEBUG
+	fprintf(stderr,"#################\n%s\n#################\n",toto1);
+	//printf("|(1)");
+	//#endif
+	t=getServiceFromFile(toto1,&s1);
+	
+	//printf("|(2)");
+	printGetCapabilitiesForProcess(m,n,s1);
+	/**
+	 * Valgrind told us that there is an issue regarding a 
+	 * "conditional jump or move depends on uninitialised value(s)" for
+	 * freeIOType
+	 */
+	//freeService(&s1);
+	scount++;
+      }
+    char buf[20];
+    sprintf(buf, "/dev/fd/%d", saved_stdout);
+    stdout = freopen(buf , "w" , stdout);
+
+    printDocument(doc);
+    fflush(stdout);
+    free(m);
+    return 0;
+  }
+  else{
+    s1=(service*)malloc(sizeof(char*)+(MAP_SIZE*2)+(2*ELEMENTS_SIZE));
+    //s[0]=(service*)malloc(sizeof(service*));
+    int t=getServiceFromFile(argv[1],&s1);
+    if(strcmp(argv[3],"DescribeProcess")==0){
+      printDescribeProcessResponse(s1,argv[2]);
+      //dumpMaps(m);
+      //free(s1);
+      return 0;
+    }
+    else
+      if(strcmp(argv[3],"Execute")!=0){
+	fprintf(stderr,"");
+	//free(s);
+	return 0;
+      }
+  }
+  //dumpService(s);
+  s[0]=s1;
+  map* inputs=NULL;
+  elements* c_inputs=s1->inputs;
+  int j;
+  for(j=0;j<argc-5;j++){
+    //dumpElements(c_inputs);
+    if(inputs!=NULL)
+      addToMap(inputs,c_inputs->name,argv[j+5]);
+    else
+      inputs=createMap(c_inputs->name,argv[j+5]);
+    if(c_inputs->next!=NULL || j+1>=argc-5)
+      c_inputs=c_inputs->next;
+    else{
+      map* tmps=createMap("text","ERROR you provided more inputs than requested.");
+      printExceptionReportResponse(m,tmps);
+      //printf("ERROR you provided more inputs than requested.");
+      return -1;
+    }
+#ifdef DEBUG
+    printf("ARGV1 %d %s\n",j,inputs->value);
+#endif
+  }
+
+#ifdef DEBUG
+  dumpMap(inputs);
+#endif
+
+  const struct tm *tm;
+  size_t len;
+  time_t now;
+  char *sDate;
+  
+  now = time ( NULL );
+  tm = localtime ( &now );
+
+  sDate = new char[TIME_SIZE];
+
+  len = strftime ( sDate, TIME_SIZE, "%d-%B-%YT%I:%M:%SZ", tm );
+
+#ifdef DEBUG
+  printf("Trying to load %s\n", argv[2]);
+#endif
+  void* so = dlopen(argv[2], RTLD_LAZY);
+  char *errstr;
+  errstr = dlerror();
+  if( so != NULL ) {
+    typedef int (*execute_t)(map**,map**);
+#ifdef DEBUG
+    printf("Library loaded %s \n",errstr);
+#endif
+    execute_t execute=(execute_t)dlsym(so,argv[4]);
+#ifdef DEBUG
+    errstr = dlerror();
+    printf("Function loaded %s\n",errstr);
+#endif	
+
+    /**
+     * Need to check if we need to fork to load a status enabled 
+     */
+    char _toto[10];
+    sprintf(_toto,"input_%i",argc-5);
+    map* toto=getMap(inputs,_toto);
+    if(strcmp(argv[argc-1],"bg")!=0){
+#ifdef DEBUG
+      printf("RUN IN NORMAL MODE \n");
+#endif
+      int res=execute(&inputs,&outputs);
+#ifdef DEBUG
+      printf("RUNNED IN NORMAL MODE \n");
+      dumpMap(inputs);
+      dumpMap(outputs);
+#endif
+      printProcessResponse(m,getpid(),s[0],argv[2],res,inputs,outputs);
+    }
+    else{
+      pid_t   pid;
+      int cpid=getpid();
+      pid = fork ();
+      if (pid > 0) {
+	/**
+	 * dady :
+	 * set status to SERVICE_ACCEPTED
+	 */
+	printProcessResponse(m,pid,s[0],argv[2],SERVICE_ACCEPTED,inputs,outputs);
+      }else if (pid == 0) {
+	/* son */
+	if (signal(SIGINT, sigint_handler) == SIG_ERR) {
+	  printf("signal");
+	  map* tmps=createMap("text","father received sigint.");
+	  printExceptionReportResponse(m,tmps);
+	  exit(1);
+	}
+#ifdef DEBUG
+	printf("RUN IN BACKGROUND MODE \n");
+#endif
+	char tmp1[256];
+	sprintf(tmp1,"service/temp/%s_%d.xml",argv[2],getpid());
+	stdout = freopen(tmp1 , "w+" , stdout);
+	/**
+	 * set status to SERVICE_STARTED
+	 */
+	printProcessResponse(m,getpid(),s[0],argv[2],SERVICE_STARTED,inputs,outputs);
+	fflush(stdout);
+	rewind(stdout);
+	int t=execute(&inputs,&outputs);
+	/**
+	 * set status to status code returned by the service function
+	 */
+	printProcessResponse(m,getpid(),s[0],argv[2],t,inputs,outputs);
+      } else {
+	/* error */
+      }
+    }
+#ifdef DEBUG
+    errstr = dlerror();
+    printf("Function successfully loaded %s, unloading now.\n",errstr);
+#endif
+    dlclose(so);
+  }
+  else {
+#ifdef DEBUG
+    printf("C Library can't be loaded %s \n",errstr);
+#endif
+    python_support(m,s[0],argc,argv,inputs,outputs);
+  }
+  return 0;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/service_yaml.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/service_yaml.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/service_yaml.c	(revision 942)
@@ -0,0 +1,612 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2014 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <service.h>
+#include <yaml.h>
+
+static service* my_service=NULL;
+static map* current_content=NULL;
+static elements* current_element=NULL;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Read and parse a ZCFG file in YAML format 
+ *
+ * @param conf the conf maps containing the main.cfg settings
+ * @param file the file name to read
+ * @param service the service structure to fill
+ * @param name the service name
+ * @return 1 on success, -1 if error occurred
+ */
+int getServiceFromYAML(maps* conf, char* file,service** service,char *name){
+  FILE *fh;
+  if(current_content!=NULL){
+    freeMap(&current_content);
+    free(current_content);
+    current_content=NULL;
+  }
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"(STARTING)FREE current_element\n");
+#endif
+  if(current_element!=NULL){
+    freeElements(&current_element);
+    free(current_element);
+    current_element=NULL;
+  }
+  my_service=NULL;
+  
+  my_service=*service;
+  my_service->name=strdup(name);
+  my_service->content=NULL;
+  my_service->metadata=NULL;
+  my_service->inputs=NULL;
+  my_service->outputs=NULL;
+  fh = fopen(file,"r");
+  if (fh==NULL){
+    fprintf(stderr,"error : file not found\n") ;
+    return -1;
+  }
+  yaml_parser_t parser;
+  yaml_token_t  token;   /* new variable */
+
+  /* Initialize parser */
+  if(!yaml_parser_initialize(&parser))
+    fputs("Failed to initialize parser!\n", stderr);
+  if(fh == NULL)
+    fputs("Failed to open file!\n", stderr);
+  /* Set input file */
+  yaml_parser_set_input_file(&parser, fh);
+  /* BEGIN new code */
+  int nleveld=-1;
+  int level=0;
+  int plevel=level;
+  int nlevel=0;
+  int pnlevel=0;
+  int ilevel=-1;
+  int blevel=-1;
+  int ttype=0;
+  int outputs=-1;
+  int noutputs=-1;
+  int wait_metadata=-1;
+  char *cur_key;
+  do {
+    yaml_parser_scan(&parser, &token);
+    switch(token.type)
+    {
+    /* Stream start/end */
+    case YAML_STREAM_START_TOKEN: 
+#ifdef DEBUG_YAML
+      puts("STREAM START"); 
+#endif
+      break;
+    case YAML_STREAM_END_TOKEN:   
+#ifdef DEBUG_YAML
+      puts("STREAM END");   
+#endif
+      break;
+    /* Token types (read before actual token) */
+    case YAML_KEY_TOKEN:   
+#ifdef DEBUG_YAML
+      printf("(Key token)   "); 
+#endif
+      ttype=0;
+      break;
+    case YAML_VALUE_TOKEN: 
+#ifdef DEBUG_YAML
+      printf("(Value token) "); 
+#endif
+      ttype=1;
+      break;
+    /* Block delimeters */
+    case YAML_BLOCK_SEQUENCE_START_TOKEN: 
+#ifdef DEBUG_YAML
+      puts("<b>Start Block (Sequence)</b>"); 
+#endif
+      break;
+    case YAML_BLOCK_ENTRY_TOKEN:          
+#ifdef DEBUG_YAML
+      puts("<b>Start Block (Entry)</b>");    
+#endif
+      break;
+    case YAML_BLOCK_END_TOKEN:      
+      blevel--;
+      if(ilevel>=0)
+	ilevel--;
+#ifdef DEBUG_YAML
+      printf("<b>End block</b> (%d,%d,%d,%d)\n", blevel,level,ilevel,ttype); 
+#endif
+      break;
+    /* Data */
+    case YAML_BLOCK_MAPPING_START_TOKEN:  
+#ifdef DEBUG_YAML
+      puts("[Block mapping]");            
+#endif
+      blevel++;
+      break;
+    case YAML_SCALAR_TOKEN:
+      if((blevel-1)/2<nlevel){
+	pnlevel=nlevel;
+	nlevel=(blevel-1)/2;
+	nleveld=1;
+      }else
+	nleveld=-1;
+      if(ttype==0){
+	cur_key=zStrdup((char *)token.data.scalar.value);
+      }
+      if(ttype==1){
+	if(current_content==NULL){
+	  current_content=createMap(cur_key,(char *)token.data.scalar.value);
+	}else{
+	  addToMap(current_content,cur_key,(char *)token.data.scalar.value);
+	}
+	free(cur_key);
+	cur_key=NULL;
+      }
+
+      if(ttype==0 && blevel==0 && level==0 && strcasecmp((char *)token.data.scalar.value,"MetaData")==0 && blevel==0){
+	addMapToMap(&my_service->content,current_content);
+#ifdef DEBUG_YAML
+	fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	freeMap(&current_content);
+	free(current_content);
+	current_content=NULL;
+	wait_metadata=1;
+      }
+      if(ttype==0 && blevel>0 && level>0 && strcasecmp((char *)token.data.scalar.value,"MetaData")==0){
+	if(current_element->content==NULL && current_content!=NULL)
+	  addMapToMap(&current_element->content,current_content);
+#ifdef DEBUG_YAML
+	dumpMap(current_content);
+	fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	freeMap(&current_content);
+	free(current_content);
+	current_content=NULL;
+	wait_metadata=1;
+      }
+      if(strcasecmp((char *)token.data.scalar.value,"Child")==0){
+	elements* cursor=my_service->inputs;
+	if(outputs==1)
+	  cursor=my_service->outputs;
+	for(int i=0;(blevel/2)>1 && i<(blevel/2)-1 && cursor!=NULL;i++){
+	  while(cursor->next!=NULL)
+	    cursor=cursor->next;
+	  if(cursor->child!=NULL){
+	    cursor=cursor->child;
+	  }
+	}
+	if(current_content!=NULL){
+	  addMapToMap(&current_element->content,current_content);
+	  freeMap(&current_content);
+	  free(current_content);
+	  current_content=NULL;
+	}
+	if(current_element!=NULL){
+	  if(blevel/2>1 && cursor!=NULL){
+	    if(cursor->child==NULL)
+	      cursor->child=dupElements(current_element);
+	    else
+	      addToElements(&cursor->child,current_element);
+	  }
+	  else{
+	    if(outputs<0)
+	      if(my_service->inputs==NULL)
+		my_service->inputs=dupElements(current_element);
+	      else
+		addToElements(&my_service->inputs,current_element);
+	    else
+	      if(my_service->inputs==NULL)
+		my_service->outputs=dupElements(current_element);
+	      else
+		addToElements(&my_service->outputs,current_element);
+	  }
+	  freeElements(&current_element);
+	  free(current_element);
+	  current_element=NULL;
+	}
+	nlevel+=1;
+      }
+      if(ttype==0 && strcasecmp((char *)token.data.scalar.value,"inputs")==0 && blevel==0){
+	if(wait_metadata>0){
+	  addMapToMap(&my_service->metadata,current_content);
+	  wait_metadata=-1;
+	}else{
+	  if(current_content!=NULL && my_service->content==NULL)
+	    addMapToMap(&my_service->content,current_content);
+	}
+#ifdef DEBUG_YAML
+	dumpMap(current_content);
+	fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	freeMap(&current_content);
+	free(current_content);
+	current_content=NULL;
+	wait_metadata=false;
+	level++;
+      }
+      if(ttype==0 && strcasecmp((char *)token.data.scalar.value,"outputs")==0 && blevel==1){
+	outputs=1;
+	level++;
+#ifdef DEBUG_YAML
+	dumpMap(current_content);
+	printf("\n***\n%d (%d,%d,%d,%d)\n+++\n", current_element->defaults==NULL,blevel,level,ilevel,ttype); 
+#endif
+	if(current_element->defaults==NULL && current_content!=NULL && ilevel<0){
+	  current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+	  current_element->defaults->content=NULL;
+	  current_element->defaults->next=NULL;
+	  addMapToMap(&current_element->defaults->content,current_content);
+#ifdef DEBUG_YAML
+	  dumpElements(current_element);
+	  dumpMap(current_content);
+	  fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	  freeMap(&current_content);
+	  free(current_content);
+	  current_content=NULL;
+	}else{
+	  if(current_content!=NULL && ilevel<=0){
+	    addMapToIoType(&current_element->supported,current_content);
+#ifdef DEBUG_YAML
+	    dumpElements(current_element);
+	    dumpMap(current_content);
+	    fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	    freeMap(&current_content);
+	    free(current_content);
+	    current_content=NULL;
+	  }
+	}
+      }
+      if(level==1 && strcasecmp((char *)token.data.scalar.value,"default")==0){
+	ilevel=0;
+      }
+      if(level==1 && strcasecmp((char *)token.data.scalar.value,"supported")==0){
+#ifdef DEBUG_YAML
+	dumpMap(current_content);
+	printf("\n***\n%d (%d,%d,%d,%d)\n+++\n", current_element->defaults==NULL,blevel,level,ilevel,ttype); 
+#endif
+	if(current_element->defaults==NULL && current_content!=NULL && ilevel<0){
+	  current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+	  current_element->defaults->content=NULL;
+	  current_element->defaults->next=NULL;
+	  addMapToMap(&current_element->defaults->content,current_content);
+#ifdef DEBUG_YAML
+	  dumpElements(current_element);
+	  dumpMap(current_content);
+	  fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	  freeMap(&current_content);
+	  free(current_content);
+	  current_content=NULL;
+	}else{
+	  if(current_content!=NULL && ilevel<=0){
+	    if(current_element->supported==NULL){
+	      current_element->supported=(iotype*)malloc(IOTYPE_SIZE);
+	      current_element->supported->content=NULL;
+	      current_element->supported->next=NULL;
+	    }
+	    addMapToMap(&current_element->supported->content,current_content);
+#ifdef DEBUG_YAML
+	    dumpElements(current_element);
+	    fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	    freeMap(&current_content);
+	    free(current_content);
+	    current_content=NULL;
+	  }
+	}
+	ilevel=1;
+      }
+
+
+      if(strncasecmp((char *)token.data.scalar.value,"ComplexData",11)==0 || 
+	 strncasecmp((char *)token.data.scalar.value,"LiteralData",10)==0 || 
+	 strncasecmp((char *)token.data.scalar.value,"ComplexOutput",13)==0 || 
+	 strncasecmp((char *)token.data.scalar.value,"LiteralOutput",12)==0 || 
+	 strncasecmp((char *)token.data.scalar.value,"BoundingBoxOutput",13)==0 || 
+	 strncasecmp((char *)token.data.scalar.value,"BoundingBoxData",12)==0){
+	current_element->format=zStrdup((char *)token.data.scalar.value);
+	free(cur_key);
+	cur_key=NULL;
+	if(wait_metadata>0 && current_content!=NULL){
+	  addMapToMap(&current_element->metadata,current_content);
+	  wait_metadata=-1;
+	}else{
+	  if(current_content!=NULL){
+	    addMapToMap(&current_element->content,current_content);
+	  }
+	}
+#ifdef DEBUG_YAML
+	dumpMap(current_content);
+	fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+	freeMap(&current_content);
+	free(current_content);
+	current_content=NULL;
+#ifdef DEBUG_YAML
+	dumpElements(current_element);
+#endif
+      }
+
+      if(strcasecmp(token.data.scalar.value,"default")!=0 && strcasecmp(token.data.scalar.value,"supported")!=0 && level==1 && (blevel-1)%2==0 && blevel!=1 && (blevel-1)/2==nlevel){
+	if(current_element==NULL)
+	  current_element=createElements((char *)token.data.scalar.value);
+	else{
+	  if(current_content!=NULL){
+	    if(current_element->defaults==NULL){
+	      current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+	      current_element->defaults->content=NULL;
+	      current_element->defaults->next=NULL;
+	      addMapToMap(&current_element->defaults->content,current_content);
+	    }else{
+	      if(current_element->supported==NULL){
+		current_element->supported=(iotype*)malloc(IOTYPE_SIZE);
+		current_element->supported->content=NULL;
+		current_element->supported->next=NULL;
+		addMapToMap(&current_element->supported->content,current_content);
+	      }else
+		addMapToIoType(&current_element->supported,current_content);
+	    }
+	    freeMap(&current_content);
+	    free(current_content);
+	    current_content=NULL;
+	  }
+	  
+	  elements* cursor=my_service->inputs;
+	  if(outputs==1)
+	    cursor=my_service->outputs;
+	  int llevel=((blevel-1)/2);
+	  if(nleveld>0)
+	    llevel=((blevel-1)/2)+1;
+	  for(int i=0;llevel>1 && i<llevel-1 && cursor!=NULL;i++){
+	    while(cursor->next!=NULL)
+	      cursor=cursor->next;
+	    if(cursor->child!=NULL){
+	      cursor=cursor->child;
+	    }
+	  }
+	  if(llevel>1)
+	    if(cursor->child==NULL)
+	      cursor->child=dupElements(current_element);
+	    else
+	      addToElements(&cursor->child,current_element);
+	  else
+	    if(cursor==NULL)
+	      cursor=dupElements(current_element);
+	    else
+	      addToElements(&cursor,current_element);
+	  freeElements(&current_element);
+	  free(current_element);
+	  current_element=NULL;
+	  current_element=createElements((char *)token.data.scalar.value);
+	}
+      }
+      if(blevel==1 && level==1){
+	if(current_element!=NULL && current_content!=NULL){
+	  if(current_element->defaults==NULL){
+	    current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+	    current_element->defaults->content=NULL;
+	    current_element->defaults->next=NULL;
+	    addMapToMap(&current_element->defaults->content,current_content);
+	  }else{
+	    if(current_element->supported==NULL){
+	      current_element->supported=(iotype*)malloc(IOTYPE_SIZE);
+	      current_element->supported->content=NULL;
+	      current_element->supported->next=NULL;
+	      addMapToMap(&current_element->supported->content,current_content);
+	    }else
+	      addMapToIoType(&current_element->supported,current_content);
+	  }
+	  freeMap(&current_content);
+	  free(current_content);
+	  current_content=NULL;
+	}
+	if(nleveld<0){
+	  if(current_element!=NULL){
+	    if(outputs<0)
+	      if(my_service->inputs==NULL)
+		my_service->inputs=dupElements(current_element);
+	      else
+		addToElements(&my_service->inputs,current_element);
+	    else
+	      if(my_service->outputs==NULL)
+		my_service->outputs=dupElements(current_element);
+	      else
+		addToElements(&my_service->outputs,current_element);
+	    freeElements(&current_element);
+	    free(current_element);
+	  }
+	}
+	else{
+	  if(current_element!=NULL){
+	    elements* cursor=my_service->inputs;
+	    if(outputs==1)
+	      cursor=my_service->outputs;
+	    while(cursor->next!=NULL)
+	      cursor=cursor->next;
+	    for(int i=0;pnlevel>1 && i<pnlevel-1 && cursor!=NULL;i++){
+	      while(cursor->next!=NULL)
+		cursor=cursor->next;
+	      if(cursor->child!=NULL){
+		cursor=cursor->child;
+	      }
+	    }
+	    if(cursor->child==NULL)
+	      cursor->child=dupElements(current_element);
+	    else
+	      addToElements(&cursor->child,current_element);
+	    freeElements(&current_element);
+	    free(current_element);
+	  }
+	}   
+	plevel=level;
+	current_element=createElements((char *)token.data.scalar.value);	
+      }
+      if(blevel==1 && level==2){
+	if(current_element!=NULL && current_content!=NULL){
+	  if(current_element->defaults==NULL){
+	    current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+	    current_element->defaults->content=NULL;
+	    current_element->defaults->next=NULL;
+	    addMapToMap(&current_element->defaults->content,current_content);
+	  }else{
+	    if(current_element->supported==NULL){
+	      current_element->supported=(iotype*)malloc(IOTYPE_SIZE);
+	      current_element->supported->content=NULL;
+	      current_element->supported->next=NULL;
+	      addMapToMap(&current_element->supported->content,current_content);
+	    }else
+	      addMapToIoType(&current_element->supported,current_content);
+	  }
+	  freeMap(&current_content);
+	  free(current_content);
+	  current_content=NULL;
+	}
+	if(current_element!=NULL){
+	  if(plevel==level){
+	    if(my_service->outputs==NULL)
+	      my_service->outputs=dupElements(current_element);
+	    else
+	      addToElements(&my_service->outputs,current_element);
+	  }else{
+	    if(my_service->inputs==NULL)
+	      my_service->inputs=dupElements(current_element);
+	    else
+	      addToElements(&my_service->inputs,current_element);
+	  }
+	  freeElements(&current_element);
+	  free(current_element);
+	}
+	plevel=level;
+	current_element=createElements((char *)token.data.scalar.value);	
+	
+      }
+
+      if(noutputs>0)
+	outputs=1;
+      if(strcasecmp((char *)token.data.scalar.value,"outputs")==0 && ttype==0 && blevel==0){
+	noutputs=1;
+      }
+      
+
+
+#ifdef DEBUG_YAML
+      printf("scalar %s (%d,%d,%d,%d,%d)\n", token.data.scalar.value,blevel,level,plevel,ilevel,ttype); 
+#endif
+      break;
+    /* Others */
+    default:
+      if(token.type==0){
+	char tmp[1024];
+	sprintf(tmp,"Wrong charater found in %s: \\t",name);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return -1;
+      }
+#ifdef DEBUG_YAML
+      printf("Got token of type %d\n", token.type);
+#endif
+      break;
+    }
+    if(token.type != YAML_STREAM_END_TOKEN )
+      yaml_token_delete(&token);
+  } while(token.type != YAML_STREAM_END_TOKEN);
+  yaml_token_delete(&token);
+
+
+#ifdef DEBUG_YAML
+  fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+  if(current_element!=NULL && current_content!=NULL){
+    if(current_element->defaults==NULL){
+      current_element->defaults=(iotype*)malloc(IOTYPE_SIZE);
+      current_element->defaults->content=NULL;
+      current_element->defaults->next=NULL;
+      addMapToMap(&current_element->defaults->content,current_content);
+    }else{
+      if(current_element->supported==NULL){
+	current_element->supported=(iotype*)malloc(IOTYPE_SIZE);
+	current_element->supported->content=NULL;
+	current_element->supported->next=NULL;
+	addMapToMap(&current_element->supported->content,current_content);
+      }else
+	addMapToIoType(&current_element->supported,current_content);
+    }
+#ifdef DEBUG_YAML
+    dumpMap(current_content);
+    fprintf(stderr,"MSG: %s %d \n",__FILE__,__LINE__);
+#endif
+    freeMap(&current_content);
+    free(current_content);
+    current_content=NULL;
+  }
+
+  if(current_element!=NULL){
+    if(nlevel>0){
+      elements* cursor=my_service->inputs;
+      if(outputs==1)
+	cursor=my_service->outputs;
+      for(int i=0;nlevel>1 && i<nlevel-1 && cursor!=NULL;i++){
+	while(cursor->next!=NULL)
+	  cursor=cursor->next;
+	if(cursor->child!=NULL){
+	  cursor=cursor->child;
+	}
+      }
+      if(cursor->child==NULL)
+	cursor->child=dupElements(current_element);
+      else
+	addToElements(&cursor->child,current_element);
+    }else{
+      if(my_service->outputs==NULL)
+	my_service->outputs=dupElements(current_element);
+      else
+	addToElements(&my_service->outputs,current_element);
+    }
+    freeElements(&current_element);
+    free(current_element);
+    current_element=NULL;
+  }
+  /* END new code */
+
+  /* Cleanup */
+  yaml_parser_delete(&parser);
+  fclose(fh);
+
+#ifdef DEBUG_YAML
+  dumpService(my_service);
+#endif
+  *service=my_service;
+
+  return 1;
+}
+#ifdef __cplusplus
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/sql/schema.sql
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/sql/schema.sql	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/sql/schema.sql	(revision 942)
@@ -0,0 +1,69 @@
+--------------------------------------------------------------------------------
+--
+-- PostgreSQL definition of tables required byt the ZOO-Kernel version >= 1.5.0
+-- if the the db-backend option is activated
+--
+-- Copyright (C) 2015 GeoLabs SARL. All rights reserved.
+-- Author: David Saggiorato <david.saggiorato@geolabs.fr>
+--
+-- Permission is hereby granted, free of charge, to any person obtaining a copy
+-- of this software and associated documentation files (the "Software"), to deal
+-- in the Software without restriction, including without limitation the rights
+-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+-- copies of the Software, and to permit persons to whom the Software is
+-- furnished to do so, subject to the following conditions:
+--
+-- The above copyright notice and this permission notice shall be included in
+-- all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+-- THE SOFTWARE.
+--
+-------------------------------------------------------------------------------- 
+-- If your database is not using UTF-8 per default then uncomment the following 
+-- SET client_encoding = 'UTF8';
+-------------------------------------------------------------------------------- 
+-- Create a dedicated schema to store all tables
+-- Uncomment the following 2 lines to activate the schema use
+-- CREATE SCHEMA processdb;
+-- SET search_path TO processdb;
+--------------------------------------------------------------------------------
+-- Services table
+-- Used to store information about services running asynchronously
+create table services (
+       osid TEXT unique,
+       sid TEXT unique,
+       uuid TEXT unique,
+       fstate varchar(25),
+       status TEXT,
+       response TEXT,
+       creation_time timestamp with time zone default now(),
+       end_time timestamp with time zone default NULL,
+       progress int,
+       message TEXT
+);
+--------------------------------------------------------------------------------
+-- Responses table 
+-- Used to store the response provided by a services running asynchronously
+create table responses (
+       uuid text references services(uuid) ON DELETE CASCADE,
+       content text,
+       creation_time timestamp with time zone default now()
+);
+--------------------------------------------------------------------------------
+-- Files table
+-- Used to store the files generated during the service execution
+create table files (
+       uuid TEXT references services(uuid) ON DELETE CASCADE,
+       filename text,
+       nature varchar(10),
+       name varchar(255),
+       creation_time timestamp with time zone default now(),
+       expiration_time timestamp with time zone default now() + interval '48 hours'
+);
+--------------------------------------------------------------------------------
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/sql/zoo_collectiondb.sql
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/sql/zoo_collectiondb.sql	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/sql/zoo_collectiondb.sql	(revision 942)
@@ -0,0 +1,321 @@
+create schema CollectionDB;
+
+set search_path = CollectionDB, pg_catalog;
+
+CREATE OR REPLACE FUNCTION update_Description() RETURNS trigger AS 
+$$
+DECLARE
+	i integer;
+BEGIN
+	INSERT INTO CollectionDB.Descriptions (id) VALUES (NEW.id);
+	RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION is_in_ows_DataDescription(i integer) RETURNS boolean
+    LANGUAGE plpgsql
+    AS $$
+DECLARE
+        res int;
+        mymax int;
+BEGIN
+	SELECT id from CollectionDB.ows_DataDescription where id=i INTO res ;
+	if res is NULL then
+	   return false;
+	else
+	   return true;
+	end if;
+END;
+$$;
+
+create table CollectionDB.Descriptions (
+       id serial primary key
+);
+
+create table CollectionDB.ows_Metadata (
+       id serial primary key,
+       title text,
+       role text,
+       href text
+);
+
+create table CollectionDB.DescriptionsMetadataAssignment(
+       descriptions_id int references CollectionDB.Descriptions(id),
+       metadata_id int references CollectionDB.ows_Metadata(id)
+);
+
+create table CollectionDB.ows_Keywords (
+    id serial primary key,
+    keyword varchar
+);
+
+create table CollectionDB.DescriptionsKeywordsAssignment(
+       descriptions_id int references CollectionDB.Descriptions(id),
+       keywords_id int references CollectionDB.ows_Keywords(id)
+);
+
+create table CollectionDB.ows_AdditionalParameters (
+    id serial primary key,
+    title varchar,
+    role varchar,
+    href varchar
+);
+
+create table CollectionDB.DescriptionsAdditionalParametersAssignment (
+       descriptions_id int references CollectionDB.Descriptions(id),
+       additional_parameters_id int references CollectionDB.ows_AdditionalParameters(id)
+);
+
+--
+-- See reference for primitive datatypes
+-- https://www.w3.org/TR/xmlschema-2/#built-in-primitive-datatypes
+-- 
+create table CollectionDB.PrimitiveDataTypes (
+       id serial primary key,
+       name varchar(255)
+);
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('string');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('boolean');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('integer');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('float');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('double');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('duration');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('dateTime');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('time');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('date');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gYearMonth');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gYear');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gMonthDay');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gDay');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('gMonth');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('hexBinary');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('base64Binary');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('anyURI');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('QName');
+INSERT INTO CollectionDB.PrimitiveDataTypes (name) VALUES ('NOTATION');
+
+--
+-- List all primitive formats
+--
+create table CollectionDB.PrimitiveFormats (
+       id serial primary key,
+       mime_type varchar(255),
+       encoding varchar(15),
+       schema varchar(255)
+);
+
+-- https://tools.ietf.org/html/rfc4180
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/csv','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/css','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/html','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/javascript','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('text/plain','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding,schema)
+       VALUES ('text/xml','utf-8','http://schema.opengis.net/gml/3.2.1/gml.xsd');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding,schema)
+       VALUES ('text/xml','utf-8','http://schema.opengis.net/gml/3.1.0/gml.xsd');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('application/gml+xml','utf-8');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('application/json','utf-8');
+-- https://tools.ietf.org/html/rfc3302
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/tiff');
+-- https://www.ietf.org/rfc/rfc4047.txt
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/fits');
+-- https://tools.ietf.org/html/rfc3745
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/jp2');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/png');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/jpeg');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('image/gif');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('application/octet-stream');
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('application/vnd.google-earth.kml+xml');
+-- https://www.iana.org/assignments/media-types/application/zip
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type) VALUES ('application/zip');
+-- https://www.iana.org/assignments/media-types/application/xml
+INSERT INTO CollectionDB.PrimitiveFormats (mime_type,encoding) VALUES ('application/xml','utf-8');
+
+create table CollectionDB.ows_Format (
+    id serial primary key,
+    primitive_format_id int references CollectionDB.PrimitiveFormats(id),
+    maximum_megabytes int,
+    def boolean,
+	use_mapserver bool,
+	ms_styles text
+);
+
+create table CollectionDB.ows_DataDescription (
+    id serial primary key,
+    format_id int references CollectionDB.ows_Format(id)
+);
+
+create table CollectionDB.PrimitiveUom (
+	id serial primary key,
+	uom varchar
+);
+-- source : Open Geospatial Consortium - URNs of definitions in ogc namespace
+insert into CollectionDB.PrimitiveUom (uom) values ('degree');
+insert into CollectionDB.PrimitiveUom (uom) values ('radian');
+insert into CollectionDB.PrimitiveUom (uom) values ('metre');
+insert into CollectionDB.PrimitiveUom (uom) values ('unity');
+
+create table CollectionDB.LiteralDataDomain (
+    possible_literal_values varchar,
+    default_value varchar,
+    data_type_id int references CollectionDB.PrimitiveDataTypes(id),
+    uom int references CollectionDB.PrimitiveUom(id),
+    def boolean
+) inherits (CollectionDB.ows_DataDescription);
+alter table CollectionDB.LiteralDataDomain add constraint literal_data_domain_id unique (id);
+
+create table CollectionDB.BoundingBoxData (
+    epsg int
+) inherits (CollectionDB.ows_DataDescription);
+alter table CollectionDB.BoundingBoxData add constraint bounding_box_data_id unique (id);
+
+create table CollectionDB.ComplexData (
+) inherits (CollectionDB.ows_DataDescription);
+alter table CollectionDB.ComplexData add constraint complex_data_id unique (id);
+
+create table CollectionDB.AllowedValues (
+    id serial primary key,
+    allowed_value varchar(255)
+);
+
+create table CollectionDB.AllowedValuesAssignment (
+    id serial primary key,
+    literal_data_domain_id int references CollectionDB.LiteralDataDomain (id),
+    allowed_value_id int references CollectionDB.AllowedValues (id)
+);
+
+create table CollectionDB.ows_AdditionalParameter (
+    id serial primary key,
+    key varchar,
+    value varchar,
+    additional_parameters_id int references CollectionDB.ows_AdditionalParameters(id)
+);
+
+create table CollectionDB.ows_Input (
+    id int primary key default nextval('collectiondb.descriptions_id_seq'::regclass),
+    title text,
+    abstract text,
+    identifier varchar(255),
+    min_occurs int,
+    max_occurs int
+); -- inherits (CollectionDB.Descriptions);
+alter table CollectionDB.ows_Input add constraint codb_input_id unique (id);
+CREATE TRIGGER ows_Input_proc AFTER INSERT ON CollectionDB.ows_Input FOR EACH ROW EXECUTE PROCEDURE update_Description();
+
+create table CollectionDB.ows_Output (
+    id int primary key default nextval('collectiondb.descriptions_id_seq'::regclass),
+    title text,
+    abstract text,
+    identifier varchar(255)
+); --inherits (CollectionDB.Descriptions);
+alter table CollectionDB.ows_Output add constraint codb_output_id unique (id);
+CREATE TRIGGER ows_Output_proc AFTER INSERT ON CollectionDB.ows_Output FOR EACH ROW EXECUTE PROCEDURE update_Description();
+
+create table CollectionDB.zoo_PrivateMetadata (
+    id serial primary key,
+    identifier varchar,
+    metadata_date timestamp
+);
+
+create table CollectionDB.ows_Process (
+    id int primary key default nextval('collectiondb.descriptions_id_seq'::regclass),
+    title text,
+    abstract text,
+    identifier varchar(255),
+    availability boolean,
+    process_description_xml text,
+    private_metadata_id int references CollectionDB.zoo_PrivateMetadata(id)
+); -- inherits (CollectionDB.Descriptions);
+alter table CollectionDB.ows_Process add constraint codb_process_id unique (id);
+alter table CollectionDB.ows_Process add constraint codb_process_identifier unique (identifier);
+CREATE TRIGGER ows_Process_proc AFTER INSERT ON CollectionDB.ows_Process FOR EACH ROW EXECUTE PROCEDURE update_Description();
+
+create table CollectionDB.InputInputAssignment (
+    id serial primary key,
+    parent_input int references CollectionDB.ows_Input(id),
+    child_input int references CollectionDB.ows_Input(id)
+);
+
+create table CollectionDB.InputDataDescriptionAssignment (
+    id serial primary key,
+    input_id int references CollectionDB.ows_Input(id),
+    data_description_id int check (CollectionDB.is_in_ows_DataDescription(data_description_id))
+);
+
+create table CollectionDB.OutputOutputAssignment (
+    id serial primary key,
+    parent_output int references CollectionDB.ows_Output(id),
+    child_output int references CollectionDB.ows_Output(id)
+);
+
+create table CollectionDB.OutputDataDescriptionAssignment (
+    id serial primary key,
+    output_id int references CollectionDB.ows_Output(id),
+    data_description_id int check (CollectionDB.is_in_ows_DataDescription(data_description_id))
+);
+
+create table CollectionDB.zoo_ServiceTypes (
+	id serial primary key,
+	service_type varchar
+);
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('HPC');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('C');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('Java');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('Mono');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('JS');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('PHP');
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('Python');
+
+insert into CollectionDB.zoo_ServiceTypes (service_type) VALUES ('OTB');
+
+create table CollectionDB.zoo_DeploymentMetadata (
+    id serial primary key,
+    executable_name varchar,
+    configuration_identifier varchar,
+	service_type_id int references CollectionDB.zoo_ServiceTypes(id)
+);
+
+create table CollectionDB.zoo_PrivateProcessInfo (
+    id serial primary key
+);
+
+create table CollectionDB.PrivateMetadataDeploymentMetadataAssignment (
+    id serial primary key,
+    private_metadata_id int references CollectionDB.zoo_PrivateMetadata(id),
+    deployment_metadata_id int references CollectionDB.zoo_DeploymentMetadata(id)
+);
+
+create table CollectionDB.PrivateMetadataPrivateProcessInfoAssignment (
+    id serial primary key,
+    private_metadata_id int references CollectionDB.zoo_PrivateMetadata(id),
+    private_process_info_id int references CollectionDB.zoo_PrivateProcessInfo(id)
+);
+
+create table CollectionDB.ProcessInputAssignment (
+    id serial primary key,
+    process_id int references CollectionDB.ows_Process(id),
+    input_id int references CollectionDB.ows_Input(id),
+    index int
+);
+
+create table CollectionDB.ProcessOutputAssignment (
+    id serial primary key,
+    process_id int references CollectionDB.ows_Process(id),
+    output_id int references CollectionDB.ows_Output(id),
+    index int
+);
+
+CREATE OR REPLACE VIEW public.ows_process AS
+       (SELECT
+	id,
+	identifier,
+	title,
+	abstract,
+	(SELECT service_type FROM CollectionDB.zoo_ServiceTypes WHERE id = (SELECT service_type_id FROM CollectionDB.zoo_DeploymentMetadata WHERE id = (SELECT deployment_metadata_id FROM CollectionDB.PrivateMetadataDeploymentmetadataAssignment WHERE private_metadata_id=(SELECT id FROM CollectionDB.zoo_PrivateMetadata WHERE id = CollectionDB.ows_Process.private_metadata_id)))) as service_type,
+	(SELECT executable_name  as service_provider FROM CollectionDB.zoo_DeploymentMetadata WHERE id = (SELECT deployment_metadata_id FROM CollectionDB.PrivateMetadataDeploymentmetadataAssignment WHERE private_metadata_id=(SELECT id FROM CollectionDB.zoo_PrivateMetadata WHERE id = CollectionDB.ows_Process.private_metadata_id))) as service_provider,
+	availability
+	FROM CollectionDB.ows_Process
+	WHERE
+	 availability
+	);
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/sqlapi.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/sqlapi.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/sqlapi.c	(revision 942)
@@ -0,0 +1,649 @@
+/*
+ * Authors : David Saggiorato
+ *           Gérald Fenoy
+ *  Copyright 2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#include "response_print.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+
+#include "sqlapi.h"
+#include <fcgi_stdio.h>
+#include <stdlib.h>
+
+/**
+ * Global GDALDataset pointer
+ */
+#if GDAL_VERSION_MAJOR >=2
+GDALDataset
+#else
+OGRDataSource 
+#endif
+ **zoo_DS = NULL;
+
+/**
+ * Global OGRLayer pointer pointing to the lastest result set
+ */
+OGRLayer *zoo_ResultSet = NULL;
+
+/**
+ * Create a GDAL / OGR string for connecting to a db backend defined in the
+ * key section.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param key the name of the section containing the connection setting
+ * @return the OGR connection string
+ */
+char* _createInitString(maps* conf,const char* key){
+  char* res=NULL;
+  char keywords[6][14]={
+    "dbname",
+    "host",
+    "port",
+    "user",
+    "password",
+    "active_schema"    
+  };
+  int i=0;
+  maps* cconf=getMaps(conf,key);
+  if(cconf==NULL){
+    return "-1";
+  }
+  int len=0;
+  for(i=0;i<6;i++){
+    map* tmp=getMap(cconf->content,keywords[i]);
+    if(tmp!=NULL){
+      if(res==NULL){
+	res=(char*)malloc((strlen(keywords[i])+strlen(tmp->value)+4)*sizeof(char));
+	sprintf(res,"%s='%s'",keywords[i],tmp->value);
+	len+=strlen(res);
+      }else{
+	char* res1=(char*)malloc((strlen(keywords[i])+strlen(tmp->value)+5)*sizeof(char));
+	sprintf(res1," %s='%s'",keywords[i],tmp->value);
+	res=(char*)realloc(res,(len+strlen(keywords[i])+strlen(tmp->value)+5)*sizeof(char));
+	memcpy(res+len,res1,(strlen(keywords[i])+strlen(tmp->value)+5)*sizeof(char));
+	len+=strlen(res1);
+	res[len]=0;
+	free(res1);
+      }
+    }
+  }
+  map* tmp=getMap(cconf->content,"type");
+  if(tmp!=NULL){
+    char* fres=(char*)malloc((strlen(res)+strlen(tmp->value)+2)*sizeof(char));
+    sprintf(fres,"%s:%s",tmp->value,res);
+    free(res);
+    return fres;
+  }
+  return res;
+}
+
+/**
+ * Create a GDAL / OGR string for connecting to the db backend
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @return the OGR connection string
+ */
+char* createInitString(maps* conf){
+  return _createInitString(conf,"database");
+}
+
+/**
+ * Connect to a db backend.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @see createInitString
+ */
+int _init_sql(maps* conf,const char* key){
+  char* sqlInitString=_createInitString(conf,key);
+#ifdef SQL_DEBUG
+  fprintf(stderr,"Try to connect to: %s %s !\n",key,sqlInitString);
+  fflush(stderr);  
+#endif
+  if(strncmp(sqlInitString,"-1",2)==0)
+    return -1;
+  OGRSFDriver *poDriver = NULL;
+  OGRRegisterAll();
+  int zoo_ds_nb=0;
+  map* dsNb=getMapFromMaps(conf,"lenv","ds_nb");
+  if(dsNb==NULL){
+    setMapInMaps(conf,"lenv","ds_nb","1");
+  }else{
+    zoo_ds_nb=atoi(dsNb->value);
+    char* tmp=(char*)malloc(11*sizeof(char));
+    sprintf(tmp,"%d",zoo_ds_nb+1);
+    setMapInMaps(conf,"lenv","ds_nb",(const char*)tmp);
+    free(tmp);
+  }
+  if(zoo_DS==NULL)
+    zoo_DS=
+#if GDAL_VERSION_MAJOR >= 2
+      (GDALDataset**) malloc(sizeof(GDALDataset*))
+#else
+      (OGRDataSource**) malloc(sizeof(OGRDataSource*))
+#endif
+      ;
+  else
+    zoo_DS=      
+#if GDAL_VERSION_MAJOR >= 2
+      (GDALDataset**)realloc(zoo_DS,(zoo_ds_nb+1)*sizeof(GDALDataset*))
+#else
+      (OGRDataSource**)realloc(zoo_DS,(zoo_ds_nb+1)*sizeof(OGRDataSource*))
+#endif
+      ;
+  
+#if GDAL_VERSION_MAJOR >= 2
+  zoo_DS[zoo_ds_nb] = (GDALDataset*) GDALOpenEx( sqlInitString,
+				      GDAL_OF_UPDATE | GDAL_OF_VECTOR,
+				      NULL, NULL, NULL );
+#else
+  zoo_DS[zoo_ds_nb] = OGRSFDriverRegistrar::Open(sqlInitString,false,&poDriver);
+#endif
+  if( zoo_DS[zoo_ds_nb] == NULL ){
+#ifdef SQL_DEBUG
+    fprintf(stderr,"sqlInitString: %s FAILED !\n",sqlInitString);
+    fflush(stderr);
+#endif
+    free(sqlInitString);
+    setMapInMaps(conf,"lenv","dbIssue","1");
+    setMapInMaps(conf,"lenv","message",_("Failed to connect to the database backend"));
+    return -2;
+  }
+#ifdef SQL_DEBUG
+  fprintf(stderr,"sqlInitString: %s SUCEED !\n",sqlInitString);
+  fflush(stderr);
+#endif
+  free(sqlInitString);
+  zoo_ds_nb++;
+  return zoo_ds_nb;
+}
+
+/**
+ * Connect to the db backend.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @see createInitString
+ */
+int init_sql(maps* conf){
+  return _init_sql(conf,"database");
+}
+
+/**
+ * Close any connection to the db backend.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ */
+void close_sql(maps* conf,int cid){
+  if( zoo_ResultSet != NULL ){
+    zoo_DS[cid]->ReleaseResultSet( zoo_ResultSet );
+    zoo_ResultSet=NULL;
+  }
+  if(zoo_DS!=NULL && zoo_DS[cid]!=NULL){
+#if GDAL_VERSION_MAJOR >= 2
+    GDALClose(zoo_DS[cid]);
+#else
+    OGRDataSource::DestroyDataSource( zoo_DS[cid] );
+#endif
+    zoo_DS[cid]=NULL;
+  }
+}
+
+/**
+ * Call OGRCleanupAll.
+ * 
+ */
+void end_sql(){
+  OGRCleanupAll();
+}
+
+/**
+ * Fetch a tuple set by executing a SQL query to the Database Backend.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param sqlQuery the SQL query to run
+ * @return NULL in case of failure or an OGRLayer pointer if the query succeed.
+ */
+OGRLayer *fetchSql(maps* conf,int cid,const char* sqlQuery){
+  if(zoo_DS==NULL || zoo_DS[cid]==NULL)
+    return NULL;
+  OGRLayer *res=NULL;
+#ifdef SQL_DEBUG
+  fprintf(stderr,"************************* %s %s %d\n\n",sqlQuery,__FILE__,__LINE__);
+  fflush(stderr);
+#endif
+  res = zoo_DS[cid]->ExecuteSQL( sqlQuery, NULL, NULL);
+  return res;
+}
+
+void cleanFetchSql(maps* conf,int cid,OGRLayer *objects){
+  if( objects != NULL ){
+    zoo_DS[cid]->ReleaseResultSet( objects );
+    objects=NULL;
+  }
+}
+
+/**
+ * Execute a SQL query to the SQL Database Backend.
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param sqlQuery the SQL query to run
+ * @return -1 in case of failure and 1 if the query succeed.
+ */
+int execSql(maps* conf,int cid,const char* sqlQuery){
+  int res=-1;
+  if(zoo_DS == NULL || zoo_DS[cid]==NULL)
+    return -1;
+  zoo_ResultSet = zoo_DS[cid]->ExecuteSQL( sqlQuery, NULL, NULL);
+  if( zoo_ResultSet != NULL ){
+    res=1;
+  }
+  return res;
+}
+
+/**
+ * Clean any memory allocated by executing a request
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param sqlQuery the SQL query to run
+ * @return -1 in case of failure and 1 if the query succeed.
+ */
+void cleanUpResultSet(const maps* conf,int cid){
+  if( zoo_ResultSet != NULL ){
+    zoo_DS[cid]->ReleaseResultSet( zoo_ResultSet );
+    zoo_ResultSet=NULL;
+  }
+}
+
+#ifdef RELY_ON_DB
+int getCurrentId(maps* conf){
+  int res=0;
+  map* dsNb=getMapFromMaps(conf,"lenv","ds_nb");
+  if(dsNb!=NULL)
+    res=atoi(dsNb->value);
+  return res;
+}
+
+/**
+ * Record a file stored during ZOO-Kernel execution
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param filename the file's name
+ * @param type the type (Intput,Output,Response)
+ * @param name the maps containing the setting of the main.cfg file
+ */
+void recordStoredFile(maps* conf,const char* filename,const char* type,const char* name){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *uusid=getMapFromMaps(conf,"lenv","usid");
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(uusid->value)+strlen(filename)+strlen(type)+(name!=NULL?strlen(name):2)+68+1)*sizeof(char));
+  if(name!=NULL)
+    sprintf(sqlQuery,"INSERT INTO %s.files (uuid,filename,nature,name) VALUES ('%s','%s','%s','%s');",schema->value,uusid->value,filename,type,name);
+  else
+    sprintf(sqlQuery,"INSERT INTO %s.files (uuid,filename,nature,name) VALUES ('%s','%s','%s',NULL);",schema->value,uusid->value,filename,type);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  free(sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+}
+
+/**
+ * Insert the reference tuple corresponding to the running service
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ */
+void recordServiceStatus(maps* conf){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *sid=getMapFromMaps(conf,"lenv","sid");
+  map *osid=getMapFromMaps(conf,"lenv","osid");
+  map *uusid=getMapFromMaps(conf,"lenv","usid");
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+
+				strlen(uusid->value)+
+				strlen(osid->value)+
+				strlen(sid->value)+
+				strlen(wpsStatus[2])+66+1)*sizeof(char));
+  sprintf(sqlQuery,
+	  "INSERT INTO %s.services (uuid,sid,osid,fstate)"
+	  "VALUES ('%s','%s','%s','%s');",
+	  schema->value,
+	  uusid->value,
+	  sid->value,
+	  osid->value,
+	  wpsStatus[2]);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  free(sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+}
+
+/**
+ * Store the content of the result file
+ * 
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param filename the file's name
+ */
+void recordResponse(maps* conf,char* filename){
+  int zoo_ds_nb=getCurrentId(conf);
+  FILE *file = fopen (filename, "rb");
+  fseek (file, 0, SEEK_END);
+  long flen = ftell (file);
+  fseek (file, 0, SEEK_SET);
+  char *tmps = (char *) malloc ((flen + 1) * sizeof (char));
+  fread (tmps, flen, 1, file);
+  tmps[flen]=0;
+  fclose(file);
+  map *sid=getMapFromMaps(conf,"lenv","usid");
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+flen+strlen(sid->value)+57+1)*sizeof(char));
+  sprintf(sqlQuery,"INSERT INTO %s.responses (content,uuid) VALUES ($$%s$$,$$%s$$);",schema->value,tmps,sid->value);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  free(sqlQuery);
+  free(tmps);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+}
+
+/**
+ * Update the current status of the running service.
+ *
+ * @param conf the map containing the setting of the main.cfg file
+ * @return 0 on success, -2 if shmget failed, -1 if shmat failed
+ */
+int _updateStatus(maps* conf){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *sid=getMapFromMaps(conf,"lenv","usid");
+  map *p=getMapFromMaps(conf,"lenv","status");
+  map *msg=getMapFromMaps(conf,"lenv","message");
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(msg->value)+strlen(p->value)+strlen(sid->value)+64+1)*sizeof(char));
+  sprintf(sqlQuery,"UPDATE %s.services set status=$$%s$$,message=$$%s$$ where uuid=$$%s$$;",schema->value,p->value,msg->value,sid->value);
+  if( zoo_DS == NULL || zoo_DS[zoo_ds_nb-1]==NULL ){
+    init_sql(conf);
+    zoo_ds_nb++;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  free(sqlQuery);
+  return 0;
+}
+
+/**
+ * Get the ongoing status of a running service 
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ * @return the reported status char* (MESSAGE|POURCENTAGE)
+ */
+char* _getStatus(maps* conf,char* pid){
+  int zoo_ds_nb=getCurrentId(conf);
+  int created=-1;
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+58+1)*sizeof(char));
+  sprintf(sqlQuery,"select status||'|'||message from %s.services where uuid=$$%s$$;",schema->value,pid);
+  if( zoo_ds_nb==
+#ifdef META_DB
+      1
+#else
+      0
+#endif
+      ){
+    init_sql(conf);
+    zoo_ds_nb++;
+    created=1;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  OGRFeature  *poFeature = NULL;
+  const char *tmp1;
+  while( (poFeature = zoo_ResultSet->GetNextFeature()) != NULL ){
+    for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
+      if( poFeature->IsFieldSet( iField ) ){
+	tmp1=zStrdup(poFeature->GetFieldAsString( iField ));
+      }
+      else
+	tmp1=NULL;
+    }
+    OGRFeature::DestroyFeature( poFeature );
+  }
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  free(sqlQuery);
+  return (char*)tmp1;
+}
+
+/**
+ * Read the cache file of a running service 
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ * @return the reported status char* (temporary/final result)
+ */
+char* _getStatusFile(maps* conf,char* pid){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *schema=getMapFromMaps(conf,"database","schema");
+  OGRFeature  *poFeature = NULL;
+  const char *tmp1=NULL;
+  int hasRes=-1;
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+82+1)*sizeof(char));
+  sprintf(sqlQuery,
+	  "select content from %s.responses where uuid=$$%s$$"
+	  " order by creation_time desc limit 1",schema->value,pid);
+  if( zoo_ds_nb==
+#ifdef META_DB
+      1
+#else
+      0
+#endif
+      ){
+    init_sql(conf);
+    zoo_ds_nb++;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  if(zoo_ResultSet!=NULL){
+      while( (poFeature = zoo_ResultSet->GetNextFeature()) != NULL ){
+	for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
+	  if( poFeature->IsFieldSet( iField ) ){
+	    tmp1=zStrdup(poFeature->GetFieldAsString( iField ));
+	    hasRes=1;
+	  }
+	  else
+	    tmp1=NULL;
+	}
+	OGRFeature::DestroyFeature( poFeature );
+      }
+  }
+  if(hasRes<0)
+    tmp1=NULL;
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  free(sqlQuery);
+  return (char*)tmp1;
+}
+
+/**
+ * Delete a service reference from the database.
+ *
+ * @param conf the map containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ */
+void removeService(maps* conf,char* pid){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)
+    malloc((strlen(pid)+strlen(schema->value)+38+1)
+	   *sizeof(char));
+  if( zoo_ds_nb==
+#ifdef META_DB
+      1
+#else
+      0
+#endif
+      ){
+    init_sql(conf);
+    zoo_ds_nb++;
+  }
+  sprintf(sqlQuery,
+	  "DELETE FROM %s.services where uuid=$$%s$$;",
+	  schema->value,pid);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  close_sql(conf,zoo_ds_nb-1);
+  free(sqlQuery);
+  end_sql();
+}
+
+/**
+ * Stop handling status repport.
+ *
+ * @param conf the map containing the setting of the main.cfg file
+ */
+void unhandleStatus(maps* conf){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *schema=getMapFromMaps(conf,"database","schema");
+  map *sid=getMapFromMaps(conf,"lenv","usid");
+  map *fstate=getMapFromMaps(conf,"lenv","fstate");
+  char *sqlQuery=(char*)malloc((strlen(sid->value)+
+				strlen(schema->value)+
+				(fstate!=NULL?
+				 strlen(fstate->value):
+				 6)
+				+66+1)*sizeof(char));
+  sprintf(sqlQuery,
+	  "UPDATE %s.services set end_time=now(), fstate=$$%s$$"
+	  " where uuid=$$%s$$;",
+	  schema->value,(fstate!=NULL?fstate->value:"Failed"),sid->value);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  //close_sql(conf,zoo_ds_nb-1);
+  free(sqlQuery);
+  //end_sql();
+}
+
+/**
+ * Read the sid identifier attached of a service if any
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ * @return the sid value
+ */
+char* getStatusId(maps* conf,char* pid){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+58+1)*sizeof(char));
+  sprintf(sqlQuery,
+	  "select osid from %s.services where uuid=$$%s$$",
+	  schema->value,pid);
+  if( zoo_ds_nb==0 ){
+    init_sql(conf);
+    zoo_ds_nb++;
+  }
+  if(execSql(conf,zoo_ds_nb-1,sqlQuery)<0)
+    return NULL;
+  OGRFeature  *poFeature = NULL;
+  const char *tmp1;
+  int hasRes=-1;
+  while( (poFeature = zoo_ResultSet->GetNextFeature()) != NULL ){
+    for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
+      if( poFeature->IsFieldSet( iField ) ){
+	tmp1=zStrdup(poFeature->GetFieldAsString( iField ));
+	hasRes=1;
+	break;
+      }
+    }
+    OGRFeature::DestroyFeature( poFeature );
+  }
+  if(hasRes<0)
+    tmp1=NULL;
+  free(sqlQuery);
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  return (char*)tmp1;
+}
+
+/**
+ * Read the Result file (.res).
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the service identifier (usid key from the [lenv] section)
+ */
+void readFinalRes(maps* conf,char* pid,map* statusInfo){
+  int zoo_ds_nb=getCurrentId(conf);
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+58+1)*sizeof(char));
+  sprintf(sqlQuery,
+	  "select fstate from %s.services where uuid=$$%s$$",
+	  schema->value,pid);
+  if( zoo_DS == NULL )
+    init_sql(conf);
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  OGRFeature  *poFeature = NULL;
+  int hasRes=-1;
+  while( (poFeature = zoo_ResultSet->GetNextFeature()) != NULL ){
+    for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
+      if( poFeature->IsFieldSet( iField ) ){
+	addToMap(statusInfo,"Status",poFeature->GetFieldAsString( iField ));
+	hasRes=1;
+	break;
+      }
+    }
+    OGRFeature::DestroyFeature( poFeature );
+  }
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  if(hasRes<0)
+    addToMap(statusInfo,"Status","Failed");
+  free(sqlQuery);
+  return;
+}
+
+/**
+ * Check if a service is running.
+ *
+ * @param conf the maps containing the setting of the main.cfg file
+ * @param pid the unique service identifier (usid from the lenv section)
+ * @return 1 in case the service is still running, 0 otherwise
+ */
+int isRunning(maps* conf,char* pid){
+  int res=0;
+  int zoo_ds_nb=getCurrentId(conf);
+  map *schema=getMapFromMaps(conf,"database","schema");
+  char *sqlQuery=(char*)malloc((strlen(schema->value)+strlen(pid)+73+1)*sizeof(char));
+  sprintf(sqlQuery,"select count(*) as t from %s.services where uuid=$$%s$$ and end_time is null;",schema->value,pid);
+  if( zoo_ds_nb == 0 ){
+    init_sql(conf);
+    zoo_ds_nb++;
+  }
+  execSql(conf,zoo_ds_nb-1,sqlQuery);
+  OGRFeature  *poFeature = NULL;
+  const char *tmp1;
+  while( (poFeature = zoo_ResultSet->GetNextFeature()) != NULL ){
+    for( int iField = 0; iField < poFeature->GetFieldCount(); iField++ ){
+      if( poFeature->IsFieldSet( iField ) && 
+	  atoi(poFeature->GetFieldAsString( iField ))>0 ){
+	res=1;
+	break;
+      }
+    }
+    OGRFeature::DestroyFeature( poFeature );
+  }
+  cleanUpResultSet(conf,zoo_ds_nb-1);
+  free(sqlQuery);
+  return res;
+}
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/sqlapi.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/sqlapi.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/sqlapi.h	(revision 942)
@@ -0,0 +1,77 @@
+/*
+ * Author : David Saggiorato
+ *
+ *  Copyright 2008-2009 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_SQLAPI_H
+#define ZOO_SQLAPI_H 1
+
+#ifdef META_DB
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+#endif
+
+#include "service.h"
+#include "service_internal.h"
+
+#ifdef META_DB
+extern "C" 
+#if GDAL_VERSION_MAJOR >=2
+  GDALDataset
+#else
+  OGRDataSource 
+#endif
+  **zoo_DS;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef META_DB
+  ZOO_DLL_EXPORT char* _createInitString(maps*,const char*);
+  ZOO_DLL_EXPORT int _init_sql(maps*,const char*);
+  ZOO_DLL_EXPORT OGRLayer *fetchSql(maps*,int,const char*);
+  ZOO_DLL_EXPORT void cleanFetchSql(maps*,int,OGRLayer*);
+#endif
+#ifdef RELY_ON_DB
+  ZOO_DLL_EXPORT int init_sql(maps*);
+  ZOO_DLL_EXPORT void close_sql(maps*,int);
+  ZOO_DLL_EXPORT int execSql(maps*,int,const char*);
+  ZOO_DLL_EXPORT void recordStoredFile(maps*,const char*,const char*,const char*);
+  ZOO_DLL_EXPORT void recordServiceStatus(maps*);
+  ZOO_DLL_EXPORT void recordResponse(maps*,char*);
+  ZOO_DLL_EXPORT void readFinalRes(maps*,char*,map*);
+  ZOO_DLL_EXPORT int isRunning(maps*,char*);
+  ZOO_DLL_EXPORT char* getStatusId(maps*,char*);
+  ZOO_DLL_EXPORT void removeService(maps*,char*);
+  ZOO_DLL_EXPORT void end_sql();
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/sshapi.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/sshapi.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/sshapi.c	(revision 942)
@@ -0,0 +1,763 @@
+/*
+ *
+ * Author : Gérald FENOY
+ *
+ * Copyright 2017-2019 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sshapi.h"
+#include "service_internal.h"
+
+SSHCON *sessions[MAX_PARALLEL_SSH_CON];
+
+/**
+ * Wait until one or more file descriptor has been changed for the socket for a
+ * time defined by timeout
+ * @param socket_fd int defining the sockket file descriptor
+ * @param session an exeisting LIBSSH2_SESSION
+ */ 
+int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
+{
+    struct timeval timeout;
+    int rc;
+    fd_set fd;
+    fd_set *writefd = NULL;
+    fd_set *readfd = NULL;
+    int dir;
+ 
+    timeout.tv_sec = 10;
+    timeout.tv_usec = 0;
+ 
+    FD_ZERO(&fd);
+ 
+    FD_SET(socket_fd, &fd);
+ 
+    /* now make sure we wait in the correct direction */ 
+    dir = libssh2_session_block_directions(session);
+
+ 
+    if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
+        readfd = &fd;
+ 
+    if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
+        writefd = &fd;
+ 
+    rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
+ 
+    return rc;
+}
+
+/**
+ * Connect to a remote host using SSH protocol
+ * @param conf maps The main configuration maps
+ * @return the libssh2 sessions pointer or NULL in case any failure occured. 
+ */
+SSHCON *ssh_connect(maps* conf){
+  unsigned long hostaddr;
+  int i, use_pw = 1;
+  struct sockaddr_in sin;
+  const char *fingerprint;
+  SSHCON *result=(SSHCON*)malloc((2*sizeof(int))+sizeof(LIBSSH2_SESSION*)+sizeof(LIBSSH2_SFTP*));
+  result->sock_id=NULL;
+  result->index=NULL;
+  result->session=NULL;
+  result->sftp_session=NULL;
+  const char *user;
+  const char *password=NULL;
+  const char *public_key;
+  char *private_key;
+  int rc;
+  FILE *local;
+  char mem[1024 * 1000];
+  char error[1024];
+  int port=22;
+
+  map* hpc_config=getMapFromMaps(conf,"lenv","configId");
+  map* hpc_host=getMapFromMaps(conf,hpc_config->value,"ssh_host");
+  map* hpc_port=getMapFromMaps(conf,hpc_config->value,"ssh_port");
+  map* hpc_user=getMapFromMaps(conf,hpc_config->value,"ssh_user");
+  map* hpc_password=getMapFromMaps(conf,hpc_config->value,"ssh_password");
+  map* hpc_public_key=getMapFromMaps(conf,hpc_config->value,"ssh_key");
+  
+  char ip[100];
+  struct hostent *my_hostent;
+  struct in_addr **addrs;
+  
+  if (hpc_host != NULL) {
+    // Fetch ip address for the hostname
+    if ( (my_hostent = gethostbyname( hpc_host->value ) ) == NULL){
+      herror("gethostbyname");
+      setMapInMaps(conf,"lenv","message",_("Issue when invoking gethostbyname!"));
+      return NULL;
+    }
+ 
+    addrs = (struct in_addr **) my_hostent->h_addr_list;
+  
+    for(i = 0; addrs[i] != NULL; i++) {
+      strcpy(ip , inet_ntoa(*addrs[i]) );
+      break;
+    }
+  }
+
+#ifdef WIN32
+  WSADATA wsadata;
+  int err;
+  err = WSAStartup(MAKEWORD(2,0), &wsadata);
+  if (err != 0) {
+    sprintf(error, "WSAStartup failed with error: %d\n", err);
+    setMapInMaps(conf,"lenv","message",error);
+    return NULL;
+  }
+#endif
+
+  if (hpc_host != NULL) {
+    hostaddr = inet_addr(ip);
+  } else {
+    setMapInMaps(conf,"lenv","message","No host parameter found in your main.cfg file!\n");
+    return NULL;
+  }
+
+  // Default port is 22
+  if(hpc_port!=NULL){
+    port=atoi(hpc_port->value);
+  }
+
+  // In case there is no HPC > user the it must failed
+  if (hpc_user != NULL) {
+    user = hpc_user->value;
+  }else{
+    setMapInMaps(conf,"lenv","message","No user parameter found in your main.cfg file!");
+    return NULL;
+  }
+
+  // TODO: in case password is available but there is also the public key
+  // defined, then we can consider this password as the pass phrase.
+  if (hpc_password != NULL) {
+    password = hpc_password->value;
+  }else{
+    use_pw=-1;
+    if (hpc_public_key != NULL) {
+      public_key = hpc_public_key->value;
+      private_key = zStrdup(hpc_public_key->value);
+      private_key[strlen(public_key)-4]=0;
+    }else{
+      setMapInMaps(conf,"lenv","message","No method found to authenticate!");
+      return NULL;
+    }
+  }
+
+  rc = libssh2_init (0);
+  if (rc != 0) {
+    sprintf (error, "libssh2 initialization failed (%d)\n", rc);
+    setMapInMaps(conf,"lenv","message",error);
+    return NULL;
+  }
+
+  result->sock_id = socket(AF_INET, SOCK_STREAM, 0);
+  sin.sin_family = AF_INET;
+  sin.sin_port = htons(port);
+  sin.sin_addr.s_addr = hostaddr;
+  if (connect(result->sock_id, (struct sockaddr*)(&sin),sizeof(struct sockaddr_in)) != 0) {
+    setMapInMaps(conf,"lenv","message","Failed to connect to remote host!");
+    return NULL;
+  }
+
+  result->session = libssh2_session_init();
+  result->sftp_session = NULL;
+  map* tmp=getMapFromMaps(conf,"lenv","nb_sessions");
+  if(tmp!=NULL){
+    char nb_sessions[10];
+    int nb_sess=atoi(tmp->value);
+    sprintf(nb_sessions,"%d",nb_sess+1);
+    setMapInMaps(conf,"lenv","nb_sessions",nb_sessions);
+    result->index=nb_sess+1;
+    sessions[nb_sess+1]=result;
+  }else{
+    setMapInMaps(conf,"lenv","nb_sessions","0");
+    sessions[0]=result;
+    result->index=0;
+  }
+
+  if (!result->session)
+    return NULL;
+
+  libssh2_session_set_blocking(result->session, 1);
+
+  while ((rc = libssh2_session_handshake(result->session, result->sock_id))
+	 == LIBSSH2_ERROR_EAGAIN);
+
+  if (rc) {
+    sprintf(error, "Failure establishing SSH session: %d\n", rc);
+    setMapInMaps(conf,"lenv","message",error);
+    return NULL;
+  }
+
+  fingerprint = libssh2_hostkey_hash(result->session, LIBSSH2_HOSTKEY_HASH_SHA1);
+  
+  if (use_pw>0) {
+    while ((rc = libssh2_userauth_password(result->session, user, password)) ==
+	   LIBSSH2_ERROR_EAGAIN);
+    if (rc) {
+      setMapInMaps(conf,"lenv","message","Authentication by password failed.");
+      ssh_close(conf);
+      return NULL;
+    }
+  } else {
+    while ((rc = libssh2_userauth_publickey_fromfile(result->session, user,
+						     public_key,
+						     private_key,
+						     password)) ==
+	   LIBSSH2_ERROR_EAGAIN);
+    if (rc) {
+      setMapInMaps(conf,"lenv","message","Authentication by public key failed");
+      ssh_close(conf);
+      return NULL;
+    }
+    free(private_key);
+  }
+
+  return result;
+
+}
+
+/** 
+ * Get the number of opened SSH connections
+ * @param conf maps pointer to the main configuration maps
+ * @return the number of opened SSH connections
+ */
+int ssh_get_cnt(maps* conf){
+  int result=0;
+  map* myMap=getMapFromMaps(conf,"lenv","nb_sessions");
+  if(myMap!=NULL){
+    result=atoi(myMap->value);
+  }
+  return result;
+}
+
+/** 
+ * Verify if a file exists on the remote host
+ * @param conf maps pointer to the main configuration maps
+ * @param targetPath const char* defining the path for storing the file on the
+ * remote host
+ * @return true in case of success, false if failure occured
+ */
+size_t ssh_file_exists(maps* conf,const char* targetPath,int cnt){
+  size_t result=-1;
+  if(cnt>0)
+    cnt-=1;
+  int rc;
+  LIBSSH2_SFTP_ATTRIBUTES attrs;
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+  do{
+    sftp_handle =
+      libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath, LIBSSH2_FXF_READ,
+			LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
+			LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
+    if (!sftp_handle) {
+      fprintf(stderr, "Unable to open file with SFTP: %d %ld\n",__LINE__,
+	      libssh2_sftp_last_error(sessions[cnt]->sftp_session));
+      return 0;
+    }
+  }while(!sftp_handle);
+#ifdef SSH_DEBUG
+  fprintf(stderr, "libssh2_sftp_open() is done, get file information\n");
+#endif
+  do {
+  rc = libssh2_sftp_stat_ex(sessions[cnt]->sftp_session, targetPath, strlen(targetPath),
+			    LIBSSH2_SFTP_LSTAT, &attrs );
+  if (rc<0 &&
+      (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN))
+    {
+      fprintf(stderr, "error trying to fstat_ex, returned %d\n", rc);
+      break;
+    }
+  else
+    {
+#ifdef SSH_DEBUG
+      fprintf(stderr, "Stat Data: RetCode=%d\n", rc);
+      fprintf(stderr, "Stat Data: Size=%llu\n", attrs.filesize);
+      fprintf(stderr, "Stat Data: Perm=%lx\n",  attrs.permissions);
+      fprintf(stderr, "Stat Data: mtime=%lu\n",  attrs.mtime);
+#endif
+      if(rc==0)
+	break;
+      result=attrs.filesize;
+    }
+  } while (true);
+  libssh2_sftp_close(sftp_handle);
+  //libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
+
+  return result;
+}
+
+/** 
+ * Upload a file over an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param localPath const char* defining the local path for accessing the file
+ * @param targetPath const char* defining the path for storing the file on the
+ * remote host
+ * @return true in case of success, false if failure occured
+ */
+bool ssh_copy(maps* conf,const char* localPath,const char* targetPath,int cnt){
+  char mem[1024 * 16];
+  size_t nread;
+  size_t memuse=0;
+  time_t start;
+  long total = 0;
+  int counter=0;
+  int duration;
+  int rc;
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+  //map* myMap=getMapFromMaps(conf,"lenv","cnt_session");
+  if(getMapFromMaps(conf,"lenv","cnt_session")!=NULL){
+    char tmp[10];
+    sprintf(tmp,"%d",cnt+1);
+    setMapInMaps(conf,"lenv","cnt_session",tmp);
+  }else
+    setMapInMaps(conf,"lenv","cnt_session","0");
+  FILE *local = fopen(localPath, "rb");
+  if (!local) {
+    fprintf(stderr, "Can't open local file %s\n", localPath);
+    return false;
+  }
+  
+  do {
+    sessions[cnt]->sftp_session = libssh2_sftp_init(sessions[cnt]->session);
+    if (!sessions[cnt]->sftp_session &&
+	(libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
+      
+      fprintf(stderr, "Unable to init SFTP session\n");
+      return false;
+    }
+    if(!sessions[cnt]->sftp_session)
+      zSleep(10);
+  } while (!sessions[cnt]->sftp_session);
+
+  do {
+    sftp_handle =
+      libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath,
+			LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
+			LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
+			LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
+
+    if (!sftp_handle &&
+	(libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
+      
+      fprintf(stderr, "Unable to open file with SFTP\n");
+      return false;
+    }
+    if(!sftp_handle)
+      zSleep(10);
+  } while (!sftp_handle);
+  start = time(NULL);
+  
+  do {
+    nread = fread(&mem[memuse], 1, sizeof(mem)-memuse, local);
+    if (nread <= 0) {
+      if (memuse > 0)
+	nread = 0;
+      else
+	break;
+    }
+    memuse += nread;
+    total += nread;
+    
+    while ((rc = libssh2_sftp_write(sftp_handle, mem, memuse)) ==
+	   LIBSSH2_ERROR_EAGAIN) {
+      waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+    }
+    if(rc < 0)
+      break;
+    
+    memuse = 0;
+    
+  } while (rc > 0);
+  
+  duration = (int)(time(NULL)-start);
+  fclose(local);
+  libssh2_sftp_close_handle(sftp_handle);
+
+  libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
+  return true;
+}
+
+/** 
+ * Download a file over an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param localPath const char* defining the local path for storing the file
+ * @param targetPath const char* defining the path for accessing the file on the
+ * remote host
+ * @return 0 in case of success, -1 if failure occured
+ */
+int ssh_fetch(maps* conf,const char* localPath,const char* targetPath,int cnt){
+  size_t nread;
+  size_t memuse=0;
+  time_t start;
+  long total = 0;
+  int duration;
+  int rc;
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+  FILE *local = fopen(localPath, "wb");
+  if (!local) {
+    fprintf(stderr, "Can't open local file %s\n", localPath);
+    return -1;
+  }
+
+  do {
+    sessions[cnt]->sftp_session = libssh2_sftp_init(sessions[cnt]->session);
+    if (!sessions[cnt]->sftp_session &&
+	(libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
+      fprintf(stderr, "Unable to init SFTP session\n");
+      return -1;
+    }
+    if(!sessions[cnt]->sftp_session)
+      zSleep(10);
+  } while (!sessions[cnt]->sftp_session);
+  do {
+    sftp_handle = libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath,   
+				    LIBSSH2_FXF_READ, 0);
+    if (!sftp_handle) {
+      if (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN) {
+	fprintf(stderr, " ** Unable to open file with SFTP\n");
+	return -1;
+      }
+      else {
+	waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session); 
+      }
+    }
+    if(!sftp_handle)
+      zSleep(10);
+  } while (!sftp_handle);
+
+  int result=0;
+  int counter=0;
+  do {
+    do {
+      char* mem=(char*)malloc(16*1024);
+      rc = libssh2_sftp_read(sftp_handle, mem,16*1024);
+      if(rc > 0) {
+	fwrite(mem, rc, 1, local);
+      }
+      free(mem);
+      if(counter%25==0)
+	zSleep(10);
+    } while (rc > 0);
+
+    if(rc != LIBSSH2_ERROR_EAGAIN) {
+      result=-1;
+      break;
+    }
+
+    struct timeval timeout;
+    fd_set fd;
+    timeout.tv_sec = 10;
+    timeout.tv_usec = 0;
+
+    FD_ZERO(&fd);
+
+    FD_SET(sessions[cnt]->sock_id, &fd);
+
+    rc = select(sessions[cnt]->sock_id+1, &fd, &fd, NULL, &timeout);
+    if(rc <= 0) {
+      if(rc==0)
+	fprintf(stderr, "SFTP download timed out: %d\n", rc);
+      else
+	fprintf(stderr, "SFTP download error: %d\n", rc);
+      return -1;
+    }
+
+    if(counter%50==0)
+       zSleep(10);
+    counter++;
+
+  } while (1);
+  duration = (int)(time(NULL)-start);
+  fclose(local);
+  libssh2_sftp_close_handle(sftp_handle);
+  libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
+  return 0;
+}
+
+/** 
+ * Execute a command over an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param command const char pointer to the command to be executed
+ * @return bytecount resulting from the execution of the command
+ */
+int ssh_exec(maps* conf,const char* command,int cnt){
+  LIBSSH2_CHANNEL *channel;
+  int rc;
+  int bytecount = 0;
+  int exitcode;
+  char *exitsignal=(char *)"none";
+  while( (channel = libssh2_channel_open_session(sessions[cnt]->session)) == NULL &&
+	 libssh2_session_last_error(sessions[cnt]->session,NULL,NULL,0) == LIBSSH2_ERROR_EAGAIN ) {
+    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+  }
+  if( channel == NULL ){
+    fprintf(stderr,"Error\n");
+    return -1;
+  }
+  while( (rc = libssh2_channel_exec(channel, command)) == LIBSSH2_ERROR_EAGAIN ) {
+    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+  }
+  if( rc != 0 ) {
+    fprintf(stderr,"Error\n");
+    return -1;
+  }
+
+  map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+  map* uuid=getMapFromMaps(conf,"lenv","usid");
+  char *logPath=(char*)malloc((strlen(tmpPath->value)+strlen(uuid->value)+11)*sizeof(char));
+  sprintf(logPath,"%s/exec_out_%s",tmpPath->value,uuid->value);
+  
+  FILE* logFile=fopen(logPath,"wb");
+  free(logPath);
+  while(true){
+    int rc;
+    do {
+      char buffer[0x4000];
+      rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
+      
+      if( rc > 0 ){
+	int i;
+	bytecount += rc;
+	buffer[rc]=0;
+	
+	fprintf(logFile,"%s",buffer);
+	fflush(logFile);
+      }
+    }
+    while( rc > 0 );
+    
+    if( rc == LIBSSH2_ERROR_EAGAIN ) {
+      waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+    }
+    else
+      break;
+  }
+  fclose(logFile);
+  exitcode = 127;
+  while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
+    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
+  
+  if( rc == 0 ) {
+    exitcode = libssh2_channel_get_exit_status( channel );
+    libssh2_channel_get_exit_signal(channel, &exitsignal,
+				    NULL, NULL, NULL, NULL, NULL);
+  }
+  
+  if (exitsignal)
+    fprintf(stderr, "\nGot signal: %s\n", exitsignal);
+  else
+    fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
+  
+  libssh2_channel_free(channel);
+
+  return bytecount;
+}
+
+/** 
+ * Close an opened SSH connection
+ * @param conf maps pointer to the main configuration maps
+ * @param con SSHCON pointer to the SSH connection
+ * @return true in case of success, false if failure occured
+ */
+bool ssh_close_session(maps* conf,SSHCON* con){
+  if(con==NULL)
+    return true;
+  while (libssh2_session_disconnect(con->session, "Normal Shutdown, Thank you for using the ZOO-Project sshapi")
+	 == LIBSSH2_ERROR_EAGAIN);
+#ifdef WIN32
+  closesocket(con->sock_id);
+#else
+  close(con->sock_id);
+#endif
+  libssh2_session_free(con->session);
+  con=NULL;
+  return true;
+}
+
+/** 
+ * Close all the opened SSH connections
+ * @param conf maps pointer to the main configuration maps
+ * @return true in case of success, false if failure occured
+ */
+bool ssh_close(maps* conf){
+  int i,nb_sessions;
+  map* tmp=getMapFromMaps(conf,"lenv","nb_sessions");
+  if(tmp!=NULL){
+    nb_sessions=atoi(tmp->value);
+    for(i=0;i<nb_sessions;i++)
+      ssh_close_session(conf,sessions[i]);
+  }
+  libssh2_exit();
+  return true;
+}
+
+bool addToUploadQueue(maps** conf,maps* input){
+  map* queueMap=getMapFromMaps(*conf,"uploadQueue","length");
+  if(queueMap==NULL){
+    maps* queueMaps=createMaps("uploadQueue");
+    queueMaps->content=createMap("length","0");
+    addMapsToMaps(conf,queueMaps);
+    freeMaps(&queueMaps);
+    free(queueMaps);
+    queueMap=getMapFromMaps(*conf,"uploadQueue","length");
+  }
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  int queueIndex=atoi(queueMap->value);
+  if(input!=NULL){
+    if(getMap(input->content,"cache_file")!=NULL){
+      map* length=getMap(input->content,"length");
+      if(length==NULL){
+	addToMap(input->content,"length","1");
+	length=getMap(input->content,"length");
+      }
+      int len=atoi(length->value);
+      int i=0;
+      for(i=0;i<len;i++){
+	
+	map* tmp[2]={getMapArray(input->content,"localPath",i),
+		     getMapArray(input->content,"targetPath",i)};
+
+	setMapArray(queueMaps->content,"input",queueIndex+i,input->name);
+	setMapArray(queueMaps->content,"localPath",queueIndex+i,tmp[0]->value);
+	setMapArray(queueMaps->content,"targetPath",queueIndex+i,tmp[1]->value);
+
+      }
+    }
+  }
+  return true;
+}
+
+int fileMd5Check(maps** conf,const char* localPath,const char* targetPath){
+  if(strstr(localPath,".zca")!=NULL){
+    char *logPath=NULL;    
+    char *command=(char*)malloc(((2*strlen(targetPath))+42)*sizeof(char));
+    sprintf(command,"(md5sum %s | awk {'print $1'}) && touch %s",targetPath,targetPath);
+    if(ssh_exec(*conf,command,ssh_get_cnt(*conf))<=0){
+      return -1;
+    }else{
+      struct stat f_status={};
+      map* usid=getMapFromMaps(*conf,"lenv","usid");
+      map* tmpMap=getMapFromMaps(*conf,"main","tmpPath");
+      char* tmpPath=zStrdup(localPath);
+      tmpPath[strlen(tmpPath)-2]='m';
+      tmpPath[strlen(tmpPath)-1]='d';
+      free(command);
+      logPath=(char*)malloc((strlen(tmpMap->value)+strlen(usid->value)+11)*sizeof(char));
+      sprintf(logPath,"%s/exec_out_%s",tmpMap->value,usid->value);
+      int ts=stat(logPath, &f_status);
+      if(ts==0) {
+	char* fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(logPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	fcontent[f_status.st_size-1]=0;
+	fclose(f);
+	free(logPath);
+	struct stat f_status1={};
+	int ts1=stat(tmpPath, &f_status1);
+	if(ts1==0) {
+	  char* fcontent1=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	  FILE* f1=fopen(tmpPath,"rb");
+	  fread(fcontent1,f_status1.st_size,1,f1);
+	  fcontent1[f_status1.st_size]=0;
+	  fclose(f1);
+	  free(tmpPath);
+	  if(strcmp(fcontent,fcontent1)==0){
+	    free(fcontent);
+	    free(fcontent1);
+	    return 0;
+	  }else{
+	    free(fcontent);
+	    free(fcontent1);
+	    return -1;
+	  }
+	}else{
+	  free(tmpPath);
+	  free(fcontent);
+	  return -1;
+	}	
+      }
+      free(logPath);
+      free(tmpPath);
+    }
+  }
+  return -1;
+}
+
+bool runUpload(maps** conf){
+  SSHCON *test=ssh_connect(*conf);
+  if(test==NULL){
+    return false;
+  }
+  map* queueLengthMap=getMapFromMaps(*conf,"uploadQueue","length");
+  maps* queueMaps=getMaps(*conf,"uploadQueue");
+  if(queueLengthMap!=NULL){
+    int cnt=atoi(queueLengthMap->value);
+    int i=0;
+    for(i=0;i<cnt;i++){
+      map* argv[3]={
+	getMapArray(queueMaps->content,"input",i),
+	getMapArray(queueMaps->content,"localPath",i),
+	getMapArray(queueMaps->content,"targetPath",i)
+      };
+      if(fileMd5Check(conf,argv[1]->value,argv[2]->value)<0){
+	/**/zooLock* lck;
+	if((lck=lockFile(*conf,argv[1]->value,'w'))!=NULL){/**/
+	  if(ssh_copy(*conf,argv[1]->value,argv[2]->value,ssh_get_cnt(*conf))!=true){
+	    const char* templateStr=_("Unable to copy over SSH the file requested for setting the value of %s.");
+	    char *tmpMessage=(char*)malloc((strlen(templateStr)+strlen(argv[0]->value)+1)*sizeof(char));
+	    sprintf(tmpMessage,templateStr,argv[0]->value);
+	    setMapInMaps(*conf,"lenv","message",tmpMessage);
+	    free(tmpMessage);
+	    unlockFile(*conf,lck);
+	    return false;
+	  }
+	  /**/unlockFile(*conf,lck);
+	}else{
+	  setMapInMaps(*conf,"lenv","message",_("Unable to lock the file for upload!"));
+	  return false;
+	}/**/
+      }
+    }    
+  }
+  while (libssh2_session_disconnect(test->session, "Normal Shutdown, Thank you for using the ZOO-Project sshapi")
+         == LIBSSH2_ERROR_EAGAIN);
+#ifdef WIN32
+  closesocket(test->sock_id);
+#else
+  close(test->sock_id);
+#endif
+  libssh2_session_free(test->session);
+  free(test);
+  test=NULL;
+  sessions[ssh_get_cnt(*conf)-1]=NULL;
+  maps* tmp=getMaps(*conf,"lenv");
+  addIntToMap(tmp->content,"nb_sessions",ssh_get_cnt(*conf)-1);  
+
+  return true; 
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/sshapi.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/sshapi.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/sshapi.h	(revision 942)
@@ -0,0 +1,101 @@
+/*
+ *
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed 
+ * by the French National Research Agency
+ *
+ * permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SSHAPI_H
+#define SSHAPI_H 1
+
+#pragma once 
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+ 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "service.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_PARALLEL_SSH_CON 128  
+
+  static int nb_sessions;
+
+  typedef struct {
+    int sock_id;
+    int index;
+    LIBSSH2_SESSION *session;
+    LIBSSH2_SFTP *sftp_session;
+  } SSHCON;
+
+  
+  ZOO_DLL_EXPORT SSHCON *ssh_connect(maps*);
+  ZOO_DLL_EXPORT bool ssh_copy(maps*,const char*,const char*,int);
+  ZOO_DLL_EXPORT int ssh_get_cnt(maps*);
+  ZOO_DLL_EXPORT int ssh_fetch(maps*,const char*,const char*,int);
+  ZOO_DLL_EXPORT int ssh_exec(maps*,const char*,int);
+  ZOO_DLL_EXPORT bool ssh_close_session(maps*,SSHCON*);
+  ZOO_DLL_EXPORT bool ssh_close(maps*);
+  ZOO_DLL_EXPORT bool addToUploadQueue(maps**,maps*);
+  ZOO_DLL_EXPORT bool runUpload(maps**);
+  
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/ulinet.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/ulinet.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/ulinet.c	(revision 942)
@@ -0,0 +1,721 @@
+/*
+ *  ulinet.c
+ *
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2008-2019 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#define _ULINET
+#define MAX_WAIT_MSECS 180*1000 /* Wait max. 180 seconds */
+#include "ulinet.h"
+#include "server_internal.h"
+#include <assert.h>
+#include <ctype.h>
+#include "fcgi_stdio.h"
+
+/**
+ * Write the downloaded content to a _HINTERNET structure
+ *
+ * @param buffer the buffer to read
+ * @param size size of each member
+ * @param nmemb number of element to read
+ * @param data the _HINTERNET structure to write in
+ * @return the size red, -1 if buffer is NULL
+ */
+size_t write_data_into(void *buffer, size_t size, size_t nmemb, void *data){
+  size_t realsize = size * nmemb;
+  _HINTERNET *psInternet;
+  if(buffer==NULL){
+    buffer=NULL;
+    return -1;
+  }
+  psInternet=(_HINTERNET *)data;
+  if(psInternet->pabyData){
+    psInternet->pabyData=(unsigned char*)realloc(psInternet->pabyData,psInternet->nDataLen+realsize+1);
+    psInternet->nDataAlloc+=psInternet->nDataLen+realsize+1;
+  }
+  else{
+    psInternet->pabyData=(unsigned char*)malloc(psInternet->nDataLen+realsize+1);
+    psInternet->nDataAlloc=realsize+1;
+  }
+
+  if (psInternet->pabyData) {
+    memcpy( psInternet->pabyData + psInternet->nDataLen, buffer, realsize);
+    psInternet->nDataLen += realsize;
+    psInternet->pabyData[psInternet->nDataLen] = 0;
+  }
+
+  buffer=NULL;
+  return realsize;
+}
+
+/**
+ * Write the downloaded content in the file pouted by the _HINTERNET structure
+ *
+ * @param buffer the buffer to read
+ * @param size size of each member
+ * @param nmemb number of element to read
+ * @param data the _HINTERNET structure to write in
+ * @return the size red, -1 if buffer is NULL
+ */
+size_t write_data_into_file(void *buffer, size_t size, size_t nmemb, void *data) 
+{ 
+   size_t realsize = size * nmemb;
+   int writen=0;
+   _HINTERNET *psInternet;
+   if(buffer==NULL){
+     buffer=NULL;
+     return -1;
+   }
+   psInternet=(_HINTERNET *)data;
+   writen+=fwrite(buffer, size, nmemb, psInternet->file);
+   fflush(psInternet->file);
+   psInternet->nDataLen += realsize;
+
+   buffer=NULL;
+   return realsize;
+}
+
+
+/**
+ * In case of presence of "Set-Cookie" in the headers red, store the cookie
+ * identifier in cookie
+ *
+ * @param buffer the buffer to read
+ * @param size size of each member
+ * @param nmemb number of element to read
+ * @param data the _HINTERNET structure to write in
+ * @return the size red, -1 if buffer is NULL
+ * @see cookie
+ */
+size_t header_write_data(void *buffer, size_t size, size_t nmemb, void *data){
+  if(strncmp("Set-Cookie: ",(char*)buffer,12)==0){
+    int i;
+    char* tmp;
+    for(i=0;i<12;i++)
+#ifndef WIN32
+      buffer++;
+#else
+	;
+#endif
+    tmp=strtok((char*) buffer,";"); // knut: added cast to char*
+    int cnt=0;
+    _HINTERNET *psInternet=(_HINTERNET *)data;
+    if(tmp!=NULL && psInternet!=NULL){
+      psInternet->cookie=(char*)malloc(sizeof(char)*(strlen(tmp)+1));
+      sprintf(psInternet->cookie,"%s",tmp);
+    }
+  }
+  return size * nmemb;//write_data_into(buffer,size,nmemb,data,HEADER);
+};
+
+/**
+ * Define the proxy to use for a CURL handler
+ * 
+ * @param handle the CURL handler
+ * @param host the proxy host (including http://)
+ * @param port the proxy port
+ */
+void setProxy(CURL* handle,char* host,long port){
+  char* proxyDef=(char*)malloc((strlen(host)+10+2)*sizeof(char));
+  sprintf(proxyDef,"%s:%ld",host,port);
+  curl_easy_setopt(handle,CURLOPT_PROXY,proxyDef);
+  free(proxyDef);
+}
+
+/**
+ * MACOSX
+ */
+#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
+
+
+char* CFStringToCString(CFStringRef dest,char *buffer){
+  CFStringEncoding encoding = kCFStringEncodingUTF8;
+  Boolean bool2 = CFStringGetCString(dest,buffer,1024,encoding);
+  if(bool2){
+    printf("Loaded into local_buffer");
+    return buffer;
+  }
+  return NULL;
+}
+
+OSStatus setProxiesForProtcol(CURL* handle,const char *proto){
+  OSStatus		err;
+  CFDictionaryRef proxyDict;
+  CFArrayRef		proxies;
+  
+  CFStringRef key_enabled = NULL;
+  CFStringRef key_host = NULL;
+  CFStringRef key_port = NULL;
+  
+  bool proxy_enabled;
+  char *proxy_host;
+  long proxy_port;
+  
+  proxyDict = NULL;
+  proxies = NULL;
+
+  err = noErr;
+  proxyDict = SCDynamicStoreCopyProxies(NULL);
+
+  if(strncmp(proto,"http",4)==0){
+      key_enabled=kSCPropNetProxiesHTTPEnable;
+      key_host=kSCPropNetProxiesHTTPProxy;
+      key_port=kSCPropNetProxiesHTTPPort;
+  }
+  else
+    if(strncmp(proto,"https",5)==0){
+      key_enabled=kSCPropNetProxiesHTTPSEnable;
+      key_host=kSCPropNetProxiesHTTPSProxy;
+      key_port=kSCPropNetProxiesHTTPSPort;
+    }
+
+  CFNumberGetValue(CFDictionaryGetValue(proxyDict,key_enabled),kCFNumberIntType,&proxy_enabled);
+  if(proxy_enabled){
+    CFNumberGetValue(CFDictionaryGetValue(proxyDict,key_port),CFNumberGetType(CFDictionaryGetValue(proxyDict,key_port)),&proxy_port);
+    char buffer[1024];
+    CFStringToCString(CFDictionaryGetValue(proxyDict,key_host),buffer);
+    proxy_host=buffer;
+
+#ifdef MSG_LAF_VERBOSE
+    printf("\n**[PROXY SETTINGS DETECTION %s (%d) %s:%li (%s)]**\n",proto,proxy_enabled,(char*)proxy_host,proxy_port,buffer);
+#endif
+
+    if (proxyDict == NULL) {
+      err = coreFoundationUnknownErr;
+    }
+
+    setProxy(handle,proxy_host,proxy_port);
+  }
+  return err;
+}
+#else
+/**
+ * Should autodetect the proxy configuration (do nothing on linux)
+ *
+ * @param handle a CURL handle
+ * @param proto the protocol requiring the use of a proxy
+ */
+int setProxiesForProtcol(CURL* handle,const char *proto){
+#ifdef MSG_LAF_VERBOSE
+  fprintf( stderr, "setProxiesForProtocol (do nothing) ...\n" );
+#endif
+  return 0;
+}
+#endif
+
+/**
+ * Create a HINTERNET
+ *
+ * @param lpszAgent the HTPP User-Agent to use to send requests
+ * @param  dwAccessType type of access required
+ * @param  lpszProxyName the name of the proxy server(s) to use 
+ * @param  lpszProxyBypass ip address or host names which should not be routed
+ *  through the proxy
+ * @param  dwFlags Options (INTERNET_FLAG_ASYNC,INTERNET_FLAG_FROM_CACHE,INTERNET_FLAG_OFFLINE)
+ * @return the created HINTERNET
+ */
+HINTERNET InternetOpen(char* lpszAgent,int dwAccessType,char* lpszProxyName,char* lpszProxyBypass,int dwFlags){
+  HINTERNET ret;
+  ret.handle=curl_multi_init();
+  ret.agent=zStrdup(lpszAgent);
+  ret.nb=0;
+  ret.waitingRequests[ret.nb] = NULL;
+  ret.ihandle[ret.nb].header=NULL;
+  ret.ihandle[ret.nb].handle=NULL;
+  ret.ihandle[ret.nb].hasCacheFile=0;
+  ret.ihandle[ret.nb].nDataAlloc = 0;
+  ret.ihandle[ret.nb].url = NULL;
+  ret.ihandle[ret.nb].mimeType = NULL;
+  ret.ihandle[ret.nb].cookie = NULL;
+  ret.ihandle[ret.nb].nDataLen = 0;
+  ret.ihandle[ret.nb].nDataAlloc = 0;
+  ret.ihandle[ret.nb].pabyData = NULL;
+  ret.ihandle[ret.nb].post = NULL;
+  return ret;
+}
+
+/**
+ * Verify if the URL should use a shared cache or not.
+ *
+ * In case the security section contains a key named "shared", then if the
+ * domain listed in the shared key are contained in the url given as parameter
+ * then it return "SHARED" in other cases, it returns "OTHER".
+ *
+ * @param conf the main configuration file maps
+ * @param url the URL to evaluate
+ * @return a string "SHARED" in case the host is in a domain listed in the
+ * shared key, "OTHER" in other cases.
+ */
+char* getProvenance(maps* conf,const char* url){
+  map* sharedCache=getMapFromMaps(conf,"security","shared");
+  char *res="OTHER";
+  char *paths[2]={
+    "mapserverAddress",
+    "tmpUrl"
+  };
+  if(sharedCache!=NULL){
+    char *hosts=sharedCache->value;
+    char *curs=strtok(hosts,",");
+    while(curs!=NULL){
+      if(strstr(url,curs)==NULL){
+	return "SHARED";
+      }
+      curs=strtok(NULL,",");
+    }
+  }
+  for(int i=0;i<2;i++){
+    sharedCache=getMapFromMaps(conf,"main",paths[i]);
+    if(sharedCache!=NULL){
+      if(strstr(url,sharedCache->value)!=NULL){
+	return "LOCAL";
+      }
+    }
+  }
+  return res;
+}
+
+/**
+ * Add missing headers to an existing _HINTERNET
+ * 
+ * 
+ * @param handle the _HINTERNET pointer
+ * @param key the header parameter name
+ * @param value the header parameter value
+ * @return 0 if the operation succeeded, -1 in other case.
+ */
+int AddMissingHeaderEntry(_HINTERNET* handle,const char* key,const char* value){
+  int length=strlen(key)+strlen(value)+3;
+  char *entry=(char*)malloc((length)*sizeof(char));
+  if(entry==NULL)
+    return -1;
+  snprintf (entry, length, "%s: %s", key, value);
+  handle->header = curl_slist_append (handle->header, entry);
+  free(entry);
+  return 0;
+}
+
+/**
+ * Verify if a host is protected (appear in [security] > hosts)
+ *
+ * @param protectedHosts string containing all the protected hosts (coma separated)
+ * @param url string used to extract the host from
+ * @return 1 if the host is listed as protected, 0 in other case
+ */
+int isProtectedHost(const char* protectedHosts, const char* url) {
+	char *token, *saveptr;
+	int cnt;
+	char* host;
+
+	// knut: make a copy of url since strtok family modifies first argument and cannot be used on constant strings  
+	char* urlcpy = (char*)malloc(sizeof(char)*(strlen(url) + 1));
+	urlcpy = strncpy(urlcpy, url, strlen(url) + 1); // since count > strlen(url), a null character is properly appended
+
+	//token = strtok_r (url, "//", &saveptr);
+	token = strtok_r(urlcpy, "//", &saveptr);   // knut
+	cnt = 0;
+	while (token != NULL && cnt <= 1) {
+		fprintf(stderr, "%s %d %s \n", __FILE__, __LINE__, token);
+		if (cnt == 1)
+			fprintf(stderr, "%s %d %s \n", __FILE__, __LINE__, strstr(protectedHosts, token));
+		fflush(stderr);
+		if (cnt == 1 && strstr(protectedHosts, token) != NULL) {
+			fprintf(stderr, "%s %d %s \n", __FILE__, __LINE__, strstr(protectedHosts, token));
+			free(urlcpy);
+			return 1;
+		}
+		token = strtok_r(NULL, "/", &saveptr);
+		cnt += 1;
+	}
+	free(urlcpy);
+	return 0;
+}
+
+/**
+ * Add headers defined in [security] > attributes to an existing HINTERNET
+ * @see isProtectedHost, AddMissingHeaderEntry
+ * 
+ * @param handle the _HINTERNET pointer
+ * @param conf the header parameter name
+ * @param value the header parameter value
+ * @return 0 if the operation succeeded, -1 in other case.
+ */
+void AddHeaderEntries(HINTERNET* handle,maps* conf){
+  map* passThrough=getMapFromMaps(conf,"security","attributes");
+  map* targetHosts=getMapFromMaps(conf,"security","hosts");
+  char* passedHeader[10];
+  int cnt=0;
+  if(passThrough!=NULL && targetHosts!=NULL){
+    char *tmp=zStrdup(passThrough->value);
+    int i;
+    for(i=0;i<handle->nb;i++){
+      if(strstr(targetHosts->value,"*")!=NULL || isProtectedHost(targetHosts->value,handle->ihandle[i].url)==1){
+	char *token, *saveptr;
+	token = strtok_r (tmp, ",", &saveptr);
+	while (token != NULL){
+	  int length=strlen(token)+6;
+	  char* tmp1=(char*)malloc(length*sizeof(char));
+	  map* tmpMap;
+	  snprintf(tmp1,6,"HTTP_");
+	  int j;
+	  for(j=0;token[j]!='\0';j++){
+	    if(token[j]!='-')
+	      tmp1[5+j]=toupper(token[j]);
+	    else
+	      tmp1[5+j]='_';
+	    tmp1[5+j+1]='\0';
+	  }
+	  tmpMap = getMapFromMaps(conf,"renv",tmp1);
+	  if(tmpMap!=NULL){
+	    AddMissingHeaderEntry(&handle->ihandle[i],token,tmpMap->value);
+	  }
+	  if(handle->ihandle[i].header!=NULL)
+	    curl_easy_setopt(handle->ihandle[i].handle,CURLOPT_HTTPHEADER,handle->ihandle[i].header);
+	  free(tmp1);
+	  cnt+=1;
+	  token = strtok_r (NULL, ",", &saveptr);
+	}
+      }
+    }
+    free(tmp);
+  }
+}
+
+/**
+ * Close a HINTERNET connection and free allocated resources
+ *
+ * @param handle0 the HINTERNET connection to close
+ */
+void InternetCloseHandle(HINTERNET* handle0){
+  int i=0;
+  if(handle0!=NULL){
+    for(i=0;i<handle0->nb;i++){
+      _HINTERNET handle=handle0->ihandle[i];
+      if(handle.hasCacheFile>0){
+	fclose(handle.file);
+	unlink(handle.filename);
+	free(handle.filename);
+      }
+      else{
+	handle.pabyData = NULL;
+	handle.nDataAlloc = handle.nDataLen = 0;
+      }
+      if(handle.header!=NULL){
+	curl_slist_free_all(handle.header);
+	handle.header=NULL;
+      }
+      if(handle.post!=NULL){
+	free(handle.post);
+	handle.post=NULL;
+      }
+      if(handle.url!=NULL){
+	free(handle.url);
+	handle.url=NULL;
+      }
+      if(handle.mimeType!=NULL){
+	free(handle.mimeType);
+	handle.mimeType=NULL;
+      }
+      if(handle.cookie!=NULL){
+	free(handle.cookie);
+	handle.cookie=NULL;
+      }
+      if(handle0->waitingRequests[i]!=NULL){
+	free(handle0->waitingRequests[i]);
+	handle0->waitingRequests[i]=NULL;
+      }
+    }
+    if(handle0->handle)
+      curl_multi_cleanup(handle0->handle);
+    if(handle0->agent!=NULL){
+      free(handle0->agent);
+      handle0->agent=NULL;
+    }
+  }
+}
+
+/**
+ * Create a new element in the download queue
+ *
+ * @param hInternet the HINTERNET connection to add the download link
+ * @param lpszUrl the url to download
+ * @param lpszHeaders the additional headers to be sent to the HTTP server
+ * @param dwHeadersLength the size of the additional headers
+ * @param dwFlags desired download mode (INTERNET_FLAG_NO_CACHE_WRITE for not using cache file)
+ * @param dwContext not used
+ * @param conf the main configuration file maps pointer
+ * @return the updated HINTERNET 
+ */
+HINTERNET InternetOpenUrl(HINTERNET* hInternet,LPCTSTR lpszUrl,LPCTSTR lpszHeaders,size_t dwHeadersLength,size_t dwFlags,size_t dwContext,const maps* conf){
+
+  char filename[255];
+  int ldwFlags=INTERNET_FLAG_NEED_FILE;
+  struct MemoryStruct header;
+  map* memUse=getMapFromMaps((maps*) conf,"main","memory"); // knut: addad cast to maps*
+
+  hInternet->ihandle[hInternet->nb].handle=curl_easy_init( );
+  hInternet->ihandle[hInternet->nb].hasCacheFile=0;
+  hInternet->ihandle[hInternet->nb].nDataAlloc = 0;
+  hInternet->ihandle[hInternet->nb].url = NULL;
+  hInternet->ihandle[hInternet->nb].mimeType = NULL;
+  hInternet->ihandle[hInternet->nb].cookie = NULL;
+  hInternet->ihandle[hInternet->nb].nDataLen = 0;
+  hInternet->ihandle[hInternet->nb].id = hInternet->nb;
+  hInternet->ihandle[hInternet->nb].nDataAlloc = 0;
+  hInternet->ihandle[hInternet->nb].pabyData = NULL;
+  hInternet->ihandle[hInternet->nb].post = NULL;
+  
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_COOKIEFILE, "ALL");
+#ifndef TIGER
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_COOKIELIST, "ALL");
+#endif
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_USERAGENT, hInternet->agent);
+  
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_FOLLOWLOCATION,1);
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_MAXREDIRS,3);
+  
+  header.memory=NULL;
+  header.size = 0;
+
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_HEADERFUNCTION, header_write_data);
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEHEADER, (void *)&header);
+
+#ifdef MSG_LAF_VERBOSE
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_VERBOSE, 1);
+#endif
+
+  if(memUse!=NULL && strcasecmp(memUse->value,"load")==0)
+    ldwFlags=INTERNET_FLAG_NO_CACHE_WRITE;
+  
+  switch(ldwFlags)
+    {
+    case INTERNET_FLAG_NO_CACHE_WRITE:
+      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEFUNCTION, write_data_into);
+      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEDATA, (void*)&hInternet->ihandle[hInternet->nb]);
+      hInternet->ihandle[hInternet->nb].hasCacheFile=-1;
+      break;
+    default:
+      memset(filename,0,255);
+      char* tmpUuid=get_uuid();
+      map* tmpPath=NULL;
+      if(conf!=NULL){
+	tmpPath=getMapFromMaps((maps*) conf,"main","tmpPath"); // knut added cast to maps*
+      }
+      if(tmpPath==NULL)
+	sprintf(filename,"/tmp/ZOO_Cache%s", tmpUuid);
+      else
+	sprintf(filename,"%s/ZOO_Cache%s", tmpPath->value,tmpUuid);
+      free(tmpUuid);
+      hInternet->ihandle[hInternet->nb].filename=zStrdup(filename);
+      hInternet->ihandle[hInternet->nb].file=fopen(hInternet->ihandle[hInternet->nb].filename,"w+");
+      hInternet->ihandle[hInternet->nb].hasCacheFile=1;
+      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEFUNCTION, write_data_into_file);
+      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEDATA, (void*)&hInternet->ihandle[hInternet->nb]);
+      break;
+    }
+#ifdef ULINET_DEBUG
+  fprintf(stderr,"URL (%s)\nBODY (%s)\n",lpszUrl,lpszHeaders);
+#endif
+  if(lpszHeaders!=NULL && strlen(lpszHeaders)>0){
+#ifdef MSG_LAF_VERBOSE
+    fprintf(stderr,"FROM ULINET !!");
+    fprintf(stderr,"HEADER : [%s] %d\n",lpszHeaders,dwHeadersLength);
+#endif
+    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POST,1);
+#ifdef ULINET_DEBUG
+    fprintf(stderr,"** (%s) %d **\n",lpszHeaders,dwHeadersLength);
+    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_VERBOSE,1);
+#endif
+    hInternet->ihandle[hInternet->nb].post=zStrdup(lpszHeaders);
+    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDS,hInternet->ihandle[hInternet->nb].post);
+    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDSIZE,(long)dwHeadersLength);
+  }
+  if(hInternet->ihandle[hInternet->nb].header!=NULL)
+    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_HTTPHEADER,hInternet->ihandle[hInternet->nb].header);
+
+  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_URL,lpszUrl);
+  hInternet->ihandle[hInternet->nb].url = zStrdup(lpszUrl);
+
+  curl_multi_add_handle(hInternet->handle,hInternet->ihandle[hInternet->nb].handle);
+  
+  hInternet->ihandle[hInternet->nb].header=NULL;
+  ++hInternet->nb;
+  hInternet->ihandle[hInternet->nb].header=NULL;
+
+#ifdef ULINET_DEBUG
+  fprintf(stderr,"DEBUG MIMETYPE: %s\n",hInternet.mimeType);
+  fflush(stderr);
+#endif
+  return *hInternet;
+};
+
+/**
+ * Download all opened urls in the queue
+ *
+ * @param hInternet the HINTERNET structure containing the queue
+ * @return 0
+ */
+int processDownloads(HINTERNET* hInternet){
+  int still_running=0,numfds;
+  int msgs_left=0;
+  int i=0;
+  do{
+    CURLMcode mc;
+    mc = curl_multi_perform(hInternet->handle, &still_running);
+    if(mc==CURLM_OK){
+#if LIBCURL_VERSION_MINOR >= 28
+      mc = curl_multi_wait(hInternet->handle, NULL, 0, 1000, &numfds);
+#else
+      struct timeval timeout;
+      fd_set fdread;
+      fd_set fdwrite;
+      fd_set fdexcep;
+      int maxfd = -1;
+
+      long curl_timeo = -1;
+
+      FD_ZERO(&fdread);
+      FD_ZERO(&fdwrite);
+      FD_ZERO(&fdexcep);
+
+      /* set a suitable timeout to play around with */
+      timeout.tv_sec = 1;
+      timeout.tv_usec = 0;
+
+      curl_multi_timeout(hInternet->handle, &curl_timeo);
+      if(curl_timeo >= 0) {
+	timeout.tv_sec = curl_timeo / 1000;
+	if(timeout.tv_sec > 1)
+	  timeout.tv_sec = 1;
+	else
+	  timeout.tv_usec = (curl_timeo % 1000) * 1000;
+      }
+
+      /* get file descriptors from the transfers */
+      mc = curl_multi_fdset(hInternet->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+#endif
+    }
+    if(mc != CURLM_OK) {
+      fprintf(stderr, "curl_multi failed, code %d.n", mc);
+      break;
+    }
+  }while(still_running);  
+  for(i=0;i<hInternet->nb;i++){
+    char *tmp;
+    curl_easy_getinfo(hInternet->ihandle[i].handle,CURLINFO_CONTENT_TYPE,&tmp);
+    if(tmp!=NULL)
+      hInternet->ihandle[i].mimeType=zStrdup(tmp);
+    curl_easy_getinfo(hInternet->ihandle[i].handle,CURLINFO_RESPONSE_CODE,&hInternet->ihandle[i].code);
+    curl_multi_remove_handle(hInternet->handle, hInternet->ihandle[i].handle);
+    curl_easy_cleanup(hInternet->ihandle[i].handle);
+  }
+  return 0;
+}
+
+/**
+ * Initialize the cookie for a specific index (hInternet.nb)
+ *
+ * @param hInternet the HINTERNET structure to know the cookie index to reset
+ * @return 1
+ * @see HINTERNET
+ */
+int freeCookieList(HINTERNET hInternet){
+  hInternet.ihandle[hInternet.nb].cookie=zStrdup("");
+#ifndef TIGER
+  curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_COOKIELIST, "ALL");
+#endif
+  return 1;
+}
+
+/**
+ * Copy a downloaded content
+ * 
+ * @param hInternet the _HINTERNET structure
+ * @param lpBuffer the memory space to copy the downloaded content
+ * @param dwNumberOfBytesToRead the size of lpBuffer
+ * @param lpdwNumberOfBytesRead number of bytes red
+ * @return 1 on success, 0 if failure
+ */
+int InternetReadFile(_HINTERNET hInternet,LPVOID lpBuffer,int dwNumberOfBytesToRead, size_t *lpdwNumberOfBytesRead){
+  int dwDataSize;
+
+  if(hInternet.hasCacheFile>0){
+    fseek (hInternet.file , 0 , SEEK_END);
+    dwDataSize=ftell(hInternet.file); //taille du ficher
+    //dwDataSize=hInternet.nDataLen;
+    //rewind (hInternet.file);
+    fseek(hInternet.file, 0, SEEK_SET);
+  }
+  else{
+    memset(lpBuffer,0,hInternet.nDataLen+1);
+    memcpy(lpBuffer, hInternet.pabyData, hInternet.nDataLen );
+    dwDataSize=hInternet.nDataLen;
+    free( hInternet.pabyData );
+    hInternet.pabyData=NULL;
+  }
+
+  if( dwNumberOfBytesToRead /* buffer size */ < dwDataSize ){
+    return 0;
+  }
+
+#ifdef MSG_LAF_VERBOSE
+  fprintf(stderr,"\nfile size : %dko\n",dwDataSize/1024);
+#endif
+
+  if(hInternet.hasCacheFile>0){
+    int freadRes = fread(lpBuffer,dwDataSize+1,1,hInternet.file); 
+    *lpdwNumberOfBytesRead = hInternet.nDataLen;
+  }
+  else{
+    *lpdwNumberOfBytesRead = hInternet.nDataLen;
+    free( hInternet.pabyData );
+    hInternet.pabyData = NULL;
+    hInternet.nDataAlloc = hInternet.nDataLen = 0;
+  }
+
+  if( *lpdwNumberOfBytesRead < dwDataSize )
+      return 0;
+  else
+      return 1; // TRUE
+}
+
+
+/**
+ * Use basic authentication for accessing a resource
+ * 
+ * @param hInternet the _HINTERNET structure
+ * @param login the login to use to authenticate
+ * @param passwd the password to use to authenticate
+ */
+int setBasicAuth(HINTERNET hInternet,char* login,char* passwd){
+  char *tmp;
+  tmp=(char*)malloc((strlen(login)+strlen(passwd)+2)*sizeof(char));
+  sprintf(tmp,"%s:%s",login,passwd);
+  if(curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle,CURLOPT_USERPWD,tmp)==CURLE_OUT_OF_MEMORY){
+    free(tmp);
+    return -1;
+  }
+  curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_HTTPAUTH,CURLAUTH_ANY);
+  free(tmp);
+  return 0;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/ulinet.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/ulinet.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/ulinet.h	(revision 942)
@@ -0,0 +1,182 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2008-2019 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _ULINET_H
+#define _ULINET_H 1
+
+#include "fcgi_stdio.h"
+#include <stdlib.h>
+#include <fcntl.h>
+#include <curl/curl.h>
+#include <curl/curlver.h>
+#include "service.h"
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <string.h>
+#include "time.h"
+#ifdef USE_JS
+#ifdef WIN32
+#define XP_WIN 1
+#else
+#define XP_UNIX 0
+#endif
+#include "jsapi.h"
+#endif
+#ifndef __cplusplus
+// knut: see new def of bool in service.h
+//#ifndef bool
+//#define bool int
+//#endif
+//#ifndef true
+//#define true 1
+//#define false 0
+//#endif
+#endif
+
+#define MAX_REQ 50
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  /**
+   * Headers storage
+   * @see header_write_data
+   */
+  struct MemoryStruct {
+    char *memory; //!< the memory space to store data 
+    size_t size; //!< size of the memory space
+  };
+
+  /**
+   * Individual CURL handler
+   */
+  typedef struct {
+    CURL *handle; //!< the CURL handler
+    struct curl_slist *header; //!< the headers to send
+    char* filename; //!< the cached file name
+    FILE* file; //!< the file pointer
+    unsigned char *pabyData; //!< the downloaded content
+    char *url; //!< the url used to access the server
+    char *mimeType; //!< the mimeType returned by the server
+    char *post; //!< the potential POST XML content
+    char* cookie; //!< The potential Cookie returned by the server
+    int hasCacheFile; //!< 1 if we used a cache file
+    int nDataLen; //!< the length of the downloaded content
+    int nDataAlloc; //!< 
+    long code; //!< the last received response code
+    int id; //!< The position of the element in the queue
+  } _HINTERNET;
+
+  /**
+   * Multiple CURL handlers
+   */
+  typedef struct {
+    CURLM *handle; //!< the CURLM handler
+    _HINTERNET ihandle[MAX_REQ]; //!< individual handlers in the queue 
+    char *waitingRequests[MAX_REQ]; //!< request in the queue
+    char *agent; //!< The User-Agent to use for HTTP request
+    int nb; //!< number of element in the queue 
+  } HINTERNET;
+
+  size_t write_data_into(void*,size_t,size_t,void*);
+
+  size_t write_data_into_file(void*,size_t,size_t,void*);
+
+  size_t header_write_data(void*,size_t,size_t,void*);
+
+  void setProxy(CURL*,char*,long);
+
+#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
+
+#include <CoreServices/CoreServices.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+  char* CFStringToCString(CFStringRef,char*);
+  OSStatus setProxiesForProtcol(CURL*,const char*);
+
+#else
+
+//#include <gconf/gconf-client.h>
+  int setProxiesForProtcol(CURL*,const char*);
+
+#endif
+
+
+#define INTERNET_OPEN_TYPE_DIRECT                      0
+#define INTERNET_OPEN_TYPE_PRECONFIG                   1
+#define INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY 2
+#define INTERNET_OPEN_TYPE_PROXY                       3
+#ifndef WIN32
+typedef char* LPCTSTR;
+#endif
+  HINTERNET InternetOpen(char*,int,char*,char*,int);
+
+  char* getProvenance(maps*,const char*);
+  int isProtectedHost(const char*,const char*);
+  int AddMissingHeaderEntry(_HINTERNET*,const char*,const char*);
+  void AddHeaderEntries(HINTERNET*,maps*);
+
+  void InternetCloseHandle(HINTERNET*);
+
+#define INTERNET_FLAG_EXISTING_CONNECT         0
+#define INTERNET_FLAG_HYPERLINK                1
+#define INTERNET_FLAG_IGNORE_CERT_CN_INVALID   2
+#define INTERNET_FLAG_IGNORE_CERT_DATE_INVALID 3
+#define INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP  4
+#define INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS 5
+#define INTERNET_FLAG_KEEP_CONNECTION          6
+#define INTERNET_FLAG_NEED_FILE                7
+#define INTERNET_FLAG_NO_AUTH                  8
+#define INTERNET_FLAG_NO_AUTO_REDIRECT         9
+#define INTERNET_FLAG_NO_CACHE_WRITE          10
+//typedef char* LPVOID;
+#ifndef WIN32
+  typedef void* LPVOID;
+  typedef void* LPTSTR;
+  typedef size_t* LPDWORD;
+#endif
+// knut: see new definition of bool in service.h
+//#ifndef bool
+//#define bool int
+//#endif
+
+#  define CHECK_INET_HANDLE(h) (h.handle != 0)
+
+  HINTERNET InternetOpenUrl(HINTERNET*,LPCTSTR,LPCTSTR,size_t,size_t,size_t,const maps*);
+
+  int processDownloads(HINTERNET*);
+
+  int freeCookieList(HINTERNET);
+
+  int InternetReadFile(_HINTERNET,LPVOID,int,size_t*);
+
+  int setBasicAuth(HINTERNET,char*,char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/xslt/updateExecute.xsl
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/xslt/updateExecute.xsl	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/xslt/updateExecute.xsl	(revision 942)
@@ -0,0 +1,63 @@
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:ows="http://www.opengis.net/ows/1.1"
+                xmlns:ns14="http://www.opengis.net/wps/2.0"
+                xmlns:wps="http://www.opengis.net/wps/2.0"
+                xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <!--
+      This template is used by the ZOO-Kernel to generate a specific
+      OGC WPS Execute request in case of rest service callback use.
+      In such a case the ZOO-Kernel replace every input provided by
+      value in the initial request and replace the data section by the
+      reference to the published ressource.
+      So, this template is basically made to replace any input provided
+      by value to the corresponding local WCS/WFS OGC web service
+      references.
+      --> 
+  <xsl:output method="xml"/>
+  <xsl:param name="value" select="string('-1')"/>
+  <xsl:param name="attr" select="string('-1')"/>
+  <xsl:param name="cnt" select="string('-1')"/>
+  <xsl:param name="index" select="0"/>
+
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+
+  
+  <xsl:template match="/wps:Execute/wps:Input">
+    <xsl:choose>
+      <xsl:when test="@id=$attr">
+        <xsl:copy>
+          <xsl:attribute name="id">
+            <xsl:value-of select="@id"/>
+          </xsl:attribute>
+          <ns14:Reference>
+            <xsl:attribute name="xlink:href">
+              <xsl:value-of select="$value"/>
+            </xsl:attribute>
+            <xsl:if test="./wps:Data[@mimeType!='']">
+              <xsl:attribute name="mimeType">
+                <xsl:value-of select="./wps:Data[@mimeType]"/>
+              </xsl:attribute>
+              <xsl:attribute name="encoding">
+                <xsl:value-of select="./wps:Data[@encoding]"/>
+              </xsl:attribute>
+              <xsl:attribute name="schema">
+                <xsl:value-of select="./wps:Data[@schema]"/>
+              </xsl:attribute>
+            </xsl:if>
+          </ns14:Reference>
+        </xsl:copy>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:copy-of select="."/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  
+</xsl:stylesheet>
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/zcfg2yaml.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/zcfg2yaml.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/zcfg2yaml.c	(revision 942)
@@ -0,0 +1,44 @@
+/**
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2014 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "server_internal.h"
+#include "response_print.h"
+#include "service.h"
+
+extern   int getServiceFromFile(maps*,const char*,service**);
+
+int main(int argc, char** argv){
+  service* s1=NULL;
+  maps *m=NULL;
+  char conf_file[1024];
+  snprintf(conf_file,1024,"%s",argv[1]);
+  s1=(service*)malloc(SERVICE_SIZE);
+  if(s1 == NULL){ 
+    return errorException(m, _("Unable to allocate memory"),"InternalError",NULL);
+  }
+  int t=getServiceFromFile(m,conf_file,&s1);
+  if(t>=0)
+    dumpServiceAsYAML(s1);
+  return 0;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/zoo_loader.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/zoo_loader.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/zoo_loader.c	(revision 942)
@@ -0,0 +1,419 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2008-2011 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define MALLOC_CHECK_ 0
+#define MALLOC_CHECK 0
+
+/**
+ * Specific includes
+ */
+#include "fcgio.h"
+#include "fcgi_config.h" 
+#include "fcgi_stdio.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include "service_internal.h"
+#include "response_print.h"
+
+extern "C" {
+#include "cgic.h"
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+}
+
+#ifdef WIN32
+#include "windows.h"
+#define strtok_r strtok_s
+#endif
+
+#include "service_internal.h"
+#include "request_parser.h"
+
+int runRequest(map**);
+
+using namespace std;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE -1
+#endif
+
+int cgiInit(){
+  fprintf(FCGI_stderr,"ZOO-Kernel initialization %s %d ... \n",__FILE__,__LINE__);
+  fflush(FCGI_stderr);
+  return 0;
+}
+
+/**
+ * Main entry point for cgic.
+ * @return 0 on sucess.
+ */
+int cgiMain(){
+  /**
+   * We'll use cgiOut as the default output (stdout) to produce plain text 
+   * response.
+   */
+  dup2(fileno(cgiOut),fileno(stdout));
+#ifdef DEBUG
+  fprintf(cgiOut,"Content-Type: text/plain; charset=utf-8\r\nStatus: 200 OK\r\n\r\n");
+  fprintf(cgiOut,"Welcome on ZOO verbose debuging mode \r\n\r\n");
+  fflush(cgiOut);
+  fprintf (stderr, "Addr:%s\n", cgiRemoteAddr); 
+  fprintf (stderr, "RequestMethod: (%s) %d %d\n", cgiRequestMethod,strncasecmp(cgiRequestMethod,"post",4),strncmp(cgiContentType,"text/xml",8)==0 || strncasecmp(cgiRequestMethod,"post",4)==0); 
+  fprintf (stderr, "Request: %s\n", cgiQueryString);
+  fprintf (stderr, "ContentType: %s\n", cgiContentType);
+  fprintf (stderr, "ContentLength: %d\n", cgiContentLength);
+  fflush(stderr);
+#endif
+  
+  char *strQuery=NULL;
+  if(cgiQueryString!=NULL)
+    strQuery=zStrdup(cgiQueryString);
+  map* tmpMap=NULL;
+
+  if(strncmp(cgiContentType,"text/xml",8)==0 || 
+     strncasecmp(cgiRequestMethod,"post",4)==0){
+    if(cgiContentLength==0){
+
+       char *buffer=new char[2];
+       char *res=NULL;
+       int r=0;
+       while((r=fread(buffer,sizeof(char),1,cgiIn))){
+	 buffer[1]=0;
+	 if(res==NULL){
+	   res=(char*)malloc(2*sizeof(char));
+	   sprintf(res,"%s",buffer);
+	 }
+	 else{
+	   res=(char*)realloc(res,(cgiContentLength+2)*sizeof(char));
+	   memcpy(res + cgiContentLength, buffer, sizeof(char));
+	   res[cgiContentLength+1]=0;
+	 }
+	 cgiContentLength+=r;
+       }
+       delete[] buffer;
+       if(res!=NULL && (strQuery==NULL || strlen(strQuery)==0))
+	 tmpMap=createMap("request",res);
+       if(res!=NULL)
+	 free(res);
+    }else{		
+      char *buffer=new char[cgiContentLength+1];
+      if(fread(buffer,sizeof(char),cgiContentLength,cgiIn)>0){
+	buffer[cgiContentLength]=0;
+	tmpMap=createMap("request",buffer);
+      }else{
+	buffer[0]=0;
+	char **array, **arrayStep;
+	if (cgiFormEntries(&array) != cgiFormSuccess) {
+	  return 1;
+	}
+	arrayStep = array;
+	while (*arrayStep) {
+	  char *ivalue=new char[cgiContentLength];
+	  cgiFormStringNoNewlines(*arrayStep, ivalue, cgiContentLength);
+	  char* tmpValueFinal=(char*) malloc((strlen(*arrayStep)+strlen(ivalue)+2)*sizeof(char));	
+	  sprintf(tmpValueFinal,"%s=%s",*arrayStep,ivalue);
+
+	  if(strlen(buffer)==0){		
+	    sprintf(buffer,"%s",tmpValueFinal);
+	  }else{		
+	    char *tmp=zStrdup(buffer);
+	    sprintf(buffer,"%s&%s",tmp,tmpValueFinal);
+	    free(tmp);
+	  }	  
+	  free(tmpValueFinal);
+#ifdef DEBUG
+	  fprintf(stderr,"(( \n %s \n %s \n ))",*arrayStep,ivalue);
+#endif
+	  delete[]ivalue;
+	  arrayStep++;
+	}	
+	if(tmpMap!=NULL)
+	  addToMap(tmpMap,"request",buffer);
+	else
+	  tmpMap=createMap("request",buffer);
+      }
+      delete[]buffer;
+    }	
+  }
+  else{	  
+#ifdef DEBUG
+    dumpMap(tmpMap);
+#endif
+    char **array, **arrayStep;
+    if (cgiFormEntries(&array) != cgiFormSuccess) {
+      return 1;
+    }
+    arrayStep = array;
+    while (*arrayStep) {
+      char *value=new char[cgiContentLength];
+      cgiFormStringNoNewlines(*arrayStep, value, cgiContentLength);
+#ifdef DEBUG
+      fprintf(stderr,"(( \n %s \n %s \n ))",*arrayStep,value);
+#endif
+      if(tmpMap!=NULL)
+        addToMap(tmpMap,*arrayStep,value);
+      else
+        tmpMap=createMap(*arrayStep,value);
+      arrayStep++;
+      delete[]value;
+    }
+    cgiStringArrayFree(array);
+  }
+ 
+#ifdef WIN32
+  map *tmpReq=getMap(tmpMap,"rfile");  
+  if(tmpReq!=NULL){	  	  
+    FILE *lf=fopen(tmpReq->value,"r");	
+    fseek(lf,0,SEEK_END);
+    long flen=ftell(lf);
+    fseek(lf,0,SEEK_SET);
+    char *buffer=(char*)malloc((flen+1)*sizeof(char));
+    fread(buffer,flen,1,lf);
+    char *pchr=strrchr(buffer,'>');
+    cgiContentLength=strlen(buffer)-strlen(pchr)+1;
+    buffer[cgiContentLength]=0;
+    fclose(lf);
+    addToMap(tmpMap,"request",buffer);
+    free(buffer);
+  }
+#endif
+  /**
+   * In case that the POST method was used, then check if params came in XML
+   * format else try to use the attribute "request" which should be the only 
+   * one.
+   */
+  if(strncasecmp(cgiRequestMethod,"post",4)==0 || 
+     (count(tmpMap)==1 && strncmp(tmpMap->value,"<",1)==0) 
+#ifdef WIN32
+     ||tmpReq!=NULL
+#endif
+     ){
+    /**
+     * Store the original XML request in xrequest map
+     */
+    map* t1=getMap(tmpMap,"request");
+    if(t1!=NULL && strncasecmp(t1->value,"<",1)==0) {
+      addToMap(tmpMap,"xrequest",t1->value);
+      xmlInitParser();
+      xmlDocPtr doc = xmlReadMemory(t1->value, cgiContentLength, "input_request.xml", NULL, XML_PARSE_RECOVER);
+      {
+	xmlXPathObjectPtr reqptr=extractFromDoc(doc,"/*[local-name()='Envelope']/*[local-name()='Body']/*");
+	if(reqptr!=NULL){
+	  xmlNodeSet* req=reqptr->nodesetval;
+	  if(req!=NULL && req->nodeNr==1){
+	    addToMap(tmpMap,"soap","true");
+	    for(int k=0;k < req->nodeNr;k++){
+	      xmlDocSetRootElement(doc, req->nodeTab[k]);
+	      xmlChar *xmlbuff;
+	      int buffersize;
+	      xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, "utf-8", 1);
+	      addToMap(tmpMap,"xrequest",(char*)xmlbuff);
+	      xmlFree(xmlbuff);
+	    }
+	  }
+	  xmlXPathFreeObject(reqptr);
+	}
+      }
+
+      xmlNodePtr cur = xmlDocGetRootElement(doc);
+      char *tval;
+      tval=NULL;
+      tval = (char*) xmlGetProp(cur,BAD_CAST "service");
+      if(tval!=NULL){
+	addToMap(tmpMap,"service",tval);
+	xmlFree(tval);
+      }
+      tval=NULL;
+      tval = (char*) xmlGetProp(cur,BAD_CAST "language");
+      if(tval!=NULL){
+	addToMap(tmpMap,"language",tval);
+	xmlFree(tval);
+      }
+      const char* requests[6]={"GetCapabilities","DescribeProcess","Execute","GetStatus","GetResult","Dismiss"};
+      for(int j=0;j<6;j++){
+	char tt[128];
+	sprintf(tt,"/*[local-name()='%s']",requests[j]);
+	xmlXPathObjectPtr reqptr=extractFromDoc(doc,tt);
+	if(reqptr!=NULL){
+	  xmlNodeSet* req=reqptr->nodesetval;
+#ifdef DEBUG
+	  fprintf(stderr,"%i",req->nodeNr);
+#endif
+	  if(req!=NULL && req->nodeNr==1){
+	    if(t1->value!=NULL)
+	      free(t1->value);
+	    t1->value=zStrdup(requests[j]);
+	    j=5;
+	  }
+	  xmlXPathFreeObject(reqptr);
+	}
+      }
+      if(strncasecmp(t1->value,"GetCapabilities",15)==0){
+	xmlXPathObjectPtr versptr=extractFromDoc(doc,"/*/*/*[local-name()='Version']");
+	xmlNodeSet* vers=versptr->nodesetval;
+	if(vers!=NULL && vers->nodeTab!=NULL && vers->nodeTab[0]!=NULL){
+	  xmlChar* content=xmlNodeListGetString(doc, vers->nodeTab[0]->xmlChildrenNode,1);
+	  addToMap(tmpMap,"version",(char*)content);
+	  xmlFree(content);
+	}
+	if(cur->ns){
+	  addToMap(tmpMap,"wps_schemas",(char*)cur->ns->href);
+	  int j=0;
+	  for(j=0;j<2;j++)
+	    if(strncasecmp(schemas[j][2],(char*)cur->ns->href,strlen(schemas[j][2]))==0){
+	      char vers[6];
+	      sprintf(vers,"%d.0.0",j+1);
+	      addToMap(tmpMap,"version",(char*)vers);
+	    }
+	}
+	xmlXPathFreeObject(versptr);
+      }else{
+	tval=NULL;
+	tval = (char*) xmlGetProp(cur,BAD_CAST "version");
+	if(tval!=NULL){
+	  addToMap(tmpMap,"version",tval);
+	  xmlFree(tval);
+	}
+	tval = (char*) xmlGetProp(cur,BAD_CAST "language");
+	if(tval!=NULL){
+	  addToMap(tmpMap,"language",tval);
+	  xmlFree(tval);
+	}
+	xmlXPathObjectPtr idptr=extractFromDoc(doc,"/*/*[local-name()='Identifier']");
+	if(idptr!=NULL){
+	  xmlNodeSet* id=idptr->nodesetval;
+	  if(id!=NULL){
+	    char* identifiers=NULL;
+	    identifiers=(char*)calloc(cgiContentLength,sizeof(char));
+	    identifiers[0]=0;
+	    for(int k=0;k<id->nodeNr;k++){
+	      xmlChar* content=xmlNodeListGetString(doc, id->nodeTab[k]->xmlChildrenNode,1);
+	      if(strlen(identifiers)>0){
+		char *tmp=zStrdup(identifiers);
+		snprintf(identifiers,strlen(tmp)+xmlStrlen(content)+2,"%s,%s",tmp,content);
+		free(tmp);
+	      }
+	      else{
+		snprintf(identifiers,xmlStrlen(content)+1,"%s",content);
+	      }
+	      xmlFree(content);
+	    }
+	    xmlXPathFreeObject(idptr);
+	    if(identifiers[0]!=0)
+	      addToMap(tmpMap,"Identifier",identifiers);
+	    free(identifiers);
+	  }
+	}
+	if(getMap(tmpMap,"Identifier")==NULL){
+	  idptr=extractFromDoc(doc,"/*/*[local-name()='JobID']");
+	  if(idptr!=NULL){
+	    xmlNodeSet* id=idptr->nodesetval;
+	    if(id!=NULL){
+	      char* identifiers=NULL;
+	      identifiers=(char*)calloc(cgiContentLength,sizeof(char));
+	      identifiers[0]=0;
+	      for(int k=0;k<id->nodeNr;k++){
+		  xmlChar* content=xmlNodeListGetString(doc, id->nodeTab[k]->xmlChildrenNode,1);
+		  if(strlen(identifiers)>0){
+		    char *tmp=zStrdup(identifiers);
+		    snprintf(identifiers,strlen(tmp)+xmlStrlen(content)+2,"%s,%s",tmp,content);
+		    free(tmp);
+		  }
+		  else{
+		    snprintf(identifiers,xmlStrlen(content)+1,"%s",content);
+		  }
+		  xmlFree(content);
+	      }
+	      xmlXPathFreeObject(idptr);
+	      if(identifiers[0]!=0)
+		addToMap(tmpMap,"JobID",identifiers);
+	      free(identifiers);
+	    }
+	  }
+	}
+      }
+      xmlFreeDoc(doc);
+      xmlCleanupParser();
+    }else{
+      freeMap(&tmpMap);
+      free(tmpMap);
+      tmpMap=createMap("not_valid","true");
+    }
+
+    char *token,*saveptr;
+    token=strtok_r(cgiQueryString,"&",&saveptr);
+    while(token!=NULL){
+      char *token1,*saveptr1;
+      char *name=NULL;
+      char *value=NULL;
+      token1=strtok_r(token,"=",&saveptr1);
+      while(token1!=NULL){
+        if(name==NULL)
+          name=zStrdup(token1);
+        else
+          value=zStrdup(token1);
+        token1=strtok_r(NULL,"=",&saveptr1);
+      }	  
+      //addToMap(tmpMap,name,value);
+      /* knut: strtok(_r) ignores delimiter bytes at start and end of string; 
+       * it will return non-empty string or NULL, e.g. "metapath=" yields value=NULL.
+       * This modification sets value="" instead of NULL.
+       */
+      addToMap(tmpMap,name, value != NULL ? value : "");
+      free(name);
+      free(value);
+      name=NULL;
+      value=NULL;
+      token=strtok_r(NULL,"&",&saveptr);
+    }
+  }
+  
+  if(strncasecmp(cgiContentType,"multipart/form-data",19)==0){
+    map* tmp=getMap(tmpMap,"dataInputs");
+    if(tmp!=NULL){
+      if(strcasestr(strQuery,"dataInputs=")!=NULL)
+	addToMap(tmpMap,"dataInputs",strcasestr(strQuery,"dataInputs=")+11);
+      else
+	addToMap(tmpMap,"dataInputs","None");
+    }
+  }
+
+  if(strQuery!=NULL)
+    free(strQuery);
+  
+  runRequest(&tmpMap);
+
+  if(tmpMap!=NULL){
+    freeMap(&tmpMap);
+    free(tmpMap);
+  }
+  return 0;
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-kernel/zoo_service_loader.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-kernel/zoo_service_loader.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-kernel/zoo_service_loader.c	(revision 942)
@@ -0,0 +1,2730 @@
+/*
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2008-2013 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+ 
+extern "C" int yylex ();
+extern "C" int crlex ();
+
+#ifdef META_DB
+#include "ogrsf_frmts.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+#endif
+
+#ifdef USE_OTB
+#include "service_internal_otb.h"
+#endif
+
+#ifdef USE_R
+#include "service_internal_r.h"
+#endif
+
+#ifdef USE_HPC
+#include "service_internal_hpc.h"
+#endif
+
+#ifdef USE_PYTHON
+#include "service_internal_python.h"
+#endif
+
+#include "cgic.h"
+
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include "ulinet.h"
+
+#include <libintl.h>
+#include <locale.h>
+#include <string.h>
+
+#include "service.h"
+
+#include "service_internal.h"
+#include "server_internal.h"
+#include "response_print.h"
+#include "request_parser.h"
+#include "sqlapi.h"
+#ifdef WIN32
+#include "caching.h"
+#endif
+
+#ifdef META_DB
+#include "meta_sql.h"
+#endif
+
+#ifdef USE_SAGA
+#include "service_internal_saga.h"
+#endif
+
+#ifdef USE_JAVA
+#include "service_internal_java.h"
+#endif
+
+#ifdef USE_PHP
+#include "service_internal_php.h"
+#endif
+
+#ifdef USE_JS
+#include "service_internal_js.h"
+#endif
+
+#ifdef USE_RUBY
+#include "service_internal_ruby.h"
+#endif
+
+#ifdef USE_PERL
+#include "service_internal_perl.h"
+#endif
+
+#ifdef USE_MONO
+#include "service_internal_mono.h"
+#endif
+
+#ifdef USE_CALLBACK
+#include "service_json.h"
+#include "service_callback.h"
+#endif
+
+#include <dirent.h>
+#include <signal.h>
+#ifndef WIN32
+#include <execinfo.h>
+#endif
+#include <unistd.h>
+#ifndef WIN32
+#include <dlfcn.h>
+#include <libgen.h>
+#else
+#include <windows.h>
+#include <direct.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#define pid_t int;
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <stdarg.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#ifndef WIN32
+extern char **environ;
+#endif
+
+
+#ifdef WIN32
+extern "C"
+{
+  __declspec (dllexport) char *strcasestr (char const *a, char const *b)
+#ifndef USE_MS
+  {
+    char *x = zStrdup (a);
+    char *y = zStrdup (b);
+
+      x = _strlwr (x);
+      y = _strlwr (y);
+    char *pos = strstr (x, y);
+    char *ret = pos == NULL ? NULL : (char *) (a + (pos - x));
+      free (x);
+      free (y);
+      return ret;
+  };
+#else
+   ;
+#endif
+}
+#endif
+
+/**
+ * Translation function for zoo-kernel
+ */
+#define _(String) dgettext ("zoo-kernel",String)
+/**
+ * Translation function for zoo-service
+ */
+#define __(String) dgettext ("zoo-service",String)
+
+#ifdef WIN32
+#ifndef PROGRAMNAME
+#define PROGRAMNAME "zoo_loader.cgi"
+#endif
+#endif
+
+
+/**
+ * Replace a char by another one in a string
+ *
+ * @param str the string to update
+ * @param toReplace the char to replace
+ * @param toReplaceBy the char that will be used
+ */
+void
+translateChar (char *str, char toReplace, char toReplaceBy)
+{
+  int i = 0, len = strlen (str);
+  for (i = 0; i < len; i++)
+    {
+      if (str[i] == toReplace)
+        str[i] = toReplaceBy;
+    }
+}
+
+/**
+ * Dump back the final file fbkp1 to fbkp
+ *
+ * @param m the conf maps containing the main.cfg settings
+ * @param fbkp the string corresponding to the name of the file
+ * @param fbkp1 the string corresponding to the name of the file
+ */
+int dumpBackFinalFile(maps* m,char* fbkp,char* fbkp1)
+{
+  FILE *f2 = fopen (fbkp1, "rb");
+#ifndef RELY_ON_DB
+  semid lid = getShmLockId (m, 1);
+  if (lid < 0)
+    return -1;
+  lockShm (lid);
+#endif
+  FILE *f3 = fopen (fbkp, "wb+");
+  free (fbkp);
+  fseek (f2, 0, SEEK_END);
+  long flen = ftell (f2);
+  fseek (f2, 0, SEEK_SET);
+  char *tmps1 = (char *) malloc ((flen + 1) * sizeof (char));
+  fread (tmps1, flen, 1, f2);
+#ifdef WIN32
+  /* knut: I think this block can be dropped; pchr may be NULL if result is not in XML format
+  char *pchr=strrchr(tmps1,'>');
+  flen=strlen(tmps1)-strlen(pchr)+1;
+  tmps1[flen]=0;
+  */
+#endif
+  fwrite (tmps1, 1, flen, f3);
+  fclose (f2);
+  fclose (f3);
+  free(tmps1);
+  return 1;
+}
+
+/**
+ * Recursivelly parse zcfg starting from the ZOO-Kernel cwd.
+ * Call the func function given in arguments after parsing the ZCFG file.
+ *
+ * @param m the conf maps containing the main.cfg settings
+ * @param r the registry containing profiles hierarchy
+ * @param n the root XML Node to add the sub-elements
+ * @param conf_dir the location of the main.cfg file (basically cwd)
+ * @param prefix the current prefix if any, or NULL
+ * @param saved_stdout the saved stdout identifier
+ * @param level the current level (number of sub-directories to reach the
+ * current path)
+ * @param func a pointer to a function having 4 parameters 
+ *  (registry*, maps*, xmlNodePtr and service*).
+ * @see inheritance, readServiceFile
+ */
+int
+recursReaddirF ( maps * m, registry *r, xmlDocPtr doc, xmlNodePtr n, char *conf_dir, 
+		 char *prefix, int saved_stdout, int level, 
+		 void (func) (registry *, maps *, xmlDocPtr, xmlNodePtr, service *) )
+{
+  struct dirent *dp;
+  int scount = 0;
+
+  if (conf_dir == NULL)
+    return 1;
+  DIR *dirp = opendir (conf_dir);
+  if (dirp == NULL)
+    {
+      if (level > 0)
+        return 1;
+      else
+        return -1;
+    }
+  char tmp1[25];
+  sprintf (tmp1, "sprefix_%d", level);
+  char levels[17];
+  sprintf (levels, "%d", level);
+  setMapInMaps (m, "lenv", "level", levels);
+  while ((dp = readdir (dirp)) != NULL)
+    if ((dp->d_type == DT_DIR || dp->d_type == DT_LNK) && dp->d_name[0] != '.'
+        && strstr (dp->d_name, ".") == NULL)
+      {
+
+        char *tmp =
+          (char *) malloc ((strlen (conf_dir) + strlen (dp->d_name) + 2) *
+                           sizeof (char));
+        sprintf (tmp, "%s/%s", conf_dir, dp->d_name);
+
+        if (prefix != NULL)
+          {
+            prefix = NULL;
+          }
+        prefix = (char *) malloc ((strlen (dp->d_name) + 2) * sizeof (char));
+        sprintf (prefix, "%s.", dp->d_name);
+
+        //map* tmpMap=getMapFromMaps(m,"lenv",tmp1);
+
+        int res;
+        if (prefix != NULL)
+          {
+            setMapInMaps (m, "lenv", tmp1, prefix);
+            char levels1[17];
+            sprintf (levels1, "%d", level + 1);
+            setMapInMaps (m, "lenv", "level", levels1);
+            res =
+              recursReaddirF (m, r, doc, n, tmp, prefix, saved_stdout, level + 1,
+                              func);
+            sprintf (levels1, "%d", level);
+            setMapInMaps (m, "lenv", "level", levels1);
+            free (prefix);
+            prefix = NULL;
+          }
+        else
+          res = -1;
+        free (tmp);
+        if (res < 0)
+          {
+            return res;
+          }
+      }
+    else
+      {
+        char* extn = strstr(dp->d_name, ".zcfg");
+        if(dp->d_name[0] != '.' && extn != NULL && strlen(extn) == 5 && strlen(dp->d_name)>6)
+          {
+            int t;
+            char tmps1[1024];
+            memset (tmps1, 0, 1024);
+            snprintf (tmps1, 1024, "%s/%s", conf_dir, dp->d_name);
+
+	    char *tmpsn = (char*)malloc((strlen(dp->d_name)-4)*sizeof(char));//zStrdup (dp->d_name);
+	    memset (tmpsn, 0, strlen(dp->d_name)-4);
+	    snprintf(tmpsn,strlen(dp->d_name)-4,"%s",dp->d_name);
+            
+            map* import = getMapFromMaps (m, IMPORTSERVICE, tmpsn);
+            if (import == NULL || import->value == NULL || zoo_path_compare(tmps1, import->value) != 0 ) { // service is not in [include] block 
+              service *s1 = createService();
+              if (s1 == NULL)
+                {
+                  zDup2 (saved_stdout, fileno (stdout));
+                  errorException (m, _("Unable to allocate memory"),
+                                  "InternalError", NULL);
+                  return -1;
+                }
+  #ifdef DEBUG
+              fprintf (stderr, "#################\n%s\n#################\n",
+                       tmps1);
+  #endif
+              t = readServiceFile (m, tmps1, &s1, tmpsn);
+              free (tmpsn);
+              if (t < 0)
+                {
+                  map *tmp00 = getMapFromMaps (m, "lenv", "message");
+                  char tmp01[1024];
+                  if (tmp00 != NULL)
+                    sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"),
+                             dp->d_name, tmp00->value);
+                  else
+                    sprintf (tmp01, _("Unable to parse the ZCFG file: %s."),
+                             dp->d_name);
+                  zDup2 (saved_stdout, fileno (stdout));
+                  errorException (m, tmp01, "InternalError", NULL);
+                  return -1;
+                }
+  #ifdef DEBUG
+              dumpService (s1);
+              fflush (stdout);
+              fflush (stderr);
+  #endif
+	      if(s1!=NULL)
+		inheritance(r,&s1);
+              func (r, m, doc, n, s1);
+              freeService (&s1);
+              free (s1);
+              scount++;
+            }
+          }
+      }
+  (void) closedir (dirp);
+  return 1;
+}
+
+/**
+ * Signal handling function which simply call exit(0).
+ *
+ * @param sig the signal number
+ */
+void
+donothing (int sig)
+{
+#ifdef DEBUG
+  fprintf (stderr, "Signal %d after the ZOO-Kernel returned result!\n", sig);
+#endif
+  exit (0);
+}
+
+/**
+ * Signal handling function which create an ExceptionReport node containing the
+ * information message corresponding to the signal number.
+ *
+ * @param sig the signal number
+ */
+void
+sig_handler (int sig)
+{
+  
+  char tmp[100];
+  const char *ssig;
+  switch (sig)
+    {
+    case SIGSEGV:
+      ssig = "SIGSEGV";
+      break;
+    case SIGTERM:
+      ssig = "SIGTERM";
+      break;
+    case SIGINT:
+      ssig = "SIGINT";
+      break;
+    case SIGILL:
+      ssig = "SIGILL";
+      break;
+    case SIGFPE:
+      ssig = "SIGFPE";
+      break;
+    case SIGABRT:
+      ssig = "SIGABRT";
+      break;
+    default:
+      ssig = "UNKNOWN";
+      break;
+    }
+  sprintf (tmp,
+           _
+           ("ZOO Kernel failed to process your request, receiving signal %d = %s "),
+           sig, ssig);
+  errorException (NULL, tmp, "InternalError", NULL);
+#ifdef DEBUG
+  fprintf (stderr, "Not this time!\n");
+#endif
+  exit (0);
+}
+
+/**
+ * Load a service provider and run the service function.
+ *
+ * @param myMap the conf maps containing the main.cfg settings
+ * @param s1 the service structure
+ * @param request_inputs map storing all the request parameters
+ * @param inputs the inputs maps
+ * @param ioutputs the outputs maps
+ * @param eres the result returned by the service execution
+ */
+void
+loadServiceAndRun (maps ** myMap, service * s1, map * request_inputs,
+                   maps ** inputs, maps ** ioutputs, int *eres)
+{
+  char tmps1[1024];
+  char ntmp[1024];
+  maps *m = *myMap;
+  maps *request_output_real_format = *ioutputs;
+  maps *request_input_real_format = *inputs;
+  /**
+   * Extract serviceType to know what kind of service should be loaded
+   */
+  map *r_inputs = NULL;
+  map* cwdMap=getMapFromMaps(m,"main","servicePath");
+  if(cwdMap!=NULL){
+    sprintf(ntmp,"%s",cwdMap->value);
+  }else{
+#ifndef WIN32
+    getcwd (ntmp, 1024);
+#else
+    _getcwd (ntmp, 1024);
+#endif
+  }
+  r_inputs = getMap (s1->content, "serviceType");
+#ifdef DEBUG
+  fprintf (stderr, "LOAD A %s SERVICE PROVIDER \n", r_inputs->value);
+  fflush (stderr);
+#endif
+
+  map* libp = getMapFromMaps(m, "main", "libPath");  
+  if (strlen (r_inputs->value) == 1
+      && strncasecmp (r_inputs->value, "C", 1) == 0)
+  {
+     if (libp != NULL && libp->value != NULL) {
+	    r_inputs = getMap (s1->content, "ServiceProvider");
+		sprintf (tmps1, "%s/%s", libp->value, r_inputs->value);
+	 }
+     else {	 
+        r_inputs = getMap (request_inputs, "metapath");
+        if (r_inputs != NULL)
+          sprintf (tmps1, "%s/%s", ntmp, r_inputs->value);
+        else
+          sprintf (tmps1, "%s/", ntmp);
+	  
+        char *altPath = zStrdup (tmps1);
+        r_inputs = getMap (s1->content, "ServiceProvider");
+        sprintf (tmps1, "%s/%s", altPath, r_inputs->value);
+        free (altPath);
+	 }
+#ifdef DEBUG
+      fprintf (stderr, "Trying to load %s\n", tmps1);
+#endif
+#ifdef WIN32
+      HINSTANCE so =
+        LoadLibraryEx (tmps1, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+#else
+      void *so = dlopen (tmps1, RTLD_LAZY);
+#endif
+#ifdef WIN32
+      char* errstr = getLastErrorMessage();
+#else
+      char *errstr;
+      errstr = dlerror ();
+#endif
+#ifdef DEBUG
+	  fprintf (stderr, "%s loaded (%s) \n", tmps1, errstr);
+#endif
+      if (so != NULL)
+        {
+#ifdef DEBUG
+          fprintf (stderr, "Library loaded %s \n", errstr);
+          fprintf (stderr, "Service Shared Object = %s\n", r_inputs->value);
+#endif
+          r_inputs = getMap (s1->content, "serviceType");
+#ifdef DEBUG
+          dumpMap (r_inputs);
+          fprintf (stderr, "%s\n", r_inputs->value);
+          fflush (stderr);
+#endif
+          if (strncasecmp (r_inputs->value, "C-FORTRAN", 9) == 0)
+            {
+              r_inputs = getMap (request_inputs, "Identifier");
+              char fname[1024];
+              sprintf (fname, "%s_", r_inputs->value);
+#ifdef DEBUG
+              fprintf (stderr, "Try to load function %s\n", fname);
+#endif
+#ifdef WIN32
+              typedef int (CALLBACK * execute_t) (char ***, char ***,
+                                                  char ***);
+              execute_t execute = (execute_t) GetProcAddress (so, fname);
+#else
+              typedef int (*execute_t) (char ***, char ***, char ***);
+              execute_t execute = (execute_t) dlsym (so, fname);
+#endif
+#ifdef DEBUG
+#ifdef WIN32
+			  errstr = getLastErrorMessage();
+#else
+              errstr = dlerror ();
+#endif
+              fprintf (stderr, "Function loaded %s\n", errstr);
+#endif
+
+              char main_conf[10][30][1024];
+              char inputs[10][30][1024];
+              char outputs[10][30][1024];
+              for (int i = 0; i < 10; i++)
+                {
+                  for (int j = 0; j < 30; j++)
+                    {
+                      memset (main_conf[i][j], 0, 1024);
+                      memset (inputs[i][j], 0, 1024);
+                      memset (outputs[i][j], 0, 1024);
+                    }
+                }
+              mapsToCharXXX (m, (char ***) main_conf);
+              mapsToCharXXX (request_input_real_format, (char ***) inputs);
+              mapsToCharXXX (request_output_real_format, (char ***) outputs);
+              *eres =
+                execute ((char ***) &main_conf[0], (char ***) &inputs[0],
+                         (char ***) &outputs[0]);
+#ifdef DEBUG
+              fprintf (stderr, "Function run successfully \n");
+#endif
+              charxxxToMaps ((char ***) &outputs[0],
+                             &request_output_real_format);
+            }
+          else
+            {
+#ifdef DEBUG
+#ifdef WIN32
+			  errstr = getLastErrorMessage();
+              fprintf (stderr, "Function %s failed to load because of %s\n",
+                       r_inputs->value, errstr);
+#endif
+#endif
+              r_inputs = getMapFromMaps (m, "lenv", "Identifier");
+#ifdef DEBUG
+              fprintf (stderr, "Try to load function %s\n", r_inputs->value);
+#endif
+              typedef int (*execute_t) (maps **, maps **, maps **);
+#ifdef WIN32
+              execute_t execute =
+                (execute_t) GetProcAddress (so, r_inputs->value);
+#else
+              execute_t execute = (execute_t) dlsym (so, r_inputs->value);
+#endif
+
+              if (execute == NULL)
+                {
+#ifdef WIN32
+				  errstr = getLastErrorMessage();
+#else
+                  errstr = dlerror ();
+#endif
+                  char *tmpMsg =
+                    (char *) malloc (2048 + strlen (r_inputs->value));
+                  sprintf (tmpMsg,
+                           _
+                           ("Error occurred while running the %s function: %s"),
+                           r_inputs->value, errstr);
+                  errorException (m, tmpMsg, "InternalError", NULL);
+                  free (tmpMsg);
+#ifdef DEBUG
+                  fprintf (stderr, "Function %s error %s\n", r_inputs->value,
+                           errstr);
+#endif
+                  *eres = -1;
+                  return;
+                }
+
+#ifdef DEBUG
+#ifdef WIN32
+			  errstr = getLastErrorMessage();
+#else
+              errstr = dlerror ();
+#endif
+              fprintf (stderr, "Function loaded %s\n", errstr);
+#endif
+
+#ifdef DEBUG
+              fprintf (stderr, "Now run the function \n");
+              fflush (stderr);
+#endif
+              *eres =
+                execute (&m, &request_input_real_format,
+                         &request_output_real_format);
+#ifdef DEBUG
+              fprintf (stderr, "Function loaded and returned %d\n", eres);
+              fflush (stderr);
+#endif
+            }
+#ifdef WIN32
+          *ioutputs = dupMaps (&request_output_real_format);
+          FreeLibrary (so);
+#else
+          dlclose (so);
+#endif
+        }
+      else
+        {
+      /**
+       * Unable to load the specified shared library
+       */
+          char tmps[1024];
+#ifdef WIN32
+		  errstr = getLastErrorMessage();
+#else
+	      errstr = dlerror ();
+#endif
+          sprintf (tmps, _("Unable to load C Library %s"), errstr);
+	  errorException(m,tmps,"InternalError",NULL);
+          *eres = -1;
+        }
+    }
+  else
+
+#ifdef USE_HPC
+  if (strncasecmp (r_inputs->value, "HPC", 3) == 0)
+    {
+      *eres =
+        zoo_hpc_support (&m, request_inputs, s1,
+                            &request_input_real_format,
+                            &request_output_real_format);
+    }
+  else
+#endif
+
+#ifdef USE_SAGA
+  if (strncasecmp (r_inputs->value, "SAGA", 4) == 0)
+    {
+      *eres =
+        zoo_saga_support (&m, request_inputs, s1,
+                            &request_input_real_format,
+                            &request_output_real_format);
+    }
+  else
+#endif
+
+#ifdef USE_OTB
+  if (strncasecmp (r_inputs->value, "OTB", 3) == 0)
+    {
+      *eres =
+        zoo_otb_support (&m, request_inputs, s1,
+                            &request_input_real_format,
+                            &request_output_real_format);
+    }
+  else
+#endif
+#ifdef USE_PYTHON
+  if (strncasecmp (r_inputs->value, "PYTHON", 6) == 0)
+    {		  
+      *eres =
+        zoo_python_support (&m, request_inputs, s1,
+                            &request_input_real_format,
+                            &request_output_real_format);	  
+    }
+  else
+#endif
+
+#ifdef USE_R
+  if (strncasecmp (r_inputs->value, "R", 6) == 0)
+    {	  
+      *eres =
+        zoo_r_support (&m, request_inputs, s1,
+                            &request_input_real_format,
+                            &request_output_real_format);
+    }
+  else
+#endif
+
+#ifdef USE_JAVA
+  if (strncasecmp (r_inputs->value, "JAVA", 4) == 0)
+    {
+      *eres =
+        zoo_java_support (&m, request_inputs, s1, &request_input_real_format,
+                          &request_output_real_format);
+    }
+  else
+#endif
+
+#ifdef USE_PHP
+  if (strncasecmp (r_inputs->value, "PHP", 3) == 0)
+    {
+      *eres =
+        zoo_php_support (&m, request_inputs, s1, &request_input_real_format,
+                         &request_output_real_format);		
+    }
+  else
+#endif
+
+
+#ifdef USE_PERL
+  if (strncasecmp (r_inputs->value, "PERL", 4) == 0)
+    {
+      *eres =
+        zoo_perl_support (&m, request_inputs, s1, &request_input_real_format,
+                          &request_output_real_format);
+    }
+  else
+#endif
+
+#ifdef USE_JS
+  if (strncasecmp (r_inputs->value, "JS", 2) == 0)
+    {
+      *eres =
+        zoo_js_support (&m, request_inputs, s1, &request_input_real_format,
+                        &request_output_real_format);
+    }
+  else
+#endif
+
+#ifdef USE_RUBY
+  if (strncasecmp (r_inputs->value, "Ruby", 4) == 0)
+    {
+      *eres =
+        zoo_ruby_support (&m, request_inputs, s1, &request_input_real_format,
+                          &request_output_real_format);
+    }
+  else
+#endif
+
+#ifdef USE_MONO
+  if (strncasecmp (r_inputs->value, "Mono", 4) == 0)
+    {
+      *eres =
+        zoo_mono_support (&m, request_inputs, s1, &request_input_real_format,
+                          &request_output_real_format);
+    }
+  else
+#endif
+
+    {
+      char tmpv[1024];
+      sprintf (tmpv,
+               _
+               ("Programming Language (%s) set in ZCFG file is not currently supported by ZOO Kernel.\n"),
+               r_inputs->value);
+      errorException (m, tmpv, "InternalError", NULL);
+      *eres = -1;
+    }
+  *myMap = m;
+  *ioutputs = request_output_real_format;  
+}
+
+
+#ifdef WIN32
+/**
+ * createProcess function: create a new process after setting some env variables
+ */
+void
+createProcess (maps * m, map * request_inputs, service * s1, char *opts,
+               int cpid, maps * inputs, maps * outputs)
+{
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+  ZeroMemory (&si, sizeof (si));
+  si.cb = sizeof (si);
+  ZeroMemory (&pi, sizeof (pi));
+  char *tmp = (char *) malloc ((1024 + cgiContentLength) * sizeof (char));
+  char *tmpq = (char *) malloc ((1024 + cgiContentLength) * sizeof (char));
+  map *req = getMap (request_inputs, "request");
+  map *id = getMap (request_inputs, "identifier");
+  map *di = getMap (request_inputs, "DataInputs");
+
+  // The required size for the dataInputsKVP and dataOutputsKVP buffers
+  // may exceed cgiContentLength, hence a 2 kb extension. However, a 
+  // better solution would be to have getMapsAsKVP() determine the required
+  // buffer size before allocating memory.	
+  char *dataInputsKVP = getMapsAsKVP (inputs, cgiContentLength + 2048, 0);
+  char *dataOutputsKVP = getMapsAsKVP (outputs, cgiContentLength + 2048, 1);
+#ifdef DEBUG
+  fprintf (stderr, "DATAINPUTSKVP %s\n", dataInputsKVP);
+  fprintf (stderr, "DATAOUTPUTSKVP %s\n", dataOutputsKVP);
+#endif
+  map *sid = getMapFromMaps (m, "lenv", "osid");
+  map *usid = getMapFromMaps (m, "lenv", "usid");
+  map *r_inputs = getMapFromMaps (m, "main", "tmpPath");
+  map *r_inputs1 = getMap (request_inputs, "metapath");
+  
+  int hasIn = -1;
+  if (r_inputs1 == NULL)
+    {
+      r_inputs1 = createMap ("metapath", "");
+      hasIn = 1;
+    }
+  map *r_inputs2 = getMap (request_inputs, "ResponseDocument");
+  if (r_inputs2 == NULL)
+    r_inputs2 = getMap (request_inputs, "RawDataOutput");
+  map *tmpPath = getMapFromMaps (m, "lenv", "cwd");
+
+  map *tmpReq = getMap (request_inputs, "xrequest");
+
+  if(r_inputs2 != NULL && tmpReq != NULL) {
+    const char key[] = "rfile=";
+    char* kvp = (char*) malloc((FILENAME_MAX + strlen(key))*sizeof(char));
+    char* filepath = kvp + strlen(key);
+    strncpy(kvp, key, strlen(key));
+    addToCache(m, tmpReq->value, tmpReq->value, "text/xml", strlen(tmpReq->value), 
+	       filepath, FILENAME_MAX);
+    if (filepath == NULL) {
+      errorException( m, _("Unable to cache HTTP POST Execute request."), "InternalError", NULL);  
+      return;
+    }	
+    sprintf(tmp,"\"metapath=%s&%s&cgiSid=%s&usid=%s\"",
+	    r_inputs1->value,kvp,sid->value,usid->value);
+    sprintf(tmpq,"metapath=%s&%s",
+	    r_inputs1->value,kvp);
+    free(kvp);	
+  }
+  else if (r_inputs2 != NULL)
+    {
+      sprintf (tmp,
+               "\"metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s&%s=%s&cgiSid=%s&usid=%s\"",
+               r_inputs1->value, req->value, id->value, dataInputsKVP,
+               r_inputs2->name, dataOutputsKVP, sid->value, usid->value);
+      sprintf (tmpq,
+               "metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s&%s=%s",
+               r_inputs1->value, req->value, id->value, dataInputsKVP,
+               r_inputs2->name, dataOutputsKVP);		   
+    }
+  else
+    {
+      sprintf (tmp,
+               "\"metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s&cgiSid=%s&usid=%s\"",
+               r_inputs1->value, req->value, id->value, dataInputsKVP,
+               sid->value, usid->value);
+      sprintf (tmpq,
+               "metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s",
+               r_inputs1->value, req->value, id->value, dataInputsKVP,
+               sid->value);   
+    }
+
+  if (hasIn > 0)
+    {
+      freeMap (&r_inputs1);
+      free (r_inputs1);
+    }
+  char *tmp1 = zStrdup (tmp);
+  sprintf (tmp, "\"%s\" %s \"%s\"", PROGRAMNAME, tmp1, sid->value);  
+  free (dataInputsKVP);
+  free (dataOutputsKVP);
+#ifdef DEBUG
+  fprintf (stderr, "REQUEST IS : %s \n", tmp);
+#endif
+
+  usid = getMapFromMaps (m, "lenv", "usid");
+  if (usid != NULL && usid->value != NULL) {
+    SetEnvironmentVariable("USID", TEXT (usid->value));
+  }
+  SetEnvironmentVariable ("CGISID", TEXT (sid->value));
+  SetEnvironmentVariable ("QUERY_STRING", TEXT (tmpq));
+  // knut: Prevent REQUEST_METHOD=POST in background process call to cgic:main 
+  // (process hangs when reading cgiIn):
+  SetEnvironmentVariable("REQUEST_METHOD", "GET");
+  SetEnvironmentVariable("CONTENT_TYPE", "text/plain");
+  
+  char clen[1000];
+  sprintf (clen, "%d", strlen (tmpq));
+  SetEnvironmentVariable ("CONTENT_LENGTH", TEXT (clen));
+
+  // ref. https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863%28v=vs.85%29.aspx
+  if (!CreateProcess (NULL,     // No module name (use command line)
+                      TEXT (tmp),       // Command line
+                      NULL,     // Process handle not inheritable
+                      NULL,     // Thread handle not inheritable
+                      FALSE,    // Set handle inheritance to FALSE
+                      CREATE_NO_WINDOW, // Apache won't wait until the end
+                      NULL,     // Use parent's environment block
+                      NULL,     // Use parent's starting directory 
+                      &si,      // Pointer to STARTUPINFO struct
+                      &pi)      // Pointer to PROCESS_INFORMATION struct
+    )
+    {
+#ifdef DEBUG
+      fprintf (stderr, "CreateProcess failed (%d).\n", GetLastError ());
+#endif
+      if (tmp != NULL) {
+        free(tmp);
+      }
+      if (tmpq != NULL) {
+        free(tmpq);
+      }		
+      return;
+    }
+  else
+    {
+#ifdef DEBUG
+      fprintf (stderr, "CreateProcess successful (%d).\n\n\n\n",
+               GetLastError ());
+#endif
+    }
+  CloseHandle (pi.hProcess);
+  CloseHandle (pi.hThread);
+  
+  if (tmp != NULL) {
+    free(tmp);
+  }
+  if (tmpq != NULL) {
+    free(tmpq);
+  }
+  
+#ifdef DEBUG
+  fprintf (stderr, "CreateProcess finished !\n");
+#endif
+}
+#endif
+
+/**
+ * Process the request.
+ *
+ * @param inputs the request parameters map 
+ * @return 0 on sucess, other value on failure
+ * @see conf_read,recursReaddirF
+ */
+int
+runRequest (map ** inputs)
+{
+ 
+#ifndef USE_GDB
+#ifndef WIN32
+  signal (SIGCHLD, SIG_IGN);
+#endif  
+  signal (SIGSEGV, sig_handler);
+  signal (SIGTERM, sig_handler);
+  signal (SIGINT, sig_handler);
+  signal (SIGILL, sig_handler);
+  signal (SIGFPE, sig_handler);
+  signal (SIGABRT, sig_handler);
+#endif
+
+  
+  map *r_inputs = NULL;
+  map *request_inputs = *inputs;
+  //fprintf(stderr,"%s \n",json_object_to_json_string_ext(mapToJson(request_inputs),JSON_C_TO_STRING_PLAIN));
+  
+#ifdef IGNORE_METAPATH
+  addToMap(request_inputs, "metapath", "");
+#endif  
+  maps *m = NULL;
+  char *REQUEST = NULL;
+  /**
+   * Parsing service specfic configuration file
+   */
+  m = (maps *) malloc (MAPS_SIZE);
+  if (m == NULL)
+    {
+      return errorException (NULL, _("Unable to allocate memory"),
+                             "InternalError", NULL);
+    }
+  m->child=NULL;
+  char ntmp[1024];
+#ifndef ETC_DIR
+#ifndef WIN32
+  getcwd (ntmp, 1024);
+#else
+  _getcwd (ntmp, 1024);
+#endif
+#else
+  sprintf(ntmp,"%s",ETC_DIR);
+#endif
+  r_inputs = getMapOrFill (&request_inputs, "metapath", "");
+
+  char conf_file[10240];
+  snprintf (conf_file, 10240, "%s/%s/main.cfg", ntmp, r_inputs->value);
+#ifdef ETC_DIR
+#ifndef WIN32
+  getcwd (ntmp, 1024);
+#else
+  _getcwd (ntmp, 1024);
+#endif
+#endif
+
+  if (conf_read (conf_file, m) == 2)
+    {
+      errorException (NULL, _("Unable to load the main.cfg file."),
+                      "InternalError", NULL);
+      free (m);
+      return 1;
+    }
+#ifdef DEBUG
+  fprintf (stderr, "***** BEGIN MAPS\n");
+  dumpMaps (m);
+  fprintf (stderr, "***** END MAPS\n");
+#endif
+
+  map *getPath = getMapFromMaps (m, "main", "gettextPath");
+  if (getPath != NULL)
+    {
+      bindtextdomain ("zoo-kernel", getPath->value);
+      bindtextdomain ("zoo-services", getPath->value);
+    }
+  else
+    {
+      bindtextdomain ("zoo-kernel", LOCALEDIR);
+      bindtextdomain ("zoo-services", LOCALEDIR);
+    }
+
+  /**
+   * Manage our own error log file (usefull to separate standard apache debug
+   * messages from the ZOO-Kernel ones but also for IIS users to avoid wrong 
+   * headers messages returned by the CGI due to wrong redirection of stderr)
+   */
+  FILE *fstde = NULL;
+  map *fstdem = getMapFromMaps (m, "main", "logPath");
+  if (fstdem != NULL)
+    fstde = freopen (fstdem->value, "a+", stderr);
+
+  r_inputs = getMap (request_inputs, "language");
+  if (r_inputs == NULL)
+    r_inputs = getMap (request_inputs, "AcceptLanguages");
+  if (r_inputs == NULL)
+    r_inputs = getMapFromMaps (m, "main", "language");
+  if (r_inputs != NULL)
+    {
+      if (isValidLang (m, r_inputs->value) < 0)
+        {
+          char tmp[1024];
+          sprintf (tmp,
+                   _
+                   ("The value %s is not supported for the <language> parameter"),
+                   r_inputs->value);
+          errorException (m, tmp, "InvalidParameterValue", "language");
+          freeMaps (&m);
+          free (m);
+          free (REQUEST);
+          return 1;
+
+        }
+      char *tmp = zStrdup (r_inputs->value);
+      setMapInMaps (m, "main", "language", tmp);
+#ifdef DEB
+      char tmp2[12];
+      sprintf (tmp2, "%s.utf-8", tmp);
+      translateChar (tmp2, '-', '_');
+      setlocale (LC_ALL, tmp2);
+#else
+      translateChar (tmp, '-', '_');
+      setlocale (LC_ALL, tmp);
+#endif
+#ifndef WIN32
+      setenv ("LC_ALL", tmp, 1);
+#else
+      char tmp1[13];
+      sprintf (tmp1, "LC_ALL=%s", tmp);
+      _putenv (tmp1);
+#endif
+      free (tmp);
+    }
+  else
+    {
+      setlocale (LC_ALL, "en_US");
+#ifndef WIN32
+      setenv ("LC_ALL", "en_US", 1);
+#else
+      char tmp1[13];
+      sprintf (tmp1, "LC_ALL=en_US");
+      _putenv (tmp1);
+#endif
+      setMapInMaps (m, "main", "language", "en-US");
+    }
+  setlocale (LC_NUMERIC, "C");
+#ifndef WIN32
+  setenv ("LC_NUMERIC", "C", 1);
+#else
+  char tmp1[17];
+  sprintf (tmp1, "LC_NUMERIC=C");
+  _putenv (tmp1);
+#endif
+  bind_textdomain_codeset ("zoo-kernel", "UTF-8");
+  textdomain ("zoo-kernel");
+  bind_textdomain_codeset ("zoo-services", "UTF-8");
+  textdomain ("zoo-services");
+
+  map *lsoap = getMap (request_inputs, "soap");
+  if (lsoap != NULL && strcasecmp (lsoap->value, "true") == 0)
+    setMapInMaps (m, "main", "isSoap", "true");
+  else
+    setMapInMaps (m, "main", "isSoap", "false");
+
+  if(strlen(cgiServerName)>0)
+    {
+      char tmpUrl[1024];
+	
+      if ( getenv("HTTPS") != NULL && strncmp(getenv("HTTPS"), "on", 2) == 0 ) {
+	// Knut: check if non-empty instead of "on"?		
+	if ( strncmp(cgiServerPort, "443", 3) == 0 ) { 
+	  sprintf(tmpUrl, "https://%s%s", cgiServerName, cgiScriptName);
+	}
+	else {
+	  sprintf(tmpUrl, "https://%s:%s%s", cgiServerName, cgiServerPort, cgiScriptName);
+	}
+      }
+      else {
+	if ( strncmp(cgiServerPort, "80", 2) == 0 ) { 
+	  sprintf(tmpUrl, "http://%s%s", cgiServerName, cgiScriptName);
+	}
+	else {
+	  sprintf(tmpUrl, "http://%s:%s%s", cgiServerName, cgiServerPort, cgiScriptName);
+	}
+      }
+#ifdef DEBUG
+      fprintf(stderr,"*** %s ***\n",tmpUrl);
+#endif
+      setMapInMaps(m,"main","serverAddress",tmpUrl);
+    }
+
+  // CORS Support
+  if(strncasecmp(cgiRequestMethod,"OPTIONS",7)==0){
+    map* cors=getMapFromMaps(m,"main","cors");
+    if(cors!=NULL && strncasecmp(cors->value,"true",4)==0){
+      char *encoding=getEncoding(m);
+      printHeaders(m);
+      printf("Content-Type: text/plain; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
+      printf(_("CORS is enabled.\r\n"));
+      freeMaps (&m);
+      free (m);
+      fflush (stdout);
+      return 3;
+    }
+  }
+
+  //Check for minimum inputs
+  map* version=getMap(request_inputs,"version");
+  if(version==NULL)
+    version=getMapFromMaps(m,"main","version");
+  setMapInMaps(m,"main","rversion",version->value);
+  int vid=getVersionId(version->value);
+  if(vid<0)
+    vid=0;
+  map* err=NULL;
+  const char **vvr=(const char**)requests[vid];
+  checkValidValue(request_inputs,&err,"request",vvr,1);
+  const char *vvs[]={
+    "WPS",
+    NULL
+  };
+  if(err!=NULL){
+    checkValidValue(request_inputs,&err,"service",(const char**)vvs,1);
+    printExceptionReportResponse (m, err);
+    freeMap(&err);
+    free(err);
+    if (count (request_inputs) == 1)
+      {
+	freeMap (&request_inputs);
+	free (request_inputs);
+      }
+    freeMaps (&m);
+    free (m);
+    return 1;
+  }
+  checkValidValue(request_inputs,&err,"service",(const char**)vvs,1);
+
+  const char *vvv[]={
+    "1.0.0",
+    "2.0.0",
+    NULL
+  };
+  r_inputs = getMap (request_inputs, "Request");
+  if(r_inputs!=NULL)
+    REQUEST = zStrdup (r_inputs->value);
+  int reqId=-1;
+  if (strncasecmp (REQUEST, "GetCapabilities", 15) != 0){
+    checkValidValue(request_inputs,&err,"version",(const char**)vvv,1);
+    int j=0;
+    for(j=0;j<nbSupportedRequests;j++){
+      if(requests[vid][j]!=NULL && requests[vid][j+1]!=NULL){
+	if(j<nbReqIdentifier && strncasecmp(REQUEST,requests[vid][j+1],strlen(requests[vid][j+1]))==0){
+	  checkValidValue(request_inputs,&err,"identifier",NULL,1);
+	  reqId=j+1;
+	  break;
+	}
+	else
+	  if(j>=nbReqIdentifier && j<nbReqIdentifier+nbReqJob && 
+	     strncasecmp(REQUEST,requests[vid][j+1],strlen(requests[vid][j+1]))==0){
+	    checkValidValue(request_inputs,&err,"jobid",NULL,1);
+	    reqId=j+1;
+	    break;
+	  }
+      }else
+	break;
+    }
+  }else{
+    checkValidValue(request_inputs,&err,"AcceptVersions",(const char**)vvv,-1);
+    map* version1=getMap(request_inputs,"AcceptVersions");
+    if(version1!=NULL){
+      if(strstr(version1->value,schemas[1][0])!=NULL){
+	addToMap(request_inputs,"version",schemas[1][0]);
+	setMapInMaps(m,"main","rversion",schemas[1][0]);
+      }
+      else{
+	addToMap(request_inputs,"version",version1->value);
+	setMapInMaps(m,"main","rversion",version1->value);
+      }
+      version=getMap(request_inputs,"version");
+    }
+  }
+  if(err!=NULL){
+    printExceptionReportResponse (m, err);
+    freeMap(&err);
+    free(err);
+    if (count (request_inputs) == 1)
+      {
+	freeMap (&request_inputs);
+	free (request_inputs);
+      }
+    free(REQUEST);
+    freeMaps (&m);
+    free (m);
+    return 1;
+  }
+
+  r_inputs = getMap (request_inputs, "serviceprovider");
+  if (r_inputs == NULL)
+    {
+      addToMap (request_inputs, "serviceprovider", "");
+    }
+
+  maps *request_output_real_format = NULL;
+  map *tmpm = getMapFromMaps (m, "main", "serverAddress");
+  if (tmpm != NULL)
+    SERVICE_URL = zStrdup (tmpm->value);
+  else
+    SERVICE_URL = zStrdup (DEFAULT_SERVICE_URL);
+
+
+
+  service *s1;
+  int scount = 0;
+#ifdef DEBUG
+  dumpMap (r_inputs);
+#endif
+  char conf_dir[1024];
+  int t;
+  char tmps1[1024];
+
+  r_inputs = NULL;
+  r_inputs = getMap (request_inputs, "metapath");
+  map* cwdMap0=getMapFromMaps(m,"main","servicePath");
+  if (r_inputs != NULL)
+    if(cwdMap0!=NULL)
+      snprintf (conf_dir, 1024, "%s/%s", cwdMap0->value, r_inputs->value);
+    else
+      snprintf (conf_dir, 1024, "%s/%s", ntmp, r_inputs->value);
+  else
+    if(cwdMap0!=NULL)
+      snprintf (conf_dir, 1024, "%s", cwdMap0->value);
+    else
+      snprintf (conf_dir, 1024, "%s", ntmp);
+  map* reg = getMapFromMaps (m, "main", "registry");
+  registry* zooRegistry=NULL;
+  if(reg!=NULL){
+#ifndef WIN32
+    int saved_stdout = zDup (fileno (stdout));
+    zDup2 (fileno (stderr), fileno (stdout));
+#endif
+    if(createRegistry (m,&zooRegistry,reg->value)<0){
+      map *message=getMapFromMaps(m,"lenv","message");
+      map *type=getMapFromMaps(m,"lenv","type");
+#ifndef WIN32
+      zDup2 (saved_stdout, fileno (stdout));
+#endif
+      errorException (m, message->value,
+		      type->value, NULL);
+      return 0;
+    }
+#ifndef WIN32
+    zDup2 (saved_stdout, fileno (stdout));
+    zClose(saved_stdout);
+#endif
+  }
+
+  if (strncasecmp (REQUEST, "GetCapabilities", 15) == 0)
+    {
+#ifdef DEBUG
+      dumpMap (r_inputs);
+#endif
+      xmlDocPtr doc = xmlNewDoc (BAD_CAST "1.0");
+      xmlNodePtr n=printGetCapabilitiesHeader(doc,m,(version!=NULL?version->value:"1.0.0"));
+      /**
+       * Here we need to close stdout to ensure that unsupported chars 
+       * has been found in the zcfg and then printed on stdout
+       */
+      int saved_stdout = zDup (fileno (stdout));
+      zDup2 (fileno (stderr), fileno (stdout));
+
+      maps* imports = getMaps(m, IMPORTSERVICE);
+      if (imports != NULL) {       
+        map* zcfg = imports->content;
+        
+        while (zcfg != NULL) {
+	  if (zcfg->value != NULL) {
+	    service* svc = (service*) malloc(SERVICE_SIZE);
+	    if (svc == NULL || readServiceFile(m, zcfg->value, &svc, zcfg->name) < 0) {
+	      // pass over silently
+	      zcfg = zcfg->next;
+	      continue;
+	    }
+	    inheritance(zooRegistry, &svc);
+	    printGetCapabilitiesForProcess(zooRegistry, m, doc, n, svc);
+	    freeService(&svc);
+	    free(svc);                             
+	  }
+	  zcfg = zcfg->next;
+        }            
+      }
+
+      if (int res =		  
+          recursReaddirF (m, zooRegistry, doc, n, conf_dir, NULL, saved_stdout, 0,
+                          printGetCapabilitiesForProcess) < 0)
+        {
+          freeMaps (&m);
+          free (m);
+	  if(zooRegistry!=NULL){
+	    freeRegistry(&zooRegistry);
+	    free(zooRegistry);
+	  }
+          free (REQUEST);
+          free (SERVICE_URL);
+          fflush (stdout);
+          return res;
+        }
+      fflush (stdout);
+      zDup2 (saved_stdout, fileno (stdout));
+#ifdef META_DB
+      fetchServicesFromDb(zooRegistry,m,doc,n,printGetCapabilitiesForProcess,1);
+      close_sql(m,0);
+#endif      
+      printDocument (m, doc, zGetpid ());
+      freeMaps (&m);
+      free (m);
+      if(zooRegistry!=NULL){
+	freeRegistry(&zooRegistry);
+	free(zooRegistry);
+      }
+      free (REQUEST);
+      free (SERVICE_URL);
+      fflush (stdout);
+      return 0;
+    }
+  else
+    {
+      r_inputs = getMap (request_inputs, "JobId");
+      if(reqId>nbReqIdentifier){
+	if (strncasecmp (REQUEST, "GetStatus", 9) == 0 ||
+	    strncasecmp (REQUEST, "GetResult", 9) == 0){
+	  runGetStatus(m,r_inputs->value,REQUEST);
+#ifdef RELY_ON_DB
+	  map* dsNb=getMapFromMaps(m,"lenv","ds_nb");
+	  if(dsNb!=NULL && atoi(dsNb->value)>1)
+	    close_sql(m,1);
+	  close_sql(m,0);
+#endif
+	  
+	  freeMaps (&m);
+	  free(m);
+	  if(zooRegistry!=NULL){
+	    freeRegistry(&zooRegistry);
+	    free(zooRegistry);
+	  }
+	  free (REQUEST);
+	  free (SERVICE_URL);
+	  return 0;
+	}
+	else
+	  if (strncasecmp (REQUEST, "Dismiss", strlen(REQUEST)) == 0){
+	    runDismiss(m,r_inputs->value);
+	    freeMaps (&m);
+	    free (m);
+	    if(zooRegistry!=NULL){
+	      freeRegistry(&zooRegistry);
+	      free(zooRegistry);
+	    }
+	    free (REQUEST);
+	    free (SERVICE_URL);
+	    return 0;
+	    
+	  }
+	return 0;
+      }
+      if(reqId<=nbReqIdentifier){
+	r_inputs = getMap (request_inputs, "Identifier");
+
+	struct dirent *dp;
+	DIR *dirp = opendir (conf_dir);
+	if (dirp == NULL)
+	  {
+	    errorException (m, _("The specified path does not exist."),
+			    "InternalError", NULL);
+	    freeMaps (&m);
+	    free (m);
+	    if(zooRegistry!=NULL){
+	      freeRegistry(&zooRegistry);
+	      free(zooRegistry);
+	    }
+	    free (REQUEST);
+	    free (SERVICE_URL);
+	    return 0;
+	  }
+	if (strncasecmp (REQUEST, "DescribeProcess", 15) == 0)
+	  {
+	    /**
+	     * Loop over Identifier list
+	     */
+	    xmlDocPtr doc = xmlNewDoc (BAD_CAST "1.0");
+	    r_inputs = NULL;
+	    r_inputs = getMap (request_inputs, "version");
+#ifdef DEBUG
+	    fprintf(stderr," ** DEBUG %s %d \n",__FILE__,__LINE__);
+	    fflush(stderr);
+#endif
+	    xmlNodePtr n = printWPSHeader(doc,m,"DescribeProcess",
+					  root_nodes[vid][1],(version!=NULL?version->value:"1.0.0"),1);
+
+	    r_inputs = getMap (request_inputs, "Identifier");
+
+	    char *orig = zStrdup (r_inputs->value);
+
+	    int saved_stdout = zDup (fileno (stdout));
+	    zDup2 (fileno (stderr), fileno (stdout));
+	    if (strcasecmp ("all", orig) == 0)
+	      {
+		maps* imports = getMaps(m, IMPORTSERVICE); 
+		if (imports != NULL) {       
+		  map* zcfg = imports->content;
+            
+		  while (zcfg != NULL) {
+		    if (zcfg->value != NULL) {
+		      service* svc = (service*) malloc(SERVICE_SIZE);
+		      if (svc == NULL || readServiceFile(m, zcfg->value, &svc, zcfg->name) < 0) {
+                        // pass over silently
+                        zcfg = zcfg->next;
+                        continue;
+		      }
+		      inheritance(zooRegistry, &svc);
+#ifdef USE_HPC
+		      addNestedOutputs(&svc);
+#endif
+
+		      printDescribeProcessForProcess(zooRegistry, m, doc, n, svc);
+		      freeService(&svc);
+		      free(svc);                             
+		    }
+		    zcfg = zcfg->next;
+		  }            
+		}
+  
+		if (int res =
+		    recursReaddirF (m, zooRegistry, doc, n, conf_dir, NULL, saved_stdout, 0,
+				    printDescribeProcessForProcess) < 0)
+		  return res;
+#ifdef META_DB
+		fetchServicesFromDb(zooRegistry,m,doc,n,printDescribeProcessForProcess,0);
+		close_sql(m,0);
+#endif      
+
+	      }
+	    else
+	      {
+		char *saveptr;
+		char *tmps = strtok_r (orig, ",", &saveptr);
+
+		char buff[256];
+		char buff1[1024];
+		while (tmps != NULL)
+		  {
+		    int hasVal = -1;
+		    char *corig = zStrdup (tmps);
+		    map* import = getMapFromMaps (m, IMPORTSERVICE, corig);   
+		    if (import != NULL && import->value != NULL) 
+		      {
+#ifdef META_DB			
+			service* s2=extractServiceFromDb(m,import->name,0);
+			if(s2==NULL){
+#endif
+			  s1 = createService();
+			  t = readServiceFile (m, import->value, &s1, import->name);
+                
+			  if (t < 0) // failure reading zcfg
+			    {
+			      map *tmp00 = getMapFromMaps (m, "lenv", "message");
+			      char tmp01[1024];
+			      if (tmp00 != NULL)
+				sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"), import->value, tmp00->value);
+			      else
+				sprintf (tmp01, _("Unable to parse the ZCFG file: %s."), import->value);
+			      
+			      zDup2 (saved_stdout, fileno (stdout));
+			      errorException (m, tmp01, "InternalError", NULL);
+			      
+			      freeMaps (&m);
+			      free (m);
+
+			      if(zooRegistry!=NULL){
+				freeRegistry(&zooRegistry);
+				free(zooRegistry);
+			      }
+			      free (orig);
+			      free (REQUEST);
+			      closedir (dirp);
+			      //xmlFreeDoc (doc);
+			      xmlCleanupParser ();
+			      zooXmlCleanupNs ();
+                    
+			      return 1;
+			    }
+#ifdef DEBUG
+			  dumpService (s1);
+#endif
+			  inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+			  addNestedOutputs(&s1);
+#endif
+			  printDescribeProcessForProcess (zooRegistry, m, doc, n, s1);
+			  freeService (&s1);
+			  free (s1);
+			  s1 = NULL;
+			  scount++;
+			  hasVal = 1;                
+#ifdef META_DB
+			}
+#endif
+		      }
+		    else if (strstr (corig, ".") != NULL)
+		      {
+
+			parseIdentifier (m, conf_dir, corig, buff1);
+			map *tmpMap = getMapFromMaps (m, "lenv", "metapath");
+			if (tmpMap != NULL)
+			  addToMap (request_inputs, "metapath", tmpMap->value);
+			map *tmpMapI = getMapFromMaps (m, "lenv", "Identifier");
+			/**
+			 * No support for dot in service name stored in metadb!?
+			 #ifdef META_DB
+			 service* s2=extractServiceFromDb(m,tmpMapI->value,0);
+			 if(s2==NULL){
+			 #endif
+			*/
+			s1 = createService();
+			t = readServiceFile (m, buff1, &s1, tmpMapI->value);
+			if (t < 0)
+			  {
+			    map *tmp00 = getMapFromMaps (m, "lenv", "message");
+			    char tmp01[1024];
+			    if (tmp00 != NULL)
+			      sprintf (tmp01,
+				       _
+				       ("Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"),
+				       tmps, tmp00->value);
+			    else
+			      sprintf (tmp01,
+				       _
+				       ("Unable to parse the ZCFG file for the following ZOO-Service: %s."),
+				       tmps);
+			    zDup2 (saved_stdout, fileno (stdout));
+			    errorException (m, tmp01, "InvalidParameterValue",
+					    "identifier");
+			    freeMaps (&m);
+			    free (m);
+			    if(zooRegistry!=NULL){
+			      freeRegistry(&zooRegistry);
+			      free(zooRegistry);
+			    }
+			    free (REQUEST);
+			    free (corig);
+			    free (orig);
+			    free (SERVICE_URL);
+			    free (s1);
+			    closedir (dirp);
+			    //xmlFreeDoc (doc);
+			    xmlCleanupParser ();
+			    zooXmlCleanupNs ();
+			    return 1;
+			  }
+#ifdef DEBUG
+			dumpService (s1);
+#endif
+			inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+			addNestedOutputs(&s1);
+#endif
+			printDescribeProcessForProcess (zooRegistry, m, doc, n, s1);
+			freeService (&s1);
+			free (s1);
+			s1 = NULL;
+			scount++;
+			hasVal = 1;
+			setMapInMaps (m, "lenv", "level", "0");
+		      }
+		    else
+		      {
+#ifdef META_DB
+			_init_sql(m,"metadb");
+			//FAILED CONNECTING DB
+			if(getMapFromMaps(m,"lenv","dbIssue")!=NULL){
+			  fprintf(stderr,"ERROR CONNECTING METADB");
+			}
+			service* s2=extractServiceFromDb(m,corig,0);
+			if(s2!=NULL){
+			  inheritance(zooRegistry,&s2);
+#ifdef USE_HPC
+			  addNestedOutputs(&s2);
+#endif
+			  printDescribeProcessForProcess (zooRegistry,m, doc, n, s2);
+			  freeService (&s2);
+			  free (s2);
+			  s2 = NULL;
+			  hasVal = 1;
+			}else /*TOTO*/{
+#endif
+			  memset (buff, 0, 256);
+			  snprintf (buff, 256, "%s.zcfg", corig);
+			  memset (buff1, 0, 1024);
+#ifdef DEBUG
+			  printf ("\n#######%s\n########\n", buff);
+#endif
+			  while ((dp = readdir (dirp)) != NULL)
+			    {
+			      if (strcasecmp (dp->d_name, buff) == 0)
+				{
+				  memset (buff1, 0, 1024);
+				  snprintf (buff1, 1024, "%s/%s", conf_dir,
+					    dp->d_name);
+				  s1 = createService();
+				  if (s1 == NULL)
+				    {
+				      zDup2 (saved_stdout, fileno (stdout));
+				      return errorException (m,
+							     _
+							     ("Unable to allocate memory"),
+							     "InternalError",
+							     NULL);
+				    }
+#ifdef DEBUG_SERVICE_CONF
+				  fprintf
+				    (stderr,"#################\n(%s) %s\n#################\n",
+				     r_inputs->value, buff1);
+#endif
+				  char *tmp0 = zStrdup (dp->d_name);
+				  tmp0[strlen (tmp0) - 5] = 0;
+				  t = readServiceFile (m, buff1, &s1, tmp0);
+				  free (tmp0);
+				  if (t < 0)
+				    {
+				      map *tmp00 =
+					getMapFromMaps (m, "lenv", "message");
+				      char tmp01[1024];
+				      if (tmp00 != NULL)
+					sprintf (tmp01,
+						 _
+						 ("Unable to parse the ZCFG file: %s (%s)"),
+						 dp->d_name, tmp00->value);
+				      else
+					sprintf (tmp01,
+						 _
+						 ("Unable to parse the ZCFG file: %s."),
+						 dp->d_name);
+				      zDup2 (saved_stdout, fileno (stdout));
+				      errorException (m, tmp01, "InternalError",
+						      NULL);
+				      freeMaps (&m);
+				      free (m);
+				      if(zooRegistry!=NULL){
+					freeRegistry(&zooRegistry);
+					free(zooRegistry);
+				      }
+				      free (orig);
+				      free (REQUEST);
+				      closedir (dirp);
+				      //xmlFreeDoc (doc);
+				      xmlCleanupParser ();
+				      zooXmlCleanupNs ();
+				      return 1;
+				    }
+#ifdef DEBUG
+				  dumpService (s1);
+#endif
+				  inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+				  addNestedOutputs(&s1);
+#endif
+				  /*json_object* jobj=serviceToJson(s1);
+				  const char* jsonStr=json_object_to_json_string_ext(jobj,JSON_C_TO_STRING_PLAIN);
+				  fprintf(stderr,"*** %s %d %s \n",__FILE__,__LINE__,jsonStr);*/
+
+				  printDescribeProcessForProcess (zooRegistry,m, doc, n, s1);
+				  freeService (&s1);
+				  free (s1);
+				  s1 = NULL;
+				  scount++;
+				  hasVal = 1;
+				}
+			    }
+#ifdef META_DB
+			}
+#endif
+		      }		      
+		    if (hasVal < 0)
+		      {
+			map *tmp00 = getMapFromMaps (m, "lenv", "message");
+			char tmp01[1024];
+			if (tmp00 != NULL)
+			  sprintf (tmp01,
+				   _("Unable to parse the ZCFG file: %s (%s)"),
+				   buff, tmp00->value);
+			else
+			  sprintf (tmp01,
+				   _("Unable to parse the ZCFG file: %s."),
+				   buff);
+			zDup2 (saved_stdout, fileno (stdout));
+			errorException (m, tmp01, "InvalidParameterValue",
+					"Identifier");
+			freeMaps (&m);
+			free (m);
+			if(zooRegistry!=NULL){
+			  freeRegistry(&zooRegistry);
+			  free(zooRegistry);
+			}
+			free (orig);
+			free (REQUEST);
+			closedir (dirp);
+			if (corig != NULL)
+			  free (corig);
+			xmlFreeDoc (doc);
+			xmlCleanupParser ();
+			zooXmlCleanupNs ();
+			return 1;
+		      }
+		    rewinddir (dirp);
+		    tmps = strtok_r (NULL, ",", &saveptr);
+		    if (corig != NULL)
+		      free (corig);
+		  }		  
+	      }
+	    closedir (dirp);
+	    fflush (stdout);
+	    zDup2 (saved_stdout, fileno (stdout));
+	    free (orig);
+	    printDocument (m, doc, zGetpid ());
+	    freeMaps (&m);
+	    free (m);
+	    if(zooRegistry!=NULL){
+	      freeRegistry(&zooRegistry);
+	      free(zooRegistry);
+	    }
+	    free (REQUEST);
+	    free (SERVICE_URL);
+	    fflush (stdout);
+#ifdef META_DB
+	    close_sql(m,0);
+	    //end_sql();
+#endif
+	    return 0;
+	  }
+	else if (strncasecmp (REQUEST, "Execute", strlen (REQUEST)) != 0)
+	  {
+	    map* version=getMapFromMaps(m,"main","rversion");
+	    int vid=getVersionId(version->value);	    
+	    int len = 0;
+	    int j = 0;
+	    for(j=0;j<nbSupportedRequests;j++){
+	      if(requests[vid][j]!=NULL)
+		len+=strlen(requests[vid][j])+2;
+	      else{
+		len+=4;
+		break;
+	      }
+	    }
+	    char *tmpStr=(char*)malloc(len*sizeof(char));
+	    int it=0;
+	    for(j=0;j<nbSupportedRequests;j++){
+	      if(requests[vid][j]!=NULL){
+		if(it==0){
+		  sprintf(tmpStr,"%s",requests[vid][j]);
+		  it++;
+		}else{
+		  char *tmpS=zStrdup(tmpStr);
+		  if(j+1<nbSupportedRequests && requests[vid][j+1]==NULL){
+		    sprintf(tmpStr,"%s and %s",tmpS,requests[vid][j]);
+		  }else{
+		    sprintf(tmpStr,"%s, %s",tmpS,requests[vid][j]);
+		  
+		  }
+		  free(tmpS);
+		}
+	      }
+	      else{
+		len+=4;
+		break;
+	      }
+	    }
+	    char* message=(char*)malloc((61+len)*sizeof(char));
+	    sprintf(message,"The <request> value was not recognized. Allowed values are %s.",tmpStr);
+	    errorException (m,_(message),"InvalidParameterValue", "request");
+#ifdef DEBUG
+	    fprintf (stderr, "No request found %s", REQUEST);
+#endif
+	    closedir (dirp);
+	    freeMaps (&m);
+	    free (m);
+	    if(zooRegistry!=NULL){
+	      freeRegistry(&zooRegistry);
+	      free(zooRegistry);
+	    }
+	    free (REQUEST);
+	    free (SERVICE_URL);
+	    fflush (stdout);
+	    return 0;
+	  }
+	closedir (dirp);
+      }
+    }
+
+  map *postRequest = NULL;
+  postRequest = getMap (request_inputs, "xrequest");
+  
+  if(vid==1 && postRequest==NULL){
+    errorException (m,_("Unable to run Execute request using the GET HTTP method"),"InvalidParameterValue", "request");  
+    freeMaps (&m);
+    free (m);
+    if(zooRegistry!=NULL){
+      freeRegistry(&zooRegistry);
+      free(zooRegistry);
+    }
+    free (REQUEST);
+    free (SERVICE_URL);
+    fflush (stdout);
+    return 0;
+  }
+  s1 = NULL;
+ 
+  r_inputs = getMap (request_inputs, "Identifier");
+  map* import = getMapFromMaps (m, IMPORTSERVICE, r_inputs->value); 
+  if (import != NULL && import->value != NULL) { 
+    strncpy(tmps1, import->value, 1024);
+    setMapInMaps (m, "lenv", "Identifier", r_inputs->value);
+    setMapInMaps (m, "lenv", "oIdentifier", r_inputs->value);
+  } 
+  else {
+    snprintf (tmps1, 1024, "%s/%s.zcfg", conf_dir, r_inputs->value);
+#ifdef DEBUG
+    fprintf (stderr, "Trying to load %s\n", tmps1);
+#endif
+    if (strstr (r_inputs->value, ".") != NULL)
+      {
+	char *identifier = zStrdup (r_inputs->value);
+	parseIdentifier (m, conf_dir, identifier, tmps1);
+	map *tmpMap = getMapFromMaps (m, "lenv", "metapath");
+	if (tmpMap != NULL)
+	  addToMap (request_inputs, "metapath", tmpMap->value);
+	free (identifier);
+      }
+    else
+      {
+	setMapInMaps (m, "lenv", "Identifier", r_inputs->value);
+	setMapInMaps (m, "lenv", "oIdentifier", r_inputs->value);
+      }
+  }
+
+  r_inputs = getMapFromMaps (m, "lenv", "Identifier");
+  
+#ifdef META_DB
+  int metadb_id=_init_sql(m,"metadb");
+  //FAILED CONNECTING DB
+  if(getMapFromMaps(m,"lenv","dbIssue")!=NULL || metadb_id<0){
+    fprintf(stderr,"ERROR CONNECTING METADB\n");
+  }
+  if(metadb_id>=0)
+    s1=extractServiceFromDb(m,r_inputs->value,0);
+  //close_sql(m,0);
+  if(s1!=NULL){
+    inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+    addNestedOutputs(&s1);
+#endif
+    if(zooRegistry!=NULL){
+      freeRegistry(&zooRegistry);
+      free(zooRegistry);
+    }
+  }else /* Not found in MetaDB */{
+#endif
+    s1 = createService();
+    if (s1 == NULL)
+      {
+	freeMaps (&m);
+	free (m);
+	if(zooRegistry!=NULL){
+	  freeRegistry(&zooRegistry);
+	  free(zooRegistry);
+	}
+	free (REQUEST);
+	free (SERVICE_URL);
+	return errorException (m, _("Unable to allocate memory"),
+			       "InternalError", NULL);
+      }
+
+    int saved_stdout = zDup (fileno (stdout));
+    zDup2 (fileno (stderr), fileno (stdout));
+    t = readServiceFile (m, tmps1, &s1, r_inputs->value);
+    if(t>=0){
+      inheritance(zooRegistry,&s1);
+#ifdef USE_HPC
+      addNestedOutputs(&s1);
+#endif
+    }
+    if(zooRegistry!=NULL){
+      freeRegistry(&zooRegistry);
+      free(zooRegistry);
+    }
+    fflush (stdout);
+    zDup2 (saved_stdout, fileno (stdout));
+    if (t < 0)
+      {
+	char *tmpMsg = (char *) malloc (2048 + strlen (r_inputs->value));
+	sprintf (tmpMsg,
+		 _
+		 ("The value for <identifier> seems to be wrong (%s). Please specify one of the processes in the list returned by a GetCapabilities request."),
+		 r_inputs->value);
+	errorException (m, tmpMsg, "InvalidParameterValue", "identifier");
+	free (tmpMsg);
+	free (s1);
+	freeMaps (&m);
+	free (m);
+	free (REQUEST);
+	free (SERVICE_URL);
+	return 0;
+      }
+    zClose (saved_stdout);
+#ifdef META_DB
+  }
+#endif
+  
+#ifdef DEBUG
+  dumpService (s1);
+#endif
+  int j;
+
+
+  /**
+   * Create the input and output maps data structure
+   */
+  int i = 0;
+  HINTERNET hInternet;
+  HINTERNET res;
+  hInternet = InternetOpen (
+#ifndef WIN32
+			    (LPCTSTR)
+#endif
+			    "ZooWPSClient\0",
+			    INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+
+#ifndef WIN32
+  if (!CHECK_INET_HANDLE (hInternet))
+    fprintf (stderr, "WARNING : hInternet handle failed to initialize");
+#endif
+  maps *request_input_real_format = NULL;
+  maps *tmpmaps = request_input_real_format;
+
+  if(parseRequest(&m,&request_inputs,s1,&request_input_real_format,&request_output_real_format,&hInternet)<0){
+    freeMaps (&m);
+    free (m);
+    free (REQUEST);
+    free (SERVICE_URL);
+    InternetCloseHandle (&hInternet);
+    freeService (&s1);
+    free (s1);
+    return 0;
+  }
+  //InternetCloseHandle (&hInternet);
+  
+  // Define each env variable in runing environment
+  maps *curs = getMaps (m, "env");
+  if (curs != NULL)
+    {
+      map *mapcs = curs->content;
+      while (mapcs != NULLMAP)
+        {
+#ifndef WIN32
+          setenv (mapcs->name, mapcs->value, 1);
+#ifdef DEBUG
+          fprintf (stderr, "[ZOO: setenv (%s=%s)]\n", mapcs->name,
+                   mapcs->value);
+#endif
+#else
+          if (mapcs->value[strlen (mapcs->value) - 2] == '\r')
+            {
+#ifdef DEBUG
+              fprintf (stderr, "[ZOO: Env var finish with \r]\n");
+#endif
+              mapcs->value[strlen (mapcs->value) - 1] = 0;
+            }
+#ifdef DEBUG
+          if (SetEnvironmentVariable (mapcs->name, mapcs->value) == 0)
+            {
+              fflush (stderr);
+              fprintf (stderr, "setting variable... %s\n", "OK");
+            }
+          else
+            {
+              fflush (stderr);
+              fprintf (stderr, "setting variable... %s\n", "OK");
+            }
+#else
+          SetEnvironmentVariable (mapcs->name, mapcs->value);
+#endif
+          char *toto =
+            (char *)
+            malloc ((strlen (mapcs->name) + strlen (mapcs->value) +
+                     2) * sizeof (char));
+          sprintf (toto, "%s=%s", mapcs->name, mapcs->value);
+          _putenv (toto);
+#ifdef DEBUG
+          fflush (stderr);
+#endif
+#endif
+
+#ifdef DEBUG
+          fprintf (stderr, "[ZOO: setenv (%s=%s)]\n", mapcs->name,
+                   mapcs->value);
+          fflush (stderr);
+#endif
+          mapcs = mapcs->next;
+        }
+    }
+
+#ifdef DEBUG
+  dumpMap (request_inputs);
+#endif
+
+  map *status = getMap (request_inputs, "status");
+  if(vid==0){
+    // Need to check if we need to fork to load a status enabled 
+    r_inputs = NULL;
+    map *store = getMap (request_inputs, "storeExecuteResponse");
+    /**
+     * 05-007r7 WPS 1.0.0 page 57 :
+     * 'If status="true" and storeExecuteResponse is "false" then the service 
+     * shall raise an exception.'
+     */
+    if (status != NULL && strcmp (status->value, "true") == 0 &&
+	store != NULL && strcmp (store->value, "false") == 0)
+      {
+	errorException (m,
+			_
+			("The status parameter cannot be set to true if storeExecuteResponse is set to false. Please modify your request parameters."),
+			"InvalidParameterValue", "storeExecuteResponse");
+	freeService (&s1);
+	free (s1);
+	freeMaps (&m);
+	free (m);
+	
+	freeMaps (&request_input_real_format);
+	free (request_input_real_format);
+	
+	freeMaps (&request_output_real_format);
+	free (request_output_real_format);
+
+	free (REQUEST);
+	free (SERVICE_URL);
+	return 1;
+      }
+    r_inputs = getMap (request_inputs, "storeExecuteResponse");
+  }else{
+    // Define status depending on the WPS 2.0.0 mode attribute
+    status = getMap (request_inputs, "mode");
+    map* mode=getMap(s1->content,"mode");
+    if(strcasecmp(status->value,"async")==0){
+      if(mode!=NULL && strcasecmp(mode->value,"async")==0)
+	addToMap(request_inputs,"status","true");
+      else{
+	if(mode!=NULL){
+	  // see ref. http://docs.opengeospatial.org/is/14-065/14-065.html#61
+	  errorException (m,_("The process does not permit the desired execution mode."),"NoSuchMode", mode->value);  
+	  fflush (stdout);
+	  freeMaps (&m);
+	  free (m);
+	  if(zooRegistry!=NULL){
+	    freeRegistry(&zooRegistry);
+	    free(zooRegistry);
+	  }
+	  freeMaps (&request_input_real_format);
+	  free (request_input_real_format);
+	  freeMaps (&request_output_real_format);
+	  free (request_output_real_format);
+	  free (REQUEST);
+	  free (SERVICE_URL);
+	  return 0;
+	}else
+	  addToMap(request_inputs,"status","true");
+      }
+    }
+    else{
+      if(strcasecmp(status->value,"auto")==0){
+	if(mode!=NULL){
+	  if(strcasecmp(mode->value,"async")==0)
+	    addToMap(request_inputs,"status","false");
+	  else
+	    addToMap(request_inputs,"status","true");
+	}
+	else
+	  addToMap(request_inputs,"status","false");
+      }else
+	addToMap(request_inputs,"status","false");
+    }
+    status = getMap (request_inputs, "status");
+  }
+
+  int eres = SERVICE_STARTED;
+  int cpid = zGetpid ();
+
+  // Create a map containing a copy of the request map
+  maps *_tmpMaps = createMaps("request");
+  addMapToMap(&_tmpMaps->content,request_inputs);
+  addMapsToMaps (&m, _tmpMaps);
+  freeMaps (&_tmpMaps);
+  free (_tmpMaps);
+  /**
+   * Initialize the specific [lenv] section which contains runtime variables:
+   * 
+   *  - usid : it is an universally unique identifier  
+   *  - osid : it is an idenfitication number 
+   *  - sid : it is the process idenfitication number (OS)
+   *  - uusid : it is an universally unique identifier 
+   *  - status : value between 0 and 100 to express the  completude of 
+   * the operations of the running service 
+   *  - message : is a string where you can store error messages, in case 
+   * service is failing, or o provide details on the ongoing operation.
+   *  - cwd : the current working directory or servicePath if defined
+   *  - soap : is a boolean value, true if the request was contained in a SOAP 
+   * Envelop 
+   *  - sessid : string storing the session identifier (only when cookie is 
+   * used)
+   *  - cgiSid : only defined on Window platforms (for being able to identify 
+   * the created process)
+   *
+   */
+  _tmpMaps = createMaps("lenv");
+  char tmpBuff[100];
+  struct ztimeval tp;
+  if (zGettimeofday (&tp, NULL) == 0)
+    sprintf (tmpBuff, "%i", (cpid + ((int) tp.tv_sec + (int) tp.tv_usec)));
+  else
+    sprintf (tmpBuff, "%i", (cpid + (int) time (NULL)));
+  _tmpMaps->content = createMap ("osid", tmpBuff);
+  sprintf (tmpBuff, "%i", cpid);
+  addToMap (_tmpMaps->content, "sid", tmpBuff);
+  char* tmpUuid=get_uuid();
+  addToMap (_tmpMaps->content, "uusid", tmpUuid);
+  addToMap (_tmpMaps->content, "usid", tmpUuid);
+  free(tmpUuid);
+  addToMap (_tmpMaps->content, "status", "0");
+  if(cwdMap0!=NULL){
+    addToMap (_tmpMaps->content, "cwd", cwdMap0->value);
+    addToMap (_tmpMaps->content, "rcwd", ntmp);
+  }
+  else
+    addToMap (_tmpMaps->content, "cwd", ntmp);
+  addToMap (_tmpMaps->content, "message", _("No message provided"));
+  map *ltmp = getMap (request_inputs, "soap");
+  if (ltmp != NULL)
+    addToMap (_tmpMaps->content, "soap", ltmp->value);
+  else
+    addToMap (_tmpMaps->content, "soap", "false");
+
+  // Parse the session file and add it to the main maps
+  char* originalCookie=NULL;
+  if (cgiCookie != NULL && strlen (cgiCookie) > 0)
+    {
+      int hasValidCookie = -1;
+      char *tcook = originalCookie = zStrdup (cgiCookie);
+      map *testing = getMapFromMaps (m, "main", "cookiePrefix");
+      parseCookie(&m,originalCookie);
+      map *sessId=getMapFromMaps(m,"cookies",(testing==NULL?"ID":testing->value));
+      if (sessId!=NULL)
+        {
+	  addToMap (_tmpMaps->content, "sessid", sessId->value);
+          char session_file_path[1024];
+          map *tmpPath = getMapFromMaps (m, "main", "sessPath");
+          if (tmpPath == NULL)
+            tmpPath = getMapFromMaps (m, "main", "tmpPath");
+          char *tmp1 = strtok (tcook, ";");
+          if (tmp1 != NULL)
+            sprintf (session_file_path, "%s/sess_%s.cfg", tmpPath->value,
+                     sessId->value);
+          else
+            sprintf (session_file_path, "%s/sess_%s.cfg", tmpPath->value,
+                     sessId->value);
+          free (tcook);
+          maps *tmpSess = (maps *) malloc (MAPS_SIZE);
+	  tmpSess->child=NULL;
+          struct stat file_status;
+          int istat = stat (session_file_path, &file_status);
+          if (istat == 0 && file_status.st_size > 0)
+            {
+	      int saved_stdout = zDup (fileno (stdout));
+	      zDup2 (fileno (stderr), fileno (stdout));
+              conf_read (session_file_path, tmpSess);
+              addMapsToMaps (&m, tmpSess);
+              freeMaps (&tmpSess);
+	      fflush(stdout);
+	      zDup2 (saved_stdout, fileno (stdout));
+	      zClose(saved_stdout);
+            }
+	  free (tmpSess);
+        }
+    }
+  addMapsToMaps (&m, _tmpMaps);
+  freeMaps (&_tmpMaps);
+  free (_tmpMaps);
+  maps* bmap=NULL;
+#ifdef DEBUG
+  dumpMap (request_inputs);
+#endif
+  int ei = 1;
+  
+#ifdef WIN32
+  LPVOID orig = GetEnvironmentStrings();
+  LPTSTR s = (LPTSTR) orig;
+#else
+  char **orig = environ;
+  char *s=*orig;
+#endif
+
+  _tmpMaps = createMaps("renv");
+if(orig!=NULL)
+  for (; 
+#ifdef WIN32
+       *s;
+       s++
+#else
+       s;
+       ei++
+#endif
+       ) {
+    if(strstr(s,"=")!=NULL && strlen(strstr(s,"="))>1){
+      int len=strlen(s);
+      char* tmpName=zStrdup(s);
+      char* tmpValue=strstr(s,"=")+1;
+      char* tmpName1=(char*)malloc((1+(len-(strlen(tmpValue)+1)))*sizeof(char));
+      snprintf(tmpName1,(len-strlen(tmpValue)),"%s",tmpName);
+      if(_tmpMaps->content == NULL)
+	_tmpMaps->content = createMap (tmpName1,tmpValue);
+      else
+	addToMap (_tmpMaps->content,tmpName1,tmpValue);
+      free(tmpName1);
+      free(tmpName);
+    }
+#ifndef WIN32
+    s = *(orig+ei);
+#endif
+  }
+  if(_tmpMaps->content!=NULL && getMap(_tmpMaps->content,"HTTP_COOKIE")!=NULL){
+    addToMap(_tmpMaps->content,"HTTP_COOKIE1",&cgiCookie[0]);
+  }
+  addMapsToMaps (&m, _tmpMaps);
+  freeMaps (&_tmpMaps);
+  free (_tmpMaps);
+#ifdef WIN32
+  FreeEnvironmentStrings((LPCH)orig);
+#endif
+  if(postRequest!=NULL)
+    setMapInMaps (m, "renv", "xrequest", postRequest->value);
+  //dumpMaps(m);
+#ifdef WIN32
+  char *cgiSidL = NULL;
+  if (getenv ("CGISID") != NULL)
+    addToMap (request_inputs, "cgiSid", getenv ("CGISID"));
+
+  char* usidp;
+  if ( (usidp = getenv("USID")) != NULL ) {
+    setMapInMaps (m, "lenv", "usid", usidp);
+  }
+
+  map *test1 = getMap (request_inputs, "cgiSid");
+  if (test1 != NULL){
+    cgiSid = zStrdup(test1->value);
+    addToMap (request_inputs, "storeExecuteResponse", "true");
+    addToMap (request_inputs, "status", "true");
+    setMapInMaps (m, "lenv", "osid", test1->value);
+    status = getMap (request_inputs, "status");
+  }
+  test1 = getMap (request_inputs, "usid");
+  if (test1 != NULL){
+    setMapInMaps (m, "lenv", "usid", test1->value);
+    setMapInMaps (m, "lenv", "uusid", test1->value);
+  }
+#endif
+
+  char *fbkp, *fbkpid, *fbkpres, *fbkp1, *flog;
+  FILE *f0, *f1;
+  if (status != NULL)
+    if (strcasecmp (status->value, "false") == 0)
+      status = NULLMAP;
+  if (status == NULLMAP)
+    {
+      if(validateRequest(&m,s1,request_inputs, &request_input_real_format,&request_output_real_format,&hInternet)<0){
+	freeService (&s1);
+	free (s1);
+	freeMaps (&m);
+	free (m);
+	free (REQUEST);
+	free (SERVICE_URL);
+	freeMaps (&request_input_real_format);
+	free (request_input_real_format);
+	freeMaps (&request_output_real_format);
+	free (request_output_real_format);
+	freeMaps (&tmpmaps);
+	free (tmpmaps);
+	return -1;
+      }
+      map* testMap=getMapFromMaps(m,"main","memory");
+      if(testMap==NULL || strcasecmp(testMap->value,"load")!=0)
+	dumpMapsValuesToFiles(&m,&request_input_real_format);
+      loadServiceAndRun (&m, s1, request_inputs, &request_input_real_format,
+                         &request_output_real_format, &eres);	  
+
+#ifdef META_DB
+      close_sql(m,0);      
+#endif      
+    }
+  else
+    {
+      int pid;
+#ifdef DEBUG
+      fprintf (stderr, "\nPID : %d\n", cpid);
+#endif
+#ifndef WIN32
+      pid = fork ();
+#else
+      if (cgiSid == NULL)
+        {
+	  createProcess (m, request_inputs, s1, NULL, cpid,
+			 request_input_real_format,
+			 request_output_real_format);
+	  pid = cpid;
+        }
+      else
+        {
+	  pid = 0;
+	  cpid = atoi (cgiSid);
+	  updateStatus(m,0,_("Initializing"));
+        }
+#endif
+      if (pid > 0)
+	{
+	  //
+	  // dady :
+	  // set status to SERVICE_ACCEPTED
+	  //
+#ifdef DEBUG
+	  fprintf (stderr, "father pid continue (origin %d) %d ...\n", cpid,
+		   zGetpid ());
+#endif
+	  eres = SERVICE_ACCEPTED;
+	}
+      else if (pid == 0)
+	{
+	  eres = SERVICE_ACCEPTED;
+	  //
+	  // son : have to close the stdout, stdin and stderr to let the parent
+	  // process answer to http client.
+	  //
+	  map* usid = getMapFromMaps (m, "lenv", "uusid");
+	  map* tmpm = getMapFromMaps (m, "lenv", "osid");
+	  int cpid = atoi (tmpm->value);
+	  pid=cpid;
+	  r_inputs = getMapFromMaps (m, "main", "tmpPath");
+	  setMapInMaps (m, "lenv", "async","true");
+	  map* r_inputs1 = createMap("ServiceName", s1->name);
+
+	  // Create the filename for the result file (.res)
+	  fbkpres =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) +
+		     strlen (usid->value) + 7) * sizeof (char));                    
+	  sprintf (fbkpres, "%s/%s.res", r_inputs->value, usid->value);
+	  bmap = createMaps("status");
+	  bmap->content=createMap("usid",usid->value);
+	  addToMap(bmap->content,"sid",tmpm->value);
+	  addIntToMap(bmap->content,"pid",zGetpid());
+	  
+	  // Create PID file referencing the OS process identifier
+	  fbkpid =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) +
+		     strlen (usid->value) + 7) * sizeof (char));
+	  sprintf (fbkpid, "%s/%s.pid", r_inputs->value, usid->value);
+	  setMapInMaps (m, "lenv", "file.pid", fbkpid);
+
+	  f0 = freopen (fbkpid, "w+",stdout);
+	  printf("%d",zGetpid());
+	  fflush(stdout);
+
+	  // Create SID file referencing the semaphore name
+	  fbkp =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 7) * sizeof (char));
+	  sprintf (fbkp, "%s/%s.sid", r_inputs->value, usid->value);
+	  setMapInMaps (m, "lenv", "file.sid", fbkp);
+	  FILE* f2 = freopen (fbkp, "w+",stdout);
+	  printf("%s",tmpm->value);
+	  fflush(f2);
+	  free(fbkp);
+
+	  fbkp =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 7) * sizeof (char));
+	  sprintf (fbkp, "%s/%s_%s.xml", r_inputs->value, r_inputs1->value,
+		   usid->value);
+	  setMapInMaps (m, "lenv", "file.responseInit", fbkp);
+	  flog =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 13) * sizeof (char));
+	  sprintf (flog, "%s/%s_%s_error.log", r_inputs->value,
+		   r_inputs1->value, usid->value);
+	  setMapInMaps (m, "lenv", "file.log", flog);
+#ifdef DEBUG
+	  fprintf (stderr, "RUN IN BACKGROUND MODE \n");
+	  fprintf (stderr, "son pid continue (origin %d) %d ...\n", cpid,
+		   zGetpid ());
+	  fprintf (stderr, "\nFILE TO STORE DATA %s\n", r_inputs->value);
+#endif
+	  freopen (flog, "w+", stderr);
+	  fflush (stderr);
+	  f0 = freopen (fbkp, "w+", stdout);
+	  rewind (stdout);
+#ifndef WIN32
+	  fclose (stdin);
+#endif
+#ifdef RELY_ON_DB
+	  init_sql(m);
+	  recordServiceStatus(m);
+#endif
+#ifdef USE_CALLBACK
+	  invokeCallback(m,NULL,NULL,0,0);
+#endif
+	  if(vid==0){
+	    //
+	    // set status to SERVICE_STARTED and flush stdout to ensure full 
+	    // content was outputed (the file used to store the ResponseDocument).
+	    // Then, rewind stdout to restart writing from the begining of the file.
+	    // This way, the data will be updated at the end of the process run.
+	    //
+	    printProcessResponse (m, request_inputs, cpid, s1, r_inputs1->value,
+				  SERVICE_STARTED, request_input_real_format,
+				  request_output_real_format);
+	    fflush (stdout);
+#ifdef RELY_ON_DB
+	    recordResponse(m,fbkp);
+#endif
+	  }
+
+	  fflush (stderr);
+
+	  fbkp1 =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
+		     strlen (usid->value) + 13) * sizeof (char));
+	  sprintf (fbkp1, "%s/%s_final_%s.xml", r_inputs->value,
+		   r_inputs1->value, usid->value);
+	  setMapInMaps (m, "lenv", "file.responseFinal", fbkp1);
+
+	  f1 = freopen (fbkp1, "w+", stdout);
+
+	  map* serviceTypeMap=getMap(s1->content,"serviceType");
+	  if(serviceTypeMap!=NULL)
+	    setMapInMaps (m, "lenv", "serviceType", serviceTypeMap->value);
+
+	  char *flenv =
+	    (char *)
+	    malloc ((strlen (r_inputs->value) + 
+		     strlen (usid->value) + 12) * sizeof (char));
+	  sprintf (flenv, "%s/%s_lenv.cfg", r_inputs->value, usid->value);
+	  maps* lenvMaps=getMaps(m,"lenv");
+	  dumpMapsToFile(lenvMaps,flenv,0);
+	  free(flenv);
+
+#ifdef USE_CALLBACK
+	  invokeCallback(m,request_input_real_format,NULL,1,0);
+#endif
+	  if(validateRequest(&m,s1,request_inputs, &request_input_real_format,&request_output_real_format,&hInternet)<0){
+	    freeService (&s1);
+	    free (s1);
+	    fflush (stdout);
+	    fflush (stderr);
+	    fclose (f0);
+	    fclose (f1);
+	    if(dumpBackFinalFile(m,fbkp,fbkp1)<0)
+	      return -1;
+#ifndef RELY_ON_DB
+	    dumpMapsToFile(bmap,fbkpres,1);
+	    removeShmLock (m, 1);
+#else
+	    recordResponse(m,fbkp1);
+#ifdef USE_CALLBACK
+	    invokeCallback(m,NULL,NULL,7,0);
+#endif
+#endif
+	    zUnlink (fbkpid);
+	    unhandleStatus (m);
+#ifdef RELY_ON_DB
+#ifdef META_DB
+	    cleanupCallbackThreads();
+	    close_sql(m,1);
+#endif
+	    close_sql(m,0);
+#endif
+	    freeMaps (&m);
+	    free (m);
+	    free (REQUEST);
+	    free (SERVICE_URL);
+	    freeMaps (&request_input_real_format);
+	    free (request_input_real_format);
+	    freeMaps (&request_output_real_format);
+	    free (request_output_real_format);
+	    freeMaps (&tmpmaps);
+	    free (tmpmaps);
+	    return -1;
+	  }
+	  if(getMapFromMaps(m,"lenv","mapError")!=NULL){
+	    setMapInMaps(m,"lenv","message",_("Issue with geographic data"));
+#ifdef USE_CALLBACK
+	    invokeCallback(m,NULL,NULL,7,0);
+#endif
+	    eres=-1;//SERVICE_FAILED;
+	  }else{
+	    map* testMap=getMapFromMaps(m,"main","memory");
+	    if(testMap==NULL || strcasecmp(testMap->value,"load")!=0)
+	      dumpMapsValuesToFiles(&m,&request_input_real_format);
+	    loadServiceAndRun (&m, s1, request_inputs,
+			       &request_input_real_format,
+			       &request_output_real_format, &eres);
+	  }
+	}
+      else
+        {
+	  /**
+	   * error server don't accept the process need to output a valid 
+	   * error response here !!!
+	   */
+	  eres = -1;
+	  errorException (m, _("Unable to run the child process properly"),
+			  "InternalError", NULL);
+        }
+    }
+	
+#ifdef DEBUG
+  fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
+  dumpMaps (request_output_real_format);
+  fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
+#endif
+  fflush(stdout);
+  rewind(stdout);
+
+  //fprintf(stderr,"%s %d %d\n",__FILE__,__LINE__,eres);  
+  if (eres != -1)
+    outputResponse (s1, request_input_real_format,
+                    request_output_real_format, request_inputs,
+                    cpid, m, eres);
+  fflush (stdout);
+  
+  /**
+   * Ensure that if error occurs when freeing memory, no signal will return
+   * an ExceptionReport document as the result was already returned to the 
+   * client.
+   */
+#ifndef USE_GDB
+  signal (SIGSEGV, donothing);
+  signal (SIGTERM, donothing);
+  signal (SIGINT, donothing);
+  signal (SIGILL, donothing);
+  signal (SIGFPE, donothing);
+  signal (SIGABRT, donothing);
+#endif
+
+  if (((int) zGetpid ()) != cpid || cgiSid != NULL)
+    {
+      if (eres == SERVICE_SUCCEEDED)
+#ifdef USE_CALLBACK
+	invokeCallback(m,NULL,request_output_real_format,5,1);
+#endif
+      fflush(stderr);
+      fflush(stdout);
+
+      fclose (stdout);
+
+      fclose (f0);
+      fclose (f1);
+
+      if(dumpBackFinalFile(m,fbkp,fbkp1)<0)
+	return -1;
+      zUnlink (fbkpid);
+      switch(eres){
+      default:
+      case SERVICE_FAILED:
+	setMapInMaps(bmap,"status","status",wpsStatus[1]);
+	setMapInMaps(m,"lenv","fstate",wpsStatus[1]);
+	break;
+      case SERVICE_SUCCEEDED:
+	setMapInMaps(bmap,"status","status",wpsStatus[0]);
+	setMapInMaps(m,"lenv","fstate",wpsStatus[0]);
+	break;
+      }      
+#ifndef RELY_ON_DB
+      dumpMapsToFile(bmap,fbkpres,1);
+      removeShmLock (m, 1);
+#else
+      recordResponse(m,fbkp1);
+      if (eres == SERVICE_SUCCEEDED)
+#ifdef USE_CALLBACK
+	invokeCallback(m,NULL,request_output_real_format,6,0);
+#endif
+#endif
+      freeMaps(&bmap);
+      free(bmap);
+      zUnlink (fbkp1);
+      unhandleStatus (m);
+#ifdef RELY_ON_DB
+#ifdef META_DB
+      cleanupCallbackThreads();
+      close_sql(m,1);
+#endif
+      close_sql(m,0);
+      end_sql();
+#endif
+      free(fbkpid);
+      free(fbkpres); 
+      free (fbkp1);
+      if(cgiSid!=NULL)
+	free(cgiSid);
+      //InternetCloseHandle (&hInternet);
+      fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
+      fflush(stderr);
+      fclose (stderr);
+      zUnlink (flog);
+      free (flog);
+    }
+  else{
+    //InternetCloseHandle (&hInternet);  
+#ifdef META_DB
+    close_sql(m,0);
+#endif
+  }
+  
+  freeService (&s1);
+  free (s1);
+  freeMaps (&m);
+  free (m);
+
+  freeMaps (&request_input_real_format);
+  free (request_input_real_format);
+
+  freeMaps (&request_output_real_format);
+  free (request_output_real_format);
+
+  free (REQUEST);
+  free (SERVICE_URL);
+#ifdef DEBUG
+  fprintf (stderr, "Processed response \n");
+  fflush (stdout);
+  fflush (stderr);
+#endif
+
+  if (((int) zGetpid ()) != cpid || cgiSid != NULL)
+    {
+      exit (0);
+    }
+
+  return 0;
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/Makefile	(revision 942)
@@ -0,0 +1,8 @@
+CFLAGS=-I../../zoo-kernel/ -I./ `xml2-config --cflags` `python-config --cflags`  `gdal-config --cflags`   -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/test_service.zo: test_service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/test_service.zo ./test_service.c -lzoo_service
+
+clean:
+	rm -f cgi-env/test_service.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/cgi-env/Multiply.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/cgi-env/Multiply.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/cgi-env/Multiply.zcfg	(revision 942)
@@ -0,0 +1,43 @@
+[Multiply]
+ Title = Multiply two values
+ Abstract = Multiply two values and stor the result in Result.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = test_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [A]
+   Title = first value
+   Abstract = The value used to multiply by B.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = float
+    <Default>
+    </Default>
+   </LiteralData>
+  [B]
+   Title = second value
+   Abstract = The value used to multiply by A.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = float
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = A x B 
+   Abstract = The value of A x B.
+   <LiteralOutput>
+    DataType = float
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/makefile.vc	(revision 942)
@@ -0,0 +1,12 @@
+TROOT= ../
+!INCLUDE ../../zoo-kernel/nmake.opt
+
+#CFLAGS=-I$(GEODIR)/include -I$(TOOLS)/include -I../../zoo-kernel/ -I./ -DLINUX_FREE_ISSUE -DDEBUG -DWIN32
+#CPP=cl /TP 
+
+cgi-env/test_service.zo: test_service.c
+	$(CPP) -DWIN32 -DZOO_SERVICE -DNEED_STRCASESTR $(CFLAGS) /c test_service.c
+	link /dll /out:cgi-env/test_service.zo ../../zoo-kernel/service_internal.obj ../../zoo-kernel/ulinet.obj ../../zoo-kernel/service_internal_ms.obj ../../zoo-kernel/service_internal_js.obj ./test_service.obj $(LDFLAGS)
+
+clean:
+	erase cgi-env\demo_service.*
Index: /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/test_service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/test_service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/arithmetics/test_service.c	(revision 942)
@@ -0,0 +1,42 @@
+#include "service.h"
+
+extern "C" {
+
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+  int Multiply(maps*& conf,maps*& inputs,maps*& outputs){
+  	fprintf(stderr,"\nService internal print\n");
+  	maps* cursor=inputs;
+	int A,B,res;
+	A=0;B=0;
+	if(cursor!=NULL){
+		fprintf(stderr,"\nService internal print\n");
+		dumpMaps(cursor);
+		maps* tmp=getMaps(inputs,"A");
+		if(tmp==NULL)
+			return SERVICE_FAILED;
+		fprintf(stderr,"\nService internal print\n");
+		dumpMap(tmp->content);
+		map* tmpv=getMap(tmp->content,"value");
+		fprintf(stderr,"\nService internal print\n");
+		A=atoi(tmpv->value);
+		fprintf(stderr,"\nService internal print (A value: %i)\n",A);
+		cursor=cursor->next;
+	}
+	if(cursor!=NULL){
+		maps* tmp=getMaps(cursor,"B");
+		map* tmpv=getMap(tmp->content,"value");
+		if(tmpv==NULL)
+			return SERVICE_FAILED;
+		B=atoi(tmpv->value);
+		fprintf(stderr,"\nService internal print (B value: %i)\n",B);
+	}
+	res=A*B;
+	char tmp[256];
+	sprintf(tmp,"%i",res);
+	setMapInMaps(outputs,"Result","value",tmp);
+	return SERVICE_SUCCEEDED;
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/cgal/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/cgal/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/cgal/Makefile	(revision 942)
@@ -0,0 +1,19 @@
+ZRPATH=../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS= ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} ${CGAL_CFLAGS} -frounding-math -fPIC -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/cgal_service.zo: delaunay.c voronoi.c cgal_service.o
+	g++ ${CFLAGS} -c ./delaunay.c
+	g++ ${CFLAGS} -c ./voronoi.c
+	g++ ${CFLAGS} -shared -o cgi-env/cgal_service.zo ./delaunay.o ./voronoi.o ./cgal_service.o ${GDAL_LIBS} ${CGAL_LDFLAGS} -lCGAL -lgmp ${GDAL_LIBS} -L${ZRPATH}/zoo-kernel/ -lzoo_service -lfcgi
+
+cgal_service.o: cgal_service.c cgal_service.h
+	g++ ${CFLAGS} -c ./cgal_service.c
+
+install:
+	install -d ${CGI_DIR}/cgal
+	install cgi-env/* ${CGI_DIR}/cgal/
+
+clean:
+	rm -f cgi-env/*.zo *.o
Index: /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgal_service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgal_service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgal_service.c	(revision 942)
@@ -0,0 +1,111 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2009-2013 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "cgal_service.h"
+
+int parseInput(maps* conf,maps* inputs, std::vector<Pointz>* points,char* filename){
+  map* tmpm=NULL;
+  tmpm=getMapFromMaps(inputs,"InputPoints","cache_file");
+#if GDAL_VERSION_MAJOR >= 2
+  GDALDataset *ipoDS;
+#else
+  OGRDataSource* ipoDS;
+#endif
+  if(tmpm==NULL){
+    tmpm=getMapFromMaps(inputs,"InputPoints","value");
+    VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmpm->value,strlen(tmpm->value),FALSE);
+    VSIFCloseL(ifile);
+#if GDAL_VERSION_MAJOR >= 2
+  ipoDS = (GDALDataset*) GDALOpenEx( filename,
+				     GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				     NULL, NULL, NULL );
+#else
+  ipoDS = OGRSFDriverRegistrar::Open(filename,FALSE);
+#endif
+  }else
+#if GDAL_VERSION_MAJOR >= 2
+    ipoDS = (GDALDataset*) GDALOpenEx( tmpm->value,
+				       GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				       NULL, NULL, NULL );
+#else
+    ipoDS = OGRSFDriverRegistrar::Open(tmpm->value,FALSE);
+#endif
+    
+  if( ipoDS == NULL )
+    {
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDriverManager* poR=GetGDALDriverManager();
+#else
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+#endif
+      
+      fprintf( stderr, "FAILURE:\n"
+	       "Unable to open datasource `%s' with the following drivers.\n",
+	       filename );
+      
+      for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+        {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+        }
+      char tmp[1024];
+      sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename);
+      setMapInMaps(conf,"lenv","message",tmp);
+      return SERVICE_FAILED;
+    }
+  for( int iLayer = 0; iLayer < ipoDS->GetLayerCount();
+       iLayer++ )
+    {
+      OGRLayer        *poLayer = ipoDS->GetLayer(iLayer);
+      
+      if( poLayer == NULL )
+	{
+	  fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		   iLayer );
+#ifdef ZOO_SERVICE
+	  char tmp[1024];
+	  sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	  setMapInMaps(conf,"lenv","message",tmp);
+	  return SERVICE_FAILED;
+#else
+	  exit( 1 );
+#endif
+	}
+      
+      OGRFeature  *poFeature;
+      while(TRUE){
+	poFeature = poLayer->GetNextFeature();
+	if( poFeature == NULL )
+	  break;
+	if(poFeature->GetGeometryRef() != NULL){
+	  points->push_back(Pointz(OGR_G_GetX(poFeature->GetGeometryRef(),0),OGR_G_GetY(poFeature->GetGeometryRef(),0)));
+	}
+      }
+    }
+  return SERVICE_SUCCEEDED;
+}
+
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgal_service.h
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgal_service.h	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgal_service.h	(revision 942)
@@ -0,0 +1,45 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2009-2013 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ZOO_CGAL_SERVICE_H
+#define ZOO_CGAL_SERVICE_H
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Delaunay_triangulation_2.h>
+#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+#include <vector>
+
+#include "cpl_minixml.h"
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+#include "service.h"
+#include "service_internal.h"
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel            Kernel;
+typedef Kernel::Point_2                                                Pointz;
+
+int parseInput(maps*,maps*, std::vector<Pointz>*,char*);
+
+#endif
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgi-env/Delaunay.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgi-env/Delaunay.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgi-env/Delaunay.zcfg	(revision 942)
@@ -0,0 +1,55 @@
+[Delaunay]
+ Title = Delaunay Triangulation. 
+ Abstract = Computes the edges of a Delaunay triangulation for a set of data points.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = cgal_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPoints]
+   Title = Data points
+   Abstract = The set of data points.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Delaunay Triangulation
+   Abstract = JSON String / GML Entity of the Delaunay Triangulation.
+   <ComplexOutput>
+    <Default>
+     mimeType = application/json
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     asReference = true	
+    </Supported>
+   </ComplexOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg	(revision 942)
@@ -0,0 +1,65 @@
+[Voronoi]
+ Title = Voronoi Diagram. 
+ Abstract = Computes the edges of Voronoi diagram for a set of data points.
+ Profile = urn:ogc:wps:1.0.0:voronoi
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = cgal_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPoints]
+   Title = Data points
+   Abstract = The set of data points.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Voronoi Diagram.
+   Abstract = JSON String / GML Entity of the Voronoi Diagram.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexOutput>
+    <Default>
+     mimeType = application/json
+     encoding = UTF-8
+    </Default>
+    <Supported>
+      mimeType = image/png
+      useMapserver = true
+      asReference = true
+      msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 0.3 OPACITY 65 END
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     asReference = true	
+    </Supported>
+   </ComplexOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/cgal/delaunay.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/cgal/delaunay.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/cgal/delaunay.c	(revision 942)
@@ -0,0 +1,215 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2009-2013 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "cgal_service.h"
+typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
+typedef CGAL::Triangulation_data_structure_2<Vb>                       Tds;
+typedef CGAL::Delaunay_triangulation_2<Kernel, Tds>                    DelaunayT;
+
+extern "C" {
+
+  int Delaunay(maps*& conf,maps*& inputs,maps*& outputs){
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\nStarting\n");
+#endif
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    int bufferDistance;
+    map* tmpm=NULL;
+    OGRRegisterAll();
+
+    std::vector<Pointz> points;
+    if(int res=parseInput(conf,inputs,&points,"/vsimem/tmp")!=SERVICE_SUCCEEDED)
+      return res;
+
+    DelaunayT T;
+    T.insert(points.begin(), points.end());
+
+    /* -------------------------------------------------------------------- */
+    /*      Try opening the output datasource as an existing, writable      */
+    /* -------------------------------------------------------------------- */
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *poODS;
+    GDALDriverManager* poR=GetGDALDriverManager();
+    GDALDriver          *poDriver = NULL;
+#else
+    OGRDataSource       *poODS;    
+    OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
+    OGRSFDriver          *poDriver = NULL;
+#endif
+    int                  iDriver;
+    map *tmpMap=getMapFromMaps(outputs,"Result","mimeType");
+    const char *oDriver;
+    oDriver="GeoJSON";
+    if(tmpMap!=NULL){
+      if(strcmp(tmpMap->value,"text/xml")==0){
+	oDriver="GML";
+      }
+    }
+    
+    for( iDriver = 0;
+	 iDriver < poR->GetDriverCount() && poDriver == NULL;
+	 iDriver++ )
+      {
+#ifdef DEBUG
+#if GDAL_VERSION_MAJOR >= 2
+	fprintf(stderr,"D:%s\n",poR->GetDriver(iDriver)->GetDescription());
+#else
+	fprintf(stderr,"D:%s\n",poR->GetDriver(iDriver)->GetName());
+#endif
+#endif
+	if( EQUAL(
+#if GDAL_VERSION_MAJOR >= 2
+		  poR->GetDriver(iDriver)->GetDescription()
+#else
+		  poR->GetDriver(iDriver)->GetName()
+#endif
+		  ,
+		  oDriver) )
+	  {
+	    poDriver = poR->GetDriver(iDriver);
+	  }
+      }
+
+    if( poDriver == NULL )
+      {
+	char emessage[8192];
+	sprintf( emessage, "Unable to find driver `%s'.\n", oDriver );
+	sprintf( emessage,  "%sThe following drivers are available:\n",emessage );
+        
+	for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+
+	setMapInMaps(conf,"lenv","message",emessage);
+	return SERVICE_FAILED;
+
+      }
+
+#if GDAL_VERSION_MAJOR >=2
+    if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+    if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+      {
+	char emessage[1024];
+	sprintf( emessage,  "%s driver does not support data source creation.\n",
+		 "json" );
+	setMapInMaps(conf,"lenv","message",emessage);
+	return SERVICE_FAILED;
+      }
+
+    /* -------------------------------------------------------------------- */
+    /*      Create the output data source.                                  */
+    /* -------------------------------------------------------------------- */
+    char *pszDestDataSource=(char*)malloc(100);
+    char **papszDSCO=NULL;
+    sprintf(pszDestDataSource,"/vsimem/result_%d",getpid());
+#if GDAL_VERSION_MAJOR >=2
+    poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+    poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+    if( poODS == NULL ){
+      char emessage[1024];      
+      sprintf( emessage,  "%s driver failed to create %s\n", 
+	       "json", pszDestDataSource );
+      setMapInMaps(conf,"lenv","message",emessage);
+      return SERVICE_FAILED;
+    }
+
+    /* -------------------------------------------------------------------- */
+    /*      Create the layer.                                               */
+    /* -------------------------------------------------------------------- */
+    if( !poODS->TestCapability( ODsCCreateLayer ) )
+      {
+	char emessage[1024];
+	sprintf( emessage, 
+		 "Layer %s not found, and CreateLayer not supported by driver.", 
+		 "Result" );
+	setMapInMaps(conf,"lenv","message",emessage);
+	return SERVICE_FAILED;
+      }
+    
+    CPLErrorReset();
+    
+    OGRLayer *poDstLayer = poODS->CreateLayer( "Result", NULL,wkbPolygon,NULL);
+    if( poDstLayer == NULL ){
+      setMapInMaps(conf,"lenv","message","Layer creation failed.\n");
+      return SERVICE_FAILED;
+    }
+
+
+    for(DelaunayT::Finite_faces_iterator fit = T.finite_faces_begin();
+	fit != T.finite_faces_end(); ++fit) {
+      DelaunayT::Face_handle face = fit;
+      OGRFeatureH hFeature = OGR_F_Create( OGR_L_GetLayerDefn( poDstLayer ) );
+      OGRGeometryH hCollection = OGR_G_CreateGeometry( wkbGeometryCollection );
+      OGRGeometryH currLine=OGR_G_CreateGeometry(wkbLinearRing);
+      OGRGeometryH currPoly=OGR_G_CreateGeometry(wkbPolygon);
+      OGR_G_AddPoint_2D(currLine,T.triangle(face)[0].x(),T.triangle(face)[0].y());
+      OGR_G_AddPoint_2D(currLine,T.triangle(face)[1].x(),T.triangle(face)[1].y());
+      OGR_G_AddPoint_2D(currLine,T.triangle(face)[2].x(),T.triangle(face)[2].y());
+      OGR_G_AddPoint_2D(currLine,T.triangle(face)[0].x(),T.triangle(face)[0].y());
+      OGR_G_AddGeometryDirectly( currPoly, currLine ); 
+      OGR_G_AddGeometryDirectly( hCollection, currPoly ); 
+      OGR_F_SetGeometry( hFeature, hCollection ); 
+      OGR_G_DestroyGeometry(hCollection);
+      if( OGR_L_CreateFeature( poDstLayer, hFeature ) != OGRERR_NONE ){
+	setMapInMaps(conf,"lenv","message","Failed to create feature in file.\n");
+	return SERVICE_FAILED;
+      }
+      OGR_F_Destroy( hFeature );
+    }
+    OGR_DS_Destroy( poODS );
+
+#ifdef DEBUG
+    std::cerr << "The Voronoi diagram has " << ns << " finite edges "
+	      << " and " << nr << " rays" << std::endl;
+#endif
+
+    char *res1=readVSIFile(conf,pszDestDataSource);
+    if(res1==NULL)
+      return SERVICE_FAILED;
+
+    setMapInMaps(outputs,"Result","value",res1);
+    free(res1);
+
+    if(strcmp(oDriver,"GML")==0)
+      setMapInMaps(outputs,"Result","mimeType","text/xml");
+    else
+      setMapInMaps(outputs,"Result","mimeType","application/json");
+
+    setMapInMaps(outputs,"Result","encoding","UTF-8");
+    OGRCleanupAll();
+    
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/cgal/voronoi.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/cgal/voronoi.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/cgal/voronoi.c	(revision 942)
@@ -0,0 +1,277 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2009-2013 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+//#include <CGAL/Triangulation_euclidean_traits_2.h>
+#include <CGAL/Delaunay_triangulation_2.h>
+//#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+#include <CGAL/Triangulation_conformer_2.h>
+#include <CGAL/Triangulation_face_base_2.h>
+
+#include <fstream>
+
+#include "cpl_minixml.h"
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+#include "service.h"
+#include "cgal_service.h"
+
+typedef CGAL::Delaunay_triangulation_2<Kernel>  Triangulation;
+typedef Triangulation::Face_iterator  Face_iterator;
+typedef Triangulation::Edge_iterator  Edge_iterator;
+typedef Triangulation::Vertex_circulator Vertex_circulator;
+
+extern "C" {
+
+  int Voronoi(maps*& conf,maps*& inputs,maps*& outputs){
+    //#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\nStarting\n");
+    //#endif
+    //return SERVICE_FAILED;
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    int bufferDistance;
+    map* tmpm=NULL;
+    tmpm=getMapFromMaps(inputs,"InputPoints","value");
+
+    fprintf(stderr," **** %s %d\n",__FILE__,__LINE__);
+    fflush(stderr);
+
+    OGRRegisterAll();
+
+    std::vector<Pointz> points;
+    if(int res=parseInput(conf,inputs,&points,"/vsimem/tmp")!=SERVICE_SUCCEEDED){
+      fprintf(stderr," **** %s %d\n",__FILE__,__LINE__);
+      fflush(stderr);
+      return SERVICE_FAILED;
+    }
+    fprintf(stderr," **** %s %d\n",__FILE__,__LINE__);
+    fflush(stderr);
+    
+    Triangulation T;
+    T.insert(points.begin(), points.end());
+
+    //OGRRegisterAll();
+    /* -------------------------------------------------------------------- */
+    /*      Try opening the output datasource as an existing, writable      */
+    /* -------------------------------------------------------------------- */
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *poODS;
+    GDALDriverManager* poR=GetGDALDriverManager();
+    GDALDriver          *poDriver = NULL;
+#else
+    OGRDataSource       *poODS;    
+    OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
+    OGRSFDriver          *poDriver = NULL;
+#endif
+    int                  iDriver;
+    map* tmpMap=getMapFromMaps(outputs,"Result","mimeType");
+    const char *oDriver;
+    oDriver="GeoJSON";
+    if(tmpMap!=NULL){
+      if(strcmp(tmpMap->value,"text/xml")==0){
+	oDriver="GML";
+      }
+    }
+    
+    for( iDriver = 0;
+	 iDriver < poR->GetDriverCount() && poDriver == NULL;
+	 iDriver++ )
+      {
+#ifdef DEBUG
+#if GDAL_VERSION_MAJOR >= 2
+	fprintf(stderr,"D:%s\n",poR->GetDriver(iDriver)->GetDescription());
+#else
+	fprintf(stderr,"D:%s\n",poR->GetDriver(iDriver)->GetName());
+#endif
+#endif
+	if( EQUAL(
+#if GDAL_VERSION_MAJOR >= 2
+		  poR->GetDriver(iDriver)->GetDescription()
+#else
+		  poR->GetDriver(iDriver)->GetName()
+#endif
+		  ,
+		  oDriver) )
+	  {
+	    poDriver = poR->GetDriver(iDriver);
+	  }
+      }
+
+    if( poDriver == NULL )
+      {
+	char emessage[8192];
+	sprintf( emessage, "Unable to find driver `%s'.\n", oDriver );
+	sprintf( emessage,  "%sThe following drivers are available:\n",emessage );
+        
+	for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+
+	setMapInMaps(conf,"lenv","message",emessage);
+	return SERVICE_FAILED;
+
+      }
+
+#if GDAL_VERSION_MAJOR >=2
+    if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+    if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+      {
+	char emessage[1024];
+	sprintf( emessage,  "%s driver does not support data source creation.\n",
+		 "json" );
+	setMapInMaps(conf,"lenv","message",emessage);
+	return SERVICE_FAILED;
+      }
+
+    /* -------------------------------------------------------------------- */
+    /*      Create the output data source.                                  */
+    /* -------------------------------------------------------------------- */
+    map* tpath=getMapFromMaps(conf,"main","tmpPath");
+    char *pszDestDataSource=(char*)malloc(100);
+    char **papszDSCO=NULL;
+    sprintf(pszDestDataSource,"/vsimem/result_%d.json",tpath->value,getpid());
+#if GDAL_VERSION_MAJOR >=2
+    poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+    poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+    if( poODS == NULL ){
+      char emessage[1024];      
+      sprintf( emessage,  "%s driver failed to create %s\n", 
+	       "json", pszDestDataSource );
+      setMapInMaps(conf,"lenv","message",emessage);
+      return SERVICE_FAILED;
+    }
+
+    /* -------------------------------------------------------------------- */
+    /*      Create the layer.                                               */
+    /* -------------------------------------------------------------------- */
+    if( !poODS->TestCapability( ODsCCreateLayer ) )
+      {
+	char emessage[1024];
+	sprintf( emessage, 
+		 "Layer %s not found, and CreateLayer not supported by driver.", 
+		 "Result" );
+	setMapInMaps(conf,"lenv","message",emessage);
+	return SERVICE_FAILED;
+      }
+    
+    CPLErrorReset();
+    
+    OGRLayer *poDstLayer = poODS->CreateLayer( "Result", NULL,wkbLineString,NULL);
+    if( poDstLayer == NULL ){
+      setMapInMaps(conf,"lenv","message","Layer creation failed.\n");
+      return SERVICE_FAILED;
+    }
+
+
+    int ns = 0;
+    int nr = 0;
+    int nf = 0;
+    Face_iterator fit =T.faces_begin();
+    FILE* f=fopen("/tmp/toto.log","w+");
+    for ( ; fit !=T.faces_end(); ++fit) {
+      fprintf(stderr," *** %s %d %d %d\n",__FILE__,__LINE__,nf,fit.info());
+      fflush(stderr);
+      
+      nf++;
+    }
+    fclose(f);
+    Edge_iterator eit =T.edges_begin();
+    for ( ; eit !=T.edges_end(); ++eit) {
+      CGAL::Object o = T.dual(eit);
+      if (const Kernel::Segment_2 *tmp=CGAL::object_cast<Kernel::Segment_2>(&o)) {
+	const Pointz p1=tmp->source();
+	const Pointz p2=tmp->target();
+	fprintf(stderr,"P1 %d %d | P2 %d %d\n",p1.x(),p1.y(),p2.x(),p2.y());
+#ifdef DEBUG
+	fprintf(stderr,"P1 %d %d | P2 %d %d\n",p1.x(),p1.y(),p2.x(),p2.y());
+#endif
+	OGRFeatureH hFeature = OGR_F_Create( OGR_L_GetLayerDefn( poDstLayer ) );
+	OGRGeometryH currLine=OGR_G_CreateGeometry(wkbLineString);
+	OGR_G_AddPoint_2D(currLine,p1.x(),p1.y());
+	OGR_G_AddPoint_2D(currLine,p2.x(),p2.y());
+	OGR_F_SetGeometry( hFeature, currLine ); 
+	OGR_G_DestroyGeometry(currLine);
+	if( OGR_L_CreateFeature( poDstLayer, hFeature ) != OGRERR_NONE ){
+	  setMapInMaps(conf,"lenv","message","Failed to create feature in file.\n");
+	  return SERVICE_FAILED;
+	}
+	OGR_F_Destroy( hFeature );
+	++ns ;
+      }
+      else if (const Kernel::Ray_2 *tmp=CGAL::object_cast<Kernel::Ray_2>(&o)) { 
+	const Pointz p1=tmp->source();
+	const Pointz p2=tmp->point(2);
+	OGRFeatureH hFeature = OGR_F_Create( OGR_L_GetLayerDefn( poDstLayer ) );
+	OGRGeometryH currLine=OGR_G_CreateGeometry(wkbLineString);
+	OGR_G_AddPoint_2D(currLine,p1.x(),p1.y());
+	OGR_G_AddPoint_2D(currLine,p2.x(),p2.y());
+	OGR_F_SetGeometry( hFeature, currLine );
+	OGR_G_DestroyGeometry(currLine);
+	if( OGR_L_CreateFeature( poDstLayer, hFeature ) != OGRERR_NONE ){
+	  setMapInMaps(conf,"lenv","message","Failed to create feature in file.\n");
+	  return SERVICE_FAILED;
+	}
+	OGR_F_Destroy( hFeature );
+	++nr; 
+      }
+    }
+    OGR_DS_Destroy( poODS );
+
+#ifdef DEBUG
+    std::cerr << "The Voronoi diagram has " << ns << " finite edges "
+	      << " and " << nr << " rays" << std::endl;
+    sprintf(tmp1,"%d finite edges, %d rays",ns,nr);
+#endif
+    
+
+    char *res1=readVSIFile(conf,pszDestDataSource);
+    if(res1==NULL)
+      return SERVICE_FAILED;
+    
+    setMapInMaps(outputs,"Result","value",res1);
+    
+    if(strcmp(oDriver,"GML")==0)
+      setMapInMaps(outputs,"Result","mimeType","text/xml");
+    else
+      setMapInMaps(outputs,"Result","mimeType","application/json");
+
+    setMapInMaps(outputs,"Result","encoding","UTF-8");
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\n===\n");
+#endif
+    //OGRCleanupAll();
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/data-api/cgi-env/query.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/data-api/cgi-env/query.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/data-api/cgi-env/query.zcfg	(revision 942)
@@ -0,0 +1,30 @@
+[query]
+ Title = Execute a query using DataAPI
+ Abstract = Execute a query through DataAPI.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = service
+ serviceType = Python
+ <DataInputs>
+  [query]
+   Title = JSON Query
+   Abstract = The query to be executed in JSON format.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Response
+   Abstract = The response to the DataAPI query.
+   <ComplexData>
+    <Default>
+    mimeType = application/json
+    encoding = utf-8
+    </Default>
+   </ComplexData>
+ </DataOutputs>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/data-api/cgi-env/service.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/data-api/cgi-env/service.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/data-api/cgi-env/service.py	(revision 942)
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+
+import zoo
+
+import logging
+import logging.config
+import sys
+import errno
+import os
+import json
+import geojson
+import csv
+import argparse
+
+from publicamundi.data.api import *
+
+ERROR_OK = 0
+ERROR_UNKNOWN = 1
+
+def configure_logging(filename):
+    if filename is None:
+        print 'Logging is not configured.'
+    else:
+        logging.config.fileConfig(filename)
+
+def parse_query(filename, text):
+    if not filename is None and os.path.isfile(filename):
+        with open(filename) as query_file:    
+            return json.load(query_file, cls=ShapelyJsonDecoder, encoding='utf-8')
+    if not text is None:
+        return json.loads(text, cls=ShapelyJsonDecoder, encoding='utf-8')
+        
+    return {}
+
+def query(conf,inputs,outputs):    
+    config = {
+        CONFIG_SQL_CATALOG : conf["data-api"]["catalog"],
+        CONFIG_SQL_DATA : conf["data-api"]["vectorstore"],
+        CONFIG_SQL_TIMEOUT : int(conf["data-api"]["timeout"]) * 1000
+    }
+
+    if inputs.keys().count("timeout")>0:
+        config["CONFIG_SQL_TIMEOUT"]=int(inputs["timeout"]["value"]) * 1000
+    
+    metadata = {}
+
+    configure_logging(conf["lenv"]["cwd"]+"/"+conf["lenv"]["metapath"]+"/service.ini")
+    
+    query_executor = QueryExecutor()
+    result = query_executor.execute(config, parse_query(None,inputs["query"]["value"]) )
+    
+    outputs["Result"]["value"]=geojson.dumps(result['data'][0], cls=ShapelyGeoJsonEncoder, encoding='utf-8')
+    return zoo.SERVICE_SUCCEEDED
+        
Index: /tags/rel-1.7.0/zoo-project/zoo-services/data-api/query.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/data-api/query.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/data-api/query.zcfg	(revision 942)
@@ -0,0 +1,30 @@
+[query]
+ Title = Execute a query using DataAPI
+ Abstract = Execute a query through DataAPI.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = service
+ serviceType = Python
+ <DataInputs>
+  [query]
+   Title = JSON Query
+   Abstract = The query to be executed in JSON format.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Response
+   Abstract = The response to the DataAPI query.
+   <ComplexData>
+    <Default>
+    mimeType = application/json
+    encoding = utf-8
+    </Default>
+   </ComplexData>
+ </DataOutputs>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/data-api/service.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/data-api/service.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/data-api/service.py	(revision 942)
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+
+import zoo
+
+import logging
+import logging.config
+import sys
+import errno
+import os
+import json
+import geojson
+import csv
+import argparse
+
+from publicamundi.data.api import *
+
+ERROR_OK = 0
+ERROR_UNKNOWN = 1
+
+def configure_logging(filename):
+    if filename is None:
+        print 'Logging is not configured.'
+    else:
+        logging.config.fileConfig(filename)
+
+def parse_query(filename, text):
+    if not filename is None and os.path.isfile(filename):
+        with open(filename) as query_file:    
+            return json.load(query_file, cls=ShapelyJsonDecoder, encoding='utf-8')
+    if not text is None:
+        return json.loads(text, cls=ShapelyJsonDecoder, encoding='utf-8')
+        
+    return {}
+
+def query(conf,inputs,outputs):    
+    config = {
+        CONFIG_SQL_CATALOG : conf["data-api"]["catalog"],
+        CONFIG_SQL_DATA : conf["data-api"]["vectorstore"],
+        CONFIG_SQL_TIMEOUT : int(conf["data-api"]["timeout"]) * 1000
+    }
+
+    if inputs.keys().count("timeout")>0:
+        config["CONFIG_SQL_TIMEOUT"]=int(inputs["timeout"]["value"]) * 1000
+    
+    metadata = {}
+
+    configure_logging(conf["lenv"]["cwd"]+"/"+conf["lenv"]["metapath"]+"/service.ini")
+    
+    query_executor = QueryExecutor()
+    result = query_executor.execute(config, parse_query(None,inputs["query"]["value"]) )
+    
+    outputs["Result"]["value"]=geojson.dumps(result['data'][0], cls=ShapelyGeoJsonEncoder, encoding='utf-8')
+    return zoo.SERVICE_SUCCEEDED
+        
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/Makefile	(revision 942)
@@ -0,0 +1,13 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-DZOO_SERVICE -I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/contour_service.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/contour_service.zo ./service.c ${GDAL_LIBS} ${MACOS_LD_FLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service ${FCGI_LDFLAGS}
+install:
+	install -d ${CGI_DIR}/gdal/contour
+	install cgi-env/* ${CGI_DIR}/gdal/contour
+
+clean:
+	rm -f cgi-env/*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/cgi-env/Gdal_Contour.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/cgi-env/Gdal_Contour.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/cgi-env/Gdal_Contour.zcfg	(revision 942)
@@ -0,0 +1,65 @@
+[Gdal_Contour]
+ Title = Builds vector contour lines from a raster elevation model.
+ Abstract = http://www.gdal.org/gdal_contour.html
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = contour_service.zo
+ <DataInputs>
+  [InputDSN]
+   Title = The input data source name
+   Abstract = The input data source name to use.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [OutputDSN]
+   Title = The output data source name
+   Abstract = The output data source name.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [i]
+   Title = An interval value
+   Abstract = The elevation interval between contours.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [a]
+   Title = Attribute name
+   Abstract = provides a name for the attribute in which to put the elevation. If not provided no elevation attribute is attached.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [b]
+   Title = The band number
+   Abstract = A particular band, defaults to band 1.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = integer
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/makefile.vc	(revision 942)
@@ -0,0 +1,11 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+cgi-env/contour_service.zo: service.c
+	$(CPP)  /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE -I$(GDAL_DIR)/frmts/vrt -I$(GDAL_DIR)/alg $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/contour_service.zo  $(FILES) ./service.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/contour/service.c	(revision 942)
@@ -0,0 +1,417 @@
+/******************************************************************************
+ * $Id: gdal_contour.cpp 25643 2013-02-12 13:50:42Z bishop $
+ *
+ * Project:  Contour Generator
+ * Purpose:  Contour Generator mainline.
+ * Author:   Frank Warmerdam <warmerdam@pobox.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2003, Applied Coherent Technology (www.actgate.com). 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "gdal.h"
+#include "gdal_alg.h"
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "ogr_api.h"
+#include "ogr_srs_api.h"
+#ifdef ZOO_SERVICE
+#include "service.h"
+#include "service_internal.h"
+#endif
+CPL_CVSID("$Id: gdal_contour.cpp 25643 2013-02-12 13:50:42Z bishop $");
+
+#ifdef ZOO_SERVICE
+extern "C" {
+#endif
+
+/************************************************************************/
+/*                            ArgIsNumeric()                            */
+/************************************************************************/
+
+static int ArgIsNumeric( const char *pszArg )
+
+{
+    return CPLGetValueType(pszArg) != CPL_VALUE_STRING;
+}
+
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage(const char* pszErrorMsg = NULL)
+
+{
+    printf( 
+        "Usage: gdal_contour [-b <band>] [-a <attribute_name>] [-3d] [-inodata]\n"
+        "                    [-snodata n] [-f <formatname>] [-i <interval>]\n"
+        "                    [-f <formatname>] [[-dsco NAME=VALUE] ...] [[-lco NAME=VALUE] ...]\n"   
+        "                    [-off <offset>] [-fl <level> <level>...]\n" 
+        "                    [-nln <outlayername>] [-q]\n"
+        "                    <src_filename> <dst_filename>\n" );
+
+    if( pszErrorMsg != NULL )
+        fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
+
+    exit( 1 );
+}
+
+#ifdef ZOO_SERVICE
+  int pfnProgress1( double dfComplete, const char *pszMessage, void *pData)
+  {
+    maps* conf=(maps*)pData;
+    map* tmpMap=getMapFromMaps(conf,"lenv","status");
+    char tmpStr[4];
+    sprintf(tmpStr,"%d",(int) (dfComplete*100));
+    if(tmpMap!=NULL && strcmp(tmpMap->value,tmpStr)!=0){
+      if( pszMessage != NULL && strlen(pszMessage)>1){
+	updateStatus(conf,(int) (dfComplete*100), pszMessage);
+      }      
+      else
+	updateStatus(conf,(int) (dfComplete*100), "Processing...");
+    }
+    return TRUE;
+  }
+#endif
+
+/************************************************************************/
+/*                                main()                                */
+/************************************************************************/
+
+#define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
+    do { if (i + nExtraArg >= argc) \
+        Usage(CPLSPrintf("%s option requires %d argument(s)", argv[i], nExtraArg)); } while(0)
+
+#ifndef ZOO_SERVICE
+int main( int argc, char ** argv )
+#else
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+  int Gdal_Contour(maps*& conf,maps*& inputs,maps*& outputs)
+#endif
+{
+    fprintf(stderr,"DEBUG HELLO %f %d\n",__FILE__,__LINE__);
+    fflush(stderr);
+    GDALDatasetH	hSrcDS;
+    int i, b3D = FALSE, bNoDataSet = FALSE, bIgnoreNoData = FALSE;
+    int nBandIn = 1;
+    double dfInterval = 0.0, dfNoData = 0.0, dfOffset = 0.0;
+    const char *pszSrcFilename = NULL;
+    const char *pszDstFilename = NULL;
+    const char *pszElevAttrib = NULL;
+    const char *pszFormat = "ESRI Shapefile";
+    char        **papszDSCO = NULL, **papszLCO = NULL;
+    double adfFixedLevels[1000];
+    int    nFixedLevelCount = 0;
+    const char *pszNewLayerName = "contour";
+    int bQuiet = FALSE;
+#ifndef ZOO_SERVICE
+    /* Check that we are running against at least GDAL 1.4 */
+    /* Note to developers : if we use newer API, please change the requirement */
+    if (atoi(GDALVersionInfo("VERSION_NUM")) < 1400)
+    {
+        fprintf(stderr, "At least, GDAL >= 1.4.0 is required for this version of %s, "
+                "which was compiled against GDAL %s\n", argv[0], GDAL_RELEASE_NAME);
+        exit(1);
+    }
+#endif
+    GDALAllRegister();
+    OGRRegisterAll();
+
+#ifndef ZOO_SERVICE
+    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
+
+/* -------------------------------------------------------------------- */
+/*      Parse arguments.                                                */
+/* -------------------------------------------------------------------- */
+    for( i = 1; i < argc; i++ )
+    {
+        if( EQUAL(argv[i], "--utility_version") )
+        {
+            printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
+                   argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
+            return 0;
+        }
+        else if( EQUAL(argv[i], "--help") )
+            Usage();
+        else if( EQUAL(argv[i],"-a") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            pszElevAttrib = argv[++i];
+        }
+        else if( EQUAL(argv[i],"-off") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            dfOffset = atof(argv[++i]);
+        }
+        else if( EQUAL(argv[i],"-i") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            dfInterval = atof(argv[++i]);
+        }
+        else if( EQUAL(argv[i],"-fl") )
+        {
+            if( i >= argc-1 )
+                Usage(CPLSPrintf("%s option requires at least 1 argument", argv[i]));
+            while( i < argc-1 
+                   && nFixedLevelCount 
+                             < (int)(sizeof(adfFixedLevels)/sizeof(double))
+                   && ArgIsNumeric(argv[i+1]) )
+                adfFixedLevels[nFixedLevelCount++] = atof(argv[++i]);
+        }
+        else if( EQUAL(argv[i],"-b") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            nBandIn = atoi(argv[++i]);
+        }
+        else if( EQUAL(argv[i],"-f") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            pszFormat = argv[++i];
+        }
+        else if( EQUAL(argv[i],"-dsco") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszDSCO = CSLAddString(papszDSCO, argv[++i] );
+        }
+        else if( EQUAL(argv[i],"-lco") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszLCO = CSLAddString(papszLCO, argv[++i] );
+        }
+        else if( EQUAL(argv[i],"-3d")  )
+        {
+            b3D = TRUE;
+        }
+        else if( EQUAL(argv[i],"-snodata") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            bNoDataSet = TRUE;
+            dfNoData = atof(argv[++i]);
+        }
+        else if( EQUAL(argv[i],"-nln") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            pszNewLayerName = argv[++i];
+        }
+        else if( EQUAL(argv[i],"-inodata") )
+        {
+            bIgnoreNoData = TRUE;
+        }
+        else if ( EQUAL(argv[i],"-q") || EQUAL(argv[i],"-quiet") )
+        {
+            bQuiet = TRUE;
+        }
+        else if( pszSrcFilename == NULL )
+        {
+            pszSrcFilename = argv[i];
+        }
+        else if( pszDstFilename == NULL )
+        {
+            pszDstFilename = argv[i];
+        }
+        else
+            Usage("Too many command options.");
+    }
+#else
+    bQuiet = TRUE;
+    bIgnoreNoData = TRUE;
+    map* tmpMap=NULL;
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"a","value");
+    if(tmpMap!=NULL && strncmp(tmpMap->value,"NULL",4)!=0){
+      pszElevAttrib = strdup(tmpMap->value);
+    }
+    tmpMap=getMapFromMaps(inputs,"off","value");
+    if(tmpMap!=NULL && strncmp(tmpMap->value,"NULL",4)!=0){
+      dfOffset = atof(tmpMap->value);
+    }
+    tmpMap=getMapFromMaps(inputs,"i","value");
+    if(tmpMap!=NULL && strncmp(tmpMap->value,"NULL",4)!=0){
+      dfInterval = atof(tmpMap->value);
+    }
+    tmpMap=getMapFromMaps(inputs,"b","value");
+    if(tmpMap!=NULL && strncmp(tmpMap->value,"NULL",4)!=0){
+      nBandIn = atoi(tmpMap->value);
+    }
+    tmpMap=getMapFromMaps(inputs,"InputDSN","value");
+    if(tmpMap!=NULL && strncmp(tmpMap->value,"NULL",4)!=0){
+      pszSrcFilename = strdup(tmpMap->value);
+    }
+    tmpMap=getMapFromMaps(inputs,"OutputDSN","value");
+    if(tmpMap!=NULL && strncmp(tmpMap->value,"NULL",4)!=0){
+      pszDstFilename = strdup(tmpMap->value);
+    }
+#endif
+    if( dfInterval == 0.0 && nFixedLevelCount == 0 )
+    {
+        Usage("Neither -i nor -fl are specified.");
+    }
+
+    if (pszSrcFilename == NULL)
+    {
+        Usage("Missing source filename.");
+    }
+
+    if (pszDstFilename == NULL)
+    {
+        Usage("Missing destination filename.");
+    }
+    
+    /*if (!bQuiet)
+      pfnProgress = GDALTermProgress;*/
+    //pfnProgress = GDALTermProgress;
+/* -------------------------------------------------------------------- */
+/*      Open source raster file.                                        */
+/* -------------------------------------------------------------------- */
+    GDALRasterBandH hBand;
+
+    hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly );
+    if( hSrcDS == NULL ){
+#ifndef ZOO_SERVICE
+        exit( 2 );
+#else
+	setMapInMaps(conf,"lenv","message","Unable to open the file");
+#endif
+    }
+    hBand = GDALGetRasterBand( hSrcDS, nBandIn );
+    if( hBand == NULL )
+    {
+#ifndef ZOO_SERVICE
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Band %d does not exist on dataset.", 
+                  nBandIn );
+        exit(2);
+#else
+	char tmp[1024];
+	sprintf(tmp,"Band %d does not exist on dataset.",nBandIn);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+#endif
+    }
+
+    if( !bNoDataSet && !bIgnoreNoData )
+        dfNoData = GDALGetRasterNoDataValue( hBand, &bNoDataSet );
+
+/* -------------------------------------------------------------------- */
+/*      Try to get a coordinate system from the raster.                 */
+/* -------------------------------------------------------------------- */
+    OGRSpatialReferenceH hSRS = NULL;
+
+    const char *pszWKT = GDALGetProjectionRef( hSrcDS );
+
+    if( pszWKT != NULL && strlen(pszWKT) != 0 )
+        hSRS = OSRNewSpatialReference( pszWKT );
+
+/* -------------------------------------------------------------------- */
+/*      Create the outputfile.                                          */
+/* -------------------------------------------------------------------- */
+    OGRDataSourceH hDS;
+    OGRSFDriverH hDriver = OGRGetDriverByName( pszFormat );
+    OGRFieldDefnH hFld;
+    OGRLayerH hLayer;
+
+    if( hDriver == NULL )
+    {
+#ifndef ZOO_SERVICE
+        fprintf( stderr, "Unable to find format driver named %s.\n", 
+                 pszFormat );
+        exit( 10 );
+#else
+	char tmp[1024];
+        sprintf( tmp, "Unable to find format driver named %s.\n", pszFormat );	
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+#endif
+    }
+
+    hDS = OGR_Dr_CreateDataSource( hDriver, pszDstFilename, papszDSCO );
+    if( hDS == NULL ){
+#ifndef ZOO_SERVICE
+        exit( 1 );
+#else
+	setMapInMaps(conf,"lenv","message","Unable to create the file");
+	return SERVICE_FAILED;
+#endif
+    }
+
+    hLayer = OGR_DS_CreateLayer( hDS, pszNewLayerName, hSRS, 
+                                 b3D ? wkbLineString25D : wkbLineString,
+                                 papszLCO );
+    if( hLayer == NULL )
+        exit( 1 );
+
+    hFld = OGR_Fld_Create( "ID", OFTInteger );
+    OGR_Fld_SetWidth( hFld, 8 );
+    OGR_L_CreateField( hLayer, hFld, FALSE );
+    OGR_Fld_Destroy( hFld );
+
+    if( pszElevAttrib )
+    {
+        hFld = OGR_Fld_Create( pszElevAttrib, OFTReal );
+        OGR_Fld_SetWidth( hFld, 12 );
+        OGR_Fld_SetPrecision( hFld, 3 );
+        OGR_L_CreateField( hLayer, hFld, FALSE );
+        OGR_Fld_Destroy( hFld );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Invoke.                                                         */
+/* -------------------------------------------------------------------- */
+    CPLErr eErr;
+    
+    eErr = GDALContourGenerate( hBand, dfInterval, dfOffset, 
+                         nFixedLevelCount, adfFixedLevels,
+                         bNoDataSet, dfNoData, hLayer, 
+                         OGR_FD_GetFieldIndex( OGR_L_GetLayerDefn( hLayer ), 
+                                               "ID" ), 
+                         (pszElevAttrib == NULL) ? -1 :
+                                 OGR_FD_GetFieldIndex( OGR_L_GetLayerDefn( hLayer ), 
+                                                       pszElevAttrib ), 
+				(GDALProgressFunc)pfnProgress1, conf );
+
+    OGR_DS_Destroy( hDS );
+    GDALClose( hSrcDS );
+
+    if (hSRS)
+        OSRDestroySpatialReference( hSRS );
+
+#ifndef ZOO_SERVICE
+    CSLDestroy( argv );
+    CSLDestroy( papszDSCO );
+    CSLDestroy( papszLCO );
+    GDALDestroyDriverManager();
+    OGRCleanupAll();
+    return 0;
+#else
+    GDALDestroyDriverManager();
+    OGRCleanupAll();
+    char tmp[1024];
+    sprintf(tmp,"File %s successfully created.",pszDstFilename);
+    setMapInMaps(outputs,"Result","value",tmp);
+    return SERVICE_SUCCEEDED;
+#endif
+}
+
+#ifdef ZOO_SERVICE
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/Makefile	(revision 942)
@@ -0,0 +1,15 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-DZOO_SERVICE -I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/dem_service.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/dem_service.zo ./service.c ${GDAL_LIBS} ${MACOS_LD_FLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}/gdal/dem
+	install cgi-env/* ${CGI_DIR}/gdal/dem
+
+
+clean:
+	rm -f cgi-env/*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg	(revision 942)
@@ -0,0 +1,65 @@
+[Gdal_Dem]
+ Title = Tools to analyze and visualize DEMs.
+ Abstract = http://www.gdal.org/gdaldem.html
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = dem_service.zo
+ <DataInputs>
+  [InputDSN]
+   Title = The input data source name
+   Abstract = The input data source name to use.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [OutputDSN]
+   Title = The output data source name
+   Abstract = The output data source name.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [utility]
+   Title = The mode
+   Abstract = This service has 7 different modes :  hillshade,  slope,  aspect, color-relief, TRI, TPI, roughness
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [s]
+   Title = The scale
+   Abstract = Scale is the ratio of vertical units to horizontal, for Feet:Latlong use 370400, for Meters:LatLong use 111120
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [co]
+   Title = Creation Option
+   Abstract = string representing options (NAME=VALUE)
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/makefile.vc	(revision 942)
@@ -0,0 +1,11 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+cgi-env/dem_service.zo: service.c
+	$(CPP)  /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE -I$(GDAL_DIR)/frmts/vrt $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/dem_service.zo  $(FILES) ./service.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/dem/service.c	(revision 942)
@@ -0,0 +1,2914 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  GDAL DEM Utilities
+ * Purpose:  
+ * Authors:  Matthew Perry, perrygeo at gmail.com
+ *           Even Rouault, even dot rouault at mines dash paris dot org
+ *           Howard Butler, hobu.inc at gmail.com
+ *           Chris Yesson, chris dot yesson at ioz dot ac dot uk
+ *
+ ******************************************************************************
+ * Copyright (c) 2006, 2009 Matthew Perry 
+ * Copyright (c) 2009 Even Rouault
+ * Portions derived from GRASS 4.1 (public domain) See 
+ * http://trac.osgeo.org/gdal/ticket/2975 for more information regarding 
+ * history of this code
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************
+ *
+ * Slope and aspect calculations based on original method for GRASS GIS 4.1
+ * by Michael Shapiro, U.S.Army Construction Engineering Research Laboratory
+ *    Olga Waupotitsch, U.S.Army Construction Engineering Research Laboratory
+ *    Marjorie Larson, U.S.Army Construction Engineering Research Laboratory
+ * as found in GRASS's r.slope.aspect module.
+ *
+ * Horn's formula is used to find the first order derivatives in x and y directions
+ * for slope and aspect calculations: Horn, B. K. P. (1981).
+ * "Hill Shading and the Reflectance Map", Proceedings of the IEEE, 69(1):14-47. 
+ *
+ * Other reference :
+ * Burrough, P.A. and McDonell, R.A., 1998. Principles of Geographical Information
+ * Systems. p. 190.
+ *
+ * Shaded relief based on original method for GRASS GIS 4.1 by Jim Westervelt,
+ * U.S. Army Construction Engineering Research Laboratory
+ * as found in GRASS's r.shaded.relief (formerly shade.rel.sh) module.
+ * ref: "r.mapcalc: An Algebra for GIS and Image Processing",
+ * by Michael Shapiro and Jim Westervelt, U.S. Army Construction Engineering
+ * Research Laboratory (March/1991)
+ *
+ * Color table of named colors and lookup code derived from src/libes/gis/named_colr.c
+ * of GRASS 4.1
+ *
+ * TRI - Terrain Ruggedness Index is as descibed in Wilson et al (2007)
+ * this is based on the method of Valentine et al. (2004)  
+ * 
+ * TPI - Topographic Position Index follows the description in Wilson et al (2007), following Weiss (2001)
+ * The radius is fixed at 1 cell width/height
+ * 
+ * Roughness - follows the definition in Wilson et al. (2007), which follows Dartnell (2000)
+ *
+ * References for TRI/TPI/Roughness:
+ * Dartnell, P. 2000. Applying Remote Sensing Techniques to map Seafloor 
+ *  Geology/Habitat Relationships. Masters Thesis, San Francisco State 
+ *  University, pp. 108.
+ * Valentine, P. C., S. J. Fuller, L. A. Scully. 2004. Terrain Ruggedness 
+ *  Analysis and Distribution of Boulder Ridges in the Stellwagen Bank National
+ *  Marine Sanctuary Region (poster). Galway, Ireland: 5th International 
+ *  Symposium on Marine Geological and Biological Habitat Mapping (GeoHAB), 
+ *  May 2004.
+ * Weiss, A. D. 2001. Topographic Positions and Landforms Analysis (poster), 
+ *  ESRI International User Conference, July 2001. San Diego, CA: ESRI.
+ * Wilson, M. F. J.; O'Connell, B.; Brown, C.; Guinan, J. C. & Grehan, A. J. 
+ *  Multiscale terrain analysis of multibeam bathymetry data for habitat mapping
+ *  on the continental slope Marine Geodesy, 2007, 30, 3-35
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "gdal.h"
+#include "gdal_priv.h"
+#ifndef ZOO_SERVICE
+#include "commonutils.h"
+#else
+#include "service.h"
+#endif
+
+CPL_CVSID("$Id$");
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp 
+#endif
+
+#ifdef ZOO_SERVICE
+extern "C" {
+#endif
+
+#ifndef M_PI
+# define M_PI  3.1415926535897932384626433832795
+#endif
+
+#define INTERPOL(a,b) ((bSrcHasNoData && (ARE_REAL_EQUAL(a, fSrcNoDataValue) || ARE_REAL_EQUAL(b, fSrcNoDataValue))) ? fSrcNoDataValue : 2 * (a) - (b))
+
+#ifdef ZOO_SERVICE
+static int Usage(maps*& conf, const char* pszErrorMsg = NULL){
+      setMapInMaps(conf,"lenv","message","Missing source.");
+      return SERVICE_FAILED;
+}
+#else
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage(const char* pszErrorMsg = NULL)
+
+{
+    printf( " Usage: \n"
+            " - To generate a shaded relief map from any GDAL-supported elevation raster : \n\n"
+            "     gdaldem hillshade input_dem output_hillshade \n"
+            "                 [-z ZFactor (default=1)] [-s scale* (default=1)] \n"
+            "                 [-az Azimuth (default=315)] [-alt Altitude (default=45)]\n"
+            "                 [-alg ZevenbergenThorne] [-combined]\n"
+            "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
+            "\n"
+            " - To generates a slope map from any GDAL-supported elevation raster :\n\n"
+            "     gdaldem slope input_dem output_slope_map \n"
+            "                 [-p use percent slope (default=degrees)] [-s scale* (default=1)]\n"
+            "                 [-alg ZevenbergenThorne]\n"
+            "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
+            "\n"
+            " - To generate an aspect map from any GDAL-supported elevation raster\n"
+            "   Outputs a 32-bit float tiff with pixel values from 0-360 indicating azimuth :\n\n"
+            "     gdaldem aspect input_dem output_aspect_map \n"
+            "                 [-trigonometric] [-zero_for_flat]\n"
+            "                 [-alg ZevenbergenThorne]\n"
+            "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
+            "\n"
+            " - To generate a color relief map from any GDAL-supported elevation raster\n"
+            "     gdaldem color-relief input_dem color_text_file output_color_relief_map\n"
+            "                 [-alpha] [-exact_color_entry | -nearest_color_entry]\n"
+            "                 [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
+            "     where color_text_file contains lines of the format \"elevation_value red green blue\"\n"
+            "\n"
+            " - To generate a Terrain Ruggedness Index (TRI) map from any GDAL-supported elevation raster\n"
+            "     gdaldem TRI input_dem output_TRI_map\n"
+            "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
+            "\n"
+            " - To generate a Topographic Position Index (TPI) map from any GDAL-supported elevation raster\n"
+            "     gdaldem TPI input_dem output_TPI_map\n"
+            "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
+            "\n"
+            " - To generate a roughness map from any GDAL-supported elevation raster\n"
+            "     gdaldem roughness input_dem output_roughness_map\n"
+            "                 [-compute_edges] [-b Band (default=1)] [-of format] [-co \"NAME=VALUE\"]* [-q]\n"
+            "\n"
+            " Notes : \n"
+            "   Scale is the ratio of vertical units to horizontal\n"
+            "    for Feet:Latlong use scale=370400, for Meters:LatLong use scale=111120 \n\n");
+
+    if( pszErrorMsg != NULL )
+        fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
+
+    exit( 1 );
+}
+#endif
+/************************************************************************/
+/*                          ComputeVal()                                */
+/************************************************************************/
+
+typedef float (*GDALGeneric3x3ProcessingAlg) (float* pafWindow, float fDstNoDataValue, void* pData);
+
+static float ComputeVal(int bSrcHasNoData, float fSrcNoDataValue,
+                        float* afWin, float fDstNoDataValue,
+                        GDALGeneric3x3ProcessingAlg pfnAlg,
+                        void* pData,
+                        int bComputeAtEdges)
+{
+    if (bSrcHasNoData && ARE_REAL_EQUAL(afWin[4], fSrcNoDataValue))
+    {
+        return fDstNoDataValue;
+    }
+    else if (bSrcHasNoData)
+    {
+        int k;
+        for(k=0;k<9;k++)
+        {
+            if (ARE_REAL_EQUAL(afWin[k], fSrcNoDataValue))
+            {
+                if (bComputeAtEdges)
+                    afWin[k] = afWin[4];
+                else
+                    return fDstNoDataValue;
+            }
+        }
+    }
+
+    return pfnAlg(afWin, fDstNoDataValue, pData);
+}
+
+/************************************************************************/
+/*                  GDALGeneric3x3Processing()                          */
+/************************************************************************/
+
+CPLErr GDALGeneric3x3Processing  ( GDALRasterBandH hSrcBand,
+                                   GDALRasterBandH hDstBand,
+                                   GDALGeneric3x3ProcessingAlg pfnAlg,
+                                   void* pData,
+                                   int bComputeAtEdges,
+                                   GDALProgressFunc pfnProgress,
+                                   void * pProgressData)
+{
+    CPLErr eErr;
+    float *pafThreeLineWin; /* 3 line rotating source buffer */
+    float *pafOutputBuf;     /* 1 line destination buffer */
+    int i, j;
+
+    int bSrcHasNoData, bDstHasNoData;
+    float fSrcNoDataValue = 0.0, fDstNoDataValue = 0.0;
+
+    int nXSize = GDALGetRasterBandXSize(hSrcBand);
+    int nYSize = GDALGetRasterBandYSize(hSrcBand);
+
+    if (pfnProgress == NULL)
+        pfnProgress = GDALDummyProgress;
+
+/* -------------------------------------------------------------------- */
+/*      Initialize progress counter.                                    */
+/* -------------------------------------------------------------------- */
+    if( !pfnProgress( 0.0, NULL, pProgressData ) )
+    {
+        CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
+        return CE_Failure;
+    }
+
+    pafOutputBuf = (float *) CPLMalloc(sizeof(float)*nXSize);
+    pafThreeLineWin  = (float *) CPLMalloc(3*sizeof(float)*(nXSize+1));
+
+    fSrcNoDataValue = (float) GDALGetRasterNoDataValue(hSrcBand, &bSrcHasNoData);
+    fDstNoDataValue = (float) GDALGetRasterNoDataValue(hDstBand, &bDstHasNoData);
+    if (!bDstHasNoData)
+        fDstNoDataValue = 0.0;
+
+    // Move a 3x3 pafWindow over each cell 
+    // (where the cell in question is #4)
+    // 
+    //      0 1 2
+    //      3 4 5
+    //      6 7 8
+
+    /* Preload the first 2 lines */
+    for ( i = 0; i < 2 && i < nYSize; i++)
+    {
+        GDALRasterIO(   hSrcBand,
+                        GF_Read,
+                        0, i,
+                        nXSize, 1,
+                        pafThreeLineWin + i * nXSize,
+                        nXSize, 1,
+                        GDT_Float32,
+                        0, 0);
+    }
+    
+    if (bComputeAtEdges && nXSize >= 2 && nYSize >= 2)
+    {
+        for (j = 0; j < nXSize; j++)
+        {
+            float afWin[9];
+            int jmin = (j == 0) ? j : j - 1;
+            int jmax = (j == nXSize - 1) ? j : j + 1;
+
+            afWin[0] = INTERPOL(pafThreeLineWin[jmin], pafThreeLineWin[nXSize + jmin]);
+            afWin[1] = INTERPOL(pafThreeLineWin[j],    pafThreeLineWin[nXSize + j]);
+            afWin[2] = INTERPOL(pafThreeLineWin[jmax], pafThreeLineWin[nXSize + jmax]);
+            afWin[3] = pafThreeLineWin[jmin];
+            afWin[4] = pafThreeLineWin[j];
+            afWin[5] = pafThreeLineWin[jmax];
+            afWin[6] = pafThreeLineWin[nXSize + jmin];
+            afWin[7] = pafThreeLineWin[nXSize + j];
+            afWin[8] = pafThreeLineWin[nXSize + jmax];
+
+            pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                         afWin, fDstNoDataValue,
+                                         pfnAlg, pData, bComputeAtEdges);
+        }
+        GDALRasterIO(hDstBand, GF_Write,
+                    0, 0, nXSize, 1,
+                    pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
+    }
+    else
+    {
+        // Exclude the edges
+        for (j = 0; j < nXSize; j++)
+        {
+            pafOutputBuf[j] = fDstNoDataValue;
+        }
+        GDALRasterIO(hDstBand, GF_Write,
+                    0, 0, nXSize, 1,
+                    pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
+    
+        if (nYSize > 1)
+        {
+            GDALRasterIO(hDstBand, GF_Write,
+                        0, nYSize - 1, nXSize, 1,
+                        pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
+        }
+    }
+    
+    int nLine1Off = 0*nXSize;
+    int nLine2Off = 1*nXSize;
+    int nLine3Off = 2*nXSize;
+
+    for ( i = 1; i < nYSize-1; i++)
+    {
+        /* Read third line of the line buffer */
+        eErr = GDALRasterIO(   hSrcBand,
+                        GF_Read,
+                        0, i+1,
+                        nXSize, 1,
+                        pafThreeLineWin + nLine3Off,
+                        nXSize, 1,
+                        GDT_Float32,
+                        0, 0);
+        if (eErr != CE_None)
+            goto end;
+
+        if (bComputeAtEdges && nXSize >= 2)
+        {
+            float afWin[9];
+
+            j = 0;
+            afWin[0] = INTERPOL(pafThreeLineWin[nLine1Off + j], pafThreeLineWin[nLine1Off + j+1]);
+            afWin[1] = pafThreeLineWin[nLine1Off + j];
+            afWin[2] = pafThreeLineWin[nLine1Off + j+1];
+            afWin[3] = INTERPOL(pafThreeLineWin[nLine2Off + j], pafThreeLineWin[nLine2Off + j+1]);
+            afWin[4] = pafThreeLineWin[nLine2Off + j];
+            afWin[5] = pafThreeLineWin[nLine2Off + j+1];
+            afWin[6] = INTERPOL(pafThreeLineWin[nLine3Off + j], pafThreeLineWin[nLine3Off + j+1]);
+            afWin[7] = pafThreeLineWin[nLine3Off + j];
+            afWin[8] = pafThreeLineWin[nLine3Off + j+1];
+
+            pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                         afWin, fDstNoDataValue,
+                                         pfnAlg, pData, bComputeAtEdges);
+            j = nXSize - 1;
+
+            afWin[0] = pafThreeLineWin[nLine1Off + j-1];
+            afWin[1] = pafThreeLineWin[nLine1Off + j];
+            afWin[2] = INTERPOL(pafThreeLineWin[nLine1Off + j], pafThreeLineWin[nLine1Off + j-1]);
+            afWin[3] = pafThreeLineWin[nLine2Off + j-1];
+            afWin[4] = pafThreeLineWin[nLine2Off + j];
+            afWin[5] = INTERPOL(pafThreeLineWin[nLine2Off + j], pafThreeLineWin[nLine2Off + j-1]);
+            afWin[6] = pafThreeLineWin[nLine3Off + j-1];
+            afWin[7] = pafThreeLineWin[nLine3Off + j];
+            afWin[8] = INTERPOL(pafThreeLineWin[nLine3Off + j], pafThreeLineWin[nLine3Off + j-1]);
+
+            pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                         afWin, fDstNoDataValue,
+                                         pfnAlg, pData, bComputeAtEdges);
+        }
+        else
+        {
+            // Exclude the edges
+            pafOutputBuf[0] = fDstNoDataValue;
+            if (nXSize > 1)
+                pafOutputBuf[nXSize - 1] = fDstNoDataValue;
+        }
+
+        for (j = 1; j < nXSize - 1; j++)
+        {
+            float afWin[9];
+            afWin[0] = pafThreeLineWin[nLine1Off + j-1];
+            afWin[1] = pafThreeLineWin[nLine1Off + j];
+            afWin[2] = pafThreeLineWin[nLine1Off + j+1];
+            afWin[3] = pafThreeLineWin[nLine2Off + j-1];
+            afWin[4] = pafThreeLineWin[nLine2Off + j];
+            afWin[5] = pafThreeLineWin[nLine2Off + j+1];
+            afWin[6] = pafThreeLineWin[nLine3Off + j-1];
+            afWin[7] = pafThreeLineWin[nLine3Off + j];
+            afWin[8] = pafThreeLineWin[nLine3Off + j+1];
+
+            pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                         afWin, fDstNoDataValue,
+                                         pfnAlg, pData, bComputeAtEdges);
+        }
+
+        /* -----------------------------------------
+         * Write Line to Raster
+         */
+        eErr = GDALRasterIO(hDstBand, GF_Write, 0, i, nXSize, 1,
+                     pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
+        if (eErr != CE_None)
+            goto end;
+
+        if( !pfnProgress( 1.0 * (i+1) / nYSize, NULL, pProgressData ) )
+        {
+            CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
+            eErr = CE_Failure;
+            goto end;
+        }
+        
+        int nTemp = nLine1Off;
+        nLine1Off = nLine2Off;
+        nLine2Off = nLine3Off;
+        nLine3Off = nTemp;
+    }
+
+    if (bComputeAtEdges && nXSize >= 2 && nYSize >= 2)
+    {
+        for (j = 0; j < nXSize; j++)
+        {
+            float afWin[9];
+            int jmin = (j == 0) ? j : j - 1;
+            int jmax = (j == nXSize - 1) ? j : j + 1;
+
+            afWin[0] = pafThreeLineWin[nLine1Off + jmin];
+            afWin[1] = pafThreeLineWin[nLine1Off + j];
+            afWin[2] = pafThreeLineWin[nLine1Off + jmax];
+            afWin[3] = pafThreeLineWin[nLine2Off + jmin];
+            afWin[4] = pafThreeLineWin[nLine2Off + j];
+            afWin[5] = pafThreeLineWin[nLine2Off + jmax];
+            afWin[6] = INTERPOL(pafThreeLineWin[nLine2Off + jmin], pafThreeLineWin[nLine1Off + jmin]);
+            afWin[7] = INTERPOL(pafThreeLineWin[nLine2Off + j],    pafThreeLineWin[nLine1Off + j]);
+            afWin[8] = INTERPOL(pafThreeLineWin[nLine2Off + jmax], pafThreeLineWin[nLine1Off + jmax]);
+
+            pafOutputBuf[j] = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                         afWin, fDstNoDataValue,
+                                         pfnAlg, pData, bComputeAtEdges);
+        }
+        GDALRasterIO(hDstBand, GF_Write,
+                     0, i, nXSize, 1,
+                     pafOutputBuf, nXSize, 1, GDT_Float32, 0, 0);
+    }
+
+    pfnProgress( 1.0, NULL, pProgressData );
+    eErr = CE_None;
+
+end:
+    CPLFree(pafOutputBuf);
+    CPLFree(pafThreeLineWin);
+
+    return eErr;
+}
+
+
+/************************************************************************/
+/*                         GDALHillshade()                              */
+/************************************************************************/
+
+typedef struct
+{
+    double nsres;
+    double ewres;
+    double sin_altRadians;
+    double cos_altRadians_mul_z_scale_factor;
+    double azRadians;
+    double square_z_scale_factor;
+    double square_M_PI_2;
+} GDALHillshadeAlgData;
+
+/* Unoptimized formulas are :
+    x = psData->z*((afWin[0] + afWin[3] + afWin[3] + afWin[6]) -
+        (afWin[2] + afWin[5] + afWin[5] + afWin[8])) /
+        (8.0 * psData->ewres * psData->scale);
+
+    y = psData->z*((afWin[6] + afWin[7] + afWin[7] + afWin[8]) -
+        (afWin[0] + afWin[1] + afWin[1] + afWin[2])) /
+        (8.0 * psData->nsres * psData->scale);
+
+    slope = M_PI / 2 - atan(sqrt(x*x + y*y));
+
+    aspect = atan2(y,x);
+
+    cang = sin(alt * degreesToRadians) * sin(slope) +
+           cos(alt * degreesToRadians) * cos(slope) *
+           cos(az * degreesToRadians - M_PI/2 - aspect);
+*/
+
+float GDALHillshadeAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
+    double x, y, aspect, xx_plus_yy, cang;
+    
+    // First Slope ...
+    x = ((afWin[0] + afWin[3] + afWin[3] + afWin[6]) -
+        (afWin[2] + afWin[5] + afWin[5] + afWin[8])) / psData->ewres;
+
+    y = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) -
+        (afWin[0] + afWin[1] + afWin[1] + afWin[2])) / psData->nsres;
+
+    xx_plus_yy = x * x + y * y;
+
+    // ... then aspect...
+    aspect = atan2(y,x);
+
+    // ... then the shade value
+    cang = (psData->sin_altRadians -
+           psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
+           sin(aspect - psData->azRadians)) /
+           sqrt(1 + psData->square_z_scale_factor * xx_plus_yy);
+
+    if (cang <= 0.0) 
+        cang = 1.0;
+    else
+        cang = 1.0 + (254.0 * cang);
+        
+    return (float) cang;
+}
+
+float GDALHillshadeCombinedAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
+    double x, y, aspect, xx_plus_yy, cang;
+    
+    // First Slope ...
+    x = ((afWin[0] + afWin[3] + afWin[3] + afWin[6]) -
+        (afWin[2] + afWin[5] + afWin[5] + afWin[8])) / psData->ewres;
+
+    y = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) -
+        (afWin[0] + afWin[1] + afWin[1] + afWin[2])) / psData->nsres;
+
+    xx_plus_yy = x * x + y * y;
+
+    // ... then aspect...
+    aspect = atan2(y,x);
+    double slope = xx_plus_yy * psData->square_z_scale_factor;
+
+    // ... then the shade value
+    cang = acos((psData->sin_altRadians -
+           psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
+           sin(aspect - psData->azRadians)) /
+           sqrt(1 + slope));
+
+    // combined shading
+    cang = 1 - cang * atan(sqrt(slope)) / psData->square_M_PI_2;
+
+    if (cang <= 0.0) 
+        cang = 1.0;
+    else
+        cang = 1.0 + (254.0 * cang);
+        
+    return (float) cang;
+}
+
+float GDALHillshadeZevenbergenThorneAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
+    double x, y, aspect, xx_plus_yy, cang;
+    
+    // First Slope ...
+    x = (afWin[3] - afWin[5]) / psData->ewres;
+
+    y = (afWin[7] - afWin[1]) / psData->nsres;
+
+    xx_plus_yy = x * x + y * y;
+
+    // ... then aspect...
+    aspect = atan2(y,x);
+
+    // ... then the shade value
+    cang = (psData->sin_altRadians -
+           psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
+           sin(aspect - psData->azRadians)) /
+           sqrt(1 + psData->square_z_scale_factor * xx_plus_yy);
+
+    if (cang <= 0.0) 
+        cang = 1.0;
+    else
+        cang = 1.0 + (254.0 * cang);
+        
+    return (float) cang;
+}
+
+float GDALHillshadeZevenbergenThorneCombinedAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    GDALHillshadeAlgData* psData = (GDALHillshadeAlgData*)pData;
+    double x, y, aspect, xx_plus_yy, cang;
+    
+    // First Slope ...
+    x = (afWin[3] - afWin[5]) / psData->ewres;
+
+    y = (afWin[7] - afWin[1]) / psData->nsres;
+
+    xx_plus_yy = x * x + y * y;
+
+    // ... then aspect...
+    aspect = atan2(y,x);
+    double slope = xx_plus_yy * psData->square_z_scale_factor;
+
+    // ... then the shade value
+    cang = acos((psData->sin_altRadians -
+           psData->cos_altRadians_mul_z_scale_factor * sqrt(xx_plus_yy) *
+           sin(aspect - psData->azRadians)) /
+           sqrt(1 + slope));
+
+    // combined shading
+    cang = 1 - cang * atan(sqrt(slope)) / psData->square_M_PI_2;
+
+    if (cang <= 0.0) 
+        cang = 1.0;
+    else
+        cang = 1.0 + (254.0 * cang);
+        
+    return (float) cang;
+}
+
+void*  GDALCreateHillshadeData(double* adfGeoTransform,
+                               double z,
+                               double scale,
+                               double alt,
+                               double az,
+                               int bZevenbergenThorne)
+{
+    GDALHillshadeAlgData* pData =
+        (GDALHillshadeAlgData*)CPLMalloc(sizeof(GDALHillshadeAlgData));
+        
+    const double degreesToRadians = M_PI / 180.0;
+    pData->nsres = adfGeoTransform[5];
+    pData->ewres = adfGeoTransform[1];
+    pData->sin_altRadians = sin(alt * degreesToRadians);
+    pData->azRadians = az * degreesToRadians;
+    double z_scale_factor = z / (((bZevenbergenThorne) ? 2 : 8) * scale);
+    pData->cos_altRadians_mul_z_scale_factor =
+        cos(alt * degreesToRadians) * z_scale_factor;
+    pData->square_z_scale_factor = z_scale_factor * z_scale_factor;
+    pData->square_M_PI_2 = (M_PI*M_PI)/4;
+    return pData;
+}
+
+/************************************************************************/
+/*                         GDALSlope()                                  */
+/************************************************************************/
+
+typedef struct
+{
+    double nsres;
+    double ewres;
+    double scale;
+    int    slopeFormat;
+} GDALSlopeAlgData;
+
+float GDALSlopeHornAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    const double radiansToDegrees = 180.0 / M_PI;
+    GDALSlopeAlgData* psData = (GDALSlopeAlgData*)pData;
+    double dx, dy, key;
+    
+    dx = ((afWin[0] + afWin[3] + afWin[3] + afWin[6]) - 
+          (afWin[2] + afWin[5] + afWin[5] + afWin[8]))/psData->ewres;
+
+    dy = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) - 
+          (afWin[0] + afWin[1] + afWin[1] + afWin[2]))/psData->nsres;
+
+    key = (dx * dx + dy * dy);
+
+    if (psData->slopeFormat == 1) 
+        return (float) (atan(sqrt(key) / (8*psData->scale)) * radiansToDegrees);
+    else
+        return (float) (100*(sqrt(key) / (8*psData->scale)));
+}
+
+float GDALSlopeZevenbergenThorneAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    const double radiansToDegrees = 180.0 / M_PI;
+    GDALSlopeAlgData* psData = (GDALSlopeAlgData*)pData;
+    double dx, dy, key;
+    
+    dx = (afWin[3] - afWin[5])/psData->ewres;
+
+    dy = (afWin[7] - afWin[1])/psData->nsres;
+
+    key = (dx * dx + dy * dy);
+
+    if (psData->slopeFormat == 1) 
+        return (float) (atan(sqrt(key) / (2*psData->scale)) * radiansToDegrees);
+    else
+        return (float) (100*(sqrt(key) / (2*psData->scale)));
+}
+
+void*  GDALCreateSlopeData(double* adfGeoTransform,
+                           double scale,
+                           int slopeFormat)
+{
+    GDALSlopeAlgData* pData =
+        (GDALSlopeAlgData*)CPLMalloc(sizeof(GDALSlopeAlgData));
+        
+    pData->nsres = adfGeoTransform[5];
+    pData->ewres = adfGeoTransform[1];
+    pData->scale = scale;
+    pData->slopeFormat = slopeFormat;
+    return pData;
+}
+
+/************************************************************************/
+/*                         GDALAspect()                                 */
+/************************************************************************/
+
+typedef struct
+{
+    int bAngleAsAzimuth;
+} GDALAspectAlgData;
+
+float GDALAspectAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    const double degreesToRadians = M_PI / 180.0;
+    GDALAspectAlgData* psData = (GDALAspectAlgData*)pData;
+    double dx, dy;
+    float aspect;
+    
+    dx = ((afWin[2] + afWin[5] + afWin[5] + afWin[8]) -
+          (afWin[0] + afWin[3] + afWin[3] + afWin[6]));
+
+    dy = ((afWin[6] + afWin[7] + afWin[7] + afWin[8]) - 
+          (afWin[0] + afWin[1] + afWin[1] + afWin[2]));
+
+    aspect = (float) (atan2(dy,-dx) / degreesToRadians);
+
+    if (dx == 0 && dy == 0)
+    {
+        /* Flat area */
+        aspect = fDstNoDataValue;
+    } 
+    else if ( psData->bAngleAsAzimuth )
+    {
+        if (aspect > 90.0) 
+            aspect = 450.0f - aspect;
+        else
+            aspect = 90.0f - aspect;
+    }
+    else
+    {
+        if (aspect < 0)
+            aspect += 360.0;
+    }
+
+    if (aspect == 360.0) 
+        aspect = 0.0;
+
+    return aspect;
+}
+
+float GDALAspectZevenbergenThorneAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    const double degreesToRadians = M_PI / 180.0;
+    GDALAspectAlgData* psData = (GDALAspectAlgData*)pData;
+    double dx, dy;
+    float aspect;
+    
+    dx = (afWin[5] - afWin[3]);
+
+    dy = (afWin[7] - afWin[1]);
+
+    aspect = (float) (atan2(dy,-dx) / degreesToRadians);
+
+    if (dx == 0 && dy == 0)
+    {
+        /* Flat area */
+        aspect = fDstNoDataValue;
+    } 
+    else if ( psData->bAngleAsAzimuth )
+    {
+        if (aspect > 90.0) 
+            aspect = 450.0f - aspect;
+        else
+            aspect = 90.0f - aspect;
+    }
+    else
+    {
+        if (aspect < 0)
+            aspect += 360.0;
+    }
+
+    if (aspect == 360.0) 
+        aspect = 0.0;
+
+    return aspect;
+}
+void*  GDALCreateAspectData(int bAngleAsAzimuth)
+{
+    GDALAspectAlgData* pData =
+        (GDALAspectAlgData*)CPLMalloc(sizeof(GDALAspectAlgData));
+        
+    pData->bAngleAsAzimuth = bAngleAsAzimuth;
+    return pData;
+}
+
+/************************************************************************/
+/*                      GDALColorRelief()                               */
+/************************************************************************/
+
+typedef struct
+{
+    double dfVal;
+    int nR;
+    int nG;
+    int nB;
+    int nA;
+} ColorAssociation;
+
+static int GDALColorReliefSortColors(const void* pA, const void* pB)
+{
+    ColorAssociation* pC1 = (ColorAssociation*)pA;
+    ColorAssociation* pC2 = (ColorAssociation*)pB;
+    return (pC1->dfVal < pC2->dfVal) ? -1 :
+           (pC1->dfVal == pC2->dfVal) ? 0 : 1;
+}
+
+typedef enum
+{
+    COLOR_SELECTION_INTERPOLATE,
+    COLOR_SELECTION_NEAREST_ENTRY,
+    COLOR_SELECTION_EXACT_ENTRY
+} ColorSelectionMode;
+
+static int GDALColorReliefGetRGBA (ColorAssociation* pasColorAssociation,
+                                   int nColorAssociation,
+                                   double dfVal,
+                                   ColorSelectionMode eColorSelectionMode,
+                                   int* pnR,
+                                   int* pnG,
+                                   int* pnB,
+                                   int* pnA)
+{
+    int i;
+    int lower = 0;
+    int upper = nColorAssociation - 1;
+    int mid;
+
+    /* Find the index of the first element in the LUT input array that */
+    /* is not smaller than the dfVal value. */
+    while(TRUE)
+    {
+        mid = (lower + upper) / 2;
+        if (upper - lower <= 1)
+        {
+            if (dfVal < pasColorAssociation[lower].dfVal)
+                i = lower;
+            else if (dfVal < pasColorAssociation[upper].dfVal)
+                i = upper;
+            else
+                i = upper + 1;
+            break;
+        }
+        else if (pasColorAssociation[mid].dfVal >= dfVal)
+        {
+            upper = mid;
+        }
+        else
+        {
+            lower = mid;
+        }
+    }
+
+    if (i == 0)
+    {
+        if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
+            pasColorAssociation[0].dfVal != dfVal)
+        {
+            *pnR = 0;
+            *pnG = 0;
+            *pnB = 0;
+            *pnA = 0;
+            return FALSE;
+        }
+        else
+        {
+            *pnR = pasColorAssociation[0].nR;
+            *pnG = pasColorAssociation[0].nG;
+            *pnB = pasColorAssociation[0].nB;
+            *pnA = pasColorAssociation[0].nA;
+            return TRUE;
+        }
+    }
+    else if (i == nColorAssociation)
+    {
+        if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
+            pasColorAssociation[i-1].dfVal != dfVal)
+        {
+            *pnR = 0;
+            *pnG = 0;
+            *pnB = 0;
+            *pnA = 0;
+            return FALSE;
+        }
+        else
+        {
+            *pnR = pasColorAssociation[i-1].nR;
+            *pnG = pasColorAssociation[i-1].nG;
+            *pnB = pasColorAssociation[i-1].nB;
+            *pnA = pasColorAssociation[i-1].nA;
+            return TRUE;
+        }
+    }
+    else
+    {
+        if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
+            pasColorAssociation[i-1].dfVal != dfVal)
+        {
+            *pnR = 0;
+            *pnG = 0;
+            *pnB = 0;
+            *pnA = 0;
+            return FALSE;
+        }
+        
+        if (eColorSelectionMode == COLOR_SELECTION_NEAREST_ENTRY &&
+            pasColorAssociation[i-1].dfVal != dfVal)
+        {
+            int index;
+            if (dfVal - pasColorAssociation[i-1].dfVal <
+                pasColorAssociation[i].dfVal - dfVal)
+                index = i -1;
+            else
+                index = i;
+
+            *pnR = pasColorAssociation[index].nR;
+            *pnG = pasColorAssociation[index].nG;
+            *pnB = pasColorAssociation[index].nB;
+            *pnA = pasColorAssociation[index].nA;
+            return TRUE;
+        }
+        
+        double dfRatio = (dfVal - pasColorAssociation[i-1].dfVal) /
+            (pasColorAssociation[i].dfVal - pasColorAssociation[i-1].dfVal);
+        *pnR = (int)(0.45 + pasColorAssociation[i-1].nR + dfRatio *
+                (pasColorAssociation[i].nR - pasColorAssociation[i-1].nR));
+        if (*pnR < 0) *pnR = 0;
+        else if (*pnR > 255) *pnR = 255;
+        *pnG = (int)(0.45 + pasColorAssociation[i-1].nG + dfRatio *
+                (pasColorAssociation[i].nG - pasColorAssociation[i-1].nG));
+        if (*pnG < 0) *pnG = 0;
+        else if (*pnG > 255) *pnG = 255;
+        *pnB = (int)(0.45 + pasColorAssociation[i-1].nB + dfRatio *
+                (pasColorAssociation[i].nB - pasColorAssociation[i-1].nB));
+        if (*pnB < 0) *pnB = 0;
+        else if (*pnB > 255) *pnB = 255;
+        *pnA = (int)(0.45 + pasColorAssociation[i-1].nA + dfRatio *
+                (pasColorAssociation[i].nA - pasColorAssociation[i-1].nA));
+        if (*pnA < 0) *pnA = 0;
+        else if (*pnA > 255) *pnA = 255;
+        
+        return TRUE;
+    }
+}
+
+/* dfPct : percentage between 0 and 1 */
+static double GDALColorReliefGetAbsoluteValFromPct(GDALRasterBandH hSrcBand,
+                                                   double dfPct)
+{
+    double dfMin, dfMax;
+    int bSuccessMin, bSuccessMax;
+    dfMin = GDALGetRasterMinimum(hSrcBand, &bSuccessMin);
+    dfMax = GDALGetRasterMaximum(hSrcBand, &bSuccessMax);
+    if (!bSuccessMin || !bSuccessMax)
+    {
+        double dfMean, dfStdDev;
+        fprintf(stderr, "Computing source raster statistics...\n");
+        GDALComputeRasterStatistics(hSrcBand, FALSE, &dfMin, &dfMax,
+                                    &dfMean, &dfStdDev, NULL, NULL);
+    }
+    return dfMin + dfPct * (dfMax - dfMin);
+}
+
+typedef struct
+{
+    const char *name;
+    float r, g, b;
+} NamedColor;
+
+static const NamedColor namedColors[] = {
+    { "white",  1.00, 1.00, 1.00 },
+    { "black",  0.00, 0.00, 0.00 },
+    { "red",    1.00, 0.00, 0.00 },
+    { "green",  0.00, 1.00, 0.00 },
+    { "blue",   0.00, 0.00, 1.00 },
+    { "yellow", 1.00, 1.00, 0.00 },
+    { "magenta",1.00, 0.00, 1.00 },
+    { "cyan",   0.00, 1.00, 1.00 },
+    { "aqua",   0.00, 0.75, 0.75 },
+    { "grey",   0.75, 0.75, 0.75 },
+    { "gray",   0.75, 0.75, 0.75 },
+    { "orange", 1.00, 0.50, 0.00 },
+    { "brown",  0.75, 0.50, 0.25 },
+    { "purple", 0.50, 0.00, 1.00 },
+    { "violet", 0.50, 0.00, 1.00 },
+    { "indigo", 0.00, 0.50, 1.00 },
+};
+
+static
+int GDALColorReliefFindNamedColor(const char *pszColorName, int *pnR, int *pnG, int *pnB)
+{
+    unsigned int i;
+
+    *pnR = *pnG = *pnB = 0;
+    for (i = 0; i < sizeof(namedColors) / sizeof(namedColors[0]); i++)
+    {
+        if (EQUAL(pszColorName, namedColors[i].name))
+        {
+            *pnR = (int)(255. * namedColors[i].r);
+            *pnG = (int)(255. * namedColors[i].g);
+            *pnB = (int)(255. * namedColors[i].b);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static
+ColorAssociation* GDALColorReliefParseColorFile(GDALRasterBandH hSrcBand,
+                                                const char* pszColorFilename,
+                                                int* pnColors)
+{
+    VSILFILE* fpColorFile = VSIFOpenL(pszColorFilename, "rt");
+    if (fpColorFile == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s", pszColorFilename);
+        *pnColors = 0;
+        return NULL;
+    }
+
+    ColorAssociation* pasColorAssociation = NULL;
+    int nColorAssociation = 0;
+
+    int bSrcHasNoData = FALSE;
+    double dfSrcNoDataValue = GDALGetRasterNoDataValue(hSrcBand, &bSrcHasNoData);
+
+    const char* pszLine;
+    int bIsGMT_CPT = FALSE;
+    while ((pszLine = CPLReadLineL(fpColorFile)) != NULL)
+    {
+        if (pszLine[0] == '#' && strstr(pszLine, "COLOR_MODEL"))
+        {
+            if (strstr(pszLine, "COLOR_MODEL = RGB") == NULL)
+            {
+                CPLError(CE_Failure, CPLE_AppDefined, "Only COLOR_MODEL = RGB is supported");
+                CPLFree(pasColorAssociation);
+                *pnColors = 0;
+                return NULL;
+            }
+            bIsGMT_CPT = TRUE;
+        }
+
+        char** papszFields = CSLTokenizeStringComplex(pszLine, " ,\t:", 
+                                                      FALSE, FALSE );
+        /* Skip comment lines */
+        int nTokens = CSLCount(papszFields);
+        if (nTokens >= 1 && (papszFields[0][0] == '#' ||
+                             papszFields[0][0] == '/'))
+        {
+            CSLDestroy(papszFields);
+            continue;
+        }
+
+        if (bIsGMT_CPT && nTokens == 8)
+        {
+            pasColorAssociation =
+                    (ColorAssociation*)CPLRealloc(pasColorAssociation,
+                           (nColorAssociation + 2) * sizeof(ColorAssociation));
+
+            pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[0]);
+            pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
+            pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
+            pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
+            pasColorAssociation[nColorAssociation].nA = 255;
+            nColorAssociation++;
+
+            pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[4]);
+            pasColorAssociation[nColorAssociation].nR = atoi(papszFields[5]);
+            pasColorAssociation[nColorAssociation].nG = atoi(papszFields[6]);
+            pasColorAssociation[nColorAssociation].nB = atoi(papszFields[7]);
+            pasColorAssociation[nColorAssociation].nA = 255;
+            nColorAssociation++;
+        }
+        else if (bIsGMT_CPT && nTokens == 4)
+        {
+            /* The first token might be B (background), F (foreground) or N (nodata) */
+            /* Just interested in N */
+            if (EQUAL(papszFields[0], "N") && bSrcHasNoData)
+            {
+                 pasColorAssociation =
+                    (ColorAssociation*)CPLRealloc(pasColorAssociation,
+                           (nColorAssociation + 1) * sizeof(ColorAssociation));
+
+                pasColorAssociation[nColorAssociation].dfVal = dfSrcNoDataValue;
+                pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
+                pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
+                pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
+                pasColorAssociation[nColorAssociation].nA = 255;
+                nColorAssociation++;
+            }
+        }
+        else if (!bIsGMT_CPT && nTokens >= 2)
+        {
+            pasColorAssociation =
+                    (ColorAssociation*)CPLRealloc(pasColorAssociation,
+                           (nColorAssociation + 1) * sizeof(ColorAssociation));
+            if (EQUAL(papszFields[0], "nv") && bSrcHasNoData)
+                pasColorAssociation[nColorAssociation].dfVal = dfSrcNoDataValue;
+            else if (strlen(papszFields[0]) > 1 && papszFields[0][strlen(papszFields[0])-1] == '%')
+            {
+                double dfPct = atof(papszFields[0]) / 100.;
+                if (dfPct < 0.0 || dfPct > 1.0)
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined,
+                             "Wrong value for a percentage : %s", papszFields[0]);
+                    CSLDestroy(papszFields);
+                    VSIFCloseL(fpColorFile);
+                    CPLFree(pasColorAssociation);
+                    *pnColors = 0;
+                    return NULL;
+                }
+                pasColorAssociation[nColorAssociation].dfVal =
+                        GDALColorReliefGetAbsoluteValFromPct(hSrcBand, dfPct);
+            }
+            else
+                pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[0]);
+
+            if (nTokens >= 4)
+            {
+                pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
+                pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
+                pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
+                pasColorAssociation[nColorAssociation].nA =
+                        (CSLCount(papszFields) >= 5 ) ? atoi(papszFields[4]) : 255;
+            }
+            else
+            {
+                int nR, nG, nB;
+                if (!GDALColorReliefFindNamedColor(papszFields[1], &nR, &nG, &nB))
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined,
+                             "Unknown color : %s", papszFields[1]);
+                    CSLDestroy(papszFields);
+                    VSIFCloseL(fpColorFile);
+                    CPLFree(pasColorAssociation);
+                    *pnColors = 0;
+                    return NULL;
+                }
+                pasColorAssociation[nColorAssociation].nR = nR;
+                pasColorAssociation[nColorAssociation].nG = nG;
+                pasColorAssociation[nColorAssociation].nB = nB;
+                            pasColorAssociation[nColorAssociation].nA =
+                    (CSLCount(papszFields) >= 3 ) ? atoi(papszFields[2]) : 255;
+            }
+
+            nColorAssociation ++;
+        }
+        CSLDestroy(papszFields);
+    }
+    VSIFCloseL(fpColorFile);
+
+    if (nColorAssociation == 0)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "No color association found in %s", pszColorFilename);
+        *pnColors = 0;
+        return NULL;
+    }
+
+    qsort(pasColorAssociation, nColorAssociation,
+          sizeof(ColorAssociation), GDALColorReliefSortColors);
+
+    *pnColors = nColorAssociation;
+    return pasColorAssociation;
+}
+
+static
+GByte* GDALColorReliefPrecompute(GDALRasterBandH hSrcBand,
+                                 ColorAssociation* pasColorAssociation,
+                                 int nColorAssociation,
+                                 ColorSelectionMode eColorSelectionMode,
+                                 int* pnIndexOffset)
+{
+    GDALDataType eDT = GDALGetRasterDataType(hSrcBand);
+    GByte* pabyPrecomputed = NULL;
+    int nIndexOffset = (eDT == GDT_Int16) ? 32768 : 0;
+    *pnIndexOffset = nIndexOffset;
+    int nXSize = GDALGetRasterBandXSize(hSrcBand);
+    int nYSize = GDALGetRasterBandXSize(hSrcBand);
+    if (eDT == GDT_Byte ||
+        ((eDT == GDT_Int16 || eDT == GDT_UInt16) && nXSize * nYSize > 65536))
+    {
+        int iMax = (eDT == GDT_Byte) ? 256: 65536;
+        pabyPrecomputed = (GByte*) VSIMalloc(4 * iMax);
+        if (pabyPrecomputed)
+        {
+            int i;
+            for(i=0;i<iMax;i++)
+            {
+                int nR, nG, nB, nA;
+                GDALColorReliefGetRGBA  (pasColorAssociation,
+                                         nColorAssociation,
+                                         i - nIndexOffset,
+                                         eColorSelectionMode,
+                                         &nR, &nG, &nB, &nA);
+                pabyPrecomputed[4 * i] = (GByte) nR;
+                pabyPrecomputed[4 * i + 1] = (GByte) nG;
+                pabyPrecomputed[4 * i + 2] = (GByte) nB;
+                pabyPrecomputed[4 * i + 3] = (GByte) nA;
+            }
+        }
+    }
+    return pabyPrecomputed;
+}
+
+/************************************************************************/
+/* ==================================================================== */
+/*                       GDALColorReliefDataset                        */
+/* ==================================================================== */
+/************************************************************************/
+
+class GDALColorReliefRasterBand;
+
+class GDALColorReliefDataset : public GDALDataset
+{
+    friend class GDALColorReliefRasterBand;
+
+    GDALDatasetH       hSrcDS;
+    GDALRasterBandH    hSrcBand;
+    int                nColorAssociation;
+    ColorAssociation*  pasColorAssociation;
+    ColorSelectionMode eColorSelectionMode;
+    GByte*             pabyPrecomputed;
+    int                nIndexOffset;
+    float*             pafSourceBuf;
+    int*               panSourceBuf;
+    int                nCurBlockXOff;
+    int                nCurBlockYOff;
+
+  public:
+                        GDALColorReliefDataset(GDALDatasetH hSrcDS,
+                                            GDALRasterBandH hSrcBand,
+                                            const char* pszColorFilename,
+                                            ColorSelectionMode eColorSelectionMode,
+                                            int bAlpha);
+                       ~GDALColorReliefDataset();
+
+    CPLErr      GetGeoTransform( double * padfGeoTransform );
+    const char *GetProjectionRef();
+};
+
+/************************************************************************/
+/* ==================================================================== */
+/*                    GDALColorReliefRasterBand                       */
+/* ==================================================================== */
+/************************************************************************/
+
+class GDALColorReliefRasterBand : public GDALRasterBand
+{
+    friend class GDALColorReliefDataset;
+
+    
+  public:
+                 GDALColorReliefRasterBand( GDALColorReliefDataset *, int );
+    
+    virtual CPLErr          IReadBlock( int, int, void * );
+    virtual GDALColorInterp GetColorInterpretation();
+};
+
+GDALColorReliefDataset::GDALColorReliefDataset(
+                                     GDALDatasetH hSrcDS,
+                                     GDALRasterBandH hSrcBand,
+                                     const char* pszColorFilename,
+                                     ColorSelectionMode eColorSelectionMode,
+                                     int bAlpha)
+{
+    this->hSrcDS = hSrcDS;
+    this->hSrcBand = hSrcBand;
+    nColorAssociation = 0;
+    pasColorAssociation =
+            GDALColorReliefParseColorFile(hSrcBand, pszColorFilename,
+                                          &nColorAssociation);
+    this->eColorSelectionMode = eColorSelectionMode;
+    
+    nRasterXSize = GDALGetRasterXSize(hSrcDS);
+    nRasterYSize = GDALGetRasterYSize(hSrcDS);
+    
+    int nBlockXSize, nBlockYSize;
+    GDALGetBlockSize( hSrcBand, &nBlockXSize, &nBlockYSize);
+    
+    nIndexOffset = 0;
+    pabyPrecomputed =
+        GDALColorReliefPrecompute(hSrcBand,
+                                  pasColorAssociation,
+                                  nColorAssociation,
+                                  eColorSelectionMode,
+                                  &nIndexOffset);
+    
+    int i;
+    for(i=0;i<((bAlpha) ? 4 : 3);i++)
+    {
+        SetBand(i + 1, new GDALColorReliefRasterBand(this, i+1));
+    }
+    
+    pafSourceBuf = NULL;
+    panSourceBuf = NULL;
+    if (pabyPrecomputed)
+        panSourceBuf = (int *) CPLMalloc(sizeof(int)*nBlockXSize*nBlockYSize);
+    else
+        pafSourceBuf = (float *) CPLMalloc(sizeof(float)*nBlockXSize*nBlockYSize);
+    nCurBlockXOff = -1;
+    nCurBlockYOff = -1;
+}
+
+GDALColorReliefDataset::~GDALColorReliefDataset()
+{
+    CPLFree(pasColorAssociation);
+    CPLFree(pabyPrecomputed);
+    CPLFree(panSourceBuf);
+    CPLFree(pafSourceBuf);
+}
+
+CPLErr GDALColorReliefDataset::GetGeoTransform( double * padfGeoTransform )
+{
+    return GDALGetGeoTransform(hSrcDS, padfGeoTransform);
+}
+
+const char *GDALColorReliefDataset::GetProjectionRef()
+{
+    return GDALGetProjectionRef(hSrcDS);
+}
+
+GDALColorReliefRasterBand::GDALColorReliefRasterBand(
+                                    GDALColorReliefDataset * poDS, int nBand)
+{
+    this->poDS = poDS;
+    this->nBand = nBand;
+    eDataType = GDT_Byte;
+    GDALGetBlockSize( poDS->hSrcBand, &nBlockXSize, &nBlockYSize);
+}
+
+CPLErr GDALColorReliefRasterBand::IReadBlock( int nBlockXOff,
+                                              int nBlockYOff,
+                                              void *pImage )
+{
+    GDALColorReliefDataset * poGDS = (GDALColorReliefDataset *) poDS;
+    int nReqXSize, nReqYSize;
+
+    if ((nBlockXOff + 1) * nBlockXSize >= nRasterXSize)
+        nReqXSize = nRasterXSize - nBlockXOff * nBlockXSize;
+    else
+        nReqXSize = nBlockXSize;
+        
+    if ((nBlockYOff + 1) * nBlockYSize >= nRasterYSize)
+        nReqYSize = nRasterYSize - nBlockYOff * nBlockYSize;
+    else
+        nReqYSize = nBlockYSize;
+
+    if ( poGDS->nCurBlockXOff != nBlockXOff ||
+         poGDS->nCurBlockYOff != nBlockYOff )
+    {
+        poGDS->nCurBlockXOff = nBlockXOff;
+        poGDS->nCurBlockYOff = nBlockYOff;
+        
+        CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
+                            GF_Read,
+                            nBlockXOff * nBlockXSize,
+                            nBlockYOff * nBlockYSize,
+                            nReqXSize, nReqYSize,
+                            (poGDS->panSourceBuf) ?
+                                (void*) poGDS->panSourceBuf :
+                                (void* )poGDS->pafSourceBuf,
+                            nReqXSize, nReqYSize,
+                            (poGDS->panSourceBuf) ? GDT_Int32 : GDT_Float32,
+                            0, 0);
+        if (eErr != CE_None)
+        {
+            memset(pImage, 0, nBlockXSize * nBlockYSize);
+            return eErr;
+        }
+    }
+
+    int x, y, j = 0;
+    if (poGDS->panSourceBuf)
+    {
+        for( y = 0; y < nReqYSize; y++ )
+        {
+            for( x = 0; x < nReqXSize; x++ )
+            {
+                int nIndex = poGDS->panSourceBuf[j] + poGDS->nIndexOffset;
+                ((GByte*)pImage)[y * nBlockXSize + x] = poGDS->pabyPrecomputed[4*nIndex + nBand-1];
+                j++;
+            }
+        }
+    }
+    else
+    {
+        int anComponents[4];
+        for( y = 0; y < nReqYSize; y++ )
+        {
+            for( x = 0; x < nReqXSize; x++ )
+            {
+                GDALColorReliefGetRGBA  (poGDS->pasColorAssociation,
+                                        poGDS->nColorAssociation,
+                                        poGDS->pafSourceBuf[j],
+                                        poGDS->eColorSelectionMode,
+                                        &anComponents[0],
+                                        &anComponents[1],
+                                        &anComponents[2],
+                                        &anComponents[3]);
+                ((GByte*)pImage)[y * nBlockXSize + x] = (GByte) anComponents[nBand-1];
+                j++;
+            }
+        }
+    }
+    
+    return CE_None;
+}
+
+GDALColorInterp GDALColorReliefRasterBand::GetColorInterpretation()
+{
+    return (GDALColorInterp)(GCI_RedBand + nBand - 1);
+}
+
+
+CPLErr GDALColorRelief (GDALRasterBandH hSrcBand,
+                        GDALRasterBandH hDstBand1,
+                        GDALRasterBandH hDstBand2,
+                        GDALRasterBandH hDstBand3,
+                        GDALRasterBandH hDstBand4,
+                        const char* pszColorFilename,
+                        ColorSelectionMode eColorSelectionMode,
+                        GDALProgressFunc pfnProgress,
+                        void * pProgressData)
+{
+    CPLErr eErr;
+    
+    if (hSrcBand == NULL || hDstBand1 == NULL || hDstBand2 == NULL ||
+        hDstBand3 == NULL)
+        return CE_Failure;
+
+    int nColorAssociation = 0;
+    ColorAssociation* pasColorAssociation =
+            GDALColorReliefParseColorFile(hSrcBand, pszColorFilename,
+                                          &nColorAssociation);
+    if (pasColorAssociation == NULL)
+        return CE_Failure;
+
+    int nXSize = GDALGetRasterBandXSize(hSrcBand);
+    int nYSize = GDALGetRasterBandYSize(hSrcBand);
+
+    if (pfnProgress == NULL)
+        pfnProgress = GDALDummyProgress;
+        
+    int nR = 0, nG = 0, nB = 0, nA = 0;
+    
+/* -------------------------------------------------------------------- */
+/*      Precompute the map from values to RGBA quadruplets              */
+/*      for GDT_Byte, GDT_Int16 or GDT_UInt16                           */
+/* -------------------------------------------------------------------- */
+    int nIndexOffset = 0;
+    GByte* pabyPrecomputed =
+        GDALColorReliefPrecompute(hSrcBand,
+                                  pasColorAssociation,
+                                  nColorAssociation,
+                                  eColorSelectionMode,
+                                  &nIndexOffset);
+
+/* -------------------------------------------------------------------- */
+/*      Initialize progress counter.                                    */
+/* -------------------------------------------------------------------- */
+
+    float* pafSourceBuf = NULL;
+    int* panSourceBuf = NULL;
+    if (pabyPrecomputed)
+        panSourceBuf = (int *) CPLMalloc(sizeof(int)*nXSize);
+    else
+        pafSourceBuf = (float *) CPLMalloc(sizeof(float)*nXSize);
+    GByte* pabyDestBuf1  = (GByte*) CPLMalloc( 4 * nXSize );
+    GByte* pabyDestBuf2  =  pabyDestBuf1 + nXSize;
+    GByte* pabyDestBuf3  =  pabyDestBuf2 + nXSize;
+    GByte* pabyDestBuf4  =  pabyDestBuf3 + nXSize;
+    int i, j;
+
+    if( !pfnProgress( 0.0, NULL, pProgressData ) )
+    {
+        CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
+        eErr = CE_Failure;
+        goto end;
+    }
+
+    for ( i = 0; i < nYSize; i++)
+    {
+        /* Read source buffer */
+        eErr = GDALRasterIO(   hSrcBand,
+                        GF_Read,
+                        0, i,
+                        nXSize, 1,
+                        (panSourceBuf) ? (void*) panSourceBuf : (void* )pafSourceBuf,
+                        nXSize, 1,
+                        (panSourceBuf) ? GDT_Int32 : GDT_Float32,
+                        0, 0);
+        if (eErr != CE_None)
+            goto end;
+
+        if (panSourceBuf)
+        {
+            for ( j = 0; j < nXSize; j++)
+            {
+                int nIndex = panSourceBuf[j] + nIndexOffset;
+                pabyDestBuf1[j] = pabyPrecomputed[4 * nIndex];
+                pabyDestBuf2[j] = pabyPrecomputed[4 * nIndex + 1];
+                pabyDestBuf3[j] = pabyPrecomputed[4 * nIndex + 2];
+                pabyDestBuf4[j] = pabyPrecomputed[4 * nIndex + 3];
+            }
+        }
+        else
+        {
+            for ( j = 0; j < nXSize; j++)
+            {
+                GDALColorReliefGetRGBA  (pasColorAssociation,
+                                         nColorAssociation,
+                                         pafSourceBuf[j],
+                                         eColorSelectionMode,
+                                         &nR,
+                                         &nG,
+                                         &nB,
+                                         &nA);
+                pabyDestBuf1[j] = (GByte) nR;
+                pabyDestBuf2[j] = (GByte) nG;
+                pabyDestBuf3[j] = (GByte) nB;
+                pabyDestBuf4[j] = (GByte) nA;
+            }
+        }
+        
+        /* -----------------------------------------
+         * Write Line to Raster
+         */
+        eErr = GDALRasterIO(hDstBand1,
+                      GF_Write,
+                      0, i, nXSize,
+                      1, pabyDestBuf1, nXSize, 1, GDT_Byte, 0, 0);
+        if (eErr != CE_None)
+            goto end;
+
+        eErr = GDALRasterIO(hDstBand2,
+                      GF_Write,
+                      0, i, nXSize,
+                      1, pabyDestBuf2, nXSize, 1, GDT_Byte, 0, 0);
+        if (eErr != CE_None)
+            goto end;
+            
+        eErr = GDALRasterIO(hDstBand3,
+                      GF_Write,
+                      0, i, nXSize,
+                      1, pabyDestBuf3, nXSize, 1, GDT_Byte, 0, 0);
+        if (eErr != CE_None)
+            goto end;
+            
+        if (hDstBand4)
+        {
+            eErr = GDALRasterIO(hDstBand4,
+                        GF_Write,
+                        0, i, nXSize,
+                        1, pabyDestBuf4, nXSize, 1, GDT_Byte, 0, 0);
+            if (eErr != CE_None)
+                goto end;
+        }
+
+        if( !pfnProgress( 1.0 * (i+1) / nYSize, NULL, pProgressData ) )
+        {
+            CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
+            eErr = CE_Failure;
+            goto end;
+        }
+    }
+    pfnProgress( 1.0, NULL, pProgressData );
+    eErr = CE_None;
+
+end:
+    VSIFree(pabyPrecomputed);
+    CPLFree(pafSourceBuf);
+    CPLFree(panSourceBuf);
+    CPLFree(pabyDestBuf1);
+    CPLFree(pasColorAssociation);
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                     GDALGenerateVRTColorRelief()                     */
+/************************************************************************/
+
+CPLErr GDALGenerateVRTColorRelief(const char* pszDstFilename,
+                               GDALDatasetH hSrcDataset,
+                               GDALRasterBandH hSrcBand,
+                               const char* pszColorFilename,
+                               ColorSelectionMode eColorSelectionMode,
+                               int bAddAlpha)
+{
+
+    int nColorAssociation = 0;
+    ColorAssociation* pasColorAssociation =
+            GDALColorReliefParseColorFile(hSrcBand, pszColorFilename,
+                                          &nColorAssociation);
+    if (pasColorAssociation == NULL)
+        return CE_Failure;
+
+    int nXSize = GDALGetRasterBandXSize(hSrcBand);
+    int nYSize = GDALGetRasterBandYSize(hSrcBand);
+
+    VSILFILE* fp = VSIFOpenL(pszDstFilename, "wt");
+    if (fp == NULL)
+    {
+        CPLFree(pasColorAssociation);
+        return CE_Failure;
+    }
+
+    VSIFPrintfL(fp, "<VRTDataset rasterXSize=\"%d\" rasterYSize=\"%d\">\n", nXSize, nYSize);
+    const char* pszProjectionRef = GDALGetProjectionRef(hSrcDataset);
+    if (pszProjectionRef && pszProjectionRef[0] != '\0')
+    {
+        char* pszEscapedString = CPLEscapeString(pszProjectionRef, -1, CPLES_XML);
+        VSIFPrintfL(fp, "  <SRS>%s</SRS>\n", pszEscapedString);
+        VSIFree(pszEscapedString);
+    }
+    double adfGT[6];
+    if (GDALGetGeoTransform(hSrcDataset, adfGT) == CE_None)
+    {
+        VSIFPrintfL(fp, "  <GeoTransform> %.16g, %.16g, %.16g, "
+                        "%.16g, %.16g, %.16g</GeoTransform>\n",
+                        adfGT[0], adfGT[1], adfGT[2], adfGT[3], adfGT[4], adfGT[5]);
+    }
+    int nBands = 3 + (bAddAlpha ? 1 : 0);
+    int iBand;
+
+    int nBlockXSize, nBlockYSize;
+    GDALGetBlockSize(hSrcBand, &nBlockXSize, &nBlockYSize);
+    
+    int bRelativeToVRT;
+    CPLString osPath = CPLGetPath(pszDstFilename);
+    char* pszSourceFilename = CPLStrdup(
+        CPLExtractRelativePath( osPath.c_str(), GDALGetDescription(hSrcDataset), 
+                                &bRelativeToVRT ));
+
+    for(iBand = 0; iBand < nBands; iBand++)
+    {
+        VSIFPrintfL(fp, "  <VRTRasterBand dataType=\"Byte\" band=\"%d\">\n", iBand + 1);
+        VSIFPrintfL(fp, "    <ColorInterp>%s</ColorInterp>\n",
+                    GDALGetColorInterpretationName((GDALColorInterp)(GCI_RedBand + iBand)));
+        VSIFPrintfL(fp, "    <ComplexSource>\n");
+        VSIFPrintfL(fp, "      <SourceFilename relativeToVRT=\"%d\">%s</SourceFilename>\n",
+                        bRelativeToVRT, pszSourceFilename);
+        VSIFPrintfL(fp, "      <SourceBand>%d</SourceBand>\n", GDALGetBandNumber(hSrcBand));
+        VSIFPrintfL(fp, "      <SourceProperties RasterXSize=\"%d\" "
+                        "RasterYSize=\"%d\" DataType=\"%s\" "
+                        "BlockXSize=\"%d\" BlockYSize=\"%d\"/>\n",
+                        nXSize, nYSize,
+                        GDALGetDataTypeName(GDALGetRasterDataType(hSrcBand)),
+                        nBlockXSize, nBlockYSize);
+        VSIFPrintfL(fp, "      <SrcRect xOff=\"0\" yOff=\"0\" xSize=\"%d\" ySize=\"%d\"/>\n",
+                        nXSize, nYSize);
+        VSIFPrintfL(fp, "      <DstRect xOff=\"0\" yOff=\"0\" xSize=\"%d\" ySize=\"%d\"/>\n",
+                        nXSize, nYSize);
+
+        VSIFPrintfL(fp, "      <LUT>");
+        int iColor;
+#define EPSILON 1e-8
+        for(iColor=0;iColor<nColorAssociation;iColor++)
+        {
+            if (eColorSelectionMode == COLOR_SELECTION_NEAREST_ENTRY)
+            {
+                if (iColor > 1)
+                    VSIFPrintfL(fp, ",");
+            }
+            else if (iColor > 0)
+                VSIFPrintfL(fp, ",");
+
+            double dfVal = pasColorAssociation[iColor].dfVal;
+
+            if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY)
+            {
+                VSIFPrintfL(fp, "%.12g:0,", dfVal - EPSILON);
+            }
+            else if (iColor > 0 &&
+                     eColorSelectionMode == COLOR_SELECTION_NEAREST_ENTRY)
+            {
+                double dfMidVal = (dfVal + pasColorAssociation[iColor-1].dfVal) / 2;
+                VSIFPrintfL(fp, "%.12g:%d", dfMidVal - EPSILON,
+                        (iBand == 0) ? pasColorAssociation[iColor-1].nR :
+                        (iBand == 1) ? pasColorAssociation[iColor-1].nG :
+                        (iBand == 2) ? pasColorAssociation[iColor-1].nB :
+                                       pasColorAssociation[iColor-1].nA);
+                VSIFPrintfL(fp, ",%.12g:%d", dfMidVal ,
+                        (iBand == 0) ? pasColorAssociation[iColor].nR :
+                        (iBand == 1) ? pasColorAssociation[iColor].nG :
+                        (iBand == 2) ? pasColorAssociation[iColor].nB :
+                                       pasColorAssociation[iColor].nA);
+
+            }
+
+            if (eColorSelectionMode != COLOR_SELECTION_NEAREST_ENTRY)
+            {
+                if (dfVal != (double)(int)dfVal)
+                    VSIFPrintfL(fp, "%.12g", dfVal);
+                else
+                    VSIFPrintfL(fp, "%d", (int)dfVal);
+                VSIFPrintfL(fp, ":%d",
+                            (iBand == 0) ? pasColorAssociation[iColor].nR :
+                            (iBand == 1) ? pasColorAssociation[iColor].nG :
+                            (iBand == 2) ? pasColorAssociation[iColor].nB :
+                                           pasColorAssociation[iColor].nA);
+            }
+
+            if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY)
+            {
+                VSIFPrintfL(fp, ",%.12g:0", dfVal + EPSILON);
+            }
+
+        }
+        VSIFPrintfL(fp, "</LUT>\n");
+
+        VSIFPrintfL(fp, "    </ComplexSource>\n");
+        VSIFPrintfL(fp, "  </VRTRasterBand>\n");
+    }
+
+    CPLFree(pszSourceFilename);
+
+    VSIFPrintfL(fp, "</VRTDataset>\n");
+
+    VSIFCloseL(fp);
+
+    CPLFree(pasColorAssociation);
+
+    return CE_None;
+}
+
+
+/************************************************************************/
+/*                         GDALTRIAlg()                                 */
+/************************************************************************/
+
+float GDALTRIAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    // Terrain Ruggedness is average difference in height
+    return (fabs(afWin[0]-afWin[4]) +
+            fabs(afWin[1]-afWin[4]) +
+            fabs(afWin[2]-afWin[4]) +
+            fabs(afWin[3]-afWin[4]) +
+            fabs(afWin[5]-afWin[4]) +
+            fabs(afWin[6]-afWin[4]) +
+            fabs(afWin[7]-afWin[4]) +
+            fabs(afWin[8]-afWin[4]))/8;
+}
+
+
+/************************************************************************/
+/*                         GDALTPIAlg()                                 */
+/************************************************************************/
+
+float GDALTPIAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    // Terrain Position is the difference between
+    // The central cell and the mean of the surrounding cells
+    return afWin[4] - 
+            ((afWin[0]+
+              afWin[1]+
+              afWin[2]+
+              afWin[3]+
+              afWin[5]+
+              afWin[6]+
+              afWin[7]+
+              afWin[8])/8);
+}
+
+/************************************************************************/
+/*                     GDALRoughnessAlg()                               */
+/************************************************************************/
+
+float GDALRoughnessAlg (float* afWin, float fDstNoDataValue, void* pData)
+{
+    // Roughness is the largest difference
+    //  between any two cells
+
+    float pafRoughnessMin = afWin[0];
+    float pafRoughnessMax = afWin[0];
+
+    for ( int k = 1; k < 9; k++)
+    {
+        if (afWin[k] > pafRoughnessMax)
+        {
+            pafRoughnessMax=afWin[k];
+        }
+        if (afWin[k] < pafRoughnessMin)
+        {
+            pafRoughnessMin=afWin[k];
+        }
+    }
+    return pafRoughnessMax - pafRoughnessMin;
+}
+
+/************************************************************************/
+/* ==================================================================== */
+/*                       GDALGeneric3x3Dataset                        */
+/* ==================================================================== */
+/************************************************************************/
+
+class GDALGeneric3x3RasterBand;
+
+class GDALGeneric3x3Dataset : public GDALDataset
+{
+    friend class GDALGeneric3x3RasterBand;
+
+    GDALGeneric3x3ProcessingAlg pfnAlg;
+    void*              pAlgData;
+    GDALDatasetH       hSrcDS;
+    GDALRasterBandH    hSrcBand;
+    float*             apafSourceBuf[3];
+    int                bDstHasNoData;
+    double             dfDstNoDataValue;
+    int                nCurLine;
+    int                bComputeAtEdges;
+
+  public:
+                        GDALGeneric3x3Dataset(GDALDatasetH hSrcDS,
+                                              GDALRasterBandH hSrcBand,
+                                              GDALDataType eDstDataType,
+                                              int bDstHasNoData,
+                                              double dfDstNoDataValue,
+                                              GDALGeneric3x3ProcessingAlg pfnAlg,
+                                              void* pAlgData,
+                                              int bComputeAtEdges);
+                       ~GDALGeneric3x3Dataset();
+
+    CPLErr      GetGeoTransform( double * padfGeoTransform );
+    const char *GetProjectionRef();
+};
+
+/************************************************************************/
+/* ==================================================================== */
+/*                    GDALGeneric3x3RasterBand                       */
+/* ==================================================================== */
+/************************************************************************/
+
+class GDALGeneric3x3RasterBand : public GDALRasterBand
+{
+    friend class GDALGeneric3x3Dataset;
+    int bSrcHasNoData;
+    float fSrcNoDataValue;
+    
+    void                    InitWidthNoData(void* pImage);
+    
+  public:
+                 GDALGeneric3x3RasterBand( GDALGeneric3x3Dataset *poDS,
+                                           GDALDataType eDstDataType );
+    
+    virtual CPLErr          IReadBlock( int, int, void * );
+    virtual double          GetNoDataValue( int* pbHasNoData );
+};
+
+GDALGeneric3x3Dataset::GDALGeneric3x3Dataset(
+                                     GDALDatasetH hSrcDS,
+                                     GDALRasterBandH hSrcBand,
+                                     GDALDataType eDstDataType,
+                                     int bDstHasNoData,
+                                     double dfDstNoDataValue,
+                                     GDALGeneric3x3ProcessingAlg pfnAlg,
+                                     void* pAlgData,
+                                     int bComputeAtEdges)
+{
+    this->hSrcDS = hSrcDS;
+    this->hSrcBand = hSrcBand;
+    this->pfnAlg = pfnAlg;
+    this->pAlgData = pAlgData;
+    this->bDstHasNoData = bDstHasNoData;
+    this->dfDstNoDataValue = dfDstNoDataValue;
+    this->bComputeAtEdges = bComputeAtEdges;
+    
+    CPLAssert(eDstDataType == GDT_Byte || eDstDataType == GDT_Float32);
+
+    nRasterXSize = GDALGetRasterXSize(hSrcDS);
+    nRasterYSize = GDALGetRasterYSize(hSrcDS);
+    
+    SetBand(1, new GDALGeneric3x3RasterBand(this, eDstDataType));
+    
+    apafSourceBuf[0] = (float *) CPLMalloc(sizeof(float)*nRasterXSize);
+    apafSourceBuf[1] = (float *) CPLMalloc(sizeof(float)*nRasterXSize);
+    apafSourceBuf[2] = (float *) CPLMalloc(sizeof(float)*nRasterXSize);
+
+    nCurLine = -1;
+}
+
+GDALGeneric3x3Dataset::~GDALGeneric3x3Dataset()
+{
+    CPLFree(apafSourceBuf[0]);
+    CPLFree(apafSourceBuf[1]);
+    CPLFree(apafSourceBuf[2]);
+}
+
+CPLErr GDALGeneric3x3Dataset::GetGeoTransform( double * padfGeoTransform )
+{
+    return GDALGetGeoTransform(hSrcDS, padfGeoTransform);
+}
+
+const char *GDALGeneric3x3Dataset::GetProjectionRef()
+{
+    return GDALGetProjectionRef(hSrcDS);
+}
+
+GDALGeneric3x3RasterBand::GDALGeneric3x3RasterBand(GDALGeneric3x3Dataset *poDS,
+                                                   GDALDataType eDstDataType)
+{
+    this->poDS = poDS;
+    this->nBand = 1;
+    eDataType = eDstDataType;
+    nBlockXSize = poDS->GetRasterXSize();
+    nBlockYSize = 1;
+
+    bSrcHasNoData = FALSE;
+    fSrcNoDataValue = (float)GDALGetRasterNoDataValue(poDS->hSrcBand,
+                                                      &bSrcHasNoData);
+}
+
+void   GDALGeneric3x3RasterBand::InitWidthNoData(void* pImage)
+{
+    int j;
+    GDALGeneric3x3Dataset * poGDS = (GDALGeneric3x3Dataset *) poDS;
+    if (eDataType == GDT_Byte)
+    {
+        for(j=0;j<nBlockXSize;j++)
+            ((GByte*)pImage)[j] = (GByte) poGDS->dfDstNoDataValue;
+    }
+    else
+    {
+        for(j=0;j<nBlockXSize;j++)
+            ((float*)pImage)[j] = (float) poGDS->dfDstNoDataValue;
+    }
+}
+
+CPLErr GDALGeneric3x3RasterBand::IReadBlock( int nBlockXOff,
+                                             int nBlockYOff,
+                                             void *pImage )
+{
+    int i, j;
+    float fVal;
+    GDALGeneric3x3Dataset * poGDS = (GDALGeneric3x3Dataset *) poDS;
+
+    if (poGDS->bComputeAtEdges && nRasterXSize >= 2 && nRasterYSize >= 2)
+    {
+        if (nBlockYOff == 0)
+        {
+            for(i=0;i<2;i++)
+            {
+                CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
+                                    GF_Read,
+                                    0, i, nBlockXSize, 1,
+                                    poGDS->apafSourceBuf[i+1],
+                                    nBlockXSize, 1,
+                                    GDT_Float32,
+                                    0, 0);
+                if (eErr != CE_None)
+                {
+                    InitWidthNoData(pImage);
+                    return eErr;
+                }
+            }
+            poGDS->nCurLine = 0;
+
+            for (j = 0; j < nRasterXSize; j++)
+            {
+                float afWin[9];
+                int jmin = (j == 0) ? j : j - 1;
+                int jmax = (j == nRasterXSize - 1) ? j : j + 1;
+
+                afWin[0] = INTERPOL(poGDS->apafSourceBuf[1][jmin], poGDS->apafSourceBuf[2][jmin]);
+                afWin[1] = INTERPOL(poGDS->apafSourceBuf[1][j],    poGDS->apafSourceBuf[2][j]);
+                afWin[2] = INTERPOL(poGDS->apafSourceBuf[1][jmax], poGDS->apafSourceBuf[2][jmax]);
+                afWin[3] = poGDS->apafSourceBuf[1][jmin];
+                afWin[4] = poGDS->apafSourceBuf[1][j];
+                afWin[5] = poGDS->apafSourceBuf[1][jmax];
+                afWin[6] = poGDS->apafSourceBuf[2][jmin];
+                afWin[7] = poGDS->apafSourceBuf[2][j];
+                afWin[8] = poGDS->apafSourceBuf[2][jmax];
+
+                fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                    afWin, (float) poGDS->dfDstNoDataValue,
+                                    poGDS->pfnAlg,
+                                    poGDS->pAlgData,
+                                    poGDS->bComputeAtEdges);
+
+                if (eDataType == GDT_Byte)
+                    ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
+                else
+                    ((float*)pImage)[j] = fVal;
+            }
+
+            return CE_None;
+        }
+        else if (nBlockYOff == nRasterYSize - 1)
+        {
+            if (poGDS->nCurLine != nRasterYSize - 2)
+            {
+                for(i=0;i<2;i++)
+                {
+                    CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
+                                        GF_Read,
+                                        0, nRasterYSize - 2 + i, nBlockXSize, 1,
+                                        poGDS->apafSourceBuf[i+1],
+                                        nBlockXSize, 1,
+                                        GDT_Float32,
+                                        0, 0);
+                    if (eErr != CE_None)
+                    {
+                        InitWidthNoData(pImage);
+                        return eErr;
+                    }
+                }
+            }
+
+            for (j = 0; j < nRasterXSize; j++)
+            {
+                float afWin[9];
+                int jmin = (j == 0) ? j : j - 1;
+                int jmax = (j == nRasterXSize - 1) ? j : j + 1;
+
+                afWin[0] = poGDS->apafSourceBuf[1][jmin];
+                afWin[1] = poGDS->apafSourceBuf[1][j];
+                afWin[2] = poGDS->apafSourceBuf[1][jmax];
+                afWin[3] = poGDS->apafSourceBuf[2][jmin];
+                afWin[4] = poGDS->apafSourceBuf[2][j];
+                afWin[5] = poGDS->apafSourceBuf[2][jmax];
+                afWin[6] = INTERPOL(poGDS->apafSourceBuf[2][jmin], poGDS->apafSourceBuf[1][jmin]);
+                afWin[7] = INTERPOL(poGDS->apafSourceBuf[2][j],    poGDS->apafSourceBuf[1][j]);
+                afWin[8] = INTERPOL(poGDS->apafSourceBuf[2][jmax], poGDS->apafSourceBuf[1][jmax]);
+
+                fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                    afWin, (float) poGDS->dfDstNoDataValue,
+                                    poGDS->pfnAlg,
+                                    poGDS->pAlgData,
+                                    poGDS->bComputeAtEdges);
+
+                if (eDataType == GDT_Byte)
+                    ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
+                else
+                    ((float*)pImage)[j] = fVal;
+            }
+
+            return CE_None;
+        }
+    }
+    else if ( nBlockYOff == 0 || nBlockYOff == nRasterYSize - 1)
+    {
+        InitWidthNoData(pImage);
+        return CE_None;
+    }
+
+    if ( poGDS->nCurLine != nBlockYOff )
+    {
+        if (poGDS->nCurLine + 1 == nBlockYOff)
+        {
+            float* pafTmp =  poGDS->apafSourceBuf[0];
+            poGDS->apafSourceBuf[0] = poGDS->apafSourceBuf[1];
+            poGDS->apafSourceBuf[1] = poGDS->apafSourceBuf[2];
+            poGDS->apafSourceBuf[2] = pafTmp;
+
+            CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
+                                    GF_Read,
+                                    0, nBlockYOff + 1, nBlockXSize, 1,
+                                    poGDS->apafSourceBuf[2],
+                                    nBlockXSize, 1,
+                                    GDT_Float32,
+                                    0, 0);
+
+            if (eErr != CE_None)
+            {
+                InitWidthNoData(pImage);
+                return eErr;
+            }
+        }
+        else
+        {
+            for(i=0;i<3;i++)
+            {
+                CPLErr eErr = GDALRasterIO( poGDS->hSrcBand,
+                                    GF_Read,
+                                    0, nBlockYOff + i - 1, nBlockXSize, 1,
+                                    poGDS->apafSourceBuf[i],
+                                    nBlockXSize, 1,
+                                    GDT_Float32,
+                                    0, 0);
+                if (eErr != CE_None)
+                {
+                    InitWidthNoData(pImage);
+                    return eErr;
+                }
+            }
+        }
+
+        poGDS->nCurLine = nBlockYOff;
+    }
+
+    if (poGDS->bComputeAtEdges && nRasterXSize >= 2)
+    {
+        float afWin[9];
+
+        j = 0;
+        afWin[0] = INTERPOL(poGDS->apafSourceBuf[0][j], poGDS->apafSourceBuf[0][j+1]);
+        afWin[1] = poGDS->apafSourceBuf[0][j];
+        afWin[2] = poGDS->apafSourceBuf[0][j+1];
+        afWin[3] = INTERPOL(poGDS->apafSourceBuf[1][j], poGDS->apafSourceBuf[1][j+1]);
+        afWin[4] = poGDS->apafSourceBuf[1][j];
+        afWin[5] = poGDS->apafSourceBuf[1][j+1];
+        afWin[6] = INTERPOL(poGDS->apafSourceBuf[2][j], poGDS->apafSourceBuf[2][j+1]);
+        afWin[7] = poGDS->apafSourceBuf[2][j];
+        afWin[8] = poGDS->apafSourceBuf[2][j+1];
+
+        fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                    afWin, (float) poGDS->dfDstNoDataValue,
+                                    poGDS->pfnAlg,
+                                    poGDS->pAlgData,
+                                    poGDS->bComputeAtEdges);
+
+        if (eDataType == GDT_Byte)
+            ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
+        else
+            ((float*)pImage)[j] = fVal;
+
+        j = nRasterXSize - 1;
+
+        afWin[0] = poGDS->apafSourceBuf[0][j-1];
+        afWin[1] = poGDS->apafSourceBuf[0][j];
+        afWin[2] = INTERPOL(poGDS->apafSourceBuf[0][j], poGDS->apafSourceBuf[0][j-1]);
+        afWin[3] = poGDS->apafSourceBuf[1][j-1];
+        afWin[4] = poGDS->apafSourceBuf[1][j];
+        afWin[5] = INTERPOL(poGDS->apafSourceBuf[1][j], poGDS->apafSourceBuf[1][j-1]);
+        afWin[6] = poGDS->apafSourceBuf[2][j-1];
+        afWin[7] = poGDS->apafSourceBuf[2][j];
+        afWin[8] = INTERPOL(poGDS->apafSourceBuf[2][j], poGDS->apafSourceBuf[2][j-1]);
+
+        fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                    afWin, (float) poGDS->dfDstNoDataValue,
+                                    poGDS->pfnAlg,
+                                    poGDS->pAlgData,
+                                    poGDS->bComputeAtEdges);
+
+        if (eDataType == GDT_Byte)
+            ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
+        else
+            ((float*)pImage)[j] = fVal;
+    }
+    else
+    {
+        if (eDataType == GDT_Byte)
+        {
+            ((GByte*)pImage)[0] = (GByte) poGDS->dfDstNoDataValue;
+            if (nBlockXSize > 1)
+                ((GByte*)pImage)[nBlockXSize - 1] = (GByte) poGDS->dfDstNoDataValue;
+        }
+        else
+        {
+            ((float*)pImage)[0] = (float) poGDS->dfDstNoDataValue;
+            if (nBlockXSize > 1)
+                ((float*)pImage)[nBlockXSize - 1] = (float) poGDS->dfDstNoDataValue;
+        }
+    }
+
+
+    for(j=1;j<nBlockXSize - 1;j++)
+    {
+        float afWin[9];
+        afWin[0] = poGDS->apafSourceBuf[0][j-1];
+        afWin[1] = poGDS->apafSourceBuf[0][j];
+        afWin[2] = poGDS->apafSourceBuf[0][j+1];
+        afWin[3] = poGDS->apafSourceBuf[1][j-1];
+        afWin[4] = poGDS->apafSourceBuf[1][j];
+        afWin[5] = poGDS->apafSourceBuf[1][j+1];
+        afWin[6] = poGDS->apafSourceBuf[2][j-1];
+        afWin[7] = poGDS->apafSourceBuf[2][j];
+        afWin[8] = poGDS->apafSourceBuf[2][j+1];
+
+        fVal = ComputeVal(bSrcHasNoData, fSrcNoDataValue,
+                                afWin, (float) poGDS->dfDstNoDataValue,
+                                poGDS->pfnAlg,
+                                poGDS->pAlgData,
+                                poGDS->bComputeAtEdges);
+
+        if (eDataType == GDT_Byte)
+            ((GByte*)pImage)[j] = (GByte) (fVal + 0.5);
+        else
+            ((float*)pImage)[j] = fVal;
+
+    }
+
+    return CE_None;
+}
+
+double GDALGeneric3x3RasterBand::GetNoDataValue( int* pbHasNoData )
+{
+    GDALGeneric3x3Dataset * poGDS = (GDALGeneric3x3Dataset *) poDS;
+    if (pbHasNoData)
+        *pbHasNoData = poGDS->bDstHasNoData;
+    return poGDS->dfDstNoDataValue;
+}
+
+/************************************************************************/
+/*                                main()                                */
+/************************************************************************/
+
+typedef enum
+{
+    HILL_SHADE,
+    SLOPE,
+    ASPECT,
+    COLOR_RELIEF,
+    TRI,
+    TPI,
+    ROUGHNESS
+} Algorithm;
+
+#define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
+    do { if (i + nExtraArg >= argc) \
+        Usage(CPLSPrintf("%s option requires %d argument(s)", argv[i], nExtraArg)); } while(0)
+
+#ifndef ZOO_SERVICE
+int main( int argc, char ** argv )
+#else
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+  int Gdal_Dem(maps*& conf,maps*& inputs,maps*& outputs)
+#endif
+{
+    Algorithm eUtilityMode = HILL_SHADE;
+    double z = 1.0;
+    double scale = 1.0;
+    double az = 315.0;
+    double alt = 45.0;
+    // 0 = 'percent' or 1 = 'degrees'
+    int slopeFormat = 1; 
+    int bAddAlpha = FALSE;
+    int bZeroForFlat = FALSE;
+    int bAngleAsAzimuth = TRUE;
+    ColorSelectionMode eColorSelectionMode = COLOR_SELECTION_INTERPOLATE;
+    
+    int nBand = 1;
+    double  adfGeoTransform[6];
+
+    const char *pszSrcFilename = NULL;
+    const char *pszDstFilename = NULL;
+    const char *pszColorFilename = NULL;
+    const char *pszFormat = "GTiff";
+    int bFormatExplicitelySet = FALSE;
+    char **papszCreateOptions = NULL;
+    
+    GDALDatasetH hSrcDataset = NULL;
+    GDALDatasetH hDstDataset = NULL;
+    GDALRasterBandH hSrcBand = NULL;
+    GDALRasterBandH hDstBand = NULL;
+    GDALDriverH hDriver = NULL;
+
+    GDALProgressFunc pfnProgress = GDALTermProgress;
+    
+    int nXSize = 0;
+    int nYSize = 0;
+    
+    int bComputeAtEdges = FALSE;
+    int bZevenbergenThorne = FALSE;
+    int bCombined = FALSE;
+    int bQuiet = FALSE;
+    
+#ifndef ZOO_SERVICE
+    /* Check strict compilation and runtime library version as we use C++ API */
+    if (! GDAL_CHECK_VERSION(argv[0]))
+        exit(1);
+
+    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
+    if( argc < 2 )
+    {
+        Usage("Not enough arguments.");
+    }
+
+    if( EQUAL(argv[1], "--utility_version") || EQUAL(argv[1], "--utility-version") )
+    {
+        printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
+                argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
+        return 0;
+    }
+    else if( EQUAL(argv[1],"--help") )
+        Usage();
+    else if ( EQUAL(argv[1], "shade") || EQUAL(argv[1], "hillshade") )
+    {
+        eUtilityMode = HILL_SHADE;
+    }
+    else if ( EQUAL(argv[1], "slope") )
+    {
+        eUtilityMode = SLOPE;
+    }
+    else if ( EQUAL(argv[1], "aspect") )
+    {
+        eUtilityMode = ASPECT;
+    }
+    else if ( EQUAL(argv[1], "color-relief") )
+    {
+        eUtilityMode = COLOR_RELIEF;
+    }
+    else if ( EQUAL(argv[1], "TRI") )
+    {
+        eUtilityMode = TRI;
+    }
+    else if ( EQUAL(argv[1], "TPI") )
+    {
+        eUtilityMode = TPI;
+    }
+    else if ( EQUAL(argv[1], "roughness") )
+    {
+        eUtilityMode = ROUGHNESS;
+    }
+    else
+    {
+        Usage("Missing valid sub-utility mention.");
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Parse arguments.                                                */
+/* -------------------------------------------------------------------- */
+    for(int i = 2; i < argc; i++ )
+    {
+        if( eUtilityMode == HILL_SHADE &&
+            (EQUAL(argv[i], "--z") || EQUAL(argv[i], "-z")))
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            z = atof(argv[++i]);
+        }
+        else if ( eUtilityMode == SLOPE && EQUAL(argv[i], "-p"))
+        {
+            slopeFormat = 0;
+        }
+        else if ( (eUtilityMode == HILL_SHADE || eUtilityMode == SLOPE ||
+                   eUtilityMode == ASPECT) && EQUAL(argv[i], "-alg") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            i ++;
+            if (EQUAL(argv[i], "ZevenbergenThorne"))
+                bZevenbergenThorne = TRUE;
+            else if (!EQUAL(argv[i], "Horn"))
+            {
+                Usage(CPLSPrintf("Wrong value for alg : %s.", argv[i]));
+            }
+        }
+        else if ( eUtilityMode == ASPECT && EQUAL(argv[i], "-trigonometric"))
+        {
+            bAngleAsAzimuth = FALSE;
+        }
+        else if ( eUtilityMode == ASPECT && EQUAL(argv[i], "-zero_for_flat"))
+        {
+            bZeroForFlat = TRUE;
+        }
+        else if ( eUtilityMode == COLOR_RELIEF && EQUAL(argv[i], "-exact_color_entry"))
+        {
+            eColorSelectionMode = COLOR_SELECTION_EXACT_ENTRY;
+        }
+        else if ( eUtilityMode == COLOR_RELIEF && EQUAL(argv[i], "-nearest_color_entry"))
+        {
+            eColorSelectionMode = COLOR_SELECTION_NEAREST_ENTRY;
+        }
+        else if( 
+            (EQUAL(argv[i], "--s") || 
+             EQUAL(argv[i], "-s") ||
+             EQUAL(argv[i], "--scale") ||
+             EQUAL(argv[i], "-scale"))
+          )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            scale = atof(argv[++i]);
+        }
+        else if( eUtilityMode == HILL_SHADE &&
+            (EQUAL(argv[i], "--az") || 
+             EQUAL(argv[i], "-az") ||
+             EQUAL(argv[i], "--azimuth") ||
+             EQUAL(argv[i], "-azimuth"))
+          )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            az = atof(argv[++i]);
+        }
+        else if( eUtilityMode == HILL_SHADE &&
+            (EQUAL(argv[i], "--alt") || 
+             EQUAL(argv[i], "-alt") ||
+             EQUAL(argv[i], "--alt") ||
+             EQUAL(argv[i], "-alt"))
+          )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            alt = atof(argv[++i]);
+        }
+        else if( eUtilityMode == HILL_SHADE &&
+            (EQUAL(argv[i], "-combined") || 
+             EQUAL(argv[i], "--combined"))
+          )
+        {
+            bCombined = TRUE;
+        }
+        else if( eUtilityMode == COLOR_RELIEF &&
+                 EQUAL(argv[i], "-alpha"))
+        {
+            bAddAlpha = TRUE;
+        }
+        else if( eUtilityMode != COLOR_RELIEF &&
+                 EQUAL(argv[i], "-compute_edges"))
+        {
+            bComputeAtEdges = TRUE;
+        }
+        else if( i + 1 < argc &&
+            (EQUAL(argv[i], "--b") || 
+             EQUAL(argv[i], "-b"))
+          )
+        {
+            nBand = atoi(argv[++i]);
+        }
+        else if ( EQUAL(argv[i], "-q") || EQUAL(argv[i], "-quiet") )
+        {
+            pfnProgress = GDALDummyProgress;
+            bQuiet = TRUE;
+        }
+        else if( EQUAL(argv[i],"-co") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszCreateOptions = CSLAddString( papszCreateOptions, argv[++i] );
+        }
+        else if( EQUAL(argv[i],"-of") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            pszFormat = argv[++i];
+            bFormatExplicitelySet = TRUE;
+        }
+        else if( argv[i][0] == '-' )
+        {
+            Usage(CPLSPrintf("Unkown option name '%s'", argv[i]));
+        }
+        else if( pszSrcFilename == NULL )
+        {
+            pszSrcFilename = argv[i];
+        }
+        else if( eUtilityMode == COLOR_RELIEF && pszColorFilename == NULL )
+        {
+            pszColorFilename = argv[i];
+        }
+        else if( pszDstFilename == NULL )
+        {
+            pszDstFilename = argv[i];
+        }
+        else
+            Usage("Too many command options.");
+    }
+
+    if( pszSrcFilename == NULL )
+    {
+        Usage("Missing source.");
+    }
+    if ( eUtilityMode == COLOR_RELIEF && pszColorFilename == NULL )
+    {
+        Usage("Missing color file.");
+    }
+    if( pszDstFilename == NULL )
+    {
+        Usage("Missing destination.");
+    }
+#else
+    map* tmpMap=NULL;
+
+    pfnProgress = GDALDummyProgress;
+    bQuiet = TRUE;
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"InputDSN","value");
+    if(tmpMap!=NULL){
+      pszSrcFilename=(char*)CPLMalloc(sizeof(char)*(strlen(tmpMap->value)+1));
+      sprintf((char*)pszSrcFilename,"%s",tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"OutputDSN","value");
+    if(tmpMap!=NULL){
+      pszDstFilename=(char*)CPLMalloc(sizeof(char)*(strlen(tmpMap->value)+1));
+      sprintf((char*)pszDstFilename,"%s",tmpMap->value);
+      setMapInMaps(outputs,"Result","value",tmpMap->value);
+    }
+    
+    tmpMap=getMapFromMaps(inputs,"co","value");
+    if(tmpMap!=NULL){
+      papszCreateOptions = CSLAddString( papszCreateOptions, tmpMap->value );  
+      map* tmpMap1;
+      maps* tmpMaps=getMaps(inputs,"co");
+      if((tmpMap1=getMapFromMaps(inputs,"co","length"))!=NULL){
+        int i=1;
+        int length=atoi(tmpMap1->value);
+        for(;i<length;i++){
+          tmpMap=getMapArray(tmpMaps->content,"value",i);
+          papszCreateOptions = CSLAddString( papszCreateOptions, tmpMap->value );
+        }
+      } 
+    }    
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"utility","value");
+    if(tmpMap!=NULL){
+      if ( EQUAL(tmpMap->value, "shade") || EQUAL(tmpMap->value, "hillshade") )
+	{
+	  eUtilityMode = HILL_SHADE;
+	  map* tmpMap1=getMapFromMaps(inputs,"z","value");
+	  if(tmpMap1==NULL)
+	    return Usage(conf,"Unable to parse your z value");
+	  z = atof(tmpMap1->value);
+
+	  tmpMap1=getMapFromMaps(inputs,"az","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"NULL")!=0 )
+	    az = atof(tmpMap1->value);
+
+	  tmpMap1=getMapFromMaps(inputs,"alt","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"NULL")!=0 )
+	    alt = atof(tmpMap1->value);
+
+	  tmpMap1=getMapFromMaps(inputs,"c","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"true")==0 )	  
+	    bCombined = TRUE;
+	}
+      else if ( EQUAL(tmpMap->value, "slope") )
+	{
+	  eUtilityMode = SLOPE;
+	  map* tmpMap1=getMapFromMaps(inputs,"p","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"true")==0)
+	    slopeFormat = 0;
+	}
+      else if ( EQUAL(tmpMap->value, "aspect") )
+	{
+	  eUtilityMode = ASPECT;
+	  map* tmpMap1=getMapFromMaps(inputs,"ece","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"true")==0)
+            eColorSelectionMode = COLOR_SELECTION_EXACT_ENTRY;
+	  tmpMap1=getMapFromMaps(inputs,"nce","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"true")==0)
+            eColorSelectionMode = COLOR_SELECTION_NEAREST_ENTRY;
+	}
+      else if ( EQUAL(tmpMap->value, "color-relief") )
+	{
+	  eUtilityMode = COLOR_RELIEF;
+	  map* tmpMap1=getMapFromMaps(inputs,"cfn","value");
+	  if(tmpMap!=NULL){
+	    pszColorFilename=strdup(tmpMap1->value);
+	  } 
+	  tmpMap1=getMapFromMaps(inputs,"a","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"true")==0)	  
+	    bAddAlpha = TRUE;
+	  tmpMap1=getMapFromMaps(inputs,"ce","value");
+	  if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"true")==0)	  
+	    bComputeAtEdges = TRUE;
+	}
+      else if ( EQUAL(tmpMap->value, "TRI") )
+	{
+	  eUtilityMode = TRI;
+	}
+      else if ( EQUAL(tmpMap->value, "TPI") )
+	{
+	  eUtilityMode = TPI;
+	}
+      else if ( EQUAL(tmpMap->value, "roughness") )
+	{
+	  eUtilityMode = ROUGHNESS;
+	}
+      else
+	{
+	  return Usage(conf,"Missing valid utility mention.");
+	}
+    }
+    map* tmpMap1=getMapFromMaps(inputs,"s","value");
+    if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"NULL")!=0 )
+      scale = atof(tmpMap1->value);
+    tmpMap1=getMapFromMaps(inputs,"b","value");
+    if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"NULL")!=0 )
+      nBand = atoi(tmpMap1->value);
+
+    if( pszSrcFilename == NULL )
+    {
+      return Usage(conf,"Missing source.");
+    }
+    if ( eUtilityMode == COLOR_RELIEF && pszColorFilename == NULL )
+    {
+      return Usage(conf,"Missing color file.");
+    }
+    if( pszDstFilename == NULL )
+    {
+      return Usage(conf,"Missing destination.");
+    }
+#endif
+
+    GDALAllRegister();
+
+    // Open Dataset and get raster band
+    hSrcDataset = GDALOpen( pszSrcFilename, GA_ReadOnly );
+    
+    if( hSrcDataset == NULL )
+    {
+        fprintf( stderr,
+                 "GDALOpen failed - %d\n%s\n",
+                 CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
+        GDALDestroyDriverManager();
+#ifdef ZOO_SERVICE
+	char *tmp=(char*)malloc(1024*sizeof(char));
+	sprintf(tmp,"GDALOpen failed - %d\n%s\n",
+                 CPLGetLastErrorNo(), CPLGetLastErrorMsg());
+	return Usage(conf,"GDALOpen failed");
+#else
+        exit( 1 );
+#endif
+    }
+
+    nXSize = GDALGetRasterXSize(hSrcDataset);
+    nYSize = GDALGetRasterYSize(hSrcDataset);
+
+    if( nBand <= 0 || nBand > GDALGetRasterCount(hSrcDataset) )
+    {
+        fprintf( stderr,
+                 "Unable to fetch band #%d\n", nBand );
+        GDALDestroyDriverManager();
+#ifdef ZOO_SERVICE
+	char *tmp=(char*)malloc(128*sizeof(char));
+	sprintf(tmp,"Unable to fetch band #%d\n", nBand );
+	return Usage(conf,tmp);
+#else
+        exit( 1 );
+#endif
+    }
+    hSrcBand = GDALGetRasterBand( hSrcDataset, nBand );
+
+    GDALGetGeoTransform(hSrcDataset, adfGeoTransform);
+
+    hDriver = GDALGetDriverByName(pszFormat);
+    if( hDriver == NULL 
+        || (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL &&
+            GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) == NULL))
+    {
+        int	iDr;
+
+        fprintf( stderr, "Output driver `%s' not recognised to have\n", 
+                 pszFormat );
+        fprintf( stderr, "output support.  The following format drivers are configured\n"
+                "and support output:\n" );
+
+        for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
+        {
+            GDALDriverH hDriver = GDALGetDriver(iDr);
+
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL ||
+                GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL )
+            {
+                printf( "  %s: %s\n",
+                        GDALGetDriverShortName( hDriver  ),
+                        GDALGetDriverLongName( hDriver ) );
+            }
+        }
+        GDALDestroyDriverManager();
+#ifdef ZOO_SERVICE
+	return Usage(conf,"Output driver not recognised to have output support.");
+#else
+        exit( 1 );
+#endif
+    }
+
+#ifndef ZOO_SERVICE
+    if (!bQuiet && !bFormatExplicitelySet)
+        CheckExtensionConsistency(pszDstFilename, pszFormat);
+#endif
+
+    double dfDstNoDataValue = 0;
+    int bDstHasNoData = FALSE;
+    void* pData = NULL;
+    GDALGeneric3x3ProcessingAlg pfnAlg = NULL;
+
+    if (eUtilityMode == HILL_SHADE)
+    {
+        dfDstNoDataValue = 0;
+        bDstHasNoData = TRUE;
+        pData = GDALCreateHillshadeData   (adfGeoTransform,
+                                           z,
+                                           scale,
+                                           alt,
+                                           az,
+                                           bZevenbergenThorne);
+        if (bZevenbergenThorne)
+        {
+            if(!bCombined)
+                pfnAlg = GDALHillshadeZevenbergenThorneAlg;
+            else
+                pfnAlg = GDALHillshadeZevenbergenThorneCombinedAlg;
+        }
+        else
+        {
+            if(!bCombined)
+                pfnAlg = GDALHillshadeAlg;
+            else
+                pfnAlg = GDALHillshadeCombinedAlg;
+        }
+    }
+    else if (eUtilityMode == SLOPE)
+    {
+        dfDstNoDataValue = -9999;
+        bDstHasNoData = TRUE;
+
+        pData = GDALCreateSlopeData(adfGeoTransform, scale, slopeFormat);
+        if (bZevenbergenThorne)
+            pfnAlg = GDALSlopeZevenbergenThorneAlg;
+        else
+            pfnAlg = GDALSlopeHornAlg;
+    }
+
+    else if (eUtilityMode == ASPECT)
+    {
+        if (!bZeroForFlat)
+        {
+            dfDstNoDataValue = -9999;
+            bDstHasNoData = TRUE;
+        }
+
+        pData = GDALCreateAspectData(bAngleAsAzimuth);
+        if (bZevenbergenThorne)
+            pfnAlg = GDALAspectZevenbergenThorneAlg;
+        else
+            pfnAlg = GDALAspectAlg;
+    }
+    else if (eUtilityMode == TRI)
+    {
+        dfDstNoDataValue = -9999;
+        bDstHasNoData = TRUE;
+        pfnAlg = GDALTRIAlg;
+    }
+    else if (eUtilityMode == TPI)
+    {
+        dfDstNoDataValue = -9999;
+        bDstHasNoData = TRUE;
+        pfnAlg = GDALTPIAlg;
+    }
+    else if (eUtilityMode == ROUGHNESS)
+    {
+        dfDstNoDataValue = -9999;
+        bDstHasNoData = TRUE;
+        pfnAlg = GDALRoughnessAlg;
+    }
+    
+    GDALDataType eDstDataType = (eUtilityMode == HILL_SHADE ||
+                                 eUtilityMode == COLOR_RELIEF) ? GDT_Byte :
+                                                               GDT_Float32;
+
+    if( EQUAL(pszFormat, "VRT") )
+    {
+        if (eUtilityMode == COLOR_RELIEF)
+        {
+            GDALGenerateVRTColorRelief(pszDstFilename,
+                                       hSrcDataset,
+                                       hSrcBand,
+                                       pszColorFilename,
+                                       eColorSelectionMode,
+                                       bAddAlpha);
+            GDALClose(hSrcDataset);
+        
+            CPLFree(pData);
+
+            GDALDestroyDriverManager();
+#ifndef ZOO_SERVICE
+            CSLDestroy( argv );
+#endif
+            CSLDestroy( papszCreateOptions );    
+#ifdef ZOO_SERVICE
+	    return SERVICE_SUCCEEDED;
+#else
+            return 0;
+#endif
+        }
+        else
+        {
+            fprintf(stderr, "VRT driver can only be used with color-relief utility\n");
+            GDALDestroyDriverManager();
+#ifdef ZOO_SERVICE
+	    return Usage(conf,"VRT driver can only be used with color-relief utility");
+#else
+            exit(1);
+#endif
+        }
+    }
+    
+    if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL &&
+        GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL)
+    {
+        GDALDatasetH hIntermediateDataset;
+        
+        if (eUtilityMode == COLOR_RELIEF)
+            hIntermediateDataset = (GDALDatasetH)
+                new GDALColorReliefDataset (hSrcDataset,
+                                            hSrcBand,
+                                            pszColorFilename,
+                                            eColorSelectionMode,
+                                            bAddAlpha);
+        else
+            hIntermediateDataset = (GDALDatasetH)
+                new GDALGeneric3x3Dataset(hSrcDataset, hSrcBand,
+                                          eDstDataType,
+                                          bDstHasNoData,
+                                          dfDstNoDataValue,
+                                          pfnAlg,
+                                          pData,
+                                          bComputeAtEdges);
+
+        GDALDatasetH hOutDS = GDALCreateCopy(
+                                 hDriver, pszDstFilename, hIntermediateDataset, 
+                                 TRUE, papszCreateOptions, 
+                                 pfnProgress, NULL );
+
+        if( hOutDS != NULL )
+            GDALClose( hOutDS );
+        GDALClose(hIntermediateDataset);
+        GDALClose(hSrcDataset);
+        
+        CPLFree(pData);
+
+        GDALDestroyDriverManager();
+#ifndef ZOO_SERVICE
+        CSLDestroy( argv );
+#endif
+        CSLDestroy( papszCreateOptions );
+        
+#ifdef ZOO_SERVICE
+	return SERVICE_SUCCEEDED;
+#else
+        return 0;
+#endif
+    }
+
+    int nDstBands;
+    if (eUtilityMode == COLOR_RELIEF)
+        nDstBands = (bAddAlpha) ? 4 : 3;
+    else
+        nDstBands = 1;
+
+    hDstDataset = GDALCreate(   hDriver,
+                                pszDstFilename,
+                                nXSize,
+                                nYSize,
+                                nDstBands,
+                                eDstDataType,
+                                papszCreateOptions);
+
+    if( hDstDataset == NULL )
+    {
+        fprintf( stderr,
+                 "Unable to create dataset %s %d\n%s\n", pszDstFilename,
+                 CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
+        GDALDestroyDriverManager();
+#ifdef ZOO_SERVICE
+	char *tmp=(char*)malloc(1024*sizeof(char));
+        sprintf( tmp,
+                 "Unable to create dataset %s %d\n%s\n", pszDstFilename,
+                 CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
+	return Usage(conf,tmp);
+#else
+        exit( 1 );
+#endif
+    }
+    
+    hDstBand = GDALGetRasterBand( hDstDataset, 1 );
+
+    GDALSetGeoTransform(hDstDataset, adfGeoTransform);
+    GDALSetProjection(hDstDataset, GDALGetProjectionRef(hSrcDataset));
+    
+    if (eUtilityMode == COLOR_RELIEF)
+    {
+        GDALColorRelief (hSrcBand, 
+                         GDALGetRasterBand(hDstDataset, 1),
+                         GDALGetRasterBand(hDstDataset, 2),
+                         GDALGetRasterBand(hDstDataset, 3),
+                         (bAddAlpha) ? GDALGetRasterBand(hDstDataset, 4) : NULL,
+                         pszColorFilename,
+                         eColorSelectionMode,
+                         pfnProgress, NULL);
+    }
+    else
+    {
+        if (bDstHasNoData)
+            GDALSetRasterNoDataValue(hDstBand, dfDstNoDataValue);
+        
+        GDALGeneric3x3Processing(hSrcBand, hDstBand,
+                                 pfnAlg, pData,
+                                 bComputeAtEdges,
+                                 pfnProgress, NULL);
+                                    
+    }
+
+    GDALClose(hSrcDataset);
+    GDALClose(hDstDataset);
+    CPLFree(pData);
+
+    GDALDestroyDriverManager();
+#ifdef ZOO_SERVICE
+    CSLDestroy( papszCreateOptions );
+    return SERVICE_SUCCEEDED;
+#else
+    CSLDestroy( argv );
+    CSLDestroy( papszCreateOptions );
+    return 0;
+#endif
+
+}
+
+#ifdef ZOO_SERVICE
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/Makefile	(revision 942)
@@ -0,0 +1,15 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/service.zo: service.c
+	g++  -DZOO_SERVICE ${CFLAGS} -shared -fpic -o cgi-env/gdal_grid_service.zo ./service.c ${GDAL_LIBS} ${MACOS_LD_FLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}/gdal/grid
+	install cgi-env/* ${CGI_DIR}/gdal/grid
+
+
+clean:
+	rm -f cgi-env/*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/cgi-env/Gdal_Grid.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/cgi-env/Gdal_Grid.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/cgi-env/Gdal_Grid.zcfg	(revision 942)
@@ -0,0 +1,69 @@
+[Gdal_Grid]
+ Title =  Computes a regular grid (raster) from scattered data read from a vector data source. 
+ Abstract = http://www.gdal.org/gdal_grid.html
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = gdal_grid_service.zo
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [OF]
+   Title = Format of the output data
+   Abstract = Select the output format.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = AAIGrid
+    </Default>
+    <Supported>
+     value = AAIGrid
+    </Supported>
+   </LiteralData>
+  [InputDSN]
+   Title = The input data source name
+   Abstract = The input data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     uom = feet
+    </Default>	
+    <Supported>
+     value = AAIGrid
+    </Supported>
+   </LiteralData>
+  [OutputDSN]
+   Title = The output data source name
+   Abstract = The output data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     uom = feet
+    </Default>	
+    <Supported>
+     value = AAIGrid
+    </Supported>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [OutputedDataSourceName]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default>
+     uom = feet
+    </Default>	
+    <Supported>
+     value = AAIGrid
+    </Supported>
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/makefile.vc	(revision 942)
@@ -0,0 +1,11 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+cgi-env/gdal_grid_service.zo: service.c
+	$(CPP)  /DOGR_ENABLED /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE -I$(GDAL_DIR)/frmts/ -I$(GDAL_DIR)/alg/ $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/gdal_grid_service.zo  $(FILES) ./service.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\gdal_grid_service.*
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/grid/service.c	(revision 942)
@@ -0,0 +1,1264 @@
+/* ****************************************************************************
+ * $Id: gdal_grid.cpp 15053 2008-07-27 17:29:27Z rouault $
+ *
+ * Project:  GDAL Utilities
+ * Purpose:  GDAL scattered data gridding (interpolation) tool
+ * Author:   Andrey Kiselev, dron@ak4719.spb.edu
+ *
+ * ****************************************************************************
+ * Copyright (c) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include <vector>
+#include <algorithm>
+
+#include "cpl_string.h"
+#include "gdal.h"
+#include "gdal_alg.h"
+#include "ogr_spatialref.h"
+#include "ogr_api.h"
+
+#ifdef ZOO_SERVICE
+#include "service.h"
+#endif
+
+CPL_CVSID("$Id: gdal_grid.cpp 15053 2008-07-27 17:29:27Z rouault $");
+
+#ifdef ZOO_SERVICE
+extern "C" {
+#endif
+
+static const char szAlgNameInvDist[] = "invdist";
+static const char szAlgNameAverage[] = "average";
+static const char szAlgNameNearest[] = "nearest";
+static const char szAlgNameMinimum[] = "minimum";
+static const char szAlgNameMaximum[] = "maximum";
+static const char szAlgNameRange[] = "range";
+
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage()
+{
+#ifdef ZOO_SERVICE
+  fprintf(stderr,
+#else
+    printf( 
+#endif
+        "Usage: gdal_grid [--help-general] [--formats]\n"
+        "    [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/\n"
+        "          CInt16/CInt32/CFloat32/CFloat64}]\n"
+        "    [-of format] [-co \"NAME=VALUE\"]\n"
+        "    [-zfield field_name]\n"
+        "    [-a_srs srs_def] [-spat xmin ymin xmax ymax]\n"
+        "    [-l layername]* [-where expression] [-sql select_statement]\n"
+        "    [-txe xmin xmax] [-tye ymin ymax] [-outsize xsize ysize]\n"
+        "    [-a algorithm[:parameter1=value1]*]"
+        "    [-quiet]\n"
+        "    <src_datasource> <dst_filename>\n"
+        "\n"
+        "Available algorithms and parameters with their defaults:\n"
+        "    Inverse distance to a power (default)\n"
+        "        invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0\n"
+        "    Moving average\n"
+        "        average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0\n"
+        "    Nearest neighbor\n"
+        "        nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0\n"
+        "    Various data metrics\n"
+        "        <metric name>:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0\n"
+        "        possible metrics are:\n"
+        "            minimum\n"
+        "            maximum\n"
+        "            range\n"
+        "\n");
+#ifndef ZOO_SERVICE
+    exit( 1 );
+#endif
+}
+
+/************************************************************************/
+/*                          GetAlgorithmName()                          */
+/*                                                                      */
+/*      Translates algortihm code into mnemonic name.                   */
+/************************************************************************/
+
+void PrintAlgorithmAndOptions(GDALGridAlgorithm eAlgorithm, void *pOptions)
+{
+    switch ( eAlgorithm )
+    {
+        case GGA_InverseDistanceToAPower:
+
+#ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+		   "Algorithm name: \"%s\".\n", szAlgNameInvDist );
+#ifdef ZOO_SERVICE
+		fprintf(stderr,
+#else
+			  printf( 
+#endif
+				 "Options are "
+				 "\"power=%f:smoothing=%f:radius1=%f:radius2=%f:angle=%f"
+                    ":max_points=%lu:min_points=%lu:nodata=%f\"\n",
+                ((GDALGridInverseDistanceToAPowerOptions *)pOptions)->dfPower,
+                ((GDALGridInverseDistanceToAPowerOptions *)pOptions)->dfSmoothing,
+                ((GDALGridInverseDistanceToAPowerOptions *)pOptions)->dfRadius1,
+                ((GDALGridInverseDistanceToAPowerOptions *)pOptions)->dfRadius2,
+                ((GDALGridInverseDistanceToAPowerOptions *)pOptions)->dfAngle,
+                (unsigned long)((GDALGridInverseDistanceToAPowerOptions *)pOptions)->nMaxPoints,
+                (unsigned long)((GDALGridInverseDistanceToAPowerOptions *)pOptions)->nMinPoints,
+                ((GDALGridInverseDistanceToAPowerOptions *)pOptions)->dfNoDataValue);
+            break;
+        case GGA_MovingAverage:
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Algorithm name: \"%s\".\n", szAlgNameAverage );
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Options are "
+                    "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
+                    ":nodata=%f\"\n",
+                ((GDALGridMovingAverageOptions *)pOptions)->dfRadius1,
+                ((GDALGridMovingAverageOptions *)pOptions)->dfRadius2,
+                ((GDALGridMovingAverageOptions *)pOptions)->dfAngle,
+                (unsigned long)((GDALGridMovingAverageOptions *)pOptions)->nMinPoints,
+                ((GDALGridMovingAverageOptions *)pOptions)->dfNoDataValue);
+            break;
+        case GGA_NearestNeighbor:
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Algorithm name: \"%s\".\n", szAlgNameNearest );
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Options are "
+                    "\"radius1=%f:radius2=%f:angle=%f:nodata=%f\"\n",
+                ((GDALGridNearestNeighborOptions *)pOptions)->dfRadius1,
+                ((GDALGridNearestNeighborOptions *)pOptions)->dfRadius2,
+                ((GDALGridNearestNeighborOptions *)pOptions)->dfAngle,
+                ((GDALGridNearestNeighborOptions *)pOptions)->dfNoDataValue);
+            break;
+        case GGA_MetricMinimum:
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Algorithm name: \"%s\".\n", szAlgNameMinimum );
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Options are "
+                    "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
+                    ":nodata=%f\"\n",
+                ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfRadius2,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfAngle,
+                (unsigned long)((GDALGridDataMetricsOptions *)pOptions)->nMinPoints,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfNoDataValue);
+            break;
+        case GGA_MetricMaximum:
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Algorithm name: \"%s\".\n", szAlgNameMaximum );
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Options are "
+                    "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
+                    ":nodata=%f\"\n",
+                ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfRadius2,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfAngle,
+                (unsigned long)((GDALGridDataMetricsOptions *)pOptions)->nMinPoints,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfNoDataValue);
+            break;
+        case GGA_MetricRange:
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Algorithm name: \"%s\".\n", szAlgNameRange );
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Options are "
+                    "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
+                    ":nodata=%f\"\n",
+                ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfRadius2,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfAngle,
+                (unsigned long)((GDALGridDataMetricsOptions *)pOptions)->nMinPoints,
+                ((GDALGridDataMetricsOptions *)pOptions)->dfNoDataValue);
+            break;
+        default:
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Algorithm unknown.\n" );
+            break;
+    }
+}
+
+/************************************************************************/
+/*                      ParseAlgorithmAndOptions()                      */
+/*                                                                      */
+/*      Translates mnemonic gridding algorithm names into               */
+/*      GDALGridAlgorithm code, parse control parameters and assign     */
+/*      defaults.                                                       */
+/************************************************************************/
+
+static CPLErr ParseAlgorithmAndOptions( const char *pszAlgoritm,
+                                        GDALGridAlgorithm *peAlgorithm,
+                                        void **ppOptions )
+{
+    char **papszParms = CSLTokenizeString2( pszAlgoritm, ":", FALSE );
+
+    if ( CSLCount(papszParms) < 1 )
+        return CE_Failure;
+
+    if ( EQUAL(papszParms[0], szAlgNameInvDist) )
+        *peAlgorithm = GGA_InverseDistanceToAPower;
+    else if ( EQUAL(papszParms[0], szAlgNameAverage) )
+        *peAlgorithm = GGA_MovingAverage;
+    else if ( EQUAL(papszParms[0], szAlgNameNearest) )
+        *peAlgorithm = GGA_NearestNeighbor;
+    else if ( EQUAL(papszParms[0], szAlgNameMinimum) )
+        *peAlgorithm = GGA_MetricMinimum;
+    else if ( EQUAL(papszParms[0], szAlgNameMaximum) )
+        *peAlgorithm = GGA_MetricMaximum;
+    else if ( EQUAL(papszParms[0], szAlgNameRange) )
+        *peAlgorithm = GGA_MetricRange;
+    else
+    {
+        fprintf( stderr, "Unsupported gridding method \"%s\".\n",
+                 papszParms[0] );
+        CSLDestroy( papszParms );
+        return CE_Failure;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Parse algorithm parameters and assign defaults.                 */
+/* -------------------------------------------------------------------- */
+    const char  *pszValue;
+
+    switch ( *peAlgorithm )
+    {
+        case GGA_InverseDistanceToAPower:
+        default:
+            *ppOptions =
+                CPLMalloc( sizeof(GDALGridInverseDistanceToAPowerOptions) );
+
+            pszValue = CSLFetchNameValue( papszParms, "power" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                dfPower = (pszValue) ? atof(pszValue) : 2.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "smoothing" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                dfSmoothing = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "radius1" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                dfRadius1 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "radius2" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                dfRadius2 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "angle" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                dfAngle = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "max_points" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                nMaxPoints = (pszValue) ? atol(pszValue) : 0;
+
+            pszValue = CSLFetchNameValue( papszParms, "min_points" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                nMinPoints = (pszValue) ? atol(pszValue) : 0;
+
+            pszValue = CSLFetchNameValue( papszParms, "nodata" );
+            ((GDALGridInverseDistanceToAPowerOptions *)*ppOptions)->
+                dfNoDataValue = (pszValue) ? atof(pszValue) : 0.0;
+            break;
+
+        case GGA_MovingAverage:
+            *ppOptions =
+                CPLMalloc( sizeof(GDALGridMovingAverageOptions) );
+
+            pszValue = CSLFetchNameValue( papszParms, "radius1" );
+            ((GDALGridMovingAverageOptions *)*ppOptions)->
+                dfRadius1 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "radius2" );
+            ((GDALGridMovingAverageOptions *)*ppOptions)->
+                dfRadius2 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "angle" );
+            ((GDALGridMovingAverageOptions *)*ppOptions)->
+                dfAngle = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "min_points" );
+            ((GDALGridMovingAverageOptions *)*ppOptions)->
+                nMinPoints = (pszValue) ? atol(pszValue) : 0;
+
+            pszValue = CSLFetchNameValue( papszParms, "nodata" );
+            ((GDALGridMovingAverageOptions *)*ppOptions)->
+                dfNoDataValue = (pszValue) ? atof(pszValue) : 0.0;
+            break;
+
+        case GGA_NearestNeighbor:
+            *ppOptions =
+                CPLMalloc( sizeof(GDALGridNearestNeighborOptions) );
+
+            pszValue = CSLFetchNameValue( papszParms, "radius1" );
+            ((GDALGridNearestNeighborOptions *)*ppOptions)->
+                dfRadius1 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "radius2" );
+            ((GDALGridNearestNeighborOptions *)*ppOptions)->
+                dfRadius2 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "angle" );
+            ((GDALGridNearestNeighborOptions *)*ppOptions)->
+                dfAngle = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "nodata" );
+            ((GDALGridNearestNeighborOptions *)*ppOptions)->
+                dfNoDataValue = (pszValue) ? atof(pszValue) : 0.0;
+            break;
+
+        case GGA_MetricMinimum:
+        case GGA_MetricMaximum:
+        case GGA_MetricRange:
+            *ppOptions =
+                CPLMalloc( sizeof(GDALGridDataMetricsOptions) );
+
+            pszValue = CSLFetchNameValue( papszParms, "radius1" );
+            ((GDALGridDataMetricsOptions *)*ppOptions)->
+                dfRadius1 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "radius2" );
+            ((GDALGridDataMetricsOptions *)*ppOptions)->
+                dfRadius2 = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "angle" );
+            ((GDALGridDataMetricsOptions *)*ppOptions)->
+                dfAngle = (pszValue) ? atof(pszValue) : 0.0;
+
+            pszValue = CSLFetchNameValue( papszParms, "min_points" );
+            ((GDALGridDataMetricsOptions *)*ppOptions)->
+                nMinPoints = (pszValue) ? atol(pszValue) : 0;
+
+            pszValue = CSLFetchNameValue( papszParms, "nodata" );
+            ((GDALGridDataMetricsOptions *)*ppOptions)->
+                dfNoDataValue = (pszValue) ? atof(pszValue) : 0.0;
+            break;
+
+   }
+
+    CSLDestroy( papszParms );
+    return CE_None;
+}
+
+/************************************************************************/
+/*                            ProcessLayer()                            */
+/*                                                                      */
+/*      Process all the features in a layer selection, collecting       */
+/*      geometries and burn values.                                     */
+/************************************************************************/
+
+static void ProcessLayer( OGRLayerH hSrcLayer, GDALDatasetH hDstDS,
+                          GUInt32 nXSize, GUInt32 nYSize, int nBand,
+                          int& bIsXExtentSet, int& bIsYExtentSet,
+                          double& dfXMin, double& dfXMax,
+                          double& dfYMin, double& dfYMax,
+                          const char *pszBurnAttribute,
+                          GDALDataType eType,
+                          GDALGridAlgorithm eAlgorithm, void *pOptions,
+                          int bQuiet, GDALProgressFunc pfnProgress )
+
+{
+/* -------------------------------------------------------------------- */
+/*      Get field index, and check.                                     */
+/* -------------------------------------------------------------------- */
+    int iBurnField = -1;
+
+    if ( pszBurnAttribute )
+    {
+        iBurnField = OGR_FD_GetFieldIndex( OGR_L_GetLayerDefn( hSrcLayer ),
+                                           pszBurnAttribute );
+        if( iBurnField == -1 )
+        {
+            #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Failed to find field %s on layer %s, skipping.\n",
+                    pszBurnAttribute, 
+                    OGR_FD_GetName( OGR_L_GetLayerDefn( hSrcLayer ) ) );
+            return;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Collect the geometries from this layer, and build list of       */
+/*      values to be interpolated.                                      */
+/* -------------------------------------------------------------------- */
+    OGRFeatureH hFeat;
+    std::vector<double> adfX, adfY, adfZ;
+
+    OGR_L_ResetReading( hSrcLayer );
+
+    while( (hFeat = OGR_L_GetNextFeature( hSrcLayer )) != NULL )
+    {
+        OGRGeometryH hGeom;
+
+        hGeom = OGR_F_GetGeometryRef( hFeat );
+
+        // FIXME: handle collections
+        if ( hGeom != NULL &&
+             (OGR_G_GetGeometryType( hGeom ) == wkbPoint
+              || OGR_G_GetGeometryType( hGeom ) == wkbPoint25D) )
+        {
+            adfX.push_back( OGR_G_GetX( hGeom, 0 ) );
+            adfY.push_back( OGR_G_GetY( hGeom, 0 ) );
+            if ( iBurnField < 0 )
+                adfZ.push_back( OGR_G_GetZ( hGeom, 0 ) );
+            else
+                adfZ.push_back( OGR_F_GetFieldAsDouble( hFeat, iBurnField ) );
+        }
+
+        
+        OGR_F_Destroy( hFeat );
+    }
+
+    if (adfX.size() == 0)
+    {
+        #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "No point geometry found on layer %s, skipping.\n",
+                OGR_FD_GetName( OGR_L_GetLayerDefn( hSrcLayer ) ) );
+        return;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Compute grid geometry.                                          */
+/* -------------------------------------------------------------------- */
+
+    if ( !bIsXExtentSet )
+    {
+        dfXMin = *std::min_element(adfX.begin(), adfX.end());
+        dfXMax = *std::max_element(adfX.begin(), adfX.end());
+        bIsXExtentSet = TRUE;
+    }
+
+    if ( !bIsYExtentSet )
+    {
+        dfYMin = *std::min_element(adfY.begin(), adfY.end());
+        dfYMax = *std::max_element(adfY.begin(), adfY.end());
+        bIsYExtentSet = TRUE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Perform gridding.                                               */
+/* -------------------------------------------------------------------- */
+
+    const double    dfDeltaX = ( dfXMax - dfXMin ) / nXSize;
+    const double    dfDeltaY = ( dfYMax - dfYMin ) / nYSize;
+
+    if ( !bQuiet )
+    {
+        #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Grid data type is \"%s\"\n", GDALGetDataTypeName(eType) );
+        #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Grid size = (%lu %lu).\n",
+                (unsigned long)nXSize, (unsigned long)nYSize );
+        #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Corner coordinates = (%f %f)-(%f %f).\n",
+                dfXMin - dfDeltaX / 2, dfYMax + dfDeltaY / 2,
+                dfXMax + dfDeltaX / 2, dfYMin - dfDeltaY / 2 );
+        #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Grid cell size = (%f %f).\n", dfDeltaX, dfDeltaY );
+        #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+ "Source point count = %lu.\n", (unsigned long)adfX.size() );
+        PrintAlgorithmAndOptions( eAlgorithm, pOptions );
+        #ifdef ZOO_SERVICE
+	  fprintf(stderr,
+#else
+            printf( 
+#endif
+"\n");
+    }
+
+    GDALRasterBandH hBand = GDALGetRasterBand( hDstDS, nBand );
+
+    if (adfX.size() == 0)
+    {
+        // FIXME: Shoulda' set to nodata value instead
+        GDALFillRaster( hBand, 0.0 , 0.0 );
+        return;
+    }
+
+    GUInt32 nXOffset, nYOffset;
+    int     nBlockXSize, nBlockYSize;
+
+    GDALGetBlockSize( hBand, &nBlockXSize, &nBlockYSize );
+    void    *pData =
+        CPLMalloc( nBlockXSize * nBlockYSize * GDALGetDataTypeSize(eType) );
+
+    GUInt32 nBlock = 0;
+    GUInt32 nBlockCount = ((nXSize + nBlockXSize - 1) / nBlockXSize)
+        * ((nYSize + nBlockYSize - 1) / nBlockYSize);
+
+    for ( nYOffset = 0; nYOffset < nYSize; nYOffset += nBlockYSize )
+    {
+        for ( nXOffset = 0; nXOffset < nXSize; nXOffset += nBlockXSize )
+        {
+            void *pScaledProgress;
+            pScaledProgress =
+                GDALCreateScaledProgress( 0.0,
+                                          (double)++nBlock / nBlockCount,
+                                          pfnProgress, NULL );
+
+            int nXRequest = nBlockXSize;
+            if (nXOffset + nXRequest > nXSize)
+                nXRequest = nXSize - nXOffset;
+
+            int nYRequest = nBlockYSize;
+            if (nYOffset + nYRequest > nYSize)
+                nYRequest = nYSize - nYOffset;
+
+            GDALGridCreate( eAlgorithm, pOptions,
+                            adfX.size(), &(adfX[0]), &(adfY[0]), &(adfZ[0]),
+                            dfXMin + dfDeltaX * nXOffset,
+                            dfXMin + dfDeltaX * (nXOffset + nXRequest),
+                            dfYMin + dfDeltaY * nYOffset,
+                            dfYMin + dfDeltaY * (nYOffset + nYRequest),
+                            nXRequest, nYRequest, eType, pData,
+                            GDALScaledProgress, pScaledProgress );
+
+            GDALRasterIO( hBand, GF_Write, nXOffset, nYOffset,
+                          nXRequest, nYRequest, pData,
+                          nXRequest, nYRequest, eType, 0, 0 );
+
+            GDALDestroyScaledProgress( pScaledProgress );
+        }
+    }
+
+    CPLFree( pData );
+}
+
+/************************************************************************/
+/*                                main()                                */
+/************************************************************************/
+#ifdef ZOO_SERVICE
+int Gdal_Grid(maps*& conf,maps*& inputs,maps*& outputs)
+#else
+int main( int argc, char ** argv )
+#endif
+{
+    GDALDriverH     hDriver;
+    const char      *pszSource=NULL, *pszDest=NULL, *pszFormat = "GTiff";
+    char            **papszLayers = NULL;
+    const char      *pszBurnAttribute = NULL;
+    const char      *pszWHERE = NULL, *pszSQL = NULL;
+    GDALDataType    eOutputType = GDT_Float64;
+    char            **papszCreateOptions = NULL;
+    GUInt32         nXSize = 0, nYSize = 0;
+    double          dfXMin = 0.0, dfXMax = 0.0, dfYMin = 0.0, dfYMax = 0.0;
+    int             bIsXExtentSet = FALSE, bIsYExtentSet = FALSE;
+    GDALGridAlgorithm eAlgorithm = GGA_InverseDistanceToAPower;
+    void            *pOptions = NULL;
+    char            *pszOutputSRS = NULL;
+    int             bQuiet = FALSE;
+    GDALProgressFunc pfnProgress = GDALTermProgress;
+    int             i;
+    OGRGeometryH    hSpatialFilter = NULL;
+
+    /* Check that we are running against at least GDAL 1.5 */
+    /* Note to developers : if we use newer API, please change the requirement */
+    if (atoi(GDALVersionInfo("VERSION_NUM")) < 1500)
+    {
+#ifdef ZOO_SERVICE
+        fprintf(stderr, "At least, GDAL >= 1.5.0 is required for this version of this ZOO ServiceProvider, "
+                "which was compiled against GDAL %s\n", GDAL_RELEASE_NAME);
+#else
+        fprintf(stderr, "At least, GDAL >= 1.5.0 is required for this version of %s, "
+                "which was compiled against GDAL %s\n", argv[0], GDAL_RELEASE_NAME);
+#endif
+	return SERVICE_FAILED;
+    }
+
+    GDALAllRegister();
+    OGRRegisterAll();
+
+#ifdef ZOO_SERVICE
+    bQuiet = TRUE;
+    pfnProgress = GDALDummyProgress;
+    map* tmpMap=NULL;
+
+    char dataPath[1024];
+    tmpMap=getMapFromMaps(conf,"main","dataPath");
+    if(tmpMap!=NULL)
+      sprintf(dataPath,"%s",tmpMap->value);
+    tmpMap=NULL;
+
+    char tempPath[1024];
+    tmpMap=getMapFromMaps(conf,"main","tmpPath");
+    if(tmpMap!=NULL){
+      sprintf(tempPath,"%s",tmpMap->value);
+    }
+    tmpMap=NULL;
+
+    tmpMap=getMapFromMaps(inputs,"OF","value");
+    if(tmpMap!=NULL){
+      pszFormat=tmpMap->value;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"OT","value");
+    if(tmpMap!=NULL){
+      int iType;      
+      for( iType = 1; iType < GDT_TypeCount; iType++ )
+	{
+	  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
+	      && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
+                             tmpMap->value) )
+	    {
+	      eOutputType = (GDALDataType) iType;
+	    }
+	}
+      if( eOutputType == GDT_Unknown )
+	{
+	  fprintf( stderr, "Unknown output pixel type: %s\n", tmpMap->value );
+	  Usage();
+	  return SERVICE_FAILED;
+	}
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"TXE","value");
+    if(tmpMap!=NULL){
+      char *tmp=tmpMap->value;
+      char *t=strtok(tmp,",");
+      int cnt=0;
+      while(t!=NULL){
+        switch(cnt){
+        case 0:
+          dfXMin = atof(t);
+          break;
+        case 1:
+          dfXMax = atof(t);
+          break;
+        }
+	t=strtok(NULL,",");
+	cnt++;
+      }
+      bIsXExtentSet = TRUE;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"TYE","value");
+    if(tmpMap!=NULL){
+      char *tmp=tmpMap->value;
+      char *t=strtok(tmp,",");
+      int cnt=0;
+      while(t!=NULL){
+        switch(cnt){
+        case 0:
+          dfYMin = atof(t);
+          break;
+        case 1:
+          dfYMax = atof(t);
+          break;
+        }
+	t=strtok(NULL,",");
+	cnt++;
+	
+      }
+      bIsYExtentSet = TRUE;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"OUTSIZE","value");
+    if(tmpMap!=NULL){
+      char *tmp=tmpMap->value;
+      char *t=strtok(tmp,",");
+      int cnt=0;
+      while(t!=NULL){
+        switch(cnt){
+        case 0:
+          nXSize = atoi(t);
+          break;
+        case 1:
+          nYSize = atoi(t);
+          break;
+        }
+	cnt++;
+      }
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"CO","value");
+    if(tmpMap!=NULL){
+      papszCreateOptions = CSLAddString( papszCreateOptions, tmpMap->value );
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"ZFIELD","value");
+    if(tmpMap!=NULL){
+      pszBurnAttribute = tmpMap->value;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"WHERE","value");
+    if(tmpMap!=NULL){
+      pszWHERE = tmpMap->value;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"L","value");
+    if(tmpMap!=NULL){
+      papszLayers = CSLAddString( papszLayers, tmpMap->value );
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"SQL","value");
+    if(tmpMap!=NULL){
+      pszSQL = tmpMap->value;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"A","value");
+    if(tmpMap!=NULL){
+      if ( ParseAlgorithmAndOptions(tmpMap->value, &eAlgorithm, &pOptions )
+	   != CE_None )
+	{
+	  fprintf( stderr,
+		   "Failed to process algoritm name and parameters.\n" );
+	  return SERVICE_FAILED;
+	}
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"SPAT","value");
+    if(tmpMap!=NULL){
+      char *tmp=tmpMap->value;
+      char *t=strtok(tmp,",");
+      int cnt=0;
+      double dfULX, dfULY, dfLRX, dfLRY;
+      while(t!=NULL){
+        switch(cnt){
+        case 0:
+          dfULX = atof(t);
+          break;
+        case 1:
+          dfULY = atof(t);
+          break;
+        case 2:
+          dfLRX = atof(t);
+          break;
+        case 3:
+          dfLRY = atof(t);
+          break;
+        }
+        fprintf(stderr,"%s\n\n",t);
+        fprintf(stderr,"%f - %f - %f - %f\n\n",dfULX,dfULY,dfLRX,dfLRY);
+        t=strtok(NULL,",");
+        cnt++;
+      }
+      OGRGeometryH hRing = OGR_G_CreateGeometry( wkbLinearRing );
+      
+      OGR_G_AddPoint_2D( hRing, dfULX, dfULY );
+      OGR_G_AddPoint_2D( hRing, dfULX, dfLRY );
+      OGR_G_AddPoint_2D( hRing, dfLRY, dfLRY );
+      OGR_G_AddPoint_2D( hRing, dfLRY, dfULY );
+      OGR_G_AddPoint_2D( hRing, dfULX, dfULY );
+      
+      hSpatialFilter = OGR_G_CreateGeometry( wkbPolygon );
+      OGR_G_AddGeometry( hSpatialFilter, hRing );
+	
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"A_SRS","value");
+    if(tmpMap!=NULL){
+      OGRSpatialReference oOutputSRS;
+      
+      if( oOutputSRS.SetFromUserInput( tmpMap->value ) != OGRERR_NONE )
+	{
+	  fprintf( stderr, "Failed to process SRS definition: %s\n", 
+		   tmpMap->value );
+	  GDALDestroyDriverManager();
+	  return SERVICE_FAILED;
+	}
+      
+      oOutputSRS.exportToWkt( &pszOutputSRS );
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"InputDSN","value");
+    if(tmpMap!=NULL){
+      pszSource=(char*)malloc(sizeof(char)*(strlen(dataPath)+strlen(tmpMap->value)+1));
+      sprintf((char*)pszSource,"%s/%s",dataPath,tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"OutputDSN","value");
+    if(tmpMap!=NULL){
+      pszDest=(char*)malloc(sizeof(char)*(strlen(tempPath)+strlen(tmpMap->value)+4));
+      char *ext=new char[4];
+      ext="tif";
+      if(strncasecmp(pszFormat,"AAIGRID",7)==0)
+        ext="csv";
+      else 
+        if(strncasecmp(pszFormat,"PNG",3)==0)
+          ext="png";
+        else
+          if(strncasecmp(pszFormat,"GIF",3)==0)
+            ext="gif";
+          else
+            if(strncasecmp(pszFormat,"JPEG",4)==0)
+              ext="jpg";
+      sprintf((char*)pszDest,"%s/%s.%s",tempPath,tmpMap->value,ext);
+    }
+
+#else
+    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
+    if( argc < 1 )
+        exit( -argc );
+
+/* -------------------------------------------------------------------- */
+/*      Parse arguments.                                                */
+/* -------------------------------------------------------------------- */
+    for( i = 1; i < argc; i++ )
+    {
+        if( EQUAL(argv[i], "--utility_version") )
+        {
+            printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
+                   argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
+            return 0;
+        }
+        else if( EQUAL(argv[i],"-of") && i < argc-1 )
+        {
+            pszFormat = argv[++i];
+        }
+
+        else if( EQUAL(argv[i],"-quiet") )
+        {
+            bQuiet = TRUE;
+            pfnProgress = GDALDummyProgress;
+        }
+
+        else if( EQUAL(argv[i],"-ot") && i < argc-1 )
+        {
+            int	iType;
+            
+            for( iType = 1; iType < GDT_TypeCount; iType++ )
+            {
+                if( GDALGetDataTypeName((GDALDataType)iType) != NULL
+                    && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
+                             argv[i+1]) )
+                {
+                    eOutputType = (GDALDataType) iType;
+                }
+            }
+
+            if( eOutputType == GDT_Unknown )
+            {
+                fprintf( stderr, "Unknown output pixel type: %s\n", argv[i+1] );
+                Usage();
+                exit( 2 );
+            }
+            i++;
+        }
+
+        else if( EQUAL(argv[i],"-txe") && i < argc-2 )
+        {
+            dfXMin = atof(argv[++i]);
+            dfXMax = atof(argv[++i]);
+            bIsXExtentSet = TRUE;
+        }   
+
+        else if( EQUAL(argv[i],"-tye") && i < argc-2 )
+        {
+            dfYMin = atof(argv[++i]);
+            dfYMax = atof(argv[++i]);
+            bIsYExtentSet = TRUE;
+        }   
+
+        else if( EQUAL(argv[i],"-outsize") && i < argc-2 )
+        {
+            nXSize = atoi(argv[++i]);
+            nYSize = atoi(argv[++i]);
+        }   
+
+        else if( EQUAL(argv[i],"-co") && i < argc-1 )
+        {
+            papszCreateOptions = CSLAddString( papszCreateOptions, argv[++i] );
+        }   
+
+        else if( EQUAL(argv[i],"-zfield") && i < argc-1 )
+        {
+            pszBurnAttribute = argv[++i];
+        }
+
+        else if( EQUAL(argv[i],"-where") && i < argc-1 )
+        {
+            pszWHERE = argv[++i];
+        }
+
+        else if( EQUAL(argv[i],"-l") && i < argc-1 )
+        {
+            papszLayers = CSLAddString( papszLayers, argv[++i] );
+        }
+
+        else if( EQUAL(argv[i],"-sql") && i < argc-1 )
+        {
+            pszSQL = argv[++i];
+        }
+
+        else if( EQUAL(argv[i],"-spat") 
+                 && argv[i+1] != NULL 
+                 && argv[i+2] != NULL 
+                 && argv[i+3] != NULL 
+                 && argv[i+4] != NULL )
+        {
+            OGRGeometryH hRing = OGR_G_CreateGeometry( wkbLinearRing );
+
+            OGR_G_AddPoint_2D( hRing, atof(argv[i+1]), atof(argv[i+2]) );
+            OGR_G_AddPoint_2D( hRing, atof(argv[i+1]), atof(argv[i+4]) );
+            OGR_G_AddPoint_2D( hRing, atof(argv[i+3]), atof(argv[i+4]) );
+            OGR_G_AddPoint_2D( hRing, atof(argv[i+3]), atof(argv[i+2]) );
+            OGR_G_AddPoint_2D( hRing, atof(argv[i+1]), atof(argv[i+2]) );
+
+            hSpatialFilter = OGR_G_CreateGeometry( wkbPolygon );
+            OGR_G_AddGeometry( hSpatialFilter, hRing );
+            i += 4;
+        }
+
+        else if( EQUAL(argv[i],"-a_srs") && i < argc-1 )
+        {
+            OGRSpatialReference oOutputSRS;
+
+            if( oOutputSRS.SetFromUserInput( argv[i+1] ) != OGRERR_NONE )
+            {
+                fprintf( stderr, "Failed to process SRS definition: %s\n", 
+                         argv[i+1] );
+                GDALDestroyDriverManager();
+                exit( 1 );
+            }
+
+            oOutputSRS.exportToWkt( &pszOutputSRS );
+            i++;
+        }   
+
+        else if( EQUAL(argv[i],"-a") && i < argc-1 )
+        {
+            if ( ParseAlgorithmAndOptions( argv[++i], &eAlgorithm, &pOptions )
+                 != CE_None )
+            {
+                fprintf( stderr,
+                         "Failed to process algoritm name and parameters.\n" );
+                exit( 1 );
+            }
+        }
+
+        else if( argv[i][0] == '-' )
+        {
+            fprintf( stderr, "Option %s incomplete, or not recognised.\n\n", 
+                    argv[i] );
+            Usage();
+            GDALDestroyDriverManager();
+            exit( 2 );
+        }
+
+        else if( pszSource == NULL )
+        {
+            pszSource = argv[i];
+        }
+
+        else if( pszDest == NULL )
+        {
+            pszDest = argv[i];
+        }
+
+        else
+        {
+            fprintf( stderr, "Too many command options.\n\n" );
+            Usage();
+            GDALDestroyDriverManager();
+            exit( 2 );
+        }
+    }
+#endif
+
+    if( pszSource == NULL || pszDest == NULL
+        || (pszSQL == NULL && papszLayers == NULL) )
+    {
+        Usage();
+        GDALDestroyDriverManager();
+#ifndef ZOO_SERVICE
+        exit( 2 );
+#else
+	fprintf(stderr,"pszSource %s\n",pszSource);
+	fprintf(stderr,"pszDest %s\n",pszDest);
+	return SERVICE_FAILED;
+#endif
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the output driver.                                         */
+/* -------------------------------------------------------------------- */
+    hDriver = GDALGetDriverByName( pszFormat );
+    if( hDriver == NULL )
+    {
+        int	iDr;
+        
+        fprintf( stderr, "Output driver `%s' not recognised.\n", pszFormat );
+        fprintf( stderr,
+        "The following format drivers are configured and support output:\n" );
+        for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
+        {
+            GDALDriverH hDriver = GDALGetDriver(iDr);
+
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
+                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
+                                        NULL ) != NULL )
+            {
+                fprintf( stderr, "  %s: %s\n",
+                         GDALGetDriverShortName( hDriver  ),
+                         GDALGetDriverLongName( hDriver ) );
+            }
+        }
+        printf( "\n" );
+        Usage();
+        
+        GDALDestroyDriverManager();
+#ifndef ZOO_SERVICE
+        CSLDestroy( argv );
+#endif
+        CSLDestroy( papszCreateOptions );
+	return SERVICE_FAILED;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Open input datasource.                                          */
+/* -------------------------------------------------------------------- */
+    OGRDataSourceH hSrcDS;
+
+    hSrcDS = OGROpen( pszSource, FALSE, NULL );
+    if( hSrcDS == NULL )
+    {
+        fprintf( stderr, "Unable to open input datasource \"%s\".\n",
+                 pszSource );
+        fprintf( stderr, "%s\n", CPLGetLastErrorMsg() );
+	return SERVICE_FAILED;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create target raster file.                                      */
+/* -------------------------------------------------------------------- */
+    GDALDatasetH    hDstDS;
+    int             nLayerCount = CSLCount(papszLayers);
+    int             nBands = nLayerCount;
+
+    if ( pszSQL )
+        nBands++;
+
+    // FIXME
+    if ( nXSize == 0 )
+        nXSize = 256;
+    if ( nYSize == 0 )
+        nYSize = 256;
+
+    hDstDS = GDALCreate( hDriver, pszDest, nXSize, nYSize, nBands,
+                         eOutputType, papszCreateOptions );
+    if ( hDstDS == NULL )
+    {
+        fprintf( stderr, "Unable to create target dataset \"%s\".\n",
+                 pszDest );
+        fprintf( stderr, "%s\n", CPLGetLastErrorMsg() );
+	return SERVICE_FAILED;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If algorithm was not specified assigh default one.              */
+/* -------------------------------------------------------------------- */
+    if ( !pOptions )
+        ParseAlgorithmAndOptions( szAlgNameInvDist, &eAlgorithm, &pOptions );
+
+/* -------------------------------------------------------------------- */
+/*      Process SQL request.                                            */
+/* -------------------------------------------------------------------- */
+    if( pszSQL != NULL )
+    {
+        OGRLayerH hLayer;
+
+        hLayer = OGR_DS_ExecuteSQL( hSrcDS, pszSQL, hSpatialFilter, NULL ); 
+        if( hLayer != NULL )
+        {
+            // Custom layer will be rasterized in the first band.
+            ProcessLayer( hLayer, hDstDS, nXSize, nYSize, 1,
+                          bIsXExtentSet, bIsYExtentSet,
+                          dfXMin, dfXMax, dfYMin, dfYMax, pszBurnAttribute,
+                          eOutputType, eAlgorithm, pOptions,
+                          bQuiet, pfnProgress );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Process each layer.                                             */
+/* -------------------------------------------------------------------- */
+    for( i = 0; i < nLayerCount; i++ )
+    {
+        OGRLayerH hLayer = OGR_DS_GetLayerByName( hSrcDS, papszLayers[i] );
+        if( hLayer == NULL )
+        {
+            fprintf( stderr, "Unable to find layer \"%s\", skipping.\n", 
+                     papszLayers[i] );
+            continue;
+        }
+
+        if( pszWHERE )
+        {
+            if( OGR_L_SetAttributeFilter( hLayer, pszWHERE ) != OGRERR_NONE )
+                break;
+        }
+
+        if( hSpatialFilter != NULL )
+          OGR_L_SetSpatialFilter( hLayer, hSpatialFilter );
+
+        // Fetch the first meaningful SRS definition
+        if ( !pszOutputSRS )
+        {
+            OGRSpatialReferenceH hSRS = OGR_L_GetSpatialRef( hLayer );
+            if ( hSRS )
+                OSRExportToWkt( hSRS, &pszOutputSRS );
+        }
+
+        ProcessLayer( hLayer, hDstDS, nXSize, nYSize,
+                      i + 1 + nBands - nLayerCount,
+                      bIsXExtentSet, bIsYExtentSet,
+                      dfXMin, dfXMax, dfYMin, dfYMax, pszBurnAttribute,
+                      eOutputType, eAlgorithm, pOptions,
+                      bQuiet, pfnProgress );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Apply geotransformation matrix.                                 */
+/* -------------------------------------------------------------------- */
+    double  adfGeoTransform[6];
+    adfGeoTransform[0] = dfXMin;
+    adfGeoTransform[1] = (dfXMax - dfXMin) / nXSize;
+    adfGeoTransform[2] = 0.0;
+    adfGeoTransform[3] = dfYMin;
+    adfGeoTransform[4] = 0.0;
+    adfGeoTransform[5] = (dfYMax - dfYMin) / nYSize;
+    GDALSetGeoTransform( hDstDS, adfGeoTransform );
+
+/* -------------------------------------------------------------------- */
+/*      Apply SRS definition if set.                                    */
+/* -------------------------------------------------------------------- */
+    if ( pszOutputSRS )
+    {
+        GDALSetProjection( hDstDS, pszOutputSRS );
+        CPLFree( pszOutputSRS );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Cleanup                                                         */
+/* -------------------------------------------------------------------- */
+    CSLDestroy( papszCreateOptions );
+    CPLFree( pOptions );
+    OGR_DS_Destroy( hSrcDS );
+    GDALClose( hDstDS );
+#ifndef ZOO_SERVICE
+    CSLDestroy( argv );
+#endif
+    CSLDestroy( papszLayers );
+    OGRCleanupAll();
+
+    GDALDestroyDriverManager();
+ 
+    outputs=(maps*)malloc(sizeof(maps*));
+    outputs->name="OutputedPolygon";
+    outputs->content=createMap("value",(char*)pszDest);
+    addMapToMap(&outputs->content,createMap("dataType","string"));
+    outputs->next=NULL;
+    return SERVICE_SUCCEEDED;
+}
+
+
+#ifdef ZOO_SERVICE
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/ndvi/cgi-env/ExtractNDVI.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/ndvi/cgi-env/ExtractNDVI.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/ndvi/cgi-env/ExtractNDVI.zcfg	(revision 942)
@@ -0,0 +1,58 @@
+[ExtractNDVI]
+ Title = Normalized Difference Vegetation Index. 
+ Abstract = Computes the Normalized Difference Vegetation Index in a new raster file. 
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ndvi
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [raster]
+   Title = The raster file to be used
+   Abstract = URI to a raster file that contains the mentionned two bands.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = image/tiff
+    </Default>
+   </ComplexData>
+  [red]
+   Title = The red band number
+   Abstract = The RED band number to use.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = int
+    <Default>
+     value = 1
+    </Default>
+   </LiteralData>
+  [nir]
+   Title = The NIR band number
+   Abstract = The NIR band number to use.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = int
+    <Default>
+     value = 2
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [raster]
+   Title = The resulting raster
+   Abstract = A single band raster containing the NDVI of the original raster using formula : (NIR - RED) / (NIR + RED) .
+   <ComplexData>
+    <Default>
+     mimeType = image/tiff
+     extension = tif
+    </Default>
+   </ComplexData>
+ </DataOutputs>  
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/ndvi/cgi-env/ndvi.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/ndvi/cgi-env/ndvi.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/ndvi/cgi-env/ndvi.py	(revision 942)
@@ -0,0 +1,107 @@
+#
+# Python Scripting for ArcGIS
+# by Dr Peter Bunting is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License -
+# See more at:
+# http://www.landmap.ac.uk/index.php/Learning-Materials/Python-Scripting/9.4-Calculate-NDVI-using-GDAL
+#
+
+import sys, os, struct
+
+import osgeo.gdal as gdal
+
+# Calculate and output NDVI from raster bands
+def ExtractNDVI(conf, inputs, outputs):
+    
+    # Open the input dataset
+    gdal.FileFromMemBuffer('/vsimem//temp.tif', inputs["raster"]["value"])
+    dataset = gdal.Open( '/vsimem//temp.tif')
+    if dataset is None:
+        conf["lenv"]["message"]="The dataset could not be openned properly"
+        return 4
+
+    # Create the output dataset
+    driver = gdal.GetDriverByName( "GTiff" )
+    # Get the spatial information from the input file
+    geoTransform=None
+    geoProjection=None
+    print >> sys.stderr,dir(dataset) 
+    try:
+        geoTransform = dataset.GetGeoTransform()
+    except:
+        print >> sys.stderr, "Unable to load geotransform"
+    try:
+        geoProjection = dataset.GetProjection()
+    except:
+        print >> sys.stderr, "Unable to load projection"
+
+    # Create an output file of the same size as the inputted 
+    # image but with only 1 output image band.
+    newDataset = driver.Create("/vsimem//output"+conf["lenv"]["sid"], \
+                               dataset.RasterXSize, dataset.RasterYSize,1, \
+                               gdal.GDT_Float32)
+    # Set spatial information of the new image.
+    if geoTransform:
+        newDataset.SetGeoTransform(geoTransform)
+    if geoProjection:
+        newDataset.SetProjection(geoProjection)
+    if newDataset is None:
+        conf["lenv"]["message"]='Could not create output image'
+        return 4
+    
+    # Get the RED and NIR image bands of the image
+    red_id=int(inputs["red"]["value"])
+    nir_id=int(inputs["nir"]["value"])
+    red_band = dataset.GetRasterBand(red_id) # RED BAND
+    nir_band = dataset.GetRasterBand(nir_id) # NIR BAND
+
+    # Loop through each line in turn.
+    numLines = red_band.YSize
+    for line in range(numLines):
+        # Define variable for output line.
+        outputLine = ''
+        # Read in data for the current line from the 
+        # image band representing the red wavelength
+        red_scanline = red_band.ReadRaster( 0, line, red_band.XSize, 1, \
+                                          red_band.XSize, 1, gdal.GDT_Float32 )
+        # Unpack the line of data to be read as floating point data
+        red_tuple = struct.unpack('f' * red_band.XSize, red_scanline)
+            
+        # Read in data for the current line from the 
+        # image band representing the NIR wavelength
+        nir_scanline = nir_band.ReadRaster( 0, line, nir_band.XSize, 1, \
+                                          nir_band.XSize, 1, gdal.GDT_Float32 )
+        # Unpack the line of data to be read as floating point data
+        nir_tuple = struct.unpack('f' * nir_band.XSize, nir_scanline)
+
+        # Loop through the columns within the image
+        for i in range(len(red_tuple)):
+            # Calculate the NDVI for the current pixel.
+            ndvi_lower = (nir_tuple[i] + red_tuple[i])
+            ndvi_upper = (nir_tuple[i] - red_tuple[i])
+            ndvi = 0
+            # Becareful of zero divide 
+            if ndvi_lower == 0:
+                ndvi = 0
+            else:
+                ndvi = ndvi_upper/ndvi_lower
+            # Add the current pixel to the output line
+            outputLine = outputLine + struct.pack('f', ndvi)
+        # Write the completed line to the output image
+        newDataset.GetRasterBand(1).WriteRaster(0, line, red_band.XSize, 1, \
+                                         outputLine, buf_xsize=red_band.XSize, 
+                                         buf_ysize=1, buf_type=gdal.GDT_Float32)
+    
+        # Delete the output line following write
+        del outputLine
+    print >> sys.stderr,'NDVI Calculated and Outputted to File'
+    print >> sys.stderr,dir(newDataset)
+    newDataset.FlushCache()
+    vsiFile=gdal.VSIFOpenL("/vsimem//output"+conf["lenv"]["sid"],"r")
+    i=0
+    while gdal.VSIFSeekL(vsiFile,0,os.SEEK_END)>0:
+        i+=1
+    fileSize=gdal.VSIFTellL(vsiFile)
+    gdal.VSIFSeekL(vsiFile,0,os.SEEK_SET)
+    outputs["raster"]["value"]=gdal.VSIFReadL(fileSize,1,vsiFile)
+    gdal.Unlink("/vsimem//output"+conf["lenv"]["sid"])
+    return 3
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/Makefile	(revision 942)
@@ -0,0 +1,15 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/profile_service.zo: service.c
+	g++  -DZOO_SERVICE ${CFLAGS} -shared -fpic -o cgi-env/profile_service.zo ./service.c ${GDAL_LIBS} ${MACOS_LD_FLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}/gdal/profile
+	install cgi-env/* ${CGI_DIR}/gdal/profile
+
+
+clean:
+	rm -f cgi-env/*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/cgi-env/GdalExtractProfile.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/cgi-env/GdalExtractProfile.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/cgi-env/GdalExtractProfile.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[GdalExtractProfile]
+ Title = Extract elevation values along a line. 
+ Abstract = Fetch the x,y,z values of a DEM raster file along a linestring
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = profile_service.zo
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [RasterFile]
+   Title = The name of the MNT file
+   Abstract = The file containing elevation model relative to the dataPath defined in the ZOO-Project main configuration file.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = topofr.tif
+    </Default>
+   </LiteralData>
+  [Geometry]
+   Title = The path to calaculate profile
+   Abstract = The input data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+     asReference = true	
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Profile]
+   Title = The resulting profile
+   Abstract = GeoJSON string containing the X Y Z values where (X,Y) is corresponding to the original coordinates and the elevation value. 
+   <ComplexData>
+    <Default>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/makefile.vc	(revision 942)
@@ -0,0 +1,11 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+cgi-env/profile_service.zo: service.c
+	$(CPP)  /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE -I$(GDAL_DIR)/frmts/ $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/profile_service.zo  $(FILES) ./service.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\profile_service.*
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/profile/service.c	(revision 942)
@@ -0,0 +1,194 @@
+/* ****************************************************************************
+ * $Id$
+ *
+ * Project:  GdalExtractProfile
+ * Purpose:  Extract Profile from a Raster file for an Input Geometry (LINE)
+ * Author:   Gérald Fenoy, gerald.fenoy@geolabs.fr
+ *
+ * ****************************************************************************
+ * Copyright (c) 2010-2011, GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#ifdef ZOO_SERVICE
+#include "service.h"
+#include "service_internal.h"
+#endif
+#include "gdal.h"
+#include "cpl_conv.h"
+#include "ogr_api.h"
+
+#ifdef ZOO_SERVICE
+extern "C" {
+#endif
+
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+#ifdef ZOO_SERVICE
+int GdalExtractProfile(maps*& conf,maps*& inputs,maps*& outputs)
+#else
+int main(int argc,char** argv)
+#endif
+{
+  char *pszFilename;
+#ifdef ZOO_SERVICE
+  map* tmp=NULL;
+  map* tmp1=NULL;
+  tmp=getMapFromMaps(conf,"main","dataPath");
+  tmp1=getMapFromMaps(inputs,"RasterFile","value");
+  pszFilename=(char *)malloc((2+strlen(tmp->value)+strlen(tmp1->value))*sizeof(char));
+  sprintf(pszFilename,"%s/%s",tmp->value,tmp1->value);
+#else
+  pszFilename=argv[1];
+#endif
+  GDALDatasetH  hDataset;  
+  GDALAllRegister();
+  OGRRegisterAll();
+ 
+  hDataset = GDALOpen( pszFilename, GA_ReadOnly );
+  free(pszFilename);
+  if( hDataset != NULL )
+    {
+      GDALDriverH   hDriver;
+      double        adfGeoTransform[6];
+
+      if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None )
+	{
+
+
+        GDALRasterBandH hBand;
+        int             nBlockXSize, nBlockYSize;
+        int             bGotMin, bGotMax;
+        double          adfMinMax[2];
+        
+        hBand = GDALGetRasterBand( hDataset, 1 );
+
+        adfMinMax[0] = GDALGetRasterMinimum( hBand, &bGotMin );
+        adfMinMax[1] = GDALGetRasterMaximum( hBand, &bGotMax );
+        if( ! (bGotMin && bGotMax) )
+	  GDALComputeRasterMinMax( hBand, TRUE, adfMinMax );
+#ifdef ZOO_SERVICE
+	  tmp1=getMapFromMaps(inputs,"Geometry","value");
+	  OGRGeometryH geometry=OGR_G_CreateGeometryFromJson(tmp1->value);
+#else
+	  OGRGeometryH geometry=OGR_G_CreateGeometryFromJson(argv[2]);
+#endif
+
+	  OGR_G_Segmentize(geometry, adfGeoTransform[1]);
+	  int nbGeom=OGR_G_GetPointCount(geometry);
+	  int k=0;
+	  double ppx=0,ppy=0;
+	  double value;
+	  char *buffer=NULL;
+	  int length=0;
+	  buffer=(char*)malloc(37*sizeof(char));
+	  sprintf(buffer,"{\"type\":\"LineString\",\"coordinates\":[");
+	  length+=strlen(buffer);
+	  for(k=0;k<nbGeom;k++){
+	    //OGRGeometryH point;
+	    double prx,pry,prz;
+	    OGR_G_GetPoint(geometry,k,&prx,&pry,&prz);
+	    float *pafScanline;
+	    pafScanline = (float *) CPLMalloc(sizeof(float));
+	    int px=(int)floor((prx-adfGeoTransform[0])/adfGeoTransform[1]);
+	    int py=(int)floor((pry-adfGeoTransform[3])/adfGeoTransform[5]);
+	    if(px!=ppx || py!=ppy){
+	      if(GDALRasterIO( hBand, GF_Read, px, py, 1, 1, 
+			    pafScanline, 1, 1, GDT_Float32, 
+			       0, 0 ) != CE_None){
+		char *tmp;
+		tmp=(char*) malloc(300*sizeof(char));
+		sprintf(tmp,"GDALRasterIO failed for point (%d,%d)",px,py);
+		setMapInMaps(conf,"lenv","message",_ss(tmp));
+		CPLFree(pafScanline);
+		free(tmp);
+		return SERVICE_FAILED;
+	      }
+	      if(buffer!=NULL){
+		int len=strlen(buffer);
+		buffer=(char*)realloc(buffer,(len+50+1)*sizeof(char));
+	      }
+	      else
+		buffer=(char*)malloc((51)*sizeof(char));
+	      char *tmpValue=(char *)malloc(50*sizeof(char));
+	      sprintf(tmpValue,"[%.6f,%.6f,%.6f]%c",prx,pry,pafScanline[0],(k+1==nbGeom?' ':','));
+	      strncpy(buffer+length,tmpValue,strlen(tmpValue));
+	      length+=strlen(tmpValue);
+	      buffer[length]=0;
+	      value=pafScanline[0];
+	      free(tmpValue);
+	      //Usefull if we can export 3D JSON string at the end
+	      //OGR_G_SetPoint(geometry,k,prx,pry,pafScanline[0]);	      
+	    }
+	    else{
+	      if(buffer!=NULL)
+		buffer=(char*)realloc(buffer,(strlen(buffer)+50+1)*sizeof(char));
+	      else
+		buffer=(char*)malloc((51)*sizeof(char));
+	      char *tmpValue=(char *)malloc(50*sizeof(char));
+	      sprintf(tmpValue,"[%.6f,%.6f,%.6f]%c",prx,pry,value,(k+1==nbGeom?' ':','));
+	      strncpy(buffer+length,tmpValue,strlen(tmpValue));
+	      length+=strlen(tmpValue);
+	      buffer[length]=0;
+	      free(tmpValue);
+	      value=value;
+	    }
+	    CPLFree(pafScanline);
+	    ppx=px;
+	    ppy=py;
+	  }
+	  buffer=(char*)realloc(buffer,(strlen(buffer)+3)*sizeof(char));
+	  char *tmpValue=(char *)malloc(3*sizeof(char));
+	  sprintf(tmpValue,"]}");
+	  tmpValue[2]=0;
+	  strncpy(buffer+length,tmpValue,strlen(tmpValue));
+	  length+=strlen(tmpValue);
+	  buffer[length]=0;
+#ifdef ZOO_SERVICE
+	  setMapInMaps(outputs,"Profile","value",buffer);
+	  setMapInMaps(outputs,"Profile","mimeType","text/plain");
+#else
+	  fprintf(stderr,"%s\n",buffer);
+#endif
+	  free(buffer);
+	  free(tmpValue);
+	  OGR_G_DestroyGeometry(geometry);
+	}
+    }
+  else{
+#ifdef ZOO_SERVICE
+    setMapInMaps(conf,"lenv","message",_ss("Unable to load your raster file !"));
+    return SERVICE_FAILED;
+#else
+    printf("Unable to load your raster file %s !\n",argv[1]);
+#endif
+  }
+  OGRCleanupAll();
+  GDALClose(hDataset);
+  GDALDestroyDriverManager();
+#ifdef ZOO_SERVICE
+  return SERVICE_SUCCEEDED;
+#endif
+}
+
+#ifdef ZOO_SERVICE
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/Makefile	(revision 942)
@@ -0,0 +1,16 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/translate_service.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/translate_service.zo ./service.c ${GDAL_LIBS} ${MACOS_LD_FLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}/gdal/translate
+	install cgi-env/* ${CGI_DIR}/gdal/translate
+
+
+
+clean:
+	rm -f cgi-env/*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/cgi-env/Gdal_Translate.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/cgi-env/Gdal_Translate.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/cgi-env/Gdal_Translate.zcfg	(revision 942)
@@ -0,0 +1,61 @@
+[Gdal_Translate]
+ Title = Convert raster data from one format to another. 
+ Abstract = http://www.gdal.org/gdal_translate.html
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = translate_service.zo
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [Format]
+   Title = Format of the output data
+   Abstract = Select the output format by usig short name of the format (use gda-config --formats for list of available formats on your platform).
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = GTiff
+    </Default>
+   </LiteralData>
+  [GCP]
+   Title = Ground Point Control
+   Abstract = Ground Point Control in the form : pixel,line,eating,northing(,elev).
+   minOccurs = 0
+   maxOccurs = unbounded
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [InputDSN]
+   Title = The input data source name
+   Abstract = The input data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [OutputDSN]
+   Title = The output data source name
+   Abstract = The output data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/makefile.vc	(revision 942)
@@ -0,0 +1,11 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+cgi-env/translate_service.zo: service.c
+	$(CPP)  /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE -I$(GDAL_DIR)/frmts/vrt $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/translate_service.zo  $(FILES) ./service.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\translate_service.*
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/translate/service.c	(revision 942)
@@ -0,0 +1,925 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  GDAL Utilities
+ * Purpose:  GDAL Image Translator Program
+ * Author:   Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 1998, 2002, Frank Warmerdam
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "cpl_vsi.h"
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "gdal_priv.h"
+#include "ogr_spatialref.h"
+#include "vrtdataset.h"
+
+#include "service.h"
+
+CPL_CVSID("$Id$");
+
+extern "C" {
+
+  static void AttachMetadata( GDALDatasetH, char ** );
+  static int bSubCall = FALSE;
+
+  /************************************************************************/
+  /*                          Gdal_Translate()                            */
+  /************************************************************************/
+
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+  int Gdal_Translate(maps*& conf,maps*& inputs,maps*& outputs)
+  {
+
+
+    GDALDatasetH	hDataset, hOutDS;
+    int			i;
+    int			nRasterXSize, nRasterYSize;
+    const char		*pszSource=NULL, *pszDest=NULL, *pszFormat = "GTiff";
+    GDALDriverH		hDriver;
+    int			*panBandList = NULL, nBandCount = 0, bDefBands = TRUE;
+    double		adfGeoTransform[6];
+    GDALDataType	eOutputType = GDT_Unknown;
+    int			nOXSize = 0, nOYSize = 0;
+    char		*pszOXSize=NULL, *pszOYSize=NULL;
+    char                **papszCreateOptions = NULL;
+    int                 anSrcWin[4], bStrict = FALSE;
+    const char          *pszProjection;
+    int                 bScale = FALSE, bHaveScaleSrc = FALSE;
+    double	        dfScaleSrcMin=0.0, dfScaleSrcMax=255.0;
+    double              dfScaleDstMin=0.0, dfScaleDstMax=255.0;
+    double              dfULX, dfULY, dfLRX, dfLRY;
+    char                **papszMetadataOptions = NULL;
+    char                *pszOutputSRS = NULL;
+    int                 bQuiet = TRUE, bGotBounds = FALSE;
+    GDALProgressFunc    pfnProgress = GDALDummyProgress;
+    int                 nGCPCount = 0;
+    GDAL_GCP            *pasGCPs = NULL;
+    int                 iSrcFileArg = -1, iDstFileArg = -1;
+    int                 bCopySubDatasets = FALSE;
+    double              adfULLR[4] = { 0,0,0,0 };
+    int                 bSetNoData = FALSE;
+    double		dfNoDataReal = 0.0;
+    int                 nRGBExpand = 0;
+
+    anSrcWin[0] = 0;
+    anSrcWin[1] = 0;
+    anSrcWin[2] = 0;
+    anSrcWin[3] = 0;
+
+    dfULX = dfULY = dfLRX = dfLRY = 0.0;
+
+    /* ----------------------------------------------------------------- */
+    /*      Register standard GDAL drivers, and process generic GDAL     */
+    /* ----------------------------------------------------------------- */
+    GDALAllRegister();
+    /* ----------------------------------------------------------------- */
+    /* Extract Format, InputDSN, OutputDSN parameters                    */
+    /* ----------------------------------------------------------------- */
+
+    map* tmpMap=NULL;
+
+    char dataPath[1024];
+    tmpMap=getMapFromMaps(conf,"main","dataPath");
+    if(tmpMap!=NULL)
+      sprintf(dataPath,"%s",tmpMap->value);
+    tmpMap=NULL;
+
+    char tempPath[1024];
+    tmpMap=getMapFromMaps(conf,"main","tmpPath");
+    if(tmpMap!=NULL){
+      sprintf(tempPath,"%s",tmpMap->value);
+    }
+    tmpMap=NULL;
+
+    tmpMap=getMapFromMaps(inputs,"Format","value");
+    if(tmpMap!=NULL){
+      pszFormat=tmpMap->value;
+    }
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"InputDSN","value");
+    if(tmpMap!=NULL){
+      pszSource=(char*)CPLMalloc(sizeof(char)*(strlen(dataPath)+strlen(tmpMap->value)+4));
+      sprintf((char*)pszSource,"%s/%s",dataPath,tmpMap->value);
+    }
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"OutputDSN","value");
+    if(tmpMap!=NULL){
+      pszDest=(char*)CPLMalloc(sizeof(char)*(strlen(tempPath)+strlen(tmpMap->value)+4));
+      char *ext=new char[4];
+      ext="tif";
+      if(strncasecmp(pszFormat,"AAIGRID",7)==0)
+	ext="csv";
+      else 
+	if(strncasecmp(pszFormat,"PNG",3)==0)
+	  ext="png";
+	else
+	  if(strncasecmp(pszFormat,"GIF",3)==0)
+	    ext="gif";
+	  else
+	    if(strncasecmp(pszFormat,"JPEG",4)==0)
+	      ext="jpg";
+      sprintf((char*)pszDest,"%s/%s.%s",tempPath,tmpMap->value,ext);
+      fprintf(stderr,"DEBUG pszDest : %s\n",pszDest);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"SrcWin","value");
+    if(tmpMap!=NULL){
+      char *tmp=tmpMap->value;
+      char *t=strtok(tmp,",");
+      int cnt=0;
+      while(t!=NULL){
+	anSrcWin[cnt] = atoi(t);
+	t=strtok(NULL,",");
+	cnt++;
+      }
+    }   
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"ProjWin","value");
+    if(tmpMap!=NULL){
+      char *tmp=tmpMap->value;
+      char *t=strtok(tmp,",");
+      int cnt=0;
+      while(t!=NULL){
+	switch(cnt){
+	case 0:
+	  dfULX = atof(t);
+	  break;
+	case 1:
+	  dfULY = atof(t);
+	  break;
+	case 2:
+	  dfLRX = atof(t);
+	  break;
+	case 3:
+	  dfLRY = atof(t);
+	  break;
+	}
+	t=strtok(NULL,",");
+	cnt++;
+      }
+    }
+
+    fprintf(stderr,"DEBUG pszDest : %s %d\n",pszDest,__LINE__);
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"GCP","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      map* length=getMapFromMaps(inputs,"GCP","length");
+      int len=0;
+      if(length){
+	len=atoi(length->value);
+	int i;
+	maps* currentMaps=getMaps(inputs,"GCP");
+	for(i=0;i<len;i++){
+	  char* endptr = NULL;
+	  /* -gcp pixel line easting northing [elev] */
+	  
+	  nGCPCount++;
+	  pasGCPs = (GDAL_GCP *) 
+	    realloc( pasGCPs, sizeof(GDAL_GCP) * nGCPCount );
+	  GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 );
+
+	  map* currentMap=getMapArray(currentMaps->content,"value",i);
+
+	  char* tmpV=strdup(currentMap->value);
+	  char *res=strtok(tmpV,",");
+	  int j=0;
+	  while(res!=NULL){
+	    switch(j){
+	    case 0:
+	      pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtofM(res);
+	      break;
+	    case 1:
+	      pasGCPs[nGCPCount-1].dfGCPLine = CPLAtofM(res);
+	      break;
+	    case 2:
+	      pasGCPs[nGCPCount-1].dfGCPX = CPLAtofM(res);
+	      break;
+	    case 3:
+	      pasGCPs[nGCPCount-1].dfGCPY = CPLAtofM(res);
+	      break;
+	    case 4:
+	      if(res!=NULL && (strtod(res, &endptr) != 0.0 || res[0] == '0'))
+		if (endptr && *endptr == 0)
+		  pasGCPs[nGCPCount-1].dfGCPZ = CPLAtofM(res);
+	      break;
+	    }
+	    res=strtok(NULL,",");
+	    j++;
+	  }
+	}
+      }else{
+	char* endptr = NULL;
+	/* -gcp pixel line easting northing [elev] */
+	
+	nGCPCount++;
+	pasGCPs = (GDAL_GCP *) 
+	  realloc( pasGCPs, sizeof(GDAL_GCP) * nGCPCount );
+	GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 );
+	
+	char* tmpV=strdup(tmpMap->value);
+	char *res=strtok(tmpV,",");
+	int j=0;
+	while(res!=NULL){
+	  switch(j){
+	  case 0:
+	    pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtofM(res);
+	    break;
+	  case 1:
+	    pasGCPs[nGCPCount-1].dfGCPLine = CPLAtofM(res);
+	    break;
+	  case 2:
+	    pasGCPs[nGCPCount-1].dfGCPX = CPLAtofM(res);
+	    break;
+	  case 3:
+	    pasGCPs[nGCPCount-1].dfGCPY = CPLAtofM(res);
+	    break;
+	  case 4:
+	    if(res!=NULL && (CPLStrtod(res, &endptr) != 0.0 || res[0] == '0'))
+	      if (endptr && *endptr == 0)
+		pasGCPs[nGCPCount-1].dfGCPZ = CPLAtofM(res);
+	    break;
+	  }	    
+	  res=strtok(NULL,",");
+	  j++;
+	}
+      }
+    }
+
+    fprintf(stderr,"DEBUG pszDest : %s %d\n",pszDest,__LINE__);
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"SRS","value");
+    if(tmpMap!=NULL){
+      OGRSpatialReference oOutputSRS;
+      if( oOutputSRS.SetFromUserInput( tmpMap->value ) != OGRERR_NONE )
+	{
+	  char *msg=(char*)CPLMalloc(100*sizeof(char));
+	  sprintf( msg, "Failed to process SRS definition: %s\n", 
+		   tmpMap->value );
+	  setMapInMaps(conf,"lenv","message",msg);
+	  /**
+	   * Avoiding GDALDestroyDriverManager() call
+	   */
+	  return SERVICE_FAILED;
+	}
+      oOutputSRS.exportToWkt( &pszOutputSRS );
+    }
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"Type","value");
+    if(tmpMap!=NULL){
+      int	iType;
+      
+      for( iType = 1; iType < GDT_TypeCount; iType++ )
+	{
+	  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
+	      && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
+		       tmpMap->value) )
+	    {
+	      eOutputType = (GDALDataType) iType;
+	    }
+	}
+      
+      if( eOutputType == GDT_Unknown )
+	{
+	  printf( "Unknown output pixel type: %s\n", tmpMap->value );
+	  /**
+	   * Avoiding GDALDestroyDriverManager() call
+	   */
+	  exit( 2 );
+	}
+    }
+
+    fprintf(stderr,"DEBUG pszDest : %s %d\n",pszDest,__LINE__);
+    if( pszDest == NULL ){
+	fprintf(stderr,"exit line 416");
+	fflush(stderr);
+	/**
+	 * Avoiding GDALDestroyDriverManager() call
+	 */
+        exit( 10 );
+      }
+
+    fprintf(stderr,"DEBUG pszDest : %s %d\n",pszDest,__LINE__);
+    if ( strcmp(pszSource, pszDest) == 0)
+      {
+        fprintf(stderr, "Source and destination datasets must be different.\n");
+	fflush(stderr);
+	/**
+	 * Avoiding GDALDestroyDriverManager() call
+	 */
+        exit( 1 );
+      }
+
+    fprintf(stderr,"DEBUG pszDest : %s %d\n",pszDest,__LINE__);
+    /* ----------------------------------------------------------------- */
+    /*      Attempt to open source file.                                 */
+    /* ----------------------------------------------------------------- */
+
+    hDataset = GDALOpenShared( pszSource, GA_ReadOnly );
+    fprintf(stderr,"DEBUG pszDest : %s %d\n",pszDest,__LINE__);
+    
+    if( hDataset == NULL ){
+      char *msg=(char*) CPLMalloc(1024*sizeof(char));
+      sprintf( msg,
+	       "GDALOpen failed - %d\n%s\n",
+	       CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
+      setMapInMaps(conf,"lenv","message",msg);
+      return SERVICE_FAILED;
+    }
+
+    fprintf(stderr,"DEBUG pszDest : %s %d\n",pszDest,__LINE__);
+    /* ----------------------------------------------------------------- */
+    /*      Handle subdatasets.                                          */
+    /* ----------------------------------------------------------------- */
+    if( !bCopySubDatasets 
+        && CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0 
+        && GDALGetRasterCount(hDataset) == 0 )
+      {
+	char *msg=(char*) CPLMalloc(1024*sizeof(char));
+        sprintf( msg,
+                 "Input file contains subdatasets. Please, select one of them for reading.\n" );
+	setMapInMaps(conf,"lenv","message",msg);
+        GDALClose( hDataset );
+	/**
+	 * Avoiding GDALDestroyDriverManager() call
+	 */
+        exit( 1 );
+      }
+
+    if( CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0 
+        && bCopySubDatasets )
+      {
+        char **papszSubdatasets = GDALGetMetadata(hDataset,"SUBDATASETS");
+        char *pszSubDest = (char *) CPLMalloc(strlen(pszDest)+32);
+        int i;
+        int bOldSubCall = bSubCall;
+        
+        //argv[iDstFileArg] = pszSubDest;
+        bSubCall = TRUE;
+        for( i = 0; papszSubdatasets[i] != NULL; i += 2 )
+	  {
+            //argv[iSrcFileArg] = strstr(papszSubdatasets[i],"=")+1;
+            sprintf( pszSubDest, "%s%d", pszDest, i/2 + 1 );
+            /*if( ProxyMain( argc, argv ) != 0 )
+	      break;*/
+	  }
+        
+        bSubCall = bOldSubCall;
+        free( pszSubDest );
+
+        GDALClose( hDataset );
+
+        if( !bSubCall )
+	  {
+            GDALDumpOpenDatasets( stderr );
+	    fflush(stderr);
+	    /**
+	     * Avoiding GDALDestroyDriverManager() call
+	     */
+	  }
+        return 1;
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*      Collect some information from the source file.               */
+    /* ----------------------------------------------------------------- */
+    nRasterXSize = GDALGetRasterXSize( hDataset );
+    nRasterYSize = GDALGetRasterYSize( hDataset );
+
+    if( !bQuiet )
+      fprintf( stderr, "Input file size is %d, %d\n", nRasterXSize, nRasterYSize );
+
+    if( anSrcWin[2] == 0 && anSrcWin[3] == 0 ){
+        anSrcWin[2] = nRasterXSize;
+        anSrcWin[3] = nRasterYSize;
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*	Build band list to translate	                                 */
+    /* ----------------------------------------------------------------- */
+    if( nBandCount == 0 ){
+        nBandCount = GDALGetRasterCount( hDataset );
+        if( nBandCount == 0 ){
+            fprintf( stderr, "Input file has no bands, and so cannot be translated.\n" );
+	    fflush(stderr);
+	    /**
+	     * Avoiding GDALDestroyDriverManager() call
+	     */
+            exit(1 );
+	  }
+
+        panBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
+        for( i = 0; i < nBandCount; i++ )
+	  panBandList[i] = i+1;
+      }
+    else
+      {
+        for( i = 0; i < nBandCount; i++ )
+	  {
+            if( panBandList[i] < 1 || panBandList[i] > GDALGetRasterCount(hDataset) )
+	      {
+                fprintf( stderr, 
+                         "Band %d requested, but only bands 1 to %d available.\n",
+                         panBandList[i], GDALGetRasterCount(hDataset) );
+		fflush(stderr);
+		/**
+		 * Avoiding GDALDestroyDriverManager() call
+		 */
+                exit( 2 );
+	      }
+	  }
+
+        if( nBandCount != GDALGetRasterCount( hDataset ) )
+	  bDefBands = FALSE;
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*   Compute the source window from the projected source window      */
+    /*   if the projected coordinates were provided.  Note that the      */
+    /*   projected coordinates are in ulx, uly, lrx, lry format,         */
+    /*   while the anSrcWin is xoff, yoff, xsize, ysize with the         */
+    /*   xoff,yoff being the ulx, uly in pixel/line.                     */
+    /* ----------------------------------------------------------------- */
+    if( dfULX != 0.0 || dfULY != 0.0 
+        || dfLRX != 0.0 || dfLRY != 0.0 )
+      {
+        double	adfGeoTransform[6];
+
+        GDALGetGeoTransform( hDataset, adfGeoTransform );
+
+        if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 ){
+            fprintf( stderr, 
+                     "The -projwin option was used, but the geotransform is\n"
+                     "rotated.  This configuration is not supported.\n" );
+            GDALClose( hDataset );
+            free( panBandList );
+	    fflush(stderr);
+	    /**
+	     * Avoiding GDALDestroyDriverManager() call
+	     */
+            exit( 1 );
+	  }
+
+        anSrcWin[0] = (int) 
+	  ((dfULX - adfGeoTransform[0]) / adfGeoTransform[1] + 0.001);
+        anSrcWin[1] = (int) 
+	  ((dfULY - adfGeoTransform[3]) / adfGeoTransform[5] + 0.001);
+
+        anSrcWin[2] = (int) ((dfLRX - dfULX) / adfGeoTransform[1] + 0.5);
+        anSrcWin[3] = (int) ((dfLRY - dfULY) / adfGeoTransform[5] + 0.5);
+
+        if( !bQuiet )
+	  fprintf( stdout, 
+		   "Computed -srcwin %d %d %d %d from projected window.\n",
+		   anSrcWin[0], 
+		   anSrcWin[1], 
+		   anSrcWin[2], 
+		   anSrcWin[3] );
+        
+        if( anSrcWin[0] < 0 || anSrcWin[1] < 0 
+            || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset) 
+            || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset) )
+	  {
+            fprintf( stderr, 
+                     "Computed -srcwin falls outside raster size of %dx%d.\n",
+                     GDALGetRasterXSize(hDataset), 
+                     GDALGetRasterYSize(hDataset) );
+            exit( 1 );
+	  }
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*      Verify source window.                                        */
+    /* ----------------------------------------------------------------- */
+    if( anSrcWin[0] < 0 || anSrcWin[1] < 0 
+        || anSrcWin[2] <= 0 || anSrcWin[3] <= 0
+        || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset) 
+        || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset) )
+      {
+        fprintf( stderr, 
+                 "-srcwin %d %d %d %d falls outside raster size of %dx%d\n"
+                 "or is otherwise illegal.\n",
+                 anSrcWin[0],
+                 anSrcWin[1],
+                 anSrcWin[2],
+                 anSrcWin[3],
+                 GDALGetRasterXSize(hDataset), 
+                 GDALGetRasterYSize(hDataset) );
+        exit( 1 );
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*      Find the output driver.                                      */
+    /* ----------------------------------------------------------------- */
+    hDriver = GDALGetDriverByName( pszFormat );
+    if( hDriver == NULL )
+      {
+        int	iDr;
+        
+	char* msg=(char*) CPLMalloc(4096*sizeof(char));
+	sprintf(msg,"Output driver `%s' not recognised.\nThe following format drivers are configured and support output:\n",pszFormat);
+        for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
+	  {
+            GDALDriverH hDriver = GDALGetDriver(iDr);
+
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
+                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
+                                        NULL ) != NULL )
+	      {
+		fprintf(stderr,msg);
+		char *tmp=strdup(msg);
+                sprintf( msg,"%s  %s: %s\n",tmp,
+                        GDALGetDriverShortName( hDriver  ),
+                        GDALGetDriverLongName( hDriver ) );
+		free(tmp);
+	      }
+	  }
+	setMapInMaps(conf,"lenv","message",msg);
+        GDALClose( hDataset );
+        free( panBandList );
+	fflush(stderr);
+	/**
+	 * Avoiding GDALDestroyDriverManager() call
+	 */
+        CSLDestroy( papszCreateOptions );
+        return 4;
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*   The short form is to CreateCopy().  We use this if the input    */
+    /*   matches the whole dataset.  Eventually we should rewrite        */
+    /*   this entire program to use virtual datasets to construct a      */
+    /*   virtual input source to copy from.                              */
+    /* ----------------------------------------------------------------- */
+    int bSpatialArrangementPreserved = (
+           anSrcWin[0] == 0 && anSrcWin[1] == 0
+        && anSrcWin[2] == GDALGetRasterXSize(hDataset)
+        && anSrcWin[3] == GDALGetRasterYSize(hDataset)
+        && pszOXSize == NULL && pszOYSize == NULL );
+
+    if( eOutputType == GDT_Unknown 
+        && !bScale && CSLCount(papszMetadataOptions) == 0 && bDefBands 
+        && bSpatialArrangementPreserved
+        && nGCPCount == 0 && !bGotBounds
+        && pszOutputSRS == NULL && !bSetNoData
+        && nRGBExpand == 0)
+      {
+        
+        hOutDS = GDALCreateCopy( hDriver, pszDest, hDataset, 
+                                 FALSE, (char**)0, 
+                                 pfnProgress, NULL );
+
+        if( hOutDS != NULL )
+	  GDALClose( hOutDS );
+        
+        GDALClose( hDataset );
+
+        free( panBandList );
+
+        if( !bSubCall )
+	  {
+            GDALDumpOpenDatasets( stderr );
+	    /**
+	     * Avoiding GDALDestroyDriverManager() call
+	     */
+	  }
+	fprintf(stderr,"==%s %s %s %d==\n",pszFormat,pszSource,pszDest,__LINE__);
+	fflush(stderr);
+
+        CSLDestroy( papszCreateOptions );
+	fprintf(stderr,"==%s %s %s %d==\n",pszFormat,pszSource,pszDest,__LINE__);
+	fflush(stderr);
+	//outputs=(maps*)CPLMalloc(sizeof(maps*));
+	//outputs->name="OutputedPolygon";
+	//outputs->content=createMap("value",(char*)pszDest);
+	//outputs->next=NULL;
+	dumpMaps(outputs);
+	setMapInMaps(outputs,"Result","value",(char*)pszDest);
+	return SERVICE_SUCCEEDED;
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*      Establish some parameters.                                   */
+    /* ----------------------------------------------------------------- */
+    if( pszOXSize == NULL )
+      {
+        nOXSize = anSrcWin[2];
+        nOYSize = anSrcWin[3];
+      }
+    else
+      {
+        nOXSize = (int) ((pszOXSize[strlen(pszOXSize)-1]=='%' 
+                          ? atof(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
+        nOYSize = (int) ((pszOYSize[strlen(pszOYSize)-1]=='%' 
+                          ? atof(pszOYSize)/100*anSrcWin[3] : atoi(pszOYSize)));
+      }
+
+    /* ================================================================= */
+    /*      Create a virtual dataset.                                    */
+    /* ================================================================= */
+    VRTDataset *poVDS;
+        
+    /* ----------------------------------------------------------------- */
+    /*      Make a virtual clone.                                        */
+    /* ----------------------------------------------------------------- */
+    poVDS = (VRTDataset *) VRTCreate( nOXSize, nOYSize );
+
+    if( nGCPCount == 0 )
+      {
+        if( pszOutputSRS != NULL )
+	  {
+            poVDS->SetProjection( pszOutputSRS );
+	  }
+        else
+	  {
+            pszProjection = GDALGetProjectionRef( hDataset );
+            if( pszProjection != NULL && strlen(pszProjection) > 0 )
+	      poVDS->SetProjection( pszProjection );
+	  }
+      }
+
+    if( bGotBounds )
+      {
+        adfGeoTransform[0] = adfULLR[0];
+        adfGeoTransform[1] = (adfULLR[2] - adfULLR[0]) / nOXSize;
+        adfGeoTransform[2] = 0.0;
+        adfGeoTransform[3] = adfULLR[1];
+        adfGeoTransform[4] = 0.0;
+        adfGeoTransform[5] = (adfULLR[3] - adfULLR[1]) / nOYSize;
+
+        poVDS->SetGeoTransform( adfGeoTransform );
+      }
+
+    else if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None 
+	     && nGCPCount == 0 )
+      {
+        adfGeoTransform[0] += anSrcWin[0] * adfGeoTransform[1]
+	  + anSrcWin[1] * adfGeoTransform[2];
+        adfGeoTransform[3] += anSrcWin[0] * adfGeoTransform[4]
+	  + anSrcWin[1] * adfGeoTransform[5];
+        
+        adfGeoTransform[1] *= anSrcWin[2] / (double) nOXSize;
+        adfGeoTransform[2] *= anSrcWin[3] / (double) nOYSize;
+        adfGeoTransform[4] *= anSrcWin[2] / (double) nOXSize;
+        adfGeoTransform[5] *= anSrcWin[3] / (double) nOYSize;
+        
+        poVDS->SetGeoTransform( adfGeoTransform );
+      }
+
+    if( nGCPCount != 0 )
+      {
+        const char *pszGCPProjection = pszOutputSRS;
+
+        if( pszGCPProjection == NULL )
+	  pszGCPProjection = GDALGetGCPProjection( hDataset );
+        if( pszGCPProjection == NULL )
+	  pszGCPProjection = "";
+
+        poVDS->SetGCPs( nGCPCount, pasGCPs, pszGCPProjection );
+
+        GDALDeinitGCPs( nGCPCount, pasGCPs );
+        free( pasGCPs );
+      }
+
+    else if( GDALGetGCPCount( hDataset ) > 0 )
+      {
+        GDAL_GCP *pasGCPs;
+        int       nGCPs = GDALGetGCPCount( hDataset );
+
+        pasGCPs = GDALDuplicateGCPs( nGCPs, GDALGetGCPs( hDataset ) );
+
+        for( i = 0; i < nGCPs; i++ )
+	  {
+            pasGCPs[i].dfGCPPixel -= anSrcWin[0];
+            pasGCPs[i].dfGCPLine  -= anSrcWin[1];
+            pasGCPs[i].dfGCPPixel *= (nOXSize / (double) anSrcWin[2] );
+            pasGCPs[i].dfGCPLine  *= (nOYSize / (double) anSrcWin[3] );
+	  }
+            
+        poVDS->SetGCPs( nGCPs, pasGCPs,
+                        GDALGetGCPProjection( hDataset ) );
+
+        GDALDeinitGCPs( nGCPs, pasGCPs );
+        free( pasGCPs );
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*      Transfer generally applicable metadata.                      */
+    /* ----------------------------------------------------------------- */
+    poVDS->SetMetadata( ((GDALDataset*)hDataset)->GetMetadata() );
+    AttachMetadata( (GDALDatasetH) poVDS, papszMetadataOptions );
+
+    /* ----------------------------------------------------------------- */
+    /*      Transfer metadata that remains valid if the spatial          */
+    /*      arrangement of the data is unaltered.                        */
+    /* ----------------------------------------------------------------- */
+    if( anSrcWin[0] == 0 && anSrcWin[1] == 0 
+        && anSrcWin[2] == GDALGetRasterXSize(hDataset)
+        && anSrcWin[3] == GDALGetRasterYSize(hDataset) 
+        && pszOXSize == NULL && pszOYSize == NULL )
+      {
+        char **papszMD;
+
+        papszMD = ((GDALDataset*)hDataset)->GetMetadata("RPC");
+        if( papszMD != NULL )
+	  poVDS->SetMetadata( papszMD, "RPC" );
+      }
+
+    if (nRGBExpand != 0)
+      nBandCount += nRGBExpand - 1;
+
+    /* ================================================================= */
+    /*      Process all bands.                                           */
+    /* ================================================================= */
+    for( i = 0; i < nBandCount; i++ )
+      {
+        VRTSourcedRasterBand   *poVRTBand;
+        GDALRasterBand  *poSrcBand;
+        GDALDataType    eBandType;
+
+        if (nRGBExpand != 0 && i < nRGBExpand)
+	  {
+            poSrcBand = ((GDALDataset *) 
+			 hDataset)->GetRasterBand(panBandList[0]);
+            if (poSrcBand->GetColorTable() == NULL)
+	      {
+                fprintf(stderr, "Error : band %d has no color table\n", panBandList[0]);
+                GDALClose( hDataset );
+                free( panBandList );
+		fflush(stderr);
+		/**
+		 * Avoiding GDALDestroyDriverManager() call
+		 */
+                CSLDestroy( papszCreateOptions );
+                exit( 1 );
+	      }
+	  }
+        else
+	  poSrcBand = ((GDALDataset *) 
+		       hDataset)->GetRasterBand(panBandList[i]);
+
+	/* ------------------------------------------------------------ */
+	/*      Select output data type to match source.                */
+	/* ------------------------------------------------------------ */
+        if( eOutputType == GDT_Unknown )
+	  eBandType = poSrcBand->GetRasterDataType();
+        else
+	  eBandType = eOutputType;
+
+	/* ------------------------------------------------------------ */
+	/*      Create this band.                                       */
+	/* ------------------------------------------------------------ */
+        poVDS->AddBand( eBandType, NULL );
+        poVRTBand = (VRTSourcedRasterBand *) poVDS->GetRasterBand( i+1 );
+            
+	/* ------------------------------------------------------------ */
+	/*      Do we need to collect scaling information?              */
+	/* ------------------------------------------------------------ */
+        double dfScale=1.0, dfOffset=0.0;
+
+        if( bScale && !bHaveScaleSrc )
+	  {
+            double	adfCMinMax[2];
+            GDALComputeRasterMinMax( poSrcBand, TRUE, adfCMinMax );
+            dfScaleSrcMin = adfCMinMax[0];
+            dfScaleSrcMax = adfCMinMax[1];
+	  }
+
+        if( bScale )
+	  {
+            if( dfScaleSrcMax == dfScaleSrcMin )
+	      dfScaleSrcMax += 0.1;
+            if( dfScaleDstMax == dfScaleDstMin )
+	      dfScaleDstMax += 0.1;
+
+            dfScale = (dfScaleDstMax - dfScaleDstMin) 
+	      / (dfScaleSrcMax - dfScaleSrcMin);
+            dfOffset = -1 * dfScaleSrcMin * dfScale + dfScaleDstMin;
+	  }
+
+	/* ------------------------------------------------------------ */
+	/*      Create a simple or complex data source depending on the */
+	/*      translation type required.                              */
+	/* ------------------------------------------------------------ */
+        if( bScale || (nRGBExpand != 0 && i < nRGBExpand) )
+	  {
+            poVRTBand->AddComplexSource( poSrcBand,
+                                         anSrcWin[0], anSrcWin[1], 
+                                         anSrcWin[2], anSrcWin[3], 
+                                         0, 0, nOXSize, nOYSize,
+                                         dfOffset, dfScale,
+                                         VRT_NODATA_UNSET,
+                                         (nRGBExpand != 0 && i < nRGBExpand) ? i + 1 : 0 );
+	  }
+        else
+	  poVRTBand->AddSimpleSource( poSrcBand,
+				      anSrcWin[0], anSrcWin[1], 
+				      anSrcWin[2], anSrcWin[3], 
+				      0, 0, nOXSize, nOYSize );
+
+        /* In case of color table translate, we only set the color interpretation */
+        /* other info copied by CopyCommonInfoFrom are not relevant in RGB expansion */
+        if (nRGBExpand != 0 && i < nRGBExpand)
+	  {
+            poVRTBand->SetColorInterpretation( (GDALColorInterp) (GCI_RedBand + i) );
+	  }
+        else
+	  {
+	    /* --------------------------------------------------------- */
+	    /*      copy over some other information of interest.        */
+	    /* --------------------------------------------------------- */
+            poVRTBand->CopyCommonInfoFrom( poSrcBand );
+	  }
+
+	/* ------------------------------------------------------------- */
+	/*      Set a forcable nodata value?                             */
+	/* ------------------------------------------------------------- */
+        if( bSetNoData )
+	  poVRTBand->SetNoDataValue( dfNoDataReal );
+      }
+
+    /* ----------------------------------------------------------------- */
+    /*      Write to the output file using CopyCreate().                 */
+    /* ----------------------------------------------------------------- */
+    hOutDS = GDALCreateCopy( hDriver, pszDest, (GDALDatasetH) poVDS,
+                             bStrict, papszCreateOptions, 
+                             pfnProgress, NULL );
+
+    if( hOutDS != NULL )
+      {
+        GDALClose( hOutDS );
+      }
+    
+    GDALClose( (GDALDatasetH) poVDS );
+         
+    GDALClose( hDataset );
+   
+    free( panBandList );
+    
+    free( pszOutputSRS );
+
+    if( !bSubCall )
+      {
+        GDALDumpOpenDatasets( stderr );
+	fflush(stderr);
+	/**
+	 * Avoiding GDALDestroyDriverManager() call
+	 */
+      }
+
+    CSLDestroy( papszCreateOptions );
+    
+    setMapInMaps(outputs,"Result","value",(char*)pszDest);
+
+    return SERVICE_SUCCEEDED;
+  }
+
+
+  /************************************************************************/
+  /*                           AttachMetadata()                           */
+  /************************************************************************/
+
+  static void AttachMetadata( GDALDatasetH hDS, char **papszMetadataOptions )
+
+  {
+    int nCount = CSLCount(papszMetadataOptions);
+    int i;
+
+    for( i = 0; i < nCount; i++ )
+      {
+        char    *pszKey = NULL;
+        const char *pszValue;
+        
+        pszValue = CPLParseNameValue( papszMetadataOptions[i], &pszKey );
+        GDALSetMetadataItem(hDS,pszKey,pszValue,NULL);
+        free( pszKey );
+      }
+
+    CSLDestroy( papszMetadataOptions );
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/Makefile	(revision 942)
@@ -0,0 +1,15 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/warp_service.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/warp_service.zo ./service.c ${GDAL_LIBS} ${MACOS_LD_FLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}/gdal/warp
+	install cgi-env/* ${CGI_DIR}/gdal/warp
+
+
+clean:
+	rm -f cgi-env/warp_service.*
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/cgi-env/Gdal_Warp.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/cgi-env/Gdal_Warp.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/cgi-env/Gdal_Warp.zcfg	(revision 942)
@@ -0,0 +1,129 @@
+[Gdal_Warp]
+ Title = GDAL Warp Tool
+ Abstract = The gdalwarp utility is an image mosaicing, reprojection and warping utility. The program can reproject to any supported projection, and can also apply GCPs stored with the image if the image is "raw" with control information.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = warp_service.zo
+ <DataInputs>
+  [Format]
+   Title = Format of the output data
+   Abstract = Select the output format by usig short name of the format (use gda-config --formats for list of available formats on your platform).
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = GTiff
+    </Default>
+   </LiteralData>
+  [InputDSN]
+   Title = The input data source name
+   Abstract = The input data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [OutputDSN]
+   Title = The output data source name
+   Abstract = The output data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [s_srs]
+   Title = The source Spatial reference Set
+   Abstract = The coordinate systems that can be passed are anything supported by the OGRSpatialReference.SetFromUserInput() call, which includes EPSG PCS and GCSes (ie. EPSG:4296), PROJ.4 declarations (as above), or the name of a .prf file containing well known text.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [t_srs]
+   Title = The target Spatial reference Set
+   Abstract = The coordinate systems that can be passed are anything supported by the OGRSpatialReference.SetFromUserInput() call, which includes EPSG PCS and GCSes (ie. EPSG:4296), PROJ.4 declarations (as above), or the name of a .prf file containing well known text.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [tps]
+   Title = Thin Plate Spline
+   Abstract = Force use of thin plate spline transformer based on available GCPs
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = boolean
+    <Default />
+   </LiteralData>
+  [geoloc]
+   Title = Geolocation
+   Abstract = Force use of Geolocation Arrays
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = boolean
+    <Default />
+   </LiteralData>
+  [rpc]
+   Title = RPCs
+   Abstract =  Force use of RPCs
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = boolean
+    <Default />
+   </LiteralData>
+  [r]
+   Title = Resampling method to use
+   Abstract = Available methods are: near (nearest neighbour resampling - default, fastest algorithm, worst interpolation quality), bilinear, cubic, cubicspline, lanczos (Lanczos windowed sinc resampling)
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = boolean
+    <Default />
+   </LiteralData>
+  [order]
+   Title = The order of polynomial used for warping (1 to 3)
+   Abstract = The default is to select a polynomial order based on the number of GCPs.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value=1
+    </Default>
+    <Supported>
+     value=2
+    </Supported>
+    <Supported>
+     value=3
+    </Supported>
+   </LiteralData>
+  [te]
+   Title = xmin,ymin,xmax,ymax
+   Abstract = set georeferenced extents of output file to be created (in target SRS).
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/makefile.vc	(revision 942)
@@ -0,0 +1,11 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+cgi-env/warp_service.zo: service.c
+	$(CPP)  /DOGR_ENABLED /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE -I$(GDAL_DIR)/frmts/ -I$(GDAL_DIR)/alg/ $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/warp_service.zo  $(FILES) ./service.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\warp_service.*
Index: /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/gdal/warp/service.c	(revision 942)
@@ -0,0 +1,2150 @@
+/******************************************************************************
+ * $Id: gdalwarp.cpp 24214 2012-04-08 20:17:17Z etourigny $
+ *
+ * Project:  High Performance Image Reprojector
+ * Purpose:  Test program for high performance warper API.
+ * Author:   Frank Warmerdam <warmerdam@pobox.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2002, i3 - information integration and imaging 
+ *                          Fort Collin, CO
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "gdalwarper.h"
+#include "cpl_string.h"
+#include "ogr_spatialref.h"
+#include "ogr_api.h"
+#include <vector>
+#include "service.h"
+
+CPL_CVSID("$Id: gdalwarp.cpp 24214 2012-04-08 20:17:17Z etourigny $");
+
+extern "C"{
+static void
+LoadCutline( const char *pszCutlineDSName, const char *pszCLayer, 
+             const char *pszCWHERE, const char *pszCSQL, 
+             void **phCutlineRet );
+static void
+TransformCutlineToSource( GDALDatasetH hSrcDS, void *hCutline,
+                          char ***ppapszWarpOptions, char **papszTO );
+
+static GDALDatasetH 
+GDALWarpCreateOutput( maps*& conf,char **papszSrcFiles, const char *pszFilename, 
+                      const char *pszFormat, char **papszTO,
+                      char ***ppapszCreateOptions, GDALDataType eDT,
+                      void ** phTransformArg,
+                      GDALDatasetH* phSrcDS );
+
+static double	       dfMinX=0.0, dfMinY=0.0, dfMaxX=0.0, dfMaxY=0.0;
+static double	       dfXRes=0.0, dfYRes=0.0;
+static int             bTargetAlignedPixels = FALSE;
+static int             nForcePixels=0, nForceLines=0, bQuiet = FALSE;
+static int             bEnableDstAlpha = FALSE, bEnableSrcAlpha = FALSE;
+
+static int             bVRT = FALSE;
+
+/******************************************************************************/
+/*! \page gdalwarp gdalwarp
+
+image reprojection and warping utility
+
+\section gdalwarp_synopsis SYNOPSIS
+
+\htmlonly
+Usage: 
+\endhtmlonly
+
+\verbatim
+gdalwarp [--help-general] [--formats]
+    [-s_srs srs_def] [-t_srs srs_def] [-to "NAME=VALUE"]
+    [-order n | -tps | -rpc | -geoloc] [-et err_threshold]
+    [-refine_gcps tolerance [minimum_gcps]]
+    [-te xmin ymin xmax ymax] [-tr xres yres] [-tap] [-ts width height]
+    [-wo "NAME=VALUE"] [-ot Byte/Int16/...] [-wt Byte/Int16]
+    [-srcnodata "value [value...]"] [-dstnodata "value [value...]"] -dstalpha
+    [-r resampling_method] [-wm memory_in_mb] [-multi] [-q]
+    [-cutline datasource] [-cl layer] [-cwhere expression]
+    [-csql statement] [-cblend dist_in_pixels] [-crop_to_cutline]
+    [-of format] [-co "NAME=VALUE"]* [-overwrite]
+    srcfile* dstfile
+\endverbatim
+
+\section gdalwarp_description DESCRIPTION
+
+<p>
+The gdalwarp utility is an image mosaicing, reprojection and warping
+utility. The program can reproject to any supported projection,
+and can also apply GCPs stored with the image if the image is "raw"
+with control information.
+
+<p>
+<dl>
+<dt> <b>-s_srs</b> <em>srs def</em>:</dt><dd> source spatial reference set.
+The coordinate systems that can be passed are anything supported by the
+OGRSpatialReference.SetFromUserInput() call, which includes EPSG PCS and GCSes
+(ie. EPSG:4296), PROJ.4 declarations (as above), or the name of a .prf file
+containing well known text.</dd>
+<dt> <b>-t_srs</b> <em>srs_def</em>:</dt><dd> target spatial reference set.
+The coordinate systems that can be passed are anything supported by the
+OGRSpatialReference.SetFromUserInput() call, which includes EPSG PCS and GCSes
+(ie. EPSG:4296), PROJ.4 declarations (as above), or the name of a .prf file
+containing well known text.</dd>
+<dt> <b>-to</b> <em>NAME=VALUE</em>:</dt><dd> set a transformer option suitable
+to pass to GDALCreateGenImgProjTransformer2(). </dd>
+<dt> <b>-order</b> <em>n</em>:</dt><dd> order of polynomial used for warping
+(1 to 3). The default is to select a polynomial order based on the number of
+GCPs.</dd>
+<dt> <b>-tps</b>:</dt><dd>Force use of thin plate spline transformer based on
+available GCPs.</dd>
+<dt> <b>-rpc</b>:</dt> <dd>Force use of RPCs.</dd>
+<dt> <b>-geoloc</b>:</dt><dd>Force use of Geolocation Arrays.</dd>
+<dt> <b>-et</b> <em>err_threshold</em>:</dt><dd> error threshold for
+transformation approximation (in pixel units - defaults to 0.125).</dd>
+<dt> <b>-refine_gcps</b> <em>tolerance minimum_gcps</em>:</dt><dd>  (GDAL >= 1.9.0) refines the GCPs by automatically eliminating outliers.
+Outliers will be eliminated until minimum_gcps are left or when no outliers can be detected.
+The tolerance is passed to adjust when a GCP will be eliminated.
+Not that GCP refinement only works with polynomial interpolation.
+The tolerance is in pixel units if no projection is available, otherwise it is in SRS units.
+If minimum_gcps is not provided, the minimum GCPs according to the polynomial model is used.</dd>
+<dt> <b>-te</b> <em>xmin ymin xmax ymax</em>:</dt><dd> set georeferenced
+extents of output file to be created (in target SRS).</dd>
+<dt> <b>-tr</b> <em>xres yres</em>:</dt><dd> set output file resolution (in
+target georeferenced units)</dd>
+<dt> <b>-tap</b>:</dt><dd> (GDAL >= 1.8.0) (target aligned pixels) align
+the coordinates of the extent of the output file to the values of the -tr,
+such that the aligned extent includes the minimum extent.</dd>
+<dt> <b>-ts</b> <em>width height</em>:</dt><dd> set output file size in
+pixels and lines. If width or height is set to 0, the other dimension will be
+guessed from the computed resolution. Note that -ts cannot be used with -tr</dd>
+<dt> <b>-wo</b> <em>"NAME=VALUE"</em>:</dt><dd> Set a warp options.  The 
+GDALWarpOptions::papszWarpOptions docs show all options.  Multiple
+ <b>-wo</b> options may be listed.</dd>
+<dt> <b>-ot</b> <em>type</em>:</dt><dd> For the output bands to be of the
+indicated data type.</dd>
+<dt> <b>-wt</b> <em>type</em>:</dt><dd> Working pixel data type. The data type
+of pixels in the source image and destination image buffers.</dd>
+<dt> <b>-srcnodata</b> <em>value [value...]</em>:</dt><dd> Set nodata masking
+values for input bands (different values can be supplied for each band).  If 
+more than one value is supplied all values should be quoted to keep them 
+together as a single operating system argument.  Masked values will not be 
+used in interpolation.  Use a value of <tt>None</tt> to ignore intrinsic nodata settings on the source dataset.</dd>
+<dt> <b>-dstnodata</b> <em>value [value...]</em>:</dt><dd> Set nodata values
+for output bands (different values can be supplied for each band).  If more
+than one value is supplied all values should be quoted to keep them together
+as a single operating system argument.  New files will be initialized to this
+value and if possible the nodata value will be recorded in the output
+file.</dd>
+<dt> <b>-dstalpha</b>:</dt><dd> Create an output alpha band to identify 
+nodata (unset/transparent) pixels. </dd>
+<dt> <b>-wm</b> <em>memory_in_mb</em>:</dt><dd> Set the amount of memory (in
+megabytes) that the warp API is allowed to use for caching.</dd>
+<dt> <b>-multi</b>:</dt><dd> Use multithreaded warping implementation.
+Multiple threads will be used to process chunks of image and perform
+input/output operation simultaneously.</dd>
+<dt> <b>-q</b>:</dt><dd> Be quiet.</dd>
+<dt> <b>-of</b> <em>format</em>:</dt><dd> Select the output format. The default is GeoTIFF (GTiff). Use the short format name. </dd>
+<dt> <b>-co</b> <em>"NAME=VALUE"</em>:</dt><dd> passes a creation option to
+the output format driver. Multiple <b>-co</b> options may be listed. See
+format specific documentation for legal creation options for each format.
+</dd>
+
+<dt> <b>-cutline</b> <em>datasource</em>:</dt><dd>Enable use of a blend cutline from the name OGR support datasource.</dd>
+<dt> <b>-cl</b> <em>layername</em>:</dt><dd>Select the named layer from the 
+cutline datasource.</dd>
+<dt> <b>-cwhere</b> <em>expression</em>:</dt><dd>Restrict desired cutline features based on attribute query.</dd>
+<dt> <b>-csql</b> <em>query</em>:</dt><dd>Select cutline features using an SQL query instead of from a layer with -cl.</dd>
+<dt> <b>-cblend</b> <em>distance</em>:</dt><dd>Set a blend distance to use to blend over cutlines (in pixels).</dd>
+<dt> <b>-crop_to_cutline</b>:</dt><dd>(GDAL >= 1.8.0) Crop the extent of the target dataset to the extent of the cutline.</dd>
+<dt> <b>-overwrite</b>:</dt><dd>(GDAL >= 1.8.0) Overwrite the target dataset if it already exists.</dd>
+
+<dt> <em>srcfile</em>:</dt><dd> The source file name(s). </dd>
+<dt> <em>dstfile</em>:</dt><dd> The destination file name. </dd>
+</dl>
+
+Mosaicing into an existing output file is supported if the output file 
+already exists. The spatial extent of the existing file will not
+be modified to accomodate new data, so you may have to remove it in that case, or
+use the -overwrite option.
+
+Polygon cutlines may be used as a mask to restrict the area of the destination file
+that may be updated, including blending.  If the OGR layer containing the cutline
+features has no explicit SRS, the cutline features must be in the georeferenced
+units of the destination file. When outputing to a not yet existing target dataset,
+its extent will be the one of the original raster unless -te or -crop_to_cutline are
+specified.
+
+<p>
+\section gdalwarp_example EXAMPLE
+
+For instance, an eight bit spot scene stored in GeoTIFF with
+control points mapping the corners to lat/long could be warped to a UTM
+projection with a command like this:<p>
+
+\verbatim
+gdalwarp -t_srs '+proj=utm +zone=11 +datum=WGS84' raw_spot.tif utm11.tif
+\endverbatim
+
+For instance, the second channel of an ASTER image stored in HDF with
+control points mapping the corners to lat/long could be warped to a UTM
+projection with a command like this:<p>
+
+\verbatim
+gdalwarp HDF4_SDS:ASTER_L1B:"pg-PR1B0000-2002031402_100_001":2 pg-PR1B0000-2002031402_100_001_2.tif
+\endverbatim
+
+\if man
+\section gdalwarp_author AUTHORS
+Frank Warmerdam <warmerdam@pobox.com>, Silke Reimer <silke@intevation.de>
+\endif
+*/
+
+/************************************************************************/
+/*                               GDALExit()                             */
+/*  This function exits and cleans up GDAL and OGR resources            */
+/*  Perhaps it should be added to C api and used in all apps?           */
+/************************************************************************/
+
+static int GDALExit( int nCode )
+{
+  const char  *pszDebug = CPLGetConfigOption("CPL_DEBUG",NULL);
+  if( pszDebug && (EQUAL(pszDebug,"ON") || EQUAL(pszDebug,"") ) )
+  {  
+    GDALDumpOpenDatasets( stderr );
+    CPLDumpSharedList( NULL );
+  }
+
+  GDALDestroyDriverManager();
+
+#ifdef OGR_ENABLED
+  OGRCleanupAll();
+#endif
+
+  return SERVICE_FAILED;
+}
+
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage()
+
+{
+    printf( 
+        "Usage: gdalwarp [--help-general] [--formats]\n"
+        "    [-s_srs srs_def] [-t_srs srs_def] [-to \"NAME=VALUE\"]\n"
+        "    [-order n | -tps | -rpc | -geoloc] [-et err_threshold]\n"
+        "    [-refine_gcps tolerance [minimum_gcps]]\n"
+        "    [-te xmin ymin xmax ymax] [-tr xres yres] [-tap] [-ts width height]\n"
+        "    [-wo \"NAME=VALUE\"] [-ot Byte/Int16/...] [-wt Byte/Int16]\n"
+        "    [-srcnodata \"value [value...]\"] [-dstnodata \"value [value...]\"] -dstalpha\n" 
+        "    [-r resampling_method] [-wm memory_in_mb] [-multi] [-q]\n"
+        "    [-cutline datasource] [-cl layer] [-cwhere expression]\n"
+        "    [-csql statement] [-cblend dist_in_pixels] [-crop_to_cutline]\n"
+        "    [-of format] [-co \"NAME=VALUE\"]* [-overwrite]\n"
+        "    srcfile* dstfile\n"
+        "\n"
+        "Available resampling methods:\n"
+        "    near (default), bilinear, cubic, cubicspline, lanczos.\n" );
+    GDALExit( 1 );
+}
+
+/************************************************************************/
+/*                             SanitizeSRS                              */
+/************************************************************************/
+
+char *SanitizeSRS( const char *pszUserInput )
+
+{
+    OGRSpatialReferenceH hSRS;
+    char *pszResult = NULL;
+
+    CPLErrorReset();
+    
+    hSRS = OSRNewSpatialReference( NULL );
+    if( OSRSetFromUserInput( hSRS, pszUserInput ) == OGRERR_NONE )
+        OSRExportToWkt( hSRS, &pszResult );
+    else
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Translating source or target SRS failed:\n%s",
+                  pszUserInput );
+        GDALExit( 1 );
+    }
+    
+    OSRDestroySpatialReference( hSRS );
+
+    return pszResult;
+}
+
+/************************************************************************/
+/*                                main()                                */
+/************************************************************************/
+
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int Gdal_Warp( maps*& conf,maps*& inputs,maps*& outputs )
+
+{
+    GDALDatasetH	hDstDS;
+    const char         *pszFormat = "GTiff";
+    int bFormatExplicitelySet = FALSE;
+    char              **papszSrcFiles = NULL;
+    char               *pszDstFilename = NULL;
+    int                 bCreateOutput = FALSE, i;
+    void               *hTransformArg, *hGenImgProjArg=NULL, *hApproxArg=NULL;
+    char               **papszWarpOptions = NULL;
+    double             dfErrorThreshold = 0.125;
+    double             dfWarpMemoryLimit = 0.0;
+    GDALTransformerFunc pfnTransformer = NULL;
+    char                **papszCreateOptions = NULL;
+    GDALDataType        eOutputType = GDT_Unknown, eWorkingType = GDT_Unknown; 
+    GDALResampleAlg     eResampleAlg = GRA_NearestNeighbour;
+    const char          *pszSrcNodata = NULL;
+    const char          *pszDstNodata = NULL;
+    int                 bMulti = FALSE;
+    char                **papszTO = NULL;
+    char                *pszCutlineDSName = NULL;
+    char                *pszCLayer = NULL, *pszCWHERE = NULL, *pszCSQL = NULL;
+    void                *hCutline = NULL;
+    int                  bHasGotErr = FALSE;
+    int                  bCropToCutline = FALSE;
+    int                  bOverwrite = FALSE;
+
+
+    /* Check that we are running against at least GDAL 1.6 */
+    /* Note to developers : if we use newer API, please change the requirement */
+    if (atoi(GDALVersionInfo("VERSION_NUM")) < 1600)
+    {
+        fprintf(stderr, "At least, GDAL >= 1.6.0 is required for this version of warp_service.zo, "
+                "which was compiled against GDAL %s\n", GDAL_RELEASE_NAME);
+        GDALExit(1);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Register standard GDAL drivers, and process generic GDAL        */
+/*      command options.                                                */
+/* -------------------------------------------------------------------- */
+    GDALAllRegister();
+
+/* -------------------------------------------------------------------- */
+/*      Parse arguments.                                                */
+/* -------------------------------------------------------------------- */
+    char *dataPath;
+    map* tmpMap=getMapFromMaps(conf,"main","dataPath");
+    if(tmpMap!=NULL)
+      dataPath=strdup(tmpMap->value);
+    tmpMap=NULL;
+
+    char *tempPath;
+    tmpMap=getMapFromMaps(conf,"main","tmpPath");
+    if(tmpMap!=NULL){
+      tempPath=strdup(tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"InputDSN","value");
+    if(tmpMap!=NULL){
+      map* length=getMapFromMaps(inputs,"InputDSN","length");
+      if(length!=NULL){
+	int i=0;
+	int len=atoi(length->value);
+	maps* currentMaps=getMaps(inputs,"InputDSN");
+	for(i=0;i<len;i++){
+	  tmpMap=getMapArray(currentMaps->content,"value",i);
+	  papszSrcFiles[i]=(char*)CPLMalloc(sizeof(char)*(strlen(dataPath)+strlen(tmpMap->value)+4));
+	  sprintf((char*)papszSrcFiles[i],"%s/%s",dataPath,tmpMap->value);
+	}
+      }else{
+	char *tmp=(char*)CPLMalloc(sizeof(char)*(strlen(dataPath)+strlen(tmpMap->value)+4));
+	sprintf(tmp,"%s/%s",dataPath,tmpMap->value);
+	papszSrcFiles=CSLAddString( papszSrcFiles, tmp );
+	free(tmp);
+      }
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"OutputDSN","value");
+    if(tmpMap!=NULL){
+      pszDstFilename=(char*)CPLMalloc(sizeof(char)*(strlen(tempPath)+strlen(tmpMap->value)+4));
+      char *ext=new char[4];
+      ext="tif";
+      if(strncasecmp(pszFormat,"AAIGRID",7)==0)
+	ext="csv";
+      else 
+	if(strncasecmp(pszFormat,"PNG",3)==0)
+	  ext="png";
+	else
+	  if(strncasecmp(pszFormat,"GIF",3)==0)
+	    ext="gif";
+	  else
+	    if(strncasecmp(pszFormat,"JPEG",4)==0)
+	      ext="jpg";
+      sprintf(pszDstFilename,"%s/%s.%s",tempPath,tmpMap->value,ext);
+    }
+
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"r","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      if ( EQUAL(tmpMap->value, "near") )
+	eResampleAlg = GRA_NearestNeighbour;
+      else if ( EQUAL(tmpMap->value, "bilinear") )
+	eResampleAlg = GRA_Bilinear;
+      else if ( EQUAL(tmpMap->value, "cubic") )
+	eResampleAlg = GRA_Cubic;
+      else if ( EQUAL(tmpMap->value, "cubicspline") )
+	eResampleAlg = GRA_CubicSpline;
+      else if ( EQUAL(tmpMap->value, "lanczos") )
+	eResampleAlg = GRA_Lanczos;
+      else
+	{
+	  char tmp[1024];
+	  sprintf(tmp,"Unknown resampling method: \"%s\".", tmpMap->value );
+	  setMapInMaps(conf,"lenv","message",tmp);
+	  return SERVICE_FAILED;
+	}
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"t_srs","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      char *pszSRS = SanitizeSRS(tmpMap->value);
+      papszTO = CSLSetNameValue( papszTO, "DST_SRS", pszSRS );
+      CPLFree( pszSRS );
+    }
+
+    tmpMap=getMapFromMaps(inputs,"s_srs","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      char *pszSRS = SanitizeSRS(tmpMap->value);
+      papszTO = CSLSetNameValue( papszTO, "SRC_SRS", pszSRS );
+      CPLFree( pszSRS );
+    }
+
+    tmpMap=getMapFromMaps(inputs,"order","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      const char* pszMethod = CSLFetchNameValue(papszTO, "METHOD");
+      if (pszMethod)
+	fprintf(stderr, "Warning: only one METHOD can be used. Method %s is already defined\n",
+		pszMethod);
+      papszTO = CSLSetNameValue( papszTO, "MAX_GCP_ORDER", tmpMap->value );
+    }
+    
+    tmpMap=getMapFromMaps(inputs,"co","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      papszCreateOptions = CSLAddString( papszCreateOptions, tmpMap->value );
+      bCreateOutput = TRUE;
+    }   
+
+    tmpMap=getMapFromMaps(inputs,"wo","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      papszWarpOptions = CSLAddString( papszWarpOptions, tmpMap->value );
+    }   
+
+    tmpMap=getMapFromMaps(inputs,"multi","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      bMulti = TRUE;
+    }   
+
+    tmpMap=getMapFromMaps(inputs,"dstalpha","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      bEnableDstAlpha = TRUE;
+    }
+
+    tmpMap=getMapFromMaps(inputs,"srcalpha","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      bEnableSrcAlpha = TRUE;
+    }
+
+    tmpMap=getMapFromMaps(inputs,"tap","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      bTargetAlignedPixels = TRUE;
+    }
+
+
+    tmpMap=getMapFromMaps(inputs,"crop_to_cutline","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      bCropToCutline = TRUE;
+      bCreateOutput = TRUE;
+    }
+
+
+    tmpMap=getMapFromMaps(inputs,"tps","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      papszTO = CSLSetNameValue( papszTO, "METHOD", "GCP_TPS" );
+    }
+
+    tmpMap=getMapFromMaps(inputs,"rpc","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      papszTO = CSLSetNameValue( papszTO, "METHOD", "RPC" );
+    }
+
+    tmpMap=getMapFromMaps(inputs,"geoloc","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0 ){
+      papszTO = CSLSetNameValue( papszTO, "METHOD", "GEOLOC_ARRAY" );
+    }
+
+    tmpMap=getMapFromMaps(inputs,"wt","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      int	iType;
+      
+      for( iType = 1; iType < GDT_TypeCount; iType++ )
+	{
+	  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
+	      && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
+		       tmpMap->value) )
+	    {
+	      eWorkingType = (GDALDataType) iType;
+	    }
+	}
+      
+      if( eWorkingType == GDT_Unknown )
+	{
+	  char tmp[1024];
+	  sprintf(tmp,"Unknown output pixel type: %s\n", tmpMap->value );
+	  setMapInMaps(conf,"lenv","message",tmp);
+	  return SERVICE_FAILED;
+	}
+    }
+
+    tmpMap=getMapFromMaps(inputs,"srcnodata","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      pszSrcNodata = strdup(tmpMap->value);
+    }
+
+    tmpMap=getMapFromMaps(inputs,"dstnodata","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      pszDstNodata = strdup(tmpMap->value);
+    }
+
+
+    tmpMap=getMapFromMaps(inputs,"tr","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      char *tmpV=strdup(tmpMap->value);
+      char *res=strtok(tmpV,",");
+      int i=0;
+      while(res!=NULL){
+	if(i==0)
+	  dfXRes = CPLAtofM(res);
+	else
+	  dfYRes = fabs(CPLAtofM(res));
+	res=strtok(NULL,",");
+	i++;
+      }
+      if( dfXRes == 0 || dfYRes == 0 )
+	{
+	  setMapInMaps(conf,"lenv","message","Wrong value for TR parameters");
+	}
+      bCreateOutput = TRUE;
+    }
+
+    tmpMap=getMapFromMaps(inputs,"cblend","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      papszWarpOptions = 
+	CSLSetNameValue( papszWarpOptions, 
+			 "CUTLINE_BLEND_DIST", tmpMap->value );
+    }
+    
+    tmpMap=getMapFromMaps(inputs,"ot","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      int	iType;
+      
+      for( iType = 1; iType < GDT_TypeCount; iType++ )
+	{
+	  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
+	      && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
+		       tmpMap->value) )
+	    {
+	      eOutputType = (GDALDataType) iType;
+	    }
+	}
+
+      if( eOutputType == GDT_Unknown )
+	{
+	  char tmp[128];
+	  sprintf( tmp,"Unknown output pixel type: %s\n", tmpMap->value );
+	  setMapInMaps(conf,"lenv","message",tmp);
+	  return SERVICE_FAILED;
+	}
+      bCreateOutput = TRUE;      
+    }
+
+
+    tmpMap=getMapFromMaps(inputs,"ts","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      char *tmpV=strdup(tmpMap->value);
+      char *res=strtok(tmpV,",");
+      int i=0;
+      while(res!=NULL){
+	if(i==0)
+	  nForcePixels = atoi(res);	  
+	else
+	  nForceLines = atoi(res);	  
+	res=strtok(NULL,",");
+	i++;
+      }
+      free(tmpV);
+      bCreateOutput = TRUE;      
+    }
+
+    tmpMap=getMapFromMaps(inputs,"te","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      char *tmpV=strdup(tmpMap->value);
+      char *res=strtok(tmpV,",");
+      int i=0;
+      while(res!=NULL){
+	switch(i){
+	case 0:
+	  dfMinX = CPLAtofM(res);
+	  break;
+	case 1:
+	  dfMinY = CPLAtofM(res);
+	  break;
+	case 2:
+	  dfMaxX = CPLAtofM(res);
+	  break;
+	case 3:
+	  dfMaxY = CPLAtofM(res);
+	  break;
+	}
+	if(i==0)
+	  nForcePixels = atoi(res);	  
+	else
+	  nForceLines = atoi(res);	  
+	res=strtok(NULL,",");
+	i++;
+      }
+      free(tmpV);
+      bCreateOutput = TRUE;
+    }
+
+    tmpMap=getMapFromMaps(inputs,"te","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      pszCutlineDSName = strdup(tmpMap->value);
+    }
+
+    tmpMap=getMapFromMaps(inputs,"cwhere","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      pszCWHERE = strdup(tmpMap->value);
+    }
+
+    tmpMap=getMapFromMaps(inputs,"cl","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      pszCLayer = strdup(tmpMap->value);
+    }
+
+    tmpMap=getMapFromMaps(inputs,"csql","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      pszCSQL = strdup(tmpMap->value);
+    }
+    
+    tmpMap=getMapFromMaps(inputs,"of","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      pszFormat = strdup(tmpMap->value);
+      bFormatExplicitelySet = TRUE;
+      bCreateOutput = TRUE;
+      if( EQUAL(pszFormat,"VRT") )
+	bVRT = TRUE;
+    }
+
+    tmpMap=getMapFromMaps(inputs,"to","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      papszTO = CSLAddString( papszTO, tmpMap->value );
+    }
+
+    tmpMap=getMapFromMaps(inputs,"et","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      dfErrorThreshold = CPLAtofM(tmpMap->value);
+    }
+    
+
+    tmpMap=getMapFromMaps(inputs,"refine_gpcs","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0 ){
+      char *tmpV=strdup(tmpMap->value);
+      char *res=strtok(tmpV,",");
+      int i=0;
+      while(res!=NULL){
+	if(i==0){
+	  papszTO = CSLSetNameValue( papszTO, "REFINE_TOLERANCE", res );
+	  if(atof(res) < 0){
+	    setMapInMaps(conf,"lenv","message","The tolerance for -refine_gcps may not be negative\n");
+	    return SERVICE_FAILED;
+	  }
+	}else if(i==1){
+	  if(atoi(res) >= 0 && isdigit(res[0]))
+	    papszTO = CSLSetNameValue( papszTO, "REFINE_MINIMUM_GCPS", res );
+	  else
+	    papszTO = CSLSetNameValue( papszTO, "REFINE_MINIMUM_GCPS", "-1" );
+	}
+	res=strtok(NULL,",");
+	i++;
+      }
+    }
+
+    bQuiet = TRUE;
+    
+/* -------------------------------------------------------------------- */
+/*      Check that incompatible options are not used                    */
+/* -------------------------------------------------------------------- */
+
+    if ((nForcePixels != 0 || nForceLines != 0) && 
+        (dfXRes != 0 && dfYRes != 0))
+    {
+      setMapInMaps(conf,"lenv","message","tr and ts options cannot be used at the same time\n");
+      return SERVICE_FAILED;
+    }
+    
+    if (bTargetAlignedPixels && dfXRes == 0 && dfYRes == 0)
+    {
+      setMapInMaps(conf,"lenv","message","tap option cannot be used without using tr");
+      return SERVICE_FAILED;
+    }
+
+
+/* -------------------------------------------------------------------- */
+/*      Does the output dataset already exist?                          */
+/* -------------------------------------------------------------------- */
+
+    /* FIXME ? source filename=target filename and -overwrite is definitely */
+    /* an error. But I can't imagine of a valid case (without -overwrite), */
+    /* where it would make sense. In doubt, let's keep that dubious possibility... */
+    if ( CSLCount(papszSrcFiles) == 1 &&
+         strcmp(papszSrcFiles[0], pszDstFilename) == 0 && bOverwrite)
+    {
+      setMapInMaps(conf,"lenv","message","Source and destination datasets must be different.");
+      return GDALExit(1);
+    }
+
+    CPLPushErrorHandler( CPLQuietErrorHandler );
+    hDstDS = GDALOpen( pszDstFilename, GA_Update );
+    CPLPopErrorHandler();
+
+    if( hDstDS != NULL && bOverwrite )
+    {
+        GDALClose(hDstDS);
+        hDstDS = NULL;
+    }
+
+    if( hDstDS != NULL && bCreateOutput )
+    {
+      char tmp[024];
+      sprintf( tmp, 
+	       "Output dataset %s exists,\n"
+	       "but some commandline options were provided indicating a new dataset\n"
+	       "should be created.  Please delete existing dataset and run again.\n",
+	       pszDstFilename );
+      setMapInMaps(conf,"lenv","message",tmp);
+      return GDALExit(1);
+    }
+
+    /* Avoid overwriting an existing destination file that cannot be opened in */
+    /* update mode with a new GTiff file */
+    if ( hDstDS == NULL && !bOverwrite )
+    {
+        CPLPushErrorHandler( CPLQuietErrorHandler );
+        hDstDS = GDALOpen( pszDstFilename, GA_ReadOnly );
+        CPLPopErrorHandler();
+        
+        if (hDstDS)
+        {
+	  char tmp[1024];
+	  sprintf( tmp, 
+		   "Output dataset %s exists, but cannot be opened in update mode\n",
+		   pszDstFilename );
+	  GDALClose(hDstDS);
+	  setMapInMaps(conf,"lenv","message",tmp);
+	  return GDALExit( 1 );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If we have a cutline datasource read it and attach it in the    */
+/*      warp options.                                                   */
+/* -------------------------------------------------------------------- */
+    if( pszCutlineDSName != NULL )
+    {
+        LoadCutline( pszCutlineDSName, pszCLayer, pszCWHERE, pszCSQL,
+                     &hCutline );
+    }
+
+#ifdef OGR_ENABLED
+    if ( bCropToCutline && hCutline != NULL )
+    {
+      
+      
+        OGRGeometryH hCutlineGeom = OGR_G_Clone( (OGRGeometryH) hCutline );
+        OGRSpatialReferenceH hCutlineSRS = OGR_G_GetSpatialReference( hCutlineGeom );
+        const char *pszThisTargetSRS = CSLFetchNameValue( papszTO, "DST_SRS" );
+        OGRCoordinateTransformationH hCT = NULL;
+        if (hCutlineSRS == NULL)
+        {
+            /* We suppose it is in target coordinates */
+        }
+        else if (pszThisTargetSRS != NULL)
+        {
+            OGRSpatialReferenceH hTargetSRS = OSRNewSpatialReference(NULL);
+            if( OSRImportFromWkt( hTargetSRS, (char **)&pszThisTargetSRS ) != CE_None )
+            {
+	      setMapInMaps(conf,"lenv","message","Cannot compute bounding box of cutline.\n");
+                return GDALExit(1);
+            }
+
+            hCT = OCTNewCoordinateTransformation(hCutlineSRS, hTargetSRS);
+
+            OSRDestroySpatialReference(hTargetSRS);
+        }
+        else if (pszThisTargetSRS == NULL)
+        {
+            if (papszSrcFiles[0] != NULL)
+            {
+                GDALDatasetH hSrcDS = GDALOpen(papszSrcFiles[0], GA_ReadOnly);
+                if (hSrcDS == NULL)
+                {
+		  setMapInMaps(conf,"lenv","message","Cannot compute bounding box of cutline.");
+		  return GDALExit(1);
+                }
+
+                OGRSpatialReferenceH  hRasterSRS = NULL;
+                const char *pszProjection = NULL;
+
+                if( GDALGetProjectionRef( hSrcDS ) != NULL
+                    && strlen(GDALGetProjectionRef( hSrcDS )) > 0 )
+                    pszProjection = GDALGetProjectionRef( hSrcDS );
+                else if( GDALGetGCPProjection( hSrcDS ) != NULL )
+                    pszProjection = GDALGetGCPProjection( hSrcDS );
+
+                if( pszProjection == NULL )
+                {
+		  setMapInMaps(conf,"lenv","message","Cannot compute bounding box of cutline.");
+		  return GDALExit(1);
+                }
+
+                hRasterSRS = OSRNewSpatialReference(NULL);
+                if( OSRImportFromWkt( hRasterSRS, (char **)&pszProjection ) != CE_None )
+                {
+		  setMapInMaps(conf,"lenv","message","Cannot compute bounding box of cutline.");
+		  return GDALExit(1);
+                }
+
+                hCT = OCTNewCoordinateTransformation(hCutlineSRS, hRasterSRS);
+
+                OSRDestroySpatialReference(hRasterSRS);
+
+                GDALClose(hSrcDS);
+            }
+            else
+            {
+	      setMapInMaps(conf,"levn","message", "Cannot compute bounding box of cutline.\n");
+	      return GDALExit(1);
+            }
+        }
+
+        if (hCT)
+        {
+            OGR_G_Transform( hCutlineGeom, hCT );
+
+            OCTDestroyCoordinateTransformation(hCT);
+        }
+
+        OGREnvelope sEnvelope;
+        OGR_G_GetEnvelope(hCutlineGeom, &sEnvelope);
+
+        dfMinX = sEnvelope.MinX;
+        dfMinY = sEnvelope.MinY;
+        dfMaxX = sEnvelope.MaxX;
+        dfMaxY = sEnvelope.MaxY;
+        
+        OGR_G_DestroyGeometry(hCutlineGeom);
+    }
+#endif
+    
+/* -------------------------------------------------------------------- */
+/*      If not, we need to create it.                                   */
+/* -------------------------------------------------------------------- */
+    int   bInitDestSetForFirst = FALSE;
+
+    void* hUniqueTransformArg = NULL;
+    GDALDatasetH hUniqueSrcDS = NULL;
+
+    if( hDstDS == NULL )
+    {
+
+      hDstDS = GDALWarpCreateOutput( conf,papszSrcFiles, pszDstFilename,pszFormat,
+                                       papszTO, &papszCreateOptions, 
+                                       eOutputType, &hUniqueTransformArg,
+                                       &hUniqueSrcDS);
+        bCreateOutput = TRUE;
+
+
+        if( CSLFetchNameValue( papszWarpOptions, "INIT_DEST" ) == NULL 
+            && pszDstNodata == NULL )
+        {
+            papszWarpOptions = CSLSetNameValue(papszWarpOptions,
+                                               "INIT_DEST", "0");
+            bInitDestSetForFirst = TRUE;
+        }
+        else if( CSLFetchNameValue( papszWarpOptions, "INIT_DEST" ) == NULL )
+        {
+            papszWarpOptions = CSLSetNameValue(papszWarpOptions,
+                                               "INIT_DEST", "NO_DATA" );
+            bInitDestSetForFirst = TRUE;
+        }
+
+        CSLDestroy( papszCreateOptions );
+        papszCreateOptions = NULL;
+    }
+
+ 
+    if( hDstDS == NULL )
+        GDALExit( 1 );
+
+/* -------------------------------------------------------------------- */
+/*      Loop over all source files, processing each in turn.            */
+/* -------------------------------------------------------------------- */
+    int iSrc;
+
+    for( iSrc = 0; papszSrcFiles[iSrc] != NULL; iSrc++ )
+    {
+        GDALDatasetH hSrcDS;
+       
+/* -------------------------------------------------------------------- */
+/*      Open this file.                                                 */
+/* -------------------------------------------------------------------- */
+        if (hUniqueSrcDS)
+            hSrcDS = hUniqueSrcDS;
+        else
+            hSrcDS = GDALOpen( papszSrcFiles[iSrc], GA_ReadOnly );
+    
+        if( hSrcDS == NULL ){
+	  setMapInMaps(conf,"lenv","message",CPLGetLastErrorMsg());
+	  return GDALExit( 2 );
+	}
+
+/* -------------------------------------------------------------------- */
+/*      Check that there's at least one raster band                     */
+/* -------------------------------------------------------------------- */
+        if ( GDALGetRasterCount(hSrcDS) == 0 )
+        {    
+	  char tmp[1024];
+	  sprintf(tmp, "Input file %s has no raster bands.\n", papszSrcFiles[iSrc] );
+	  setMapInMaps(conf,"lenv","message",tmp);
+	  return GDALExit( 1 );
+        }
+	
+        if( !bQuiet )
+            printf( "Processing input file %s.\n", papszSrcFiles[iSrc] );
+
+/* -------------------------------------------------------------------- */
+/*      Warns if the file has a color table and something more          */
+/*      complicated than nearest neighbour resampling is asked          */
+/* -------------------------------------------------------------------- */
+ 
+	if ( eResampleAlg != GRA_NearestNeighbour &&
+             GDALGetRasterColorTable(GDALGetRasterBand(hSrcDS, 1)) != NULL)
+        {
+                fprintf( stderr, "Warning: Input file %s has a color table, which will likely lead to "
+                        "bad results when using a resampling method other than "
+                        "nearest neighbour. Converting the dataset prior to 24/32 bit "
+                        "is advised.\n", papszSrcFiles[iSrc] );
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Do we have a source alpha band?                                 */
+/* -------------------------------------------------------------------- */
+        if( GDALGetRasterColorInterpretation( 
+                GDALGetRasterBand(hSrcDS,GDALGetRasterCount(hSrcDS)) ) 
+            == GCI_AlphaBand 
+            && !bEnableSrcAlpha )
+        {
+            bEnableSrcAlpha = TRUE;
+            if( !bQuiet )
+                printf( "Using band %d of source image as alpha.\n", 
+                        GDALGetRasterCount(hSrcDS) );
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Create a transformation object from the source to               */
+/*      destination coordinate system.                                  */
+/* -------------------------------------------------------------------- */
+        if (hUniqueTransformArg)
+            hTransformArg = hGenImgProjArg = hUniqueTransformArg;
+        else
+            hTransformArg = hGenImgProjArg =
+                GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszTO );
+
+        if( hTransformArg == NULL ){
+	  setMapInMaps(conf,"lenv","message",CPLGetLastErrorMsg());
+	  return GDALExit( 1 );
+	}
+        
+        pfnTransformer = GDALGenImgProjTransform;
+
+/* -------------------------------------------------------------------- */
+/*      Warp the transformer with a linear approximator unless the      */
+/*      acceptable error is zero.                                       */
+/* -------------------------------------------------------------------- */
+        if( dfErrorThreshold != 0.0 )
+        {
+            hTransformArg = hApproxArg = 
+                GDALCreateApproxTransformer( GDALGenImgProjTransform, 
+                                             hGenImgProjArg, dfErrorThreshold);
+            pfnTransformer = GDALApproxTransform;
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Clear temporary INIT_DEST settings after the first image.       */
+/* -------------------------------------------------------------------- */
+        if( bInitDestSetForFirst && iSrc == 1 )
+            papszWarpOptions = CSLSetNameValue( papszWarpOptions, 
+                                                "INIT_DEST", NULL );
+
+/* -------------------------------------------------------------------- */
+/*      Setup warp options.                                             */
+/* -------------------------------------------------------------------- */
+        GDALWarpOptions *psWO = GDALCreateWarpOptions();
+
+        psWO->papszWarpOptions = CSLDuplicate(papszWarpOptions);
+        psWO->eWorkingDataType = eWorkingType;
+        psWO->eResampleAlg = eResampleAlg;
+
+        psWO->hSrcDS = hSrcDS;
+        psWO->hDstDS = hDstDS;
+
+        psWO->pfnTransformer = pfnTransformer;
+        psWO->pTransformerArg = hTransformArg;
+
+        if( !bQuiet )
+            psWO->pfnProgress = GDALTermProgress;
+
+        if( dfWarpMemoryLimit != 0.0 )
+            psWO->dfWarpMemoryLimit = dfWarpMemoryLimit;
+
+/* -------------------------------------------------------------------- */
+/*      Setup band mapping.                                             */
+/* -------------------------------------------------------------------- */
+        if( bEnableSrcAlpha )
+            psWO->nBandCount = GDALGetRasterCount(hSrcDS) - 1;
+        else
+            psWO->nBandCount = GDALGetRasterCount(hSrcDS);
+
+        psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
+        psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
+
+        for( i = 0; i < psWO->nBandCount; i++ )
+        {
+            psWO->panSrcBands[i] = i+1;
+            psWO->panDstBands[i] = i+1;
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Setup alpha bands used if any.                                  */
+/* -------------------------------------------------------------------- */
+        if( bEnableSrcAlpha )
+            psWO->nSrcAlphaBand = GDALGetRasterCount(hSrcDS);
+
+        if( !bEnableDstAlpha 
+            && GDALGetRasterCount(hDstDS) == psWO->nBandCount+1 
+            && GDALGetRasterColorInterpretation( 
+                GDALGetRasterBand(hDstDS,GDALGetRasterCount(hDstDS))) 
+            == GCI_AlphaBand )
+        {
+            if( !bQuiet )
+                printf( "Using band %d of destination image as alpha.\n", 
+                        GDALGetRasterCount(hDstDS) );
+                
+            bEnableDstAlpha = TRUE;
+        }
+
+        if( bEnableDstAlpha )
+            psWO->nDstAlphaBand = GDALGetRasterCount(hDstDS);
+
+/* -------------------------------------------------------------------- */
+/*      Setup NODATA options.                                           */
+/* -------------------------------------------------------------------- */
+        if( pszSrcNodata != NULL && !EQUALN(pszSrcNodata,"n",1) )
+        {
+            char **papszTokens = CSLTokenizeString( pszSrcNodata );
+            int  nTokenCount = CSLCount(papszTokens);
+
+            psWO->padfSrcNoDataReal = (double *) 
+                CPLMalloc(psWO->nBandCount*sizeof(double));
+            psWO->padfSrcNoDataImag = (double *) 
+                CPLMalloc(psWO->nBandCount*sizeof(double));
+
+            for( i = 0; i < psWO->nBandCount; i++ )
+            {
+                if( i < nTokenCount )
+                {
+                    CPLStringToComplex( papszTokens[i], 
+                                        psWO->padfSrcNoDataReal + i,
+                                        psWO->padfSrcNoDataImag + i );
+                }
+                else
+                {
+                    psWO->padfSrcNoDataReal[i] = psWO->padfSrcNoDataReal[i-1];
+                    psWO->padfSrcNoDataImag[i] = psWO->padfSrcNoDataImag[i-1];
+                }
+            }
+
+            CSLDestroy( papszTokens );
+
+            psWO->papszWarpOptions = CSLSetNameValue(psWO->papszWarpOptions,
+                                               "UNIFIED_SRC_NODATA", "YES" );
+        }
+
+/* -------------------------------------------------------------------- */
+/*      If -srcnodata was not specified, but the data has nodata        */
+/*      values, use them.                                               */
+/* -------------------------------------------------------------------- */
+        if( pszSrcNodata == NULL )
+        {
+            int bHaveNodata = FALSE;
+            double dfReal = 0.0;
+
+            for( i = 0; !bHaveNodata && i < psWO->nBandCount; i++ )
+            {
+                GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, i+1 );
+                dfReal = GDALGetRasterNoDataValue( hBand, &bHaveNodata );
+            }
+
+            if( bHaveNodata )
+            {
+                if( !bQuiet )
+                {
+                    if (CPLIsNan(dfReal))
+                        printf( "Using internal nodata values (eg. nan) for image %s.\n",
+                                papszSrcFiles[iSrc] );
+                    else
+                        printf( "Using internal nodata values (eg. %g) for image %s.\n",
+                                dfReal, papszSrcFiles[iSrc] );
+                }
+                psWO->padfSrcNoDataReal = (double *) 
+                    CPLMalloc(psWO->nBandCount*sizeof(double));
+                psWO->padfSrcNoDataImag = (double *) 
+                    CPLMalloc(psWO->nBandCount*sizeof(double));
+                
+                for( i = 0; i < psWO->nBandCount; i++ )
+                {
+                    GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, i+1 );
+
+                    dfReal = GDALGetRasterNoDataValue( hBand, &bHaveNodata );
+
+                    if( bHaveNodata )
+                    {
+                        psWO->padfSrcNoDataReal[i] = dfReal;
+                        psWO->padfSrcNoDataImag[i] = 0.0;
+                    }
+                    else
+                    {
+                        psWO->padfSrcNoDataReal[i] = -123456.789;
+                        psWO->padfSrcNoDataImag[i] = 0.0;
+                    }
+                }
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      If the output dataset was created, and we have a destination    */
+/*      nodata value, go through marking the bands with the information.*/
+/* -------------------------------------------------------------------- */
+        if( pszDstNodata != NULL )
+        {
+            char **papszTokens = CSLTokenizeString( pszDstNodata );
+            int  nTokenCount = CSLCount(papszTokens);
+
+            psWO->padfDstNoDataReal = (double *) 
+                CPLMalloc(psWO->nBandCount*sizeof(double));
+            psWO->padfDstNoDataImag = (double *) 
+                CPLMalloc(psWO->nBandCount*sizeof(double));
+
+            for( i = 0; i < psWO->nBandCount; i++ )
+            {
+                if( i < nTokenCount )
+                {
+                    CPLStringToComplex( papszTokens[i], 
+                                        psWO->padfDstNoDataReal + i,
+                                        psWO->padfDstNoDataImag + i );
+                }
+                else
+                {
+                    psWO->padfDstNoDataReal[i] = psWO->padfDstNoDataReal[i-1];
+                    psWO->padfDstNoDataImag[i] = psWO->padfDstNoDataImag[i-1];
+                }
+                
+                GDALRasterBandH hBand = GDALGetRasterBand( hDstDS, i+1 );
+                int bClamped = FALSE, bRounded = FALSE;
+
+#define CLAMP(val,type,minval,maxval) \
+    do { if (val < minval) { bClamped = TRUE; val = minval; } \
+    else if (val > maxval) { bClamped = TRUE; val = maxval; } \
+    else if (val != (type)val) { bRounded = TRUE; val = (type)(val + 0.5); } } \
+    while(0)
+
+                switch(GDALGetRasterDataType(hBand))
+                {
+                    case GDT_Byte:
+                        CLAMP(psWO->padfDstNoDataReal[i], GByte,
+                              0.0, 255.0);
+                        break;
+                    case GDT_Int16:
+                        CLAMP(psWO->padfDstNoDataReal[i], GInt16,
+                              -32768.0, 32767.0);
+                        break;
+                    case GDT_UInt16:
+                        CLAMP(psWO->padfDstNoDataReal[i], GUInt16,
+                              0.0, 65535.0);
+                        break;
+                    case GDT_Int32:
+                        CLAMP(psWO->padfDstNoDataReal[i], GInt32,
+                              -2147483648.0, 2147483647.0);
+                        break;
+                    case GDT_UInt32:
+                        CLAMP(psWO->padfDstNoDataReal[i], GUInt32,
+                              0.0, 4294967295.0);
+                        break;
+                    default:
+                        break;
+                }
+                    
+                if (bClamped)
+                {
+                    printf( "for band %d, destination nodata value has been clamped "
+                           "to %.0f, the original value being out of range.\n",
+                           i + 1, psWO->padfDstNoDataReal[i]);
+                }
+                else if(bRounded)
+                {
+                    printf("for band %d, destination nodata value has been rounded "
+                           "to %.0f, %s being an integer datatype.\n",
+                           i + 1, psWO->padfDstNoDataReal[i],
+                           GDALGetDataTypeName(GDALGetRasterDataType(hBand)));
+                }
+
+                if( bCreateOutput )
+                {
+                    GDALSetRasterNoDataValue( 
+                        GDALGetRasterBand( hDstDS, psWO->panDstBands[i] ), 
+                        psWO->padfDstNoDataReal[i] );
+                }
+            }
+
+            CSLDestroy( papszTokens );
+        }
+
+/* -------------------------------------------------------------------- */
+/*      If we have a cutline, transform it into the source              */
+/*      pixel/line coordinate system and insert into warp options.      */
+/* -------------------------------------------------------------------- */
+        if( hCutline != NULL )
+        {
+            TransformCutlineToSource( hSrcDS, hCutline, 
+                                      &(psWO->papszWarpOptions), 
+                                      papszTO );
+        }
+
+/* -------------------------------------------------------------------- */
+/*      If we are producing VRT output, then just initialize it with    */
+/*      the warp options and write out now rather than proceeding       */
+/*      with the operations.                                            */
+/* -------------------------------------------------------------------- */
+        if( bVRT )
+        {
+            if( GDALInitializeWarpedVRT( hDstDS, psWO ) != CE_None )
+                GDALExit( 1 );
+
+            GDALClose( hDstDS );
+            GDALClose( hSrcDS );
+
+            /* The warped VRT will clean itself the transformer used */
+            /* So we have only to destroy the hGenImgProjArg if we */
+            /* have wrapped it inside the hApproxArg */
+            if (pfnTransformer == GDALApproxTransform)
+            {
+                if( hGenImgProjArg != NULL )
+                    GDALDestroyGenImgProjTransformer( hGenImgProjArg );
+            }
+
+            GDALDestroyWarpOptions( psWO );
+
+	    setMapInMaps(outputs,"Result","value",pszDstFilename);
+
+            CPLFree( pszDstFilename );
+            CSLDestroy( papszSrcFiles );
+            CSLDestroy( papszWarpOptions );
+            CSLDestroy( papszTO );
+    
+            GDALDumpOpenDatasets( stderr );
+        
+            GDALDestroyDriverManager();
+        
+            return SERVICE_SUCCEEDED;
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Initialize and execute the warp.                                */
+/* -------------------------------------------------------------------- */
+        GDALWarpOperation oWO;
+
+        if( oWO.Initialize( psWO ) == CE_None )
+        {
+            CPLErr eErr;
+            if( bMulti )
+                eErr = oWO.ChunkAndWarpMulti( 0, 0, 
+                                       GDALGetRasterXSize( hDstDS ),
+                                       GDALGetRasterYSize( hDstDS ) );
+            else
+                eErr = oWO.ChunkAndWarpImage( 0, 0, 
+                                       GDALGetRasterXSize( hDstDS ),
+                                       GDALGetRasterYSize( hDstDS ) );
+            if (eErr != CE_None){
+                bHasGotErr = TRUE;
+	    }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Cleanup                                                         */
+/* -------------------------------------------------------------------- */
+        if( hApproxArg != NULL )
+            GDALDestroyApproxTransformer( hApproxArg );
+        
+        if( hGenImgProjArg != NULL )
+            GDALDestroyGenImgProjTransformer( hGenImgProjArg );
+        
+        GDALDestroyWarpOptions( psWO );
+
+        GDALClose( hSrcDS );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Final Cleanup.                                                  */
+/* -------------------------------------------------------------------- */
+    CPLErrorReset();
+    GDALFlushCache( hDstDS );
+    if( CPLGetLastErrorType() != CE_None )
+        bHasGotErr = TRUE;
+    GDALClose( hDstDS );
+
+    setMapInMaps(outputs,"Result","value",pszDstFilename);
+    
+    CPLFree( pszDstFilename );
+    CSLDestroy( papszSrcFiles );
+    CSLDestroy( papszWarpOptions );
+    CSLDestroy( papszTO );
+
+    GDALDumpOpenDatasets( stderr );
+
+    GDALDestroyDriverManager();
+    
+#ifdef OGR_ENABLED
+    if( hCutline != NULL )
+        OGR_G_DestroyGeometry( (OGRGeometryH) hCutline );
+    OGRCleanupAll();
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/*      Clean allocated arguments.                                      */
+/* -------------------------------------------------------------------- */
+    free(dataPath);
+    free(tempPath);
+
+    tmpMap=getMapFromMaps(inputs,"te","value");
+    if(tmpMap!=NULL){
+      free(pszCutlineDSName);
+    }
+
+    tmpMap=getMapFromMaps(inputs,"cwhere","value");
+    if(tmpMap!=NULL){
+      free(pszCWHERE);
+    }
+
+    tmpMap=getMapFromMaps(inputs,"cl","value");
+    if(tmpMap!=NULL){
+      free(pszCLayer);
+    }
+
+    tmpMap=getMapFromMaps(inputs,"csql","value");
+    if(tmpMap!=NULL){
+      free(pszCSQL);
+    }
+
+    return (bHasGotErr) ? SERVICE_FAILED : SERVICE_SUCCEEDED;
+}
+
+/************************************************************************/
+/*                        GDALWarpCreateOutput()                        */
+/*                                                                      */
+/*      Create the output file based on various commandline options,    */
+/*      and the input file.                                             */
+/*      If there's just one source file, then *phTransformArg and       */
+/*      *phSrcDS will be set, in order them to be reused by main        */
+/*      function. This saves dataset re-opening, and above all transform*/
+/*      recomputation, which can be expensive in the -tps case          */
+/************************************************************************/
+
+static GDALDatasetH 
+GDALWarpCreateOutput( maps*& conf,char **papszSrcFiles, const char *pszFilename, 
+                      const char *pszFormat, char **papszTO, 
+                      char ***ppapszCreateOptions, GDALDataType eDT,
+                      void ** phTransformArg,
+                      GDALDatasetH* phSrcDS)
+
+
+{
+    GDALDriverH hDriver;
+    GDALDatasetH hDstDS;
+    void *hTransformArg;
+    GDALColorTableH hCT = NULL;
+    double dfWrkMinX=0, dfWrkMaxX=0, dfWrkMinY=0, dfWrkMaxY=0;
+    double dfWrkResX=0, dfWrkResY=0;
+    int nDstBandCount = 0;
+    std::vector<GDALColorInterp> apeColorInterpretations;
+
+    *phTransformArg = NULL;
+    *phSrcDS = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Find the output driver.                                         */
+/* -------------------------------------------------------------------- */
+    hDriver = GDALGetDriverByName( pszFormat );
+    if( hDriver == NULL 
+        || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL )
+    {
+        int	iDr;
+        char tmp[2048];
+        sprintf( tmp, "Output driver `%s' not recognised or does not support\n"
+		 "direct output file creation.  The following format drivers are configured\n"
+		 "and support direct output:\n", 
+		 pszFormat );
+
+        for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
+        {
+            GDALDriverH hDriver = GDALGetDriver(iDr);
+
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL) != NULL )
+            {
+	      char *_tmp=strdup(tmp);
+	      sprintf( tmp,"%s  %s: %s\n",
+		       _tmp,
+		       GDALGetDriverShortName( hDriver  ),
+		       GDALGetDriverLongName( hDriver ) );
+	      free(_tmp);
+            }
+        }
+	setMapInMaps(conf,"lenv","message",tmp);
+        GDALExit( 1 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      For virtual output files, we have to set a special subclass     */
+/*      of dataset to create.                                           */
+/* -------------------------------------------------------------------- */
+    if( bVRT )
+        *ppapszCreateOptions = 
+            CSLSetNameValue( *ppapszCreateOptions, "SUBCLASS", 
+                             "VRTWarpedDataset" );
+
+/* -------------------------------------------------------------------- */
+/*      Loop over all input files to collect extents.                   */
+/* -------------------------------------------------------------------- */
+    int     iSrc;
+    char    *pszThisTargetSRS = (char*)CSLFetchNameValue( papszTO, "DST_SRS" );
+    if( pszThisTargetSRS != NULL )
+        pszThisTargetSRS = CPLStrdup( pszThisTargetSRS );
+
+    for( iSrc = 0; papszSrcFiles[iSrc] != NULL; iSrc++ )
+    {
+        GDALDatasetH hSrcDS;
+        const char *pszThisSourceSRS = CSLFetchNameValue(papszTO,"SRC_SRS");
+
+        hSrcDS = GDALOpen( papszSrcFiles[iSrc], GA_ReadOnly );
+        if( hSrcDS == NULL )
+            GDALExit( 1 );
+
+/* -------------------------------------------------------------------- */
+/*      Check that there's at least one raster band                     */
+/* -------------------------------------------------------------------- */
+        if ( GDALGetRasterCount(hSrcDS) == 0 )
+        {
+            fprintf(stderr, "Input file %s has no raster bands.\n", papszSrcFiles[iSrc] );
+            GDALExit( 1 );
+        }
+
+        if( eDT == GDT_Unknown )
+            eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDS,1));
+
+/* -------------------------------------------------------------------- */
+/*      If we are processing the first file, and it has a color         */
+/*      table, then we will copy it to the destination file.            */
+/* -------------------------------------------------------------------- */
+        if( iSrc == 0 )
+        {
+            nDstBandCount = GDALGetRasterCount(hSrcDS);
+            hCT = GDALGetRasterColorTable( GDALGetRasterBand(hSrcDS,1) );
+            if( hCT != NULL )
+            {
+                hCT = GDALCloneColorTable( hCT );
+                if( !bQuiet )
+                    printf( "Copying color table from %s to new file.\n", 
+                            papszSrcFiles[iSrc] );
+            }
+
+            for(int iBand = 0; iBand < nDstBandCount; iBand++)
+            {
+                apeColorInterpretations.push_back(
+                    GDALGetRasterColorInterpretation(GDALGetRasterBand(hSrcDS,iBand+1)) );
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Get the sourcesrs from the dataset, if not set already.         */
+/* -------------------------------------------------------------------- */
+        if( pszThisSourceSRS == NULL )
+        {
+            const char *pszMethod = CSLFetchNameValue( papszTO, "METHOD" );
+
+            if( GDALGetProjectionRef( hSrcDS ) != NULL 
+                && strlen(GDALGetProjectionRef( hSrcDS )) > 0
+                && (pszMethod == NULL || EQUAL(pszMethod,"GEOTRANSFORM")) )
+                pszThisSourceSRS = GDALGetProjectionRef( hSrcDS );
+            
+            else if( GDALGetGCPProjection( hSrcDS ) != NULL
+                     && strlen(GDALGetGCPProjection(hSrcDS)) > 0 
+                     && GDALGetGCPCount( hSrcDS ) > 1 
+                     && (pszMethod == NULL || EQUALN(pszMethod,"GCP_",4)) )
+                pszThisSourceSRS = GDALGetGCPProjection( hSrcDS );
+            else if( pszMethod != NULL && EQUAL(pszMethod,"RPC") )
+                pszThisSourceSRS = SRS_WKT_WGS84;
+            else
+                pszThisSourceSRS = "";
+        }
+
+        if( pszThisTargetSRS == NULL )
+            pszThisTargetSRS = CPLStrdup( pszThisSourceSRS );
+        
+/* -------------------------------------------------------------------- */
+/*      Create a transformation object from the source to               */
+/*      destination coordinate system.                                  */
+/* -------------------------------------------------------------------- */
+        hTransformArg = 
+            GDALCreateGenImgProjTransformer2( hSrcDS, NULL, papszTO );
+        
+        if( hTransformArg == NULL )
+        {
+            CPLFree( pszThisTargetSRS );
+            GDALClose( hSrcDS );
+            return NULL;
+        }
+        
+        GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg;
+
+/* -------------------------------------------------------------------- */
+/*      Get approximate output definition.                              */
+/* -------------------------------------------------------------------- */
+        double adfThisGeoTransform[6];
+        double adfExtent[4];
+        int    nThisPixels, nThisLines;
+
+        if( GDALSuggestedWarpOutput2( hSrcDS, 
+                                      psInfo->pfnTransform, hTransformArg, 
+                                      adfThisGeoTransform, 
+                                      &nThisPixels, &nThisLines, 
+                                      adfExtent, 0 ) != CE_None )
+        {
+            CPLFree( pszThisTargetSRS );
+            GDALClose( hSrcDS );
+            return NULL;
+        }
+        
+        if (CPLGetConfigOption( "CHECK_WITH_INVERT_PROJ", NULL ) == NULL)
+        {
+            double MinX = adfExtent[0];
+            double MaxX = adfExtent[2];
+            double MaxY = adfExtent[3];
+            double MinY = adfExtent[1];
+            int bSuccess = TRUE;
+            
+            /* Check that the the edges of the target image are in the validity area */
+            /* of the target projection */
+#define N_STEPS 20
+            int i,j;
+            for(i=0;i<=N_STEPS && bSuccess;i++)
+            {
+                for(j=0;j<=N_STEPS && bSuccess;j++)
+                {
+                    double dfRatioI = i * 1.0 / N_STEPS;
+                    double dfRatioJ = j * 1.0 / N_STEPS;
+                    double expected_x = (1 - dfRatioI) * MinX + dfRatioI * MaxX;
+                    double expected_y = (1 - dfRatioJ) * MinY + dfRatioJ * MaxY;
+                    double x = expected_x;
+                    double y = expected_y;
+                    double z = 0;
+                    /* Target SRS coordinates to source image pixel coordinates */
+                    if (!psInfo->pfnTransform(hTransformArg, TRUE, 1, &x, &y, &z, &bSuccess) || !bSuccess)
+                        bSuccess = FALSE;
+                    /* Source image pixel coordinates to target SRS coordinates */
+                    if (!psInfo->pfnTransform(hTransformArg, FALSE, 1, &x, &y, &z, &bSuccess) || !bSuccess)
+                        bSuccess = FALSE;
+                    if (fabs(x - expected_x) > (MaxX - MinX) / nThisPixels ||
+                        fabs(y - expected_y) > (MaxY - MinY) / nThisLines)
+                        bSuccess = FALSE;
+                }
+            }
+            
+            /* If not, retry with CHECK_WITH_INVERT_PROJ=TRUE that forces ogrct.cpp */
+            /* to check the consistency of each requested projection result with the */
+            /* invert projection */
+            if (!bSuccess)
+            {
+                CPLSetConfigOption( "CHECK_WITH_INVERT_PROJ", "TRUE" );
+                CPLDebug("WARP", "Recompute out extent with CHECK_WITH_INVERT_PROJ=TRUE");
+
+                if( GDALSuggestedWarpOutput2( hSrcDS, 
+                                      psInfo->pfnTransform, hTransformArg, 
+                                      adfThisGeoTransform, 
+                                      &nThisPixels, &nThisLines, 
+                                      adfExtent, 0 ) != CE_None )
+                {
+                    CPLFree( pszThisTargetSRS );
+                    GDALClose( hSrcDS );
+                    return NULL;
+                }
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Expand the working bounds to include this region, ensure the    */
+/*      working resolution is no more than this resolution.             */
+/* -------------------------------------------------------------------- */
+        if( dfWrkMaxX == 0.0 && dfWrkMinX == 0.0 )
+        {
+            dfWrkMinX = adfExtent[0];
+            dfWrkMaxX = adfExtent[2];
+            dfWrkMaxY = adfExtent[3];
+            dfWrkMinY = adfExtent[1];
+            dfWrkResX = adfThisGeoTransform[1];
+            dfWrkResY = ABS(adfThisGeoTransform[5]);
+        }
+        else
+        {
+            dfWrkMinX = MIN(dfWrkMinX,adfExtent[0]);
+            dfWrkMaxX = MAX(dfWrkMaxX,adfExtent[2]);
+            dfWrkMaxY = MAX(dfWrkMaxY,adfExtent[3]);
+            dfWrkMinY = MIN(dfWrkMinY,adfExtent[1]);
+            dfWrkResX = MIN(dfWrkResX,adfThisGeoTransform[1]);
+            dfWrkResY = MIN(dfWrkResY,ABS(adfThisGeoTransform[5]));
+        }
+
+        if (iSrc == 0 && papszSrcFiles[1] == NULL)
+        {
+            *phTransformArg = hTransformArg;
+            *phSrcDS = hSrcDS;
+        }
+        else
+        {
+            GDALDestroyGenImgProjTransformer( hTransformArg );
+            GDALClose( hSrcDS );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Did we have any usable sources?                                 */
+/* -------------------------------------------------------------------- */
+    if( nDstBandCount == 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "No usable source images." );
+        CPLFree( pszThisTargetSRS );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Turn the suggested region into a geotransform and suggested     */
+/*      number of pixels and lines.                                     */
+/* -------------------------------------------------------------------- */
+    double adfDstGeoTransform[6];
+    int nPixels, nLines;
+
+    adfDstGeoTransform[0] = dfWrkMinX;
+    adfDstGeoTransform[1] = dfWrkResX;
+    adfDstGeoTransform[2] = 0.0;
+    adfDstGeoTransform[3] = dfWrkMaxY;
+    adfDstGeoTransform[4] = 0.0;
+    adfDstGeoTransform[5] = -1 * dfWrkResY;
+
+    nPixels = (int) ((dfWrkMaxX - dfWrkMinX) / dfWrkResX + 0.5);
+    nLines = (int) ((dfWrkMaxY - dfWrkMinY) / dfWrkResY + 0.5);
+
+/* -------------------------------------------------------------------- */
+/*      Did the user override some parameters?                          */
+/* -------------------------------------------------------------------- */
+    if( dfXRes != 0.0 && dfYRes != 0.0 )
+    {
+        if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
+        {
+            dfMinX = adfDstGeoTransform[0];
+            dfMaxX = adfDstGeoTransform[0] + adfDstGeoTransform[1] * nPixels;
+            dfMaxY = adfDstGeoTransform[3];
+            dfMinY = adfDstGeoTransform[3] + adfDstGeoTransform[5] * nLines;
+        }
+        
+        if ( bTargetAlignedPixels )
+        {
+            dfMinX = floor(dfMinX / dfXRes) * dfXRes;
+            dfMaxX = ceil(dfMaxX / dfXRes) * dfXRes;
+            dfMinY = floor(dfMinY / dfYRes) * dfYRes;
+            dfMaxY = ceil(dfMaxY / dfYRes) * dfYRes;
+        }
+
+        nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
+        nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
+        adfDstGeoTransform[0] = dfMinX;
+        adfDstGeoTransform[3] = dfMaxY;
+        adfDstGeoTransform[1] = dfXRes;
+        adfDstGeoTransform[5] = -dfYRes;
+    }
+
+    else if( nForcePixels != 0 && nForceLines != 0 )
+    {
+        if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
+        {
+            dfMinX = dfWrkMinX;
+            dfMaxX = dfWrkMaxX;
+            dfMaxY = dfWrkMaxY;
+            dfMinY = dfWrkMinY;
+        }
+
+        dfXRes = (dfMaxX - dfMinX) / nForcePixels;
+        dfYRes = (dfMaxY - dfMinY) / nForceLines;
+
+        adfDstGeoTransform[0] = dfMinX;
+        adfDstGeoTransform[3] = dfMaxY;
+        adfDstGeoTransform[1] = dfXRes;
+        adfDstGeoTransform[5] = -dfYRes;
+
+        nPixels = nForcePixels;
+        nLines = nForceLines;
+    }
+
+    else if( nForcePixels != 0 )
+    {
+        if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
+        {
+            dfMinX = dfWrkMinX;
+            dfMaxX = dfWrkMaxX;
+            dfMaxY = dfWrkMaxY;
+            dfMinY = dfWrkMinY;
+        }
+
+        dfXRes = (dfMaxX - dfMinX) / nForcePixels;
+        dfYRes = dfXRes;
+
+        adfDstGeoTransform[0] = dfMinX;
+        adfDstGeoTransform[3] = dfMaxY;
+        adfDstGeoTransform[1] = dfXRes;
+        adfDstGeoTransform[5] = -dfYRes;
+
+        nPixels = nForcePixels;
+        nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
+    }
+
+    else if( nForceLines != 0 )
+    {
+        if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
+        {
+            dfMinX = dfWrkMinX;
+            dfMaxX = dfWrkMaxX;
+            dfMaxY = dfWrkMaxY;
+            dfMinY = dfWrkMinY;
+        }
+
+        dfYRes = (dfMaxY - dfMinY) / nForceLines;
+        dfXRes = dfYRes;
+
+        adfDstGeoTransform[0] = dfMinX;
+        adfDstGeoTransform[3] = dfMaxY;
+        adfDstGeoTransform[1] = dfXRes;
+        adfDstGeoTransform[5] = -dfYRes;
+
+        nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
+        nLines = nForceLines;
+    }
+
+    else if( dfMinX != 0.0 || dfMinY != 0.0 || dfMaxX != 0.0 || dfMaxY != 0.0 )
+    {
+        dfXRes = adfDstGeoTransform[1];
+        dfYRes = fabs(adfDstGeoTransform[5]);
+
+        nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
+        nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
+
+        dfXRes = (dfMaxX - dfMinX) / nPixels;
+        dfYRes = (dfMaxY - dfMinY) / nLines;
+
+        adfDstGeoTransform[0] = dfMinX;
+        adfDstGeoTransform[3] = dfMaxY;
+        adfDstGeoTransform[1] = dfXRes;
+        adfDstGeoTransform[5] = -dfYRes;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Do we want to generate an alpha band in the output file?        */
+/* -------------------------------------------------------------------- */
+    if( bEnableSrcAlpha )
+        nDstBandCount--;
+
+    if( bEnableDstAlpha )
+        nDstBandCount++;
+
+/* -------------------------------------------------------------------- */
+/*      Create the output file.                                         */
+/* -------------------------------------------------------------------- */
+    if( !bQuiet )
+        printf( "Creating output file that is %dP x %dL.\n", nPixels, nLines );
+
+    hDstDS = GDALCreate( hDriver, pszFilename, nPixels, nLines, 
+                         nDstBandCount, eDT, *ppapszCreateOptions );
+    
+    if( hDstDS == NULL )
+    {
+        CPLFree( pszThisTargetSRS );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write out the projection definition.                            */
+/* -------------------------------------------------------------------- */
+    GDALSetProjection( hDstDS, pszThisTargetSRS );
+    GDALSetGeoTransform( hDstDS, adfDstGeoTransform );
+
+    if (*phTransformArg != NULL)
+        GDALSetGenImgProjTransformerDstGeoTransform( *phTransformArg, adfDstGeoTransform);
+
+/* -------------------------------------------------------------------- */
+/*      Try to set color interpretation of source bands to target       */
+/*      dataset.                                                        */
+/*      FIXME? We should likely do that for other drivers than VRT      */
+/*      but it might create spurious .aux.xml files (at least with HFA, */
+/*      and netCDF)                                                     */
+/* -------------------------------------------------------------------- */
+    if( bVRT )
+    {
+        int nBandsToCopy = (int)apeColorInterpretations.size();
+        if ( bEnableSrcAlpha )
+            nBandsToCopy --;
+        for(int iBand = 0; iBand < nBandsToCopy; iBand++)
+        {
+            GDALSetRasterColorInterpretation(
+                GDALGetRasterBand( hDstDS, iBand + 1 ),
+                apeColorInterpretations[iBand] );
+        }
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Try to set color interpretation of output file alpha band.      */
+/* -------------------------------------------------------------------- */
+    if( bEnableDstAlpha )
+    {
+        GDALSetRasterColorInterpretation( 
+            GDALGetRasterBand( hDstDS, nDstBandCount ), 
+            GCI_AlphaBand );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Copy the color table, if required.                              */
+/* -------------------------------------------------------------------- */
+    if( hCT != NULL )
+    {
+        GDALSetRasterColorTable( GDALGetRasterBand(hDstDS,1), hCT );
+        GDALDestroyColorTable( hCT );
+    }
+
+    CPLFree( pszThisTargetSRS );
+    return hDstDS;
+}
+
+/************************************************************************/
+/*                      GeoTransform_Transformer()                      */
+/*                                                                      */
+/*      Convert points from georef coordinates to pixel/line based      */
+/*      on a geotransform.                                              */
+/************************************************************************/
+
+class CutlineTransformer : public OGRCoordinateTransformation
+{
+public:
+
+    void         *hSrcImageTransformer;
+
+    virtual OGRSpatialReference *GetSourceCS() { return NULL; }
+    virtual OGRSpatialReference *GetTargetCS() { return NULL; }
+
+    virtual int Transform( int nCount, 
+                           double *x, double *y, double *z = NULL ) {
+        int nResult;
+
+        int *pabSuccess = (int *) CPLCalloc(sizeof(int),nCount);
+        nResult = TransformEx( nCount, x, y, z, pabSuccess );
+        CPLFree( pabSuccess );
+
+        return nResult;
+    }
+
+    virtual int TransformEx( int nCount, 
+                             double *x, double *y, double *z = NULL,
+                             int *pabSuccess = NULL ) {
+        return GDALGenImgProjTransform( hSrcImageTransformer, TRUE, 
+                                        nCount, x, y, z, pabSuccess );
+    }
+};
+
+
+/************************************************************************/
+/*                            LoadCutline()                             */
+/*                                                                      */
+/*      Load blend cutline from OGR datasource.                         */
+/************************************************************************/
+
+static void
+LoadCutline( const char *pszCutlineDSName, const char *pszCLayer, 
+             const char *pszCWHERE, const char *pszCSQL, 
+             void **phCutlineRet )
+
+{
+#ifndef OGR_ENABLED
+    CPLError( CE_Failure, CPLE_AppDefined, 
+              "Request to load a cutline failed, this build does not support OGR features.\n" );
+    GDALExit( 1 );
+#else // def OGR_ENABLED
+    OGRRegisterAll();
+
+/* -------------------------------------------------------------------- */
+/*      Open source vector dataset.                                     */
+/* -------------------------------------------------------------------- */
+    OGRDataSourceH hSrcDS;
+
+    hSrcDS = OGROpen( pszCutlineDSName, FALSE, NULL );
+    if( hSrcDS == NULL )
+        GDALExit( 1 );
+
+/* -------------------------------------------------------------------- */
+/*      Get the source layer                                            */
+/* -------------------------------------------------------------------- */
+    OGRLayerH hLayer = NULL;
+
+    if( pszCSQL != NULL )
+        hLayer = OGR_DS_ExecuteSQL( hSrcDS, pszCSQL, NULL, NULL ); 
+    else if( pszCLayer != NULL )
+        hLayer = OGR_DS_GetLayerByName( hSrcDS, pszCLayer );
+    else
+        hLayer = OGR_DS_GetLayer( hSrcDS, 0 );
+
+    if( hLayer == NULL )
+    {
+        fprintf( stderr, "Failed to identify source layer from datasource.\n" );
+        GDALExit( 1 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Apply WHERE clause if there is one.                             */
+/* -------------------------------------------------------------------- */
+    if( pszCWHERE != NULL )
+        OGR_L_SetAttributeFilter( hLayer, pszCWHERE );
+
+/* -------------------------------------------------------------------- */
+/*      Collect the geometries from this layer, and build list of       */
+/*      burn values.                                                    */
+/* -------------------------------------------------------------------- */
+    OGRFeatureH hFeat;
+    OGRGeometryH hMultiPolygon = OGR_G_CreateGeometry( wkbMultiPolygon );
+
+    OGR_L_ResetReading( hLayer );
+    
+    while( (hFeat = OGR_L_GetNextFeature( hLayer )) != NULL )
+    {
+        OGRGeometryH hGeom = OGR_F_GetGeometryRef(hFeat);
+
+        if( hGeom == NULL )
+        {
+            fprintf( stderr, "ERROR: Cutline feature without a geometry.\n" );
+            GDALExit( 1 );
+        }
+        
+        OGRwkbGeometryType eType = wkbFlatten(OGR_G_GetGeometryType( hGeom ));
+
+        if( eType == wkbPolygon )
+            OGR_G_AddGeometry( hMultiPolygon, hGeom );
+        else if( eType == wkbMultiPolygon )
+        {
+            int iGeom;
+
+            for( iGeom = 0; iGeom < OGR_G_GetGeometryCount( hGeom ); iGeom++ )
+            {
+                OGR_G_AddGeometry( hMultiPolygon, 
+                                   OGR_G_GetGeometryRef(hGeom,iGeom) );
+            }
+        }
+        else
+        {
+            fprintf( stderr, "ERROR: Cutline not of polygon type.\n" );
+            GDALExit( 1 );
+        }
+
+        OGR_F_Destroy( hFeat );
+    }
+
+    if( OGR_G_GetGeometryCount( hMultiPolygon ) == 0 )
+    {
+        fprintf( stderr, "ERROR: Did not get any cutline features.\n" );
+        GDALExit( 1 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Ensure the coordinate system gets set on the geometry.          */
+/* -------------------------------------------------------------------- */
+    OGR_G_AssignSpatialReference(
+        hMultiPolygon, OGR_L_GetSpatialRef(hLayer) );
+
+    *phCutlineRet = (void *) hMultiPolygon;
+
+/* -------------------------------------------------------------------- */
+/*      Cleanup                                                         */
+/* -------------------------------------------------------------------- */
+    if( pszCSQL != NULL )
+        OGR_DS_ReleaseResultSet( hSrcDS, hLayer );
+
+    OGR_DS_Destroy( hSrcDS );
+#endif
+}
+
+/************************************************************************/
+/*                      TransformCutlineToSource()                      */
+/*                                                                      */
+/*      Transform cutline from its SRS to source pixel/line coordinates.*/
+/************************************************************************/
+static void
+TransformCutlineToSource( GDALDatasetH hSrcDS, void *hCutline,
+                          char ***ppapszWarpOptions, char **papszTO_In )
+
+{
+#ifdef OGR_ENABLED
+    OGRGeometryH hMultiPolygon = OGR_G_Clone( (OGRGeometryH) hCutline );
+    char **papszTO = CSLDuplicate( papszTO_In );
+
+/* -------------------------------------------------------------------- */
+/*      Checkout that SRS are the same.                                 */
+/* -------------------------------------------------------------------- */
+    OGRSpatialReferenceH  hRasterSRS = NULL;
+    const char *pszProjection = NULL;
+
+    if( GDALGetProjectionRef( hSrcDS ) != NULL 
+        && strlen(GDALGetProjectionRef( hSrcDS )) > 0 )
+        pszProjection = GDALGetProjectionRef( hSrcDS );
+    else if( GDALGetGCPProjection( hSrcDS ) != NULL )
+        pszProjection = GDALGetGCPProjection( hSrcDS );
+
+    if( pszProjection != NULL )
+    {
+        hRasterSRS = OSRNewSpatialReference(NULL);
+        if( OSRImportFromWkt( hRasterSRS, (char **)&pszProjection ) != CE_None )
+        {
+            OSRDestroySpatialReference(hRasterSRS);
+            hRasterSRS = NULL;
+        }
+    }
+
+    OGRSpatialReferenceH hCutlineSRS = OGR_G_GetSpatialReference( hMultiPolygon );
+    if( hRasterSRS != NULL && hCutlineSRS != NULL )
+    {
+        /* ok, we will reproject */
+    }
+    else if( hRasterSRS != NULL && hCutlineSRS == NULL )
+    {
+        fprintf(stderr,
+                "Warning : the source raster dataset has a SRS, but the cutline features\n"
+                "not.  We assume that the cutline coordinates are expressed in the destination SRS.\n"
+                "If not, cutline results may be incorrect.\n");
+    }
+    else if( hRasterSRS == NULL && hCutlineSRS != NULL )
+    {
+        fprintf(stderr,
+                "Warning : the input vector layer has a SRS, but the source raster dataset does not.\n"
+                "Cutline results may be incorrect.\n");
+    }
+
+    if( hRasterSRS != NULL )
+        OSRDestroySpatialReference(hRasterSRS);
+
+/* -------------------------------------------------------------------- */
+/*      Extract the cutline SRS WKT.                                    */
+/* -------------------------------------------------------------------- */
+    if( hCutlineSRS != NULL )
+    {
+        char *pszCutlineSRS_WKT = NULL;
+
+        OSRExportToWkt( hCutlineSRS, &pszCutlineSRS_WKT );
+        papszTO = CSLSetNameValue( papszTO, "DST_SRS", pszCutlineSRS_WKT );
+        CPLFree( pszCutlineSRS_WKT );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      It may be unwise to let the mask geometry be re-wrapped by      */
+/*      the CENTER_LONG machinery as this can easily screw up world     */
+/*      spanning masks and invert the mask topology.                    */
+/* -------------------------------------------------------------------- */
+    papszTO = CSLSetNameValue( papszTO, "INSERT_CENTER_LONG", "FALSE" );
+
+/* -------------------------------------------------------------------- */
+/*      Transform the geometry to pixel/line coordinates.               */
+/* -------------------------------------------------------------------- */
+    CutlineTransformer oTransformer;
+
+    /* The cutline transformer will *invert* the hSrcImageTransformer */
+    /* so it will convert from the cutline SRS to the source pixel/line */
+    /* coordinates */
+    oTransformer.hSrcImageTransformer = 
+        GDALCreateGenImgProjTransformer2( hSrcDS, NULL, papszTO );
+
+    CSLDestroy( papszTO );
+
+    if( oTransformer.hSrcImageTransformer == NULL )
+        GDALExit( 1 );
+
+    OGR_G_Transform( hMultiPolygon, 
+                     (OGRCoordinateTransformationH) &oTransformer );
+
+    GDALDestroyGenImgProjTransformer( oTransformer.hSrcImageTransformer );
+
+/* -------------------------------------------------------------------- */
+/*      Convert aggregate geometry into WKT.                            */
+/* -------------------------------------------------------------------- */
+    char *pszWKT = NULL;
+
+    OGR_G_ExportToWkt( hMultiPolygon, &pszWKT );
+    OGR_G_DestroyGeometry( hMultiPolygon );
+
+    *ppapszWarpOptions = CSLSetNameValue( *ppapszWarpOptions, 
+                                          "CUTLINE", pszWKT );
+    CPLFree( pszWKT );
+#endif
+}
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/LICENSE
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/LICENSE	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/LICENSE	(revision 942)
@@ -0,0 +1,21 @@
+ZOO-Kernel License
+
+Copyright (c) 2009-2013 GeoLabs SARL
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights 
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies of this Software or works derived from this Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/Makefile	(revision 942)
@@ -0,0 +1,5 @@
+cgi-env/service.zo: servive.for
+	gfortran -shared -fpic -o cgi-env/fortran_hello.zo ./service.f
+
+clean:
+	rm -f cgi-env/*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/cgi-env/hellof.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/cgi-env/hellof.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/cgi-env/hellof.zcfg	(revision 942)
@@ -0,0 +1,40 @@
+[hellof]
+ Title = Hello string
+ Abstract = Create a welcome message.
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = driftx_service.zo
+ serviceType = C-FORTRAN
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [S]
+   Title = The string
+   Abstract = The name to display in the welcome message.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [result]
+   Title = The string
+   Abstract = The string created by service.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/service.f
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/service.f	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-fortran/service.f	(revision 942)
@@ -0,0 +1,44 @@
+ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+c     Simply create a welcome message
+ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+       Integer FUNCTION HELLOF(zoo_main_cfg,zoo_inputs,zoo_outputs)
+     & RESULT (R)
+       Integer R, ls, iLenStr
+       CHARACTER*(1024) zoo_main_cfg(10,30),zoo_inputs(10,30),
+     & zoo_outputs(10,30)
+        CHARACTER*(1024) TMP
+
+       write(0,*) 'Hello '//zoo_inputs(4,1)//' from the Fortran world !'
+
+       ls = iLenStr(zoo_inputs(4,1))
+       TMP = zoo_inputs(4,1)
+       zoo_outputs(1,1) = 'name'//CHAR(0)
+       zoo_outputs(2,1) = 'result'//CHAR(0)
+       zoo_outputs(3,1) = 'value'//CHAR(0)
+       zoo_outputs(4,1) = 'Hello '//TMP(1:ls)//
+     & ' from the Fortran world !'//CHAR(0)
+       zoo_outputs(5,1) = 'datatype'//CHAR(0)
+       zoo_outputs(6,1) = 'string'//CHAR(0)
+
+       R = 3
+       Return
+       END
+
+       Integer Function iLenStr(cString)
+ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+c     Compute String Length (thanks to Abdelatif Djerboua from RHEA™)
+ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+       Character*(*) cString
+       Integer       iLen,i
+
+      iLen = Len(cString)
+      Do i=iLen,1,-1
+         If(ichar(cString(i:i)).NE.0) Goto 10
+      EndDo
+      i = 1
+  10  Continue
+      iLenStr = i
+
+      Return
+      End Function iLenStr
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/HelloJava.java
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/HelloJava.java	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/HelloJava.java	(revision 942)
@@ -0,0 +1,54 @@
+/**
+ * Author : Gérald FENOY
+ *
+ *  Copyright 2008-2009 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import java.lang.*;
+import java.util.*;
+import org.zoo_project.*;
+
+public class HelloJava {
+    public static int HelloWorldJava(HashMap conf,HashMap inputs, HashMap outputs) {
+        HashMap tmp=(HashMap)(inputs.get("S"));
+        String v=tmp.get("value").toString();
+        HashMap hm1 = (HashMap)(outputs.get("Result"));
+        hm1.put("value",ZOO.translate("Hello "+v+" from JAVA World !!"));
+        return ZOO.SERVICE_SUCCEEDED;
+    }
+    public static int JavaLongProcess(HashMap conf,HashMap inputs, HashMap outputs) {
+        HashMap tmp=(HashMap)(inputs.get("S"));
+        String v=tmp.get("value").toString();
+	Integer i;
+	for(i=0;i<100;i+=5){
+	    ZOO.updateStatus(conf,String.valueOf(i),"Currently executing tasks "+String.valueOf(i/5)+"..");
+	    try{
+		Thread.sleep(2000);
+	    }catch(java.lang.InterruptedException e){
+	    }finally{
+	    }
+	}
+        HashMap hm1 = (HashMap)(outputs.get("Result"));
+        hm1.put("value",ZOO.translate("Hello "+v+" from JAVA World !!"));
+        return ZOO.SERVICE_SUCCEEDED;
+    }
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/Makefile	(revision 942)
@@ -0,0 +1,5 @@
+cgi-env/HelloJava.class: HelloJava.java
+	javac -d cgi-env -cp ../../zoo-api/java/ HelloJava.java 
+
+clean:
+	rm cgi-env/*class
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/cgi-env/HelloWorldJava.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/cgi-env/HelloWorldJava.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/cgi-env/HelloWorldJava.zcfg	(revision 942)
@@ -0,0 +1,33 @@
+[HelloWorldJava]
+ Title = Display a string
+ Abstract = Display a string which contains an hello message
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = HelloJava
+ serviceType = Java
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [S]
+   Title = the string
+   Abstract = The string to add to the hellow one.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The hello string
+   Abstract = The Hello message string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/cgi-env/JavaLongProcess.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/cgi-env/JavaLongProcess.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-java/cgi-env/JavaLongProcess.zcfg	(revision 942)
@@ -0,0 +1,33 @@
+[JavaLongProcess]
+ Title = Display a string
+ Abstract = Display a string which contains an hello message after waiting many times to illustrate the way you can use updateStatus ZOO-API function from your Java service
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = HelloJava
+ serviceType = Java
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [S]
+   Title = the string
+   Abstract = The string to add to the hellow one.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The hello string
+   Abstract = The Hello message string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hello.js
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hello.js	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hello.js	(revision 942)
@@ -0,0 +1,36 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2009-2013 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+function hellojs(conf,inputs,outputs){
+	outputs["result"]["value"]="Hello "+inputs["S"]["value"]+" from the JS World !";
+	//SERVICE_SUCEEDED
+	return Array(3,outputs);
+}
+
+function hellojs1(conf,inputs,outputs){
+	outputs["result"]["value"]="Hello "+inputs["S"]["value"]+" from the JS World !";
+	//SERVICE_SUCEEDED
+	return {"result":3,"outputs": outputs};
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hellojs.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hellojs.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hellojs.zcfg	(revision 942)
@@ -0,0 +1,40 @@
+[hellojs]
+ Title = HelloWorld Service in JavaScript
+ Abstract = Output and Hello Wolrd string
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.js
+ serviceType = JS
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [S]
+   Title = Name
+   Abstract = The name to display in the hello message
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [result]
+   Title = The resulting string
+   Abstract = The string created by service.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <LiteralOutput>
+     dataType = string
+     <Default>
+     </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hellojs1.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hellojs1.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-js/cgi-env/hellojs1.zcfg	(revision 942)
@@ -0,0 +1,40 @@
+[hellojs1]
+ Title = HelloWorld Service in JavaScript
+ Abstract = Output and Hello Wolrd string
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.js
+ serviceType = JS
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [S]
+   Title = Name
+   Abstract = The name to display in the hello message
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [result]
+   Title = The resulting string
+   Abstract = The string created by service.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <LiteralOutput>
+     dataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/Makefile	(revision 942)
@@ -0,0 +1,7 @@
+all: cgi-env/TestService.dll
+
+cgi-env/TestService.dll: test.cs
+	mcs /target:library -r:../../zoo-api/mono/ZMaps.dll -out:cgi-env/TestService.dll test.cs 
+
+clean: 
+	rm -rf cgi-env/*dll
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/cgi-env/HelloMono.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/cgi-env/HelloMono.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/cgi-env/HelloMono.zcfg	(revision 942)
@@ -0,0 +1,43 @@
+[HelloMono]
+ Title = Create a welcome message string.
+ Abstract = Create a welcome string.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = TestService.dll
+ serviceNameSpace = Default
+ serviceClass = Service
+ serviceType = Mono
+ <DataInputs>
+  [a]
+   Title = Input string
+   Abstract = The name to display in the welcome message.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = int
+    <Default>
+    AllowedValues = 101,202,303,404
+    rangeMin = -100
+    rangeMax = 100
+    rangeSpacing = 1
+    rangeClosure = co
+      value = 11
+    </Default>
+    <Supported>
+    	AllowedValues = 405,502,503,504
+    </Supported>
+    <Supported>
+    	AllowedValues = 540,502,603,604
+    </Supported>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The welcome message
+   Abstract = The welcome message created by service.
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataOutputs>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/cgi-env/longProcessMono.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/cgi-env/longProcessMono.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/cgi-env/longProcessMono.zcfg	(revision 942)
@@ -0,0 +1,30 @@
+[longProcessMono]
+ Title = Demo long process.
+ Abstract = This service doesn't do anything except taking its time, it demonstrates how to use the updateStatus function from your ZOO Service.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = TestService.dll
+ serviceNameSpace = Default
+ serviceClass = Service
+ serviceType = Mono
+ <DataInputs>
+  [a]
+   Title = Input string
+   Abstract = The name to display in the welcome message.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = int
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The welcome message
+   Abstract = The welcome message created by service.
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataOutputs>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/makefile.vc	(revision 942)
@@ -0,0 +1,9 @@
+!INCLUDE ../../zoo-kernel/nmake.opt
+	
+all: cgi-env/TestService.dll
+
+cgi-env/TestService.dll: test.cs
+	$(MONO_DIR)\bin\mcs /target:library -r:../../zoo-api/mono/ZMaps.dll -out:cgi-env/TestService.dll test.cs
+
+clean:
+	rm -rf cgi-env/*dll
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/test.cs
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/test.cs	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-mono/test.cs	(revision 942)
@@ -0,0 +1,66 @@
+/*
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2016 GeoLabs SARL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+using System;
+using ZooGenerics;
+using System.Threading;
+
+namespace Default
+{
+    public class Service{
+	public static int HelloMono(ZMaps conf,ZMaps inputs,ZMaps outputs){
+	    _ZMaps test;
+	    if(inputs.TryGetValue("a", out test)){
+		ZMap content=test.getContent();
+		String test1;
+		if(content.TryGetValue("value", out test1)){
+		    outputs.setMapsInMaps("Result","value",ZOO_API.Translate("Hello ")+test1+" from the Mono .NET framework World!");
+		}
+		return ZOO_API.SERVICE_SUCCEEDED;
+	    }else{
+		conf.setMapsInMaps("lenv","message","Unable to run the service");
+		return ZOO_API.SERVICE_FAILED;
+	    }
+	}
+	public static int longProcessMono(ZMaps conf,ZMaps inputs,ZMaps outputs){
+	    _ZMaps test;
+	    int i=1;
+	    while(i<10){
+		ZOO_API.UpdateStatus(conf,"Step "+i,(i*10));
+		Thread.Sleep(1000);
+		i+=1;
+	    }
+	    if(inputs.TryGetValue("a", out test)){
+		ZMap content=test.getContent();
+		String test1;
+		if(content.TryGetValue("value", out test1)){
+		    outputs.setMapsInMaps("Result","value",ZOO_API.Translate("Hello ")+test1+" from the Mono .NET framework World!");
+		}
+		return ZOO_API.SERVICE_SUCCEEDED;
+	    }else{
+		conf.setMapsInMaps("lenv","message","Unable to run the service");
+		return ZOO_API.SERVICE_FAILED;
+	    }
+	}
+    };
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-perl/Hello.pl
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-perl/Hello.pl	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-perl/Hello.pl	(revision 942)
@@ -0,0 +1,32 @@
+#
+# Author : David Saggiorato
+#
+# Copyright 2009-2013 GeoLabs SARL. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including with
+# out limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+sub HelloPL {
+	my ($main_conf,$real_inputs,$real_outputs) = @_;
+	
+	$real_outputs->{"Result"}->{"value"}=$real_inputs->{"a"}->{"value"};
+	return 3;
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-perl/cgi-env/HelloPL.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-perl/cgi-env/HelloPL.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-perl/cgi-env/HelloPL.zcfg	(revision 942)
@@ -0,0 +1,39 @@
+[HelloPL]
+ Title = Create a welcome message string.
+ Abstract = Create a welcome string.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = Hello.pl
+ serviceType = Perl
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [a]
+   Title = Input string
+   Abstract = The name to display in the welcome message.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = My test
+   </MetaData>
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The welcome message
+   Abstract = The welcome message created by service.
+   <MetaData>
+    title = My test
+   </MetaData>
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataOutputs>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-php/cgi-env/HelloPHP.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-php/cgi-env/HelloPHP.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-php/cgi-env/HelloPHP.zcfg	(revision 942)
@@ -0,0 +1,33 @@
+[HelloPHP]
+ Title = Display a string
+ Abstract = Display a string which contains an hello message
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.php
+ serviceType = PHP
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [S]
+   Title = the string
+   Abstract = The string to add to the hellow one.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The hello string
+   Abstract = The Hello message string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-php/cgi-env/hello.php
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-php/cgi-env/hello.php	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-php/cgi-env/hello.php	(revision 942)
@@ -0,0 +1,34 @@
+<?
+
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2009-20013 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+function HelloPHP(&$main_conf,&$inputs,&$outputs){
+  $tmp="Hello ".$inputs["S"]["value"]." from the PHP world !!";
+  $outputs["Result"]["value"]=zoo_Translate($tmp);
+  zoo_UpdateStatus($main_conf,"Final step",99);
+  return zoo_SERVICE_SUCCEEDED();
+}
+
+?>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-py/cgi-env/HelloPy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-py/cgi-env/HelloPy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-py/cgi-env/HelloPy.zcfg	(revision 942)
@@ -0,0 +1,47 @@
+[HelloPy]
+ Title = Create a welcome message string.
+ Abstract = Create a welcome string.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = test_service
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [a]
+   Title = Input string
+   Abstract = The name to display in the welcome message.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = My test
+   </MetaData>
+   <LiteralData>
+    DataType = string
+    <Default>
+     UOM = meter
+    </Default>
+    <Supported>
+     UOM = meter
+    </Supported>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The welcome message
+   Abstract = The welcome message created by service.
+   <MetaData>
+    title = My test
+   </MetaData>
+   <LiteralData>
+    DataType = string
+    <Default>
+     UOM = meter
+    </Default>
+    <Supported>
+     UOM = meter
+    </Supported>
+   </LiteralData>
+ </DataOutputs>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-py/cgi-env/test_service.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-py/cgi-env/test_service.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-py/cgi-env/test_service.py	(revision 942)
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+#
+# Author : Gérald FENOY
+#
+# Copyright 2008-2013 GeoLabs SARL. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including with
+# out limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+import zoo
+
+def HelloPy(conf,inputs,outputs):
+	outputs["Result"]["value"]="Hello "+inputs["a"]["value"]+" from Python World !"
+	return zoo.SERVICE_SUCCEEDED
+
+def geopaposm(conf,inputs,outputs):
+	outputs["result"]["value"]=inputs["inputvector"]["value"]
+	return zoo.SERVICE_SUCCEEDED
+    
+def publish(conf,inputs,outputs):
+    outputs["Result"]["value"]=inputs["in"]["value"]
+    return zoo.SERVICE_SUCCEEDED
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/RVoronoi.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/RVoronoi.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/RVoronoi.zcfg	(revision 942)
@@ -0,0 +1,56 @@
+[RVoronoi]
+ Title = Voronoi Diagram. 
+ Abstract = Computes the edges of Voronoi diagram for a set of data points.
+ Profile = urn:ogc:wps:1.0.0:voronoi
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.R
+ serviceType = R
+ <DataInputs>
+  [InputPoints]
+   Title = Data points
+   Abstract = The set of data points.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Voronoi Diagram.
+   Abstract = JSON String / GML Entity of the Voronoi Diagram.
+   <ComplexOutput>
+    <Default>
+     mimeType = application/json
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = image/png
+     useMapserver = true
+     msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 0.3 OPACITY 65 END
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     useMapserver = true
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     useMapserver = true
+    </Supported>
+   </ComplexOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/failR.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/failR.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/failR.zcfg	(revision 942)
@@ -0,0 +1,28 @@
+[failR]
+ Title = HelloWorld Service in R
+ Abstract = Output and Hello Wolrd string
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.R
+ serviceType = R
+ <DataInputs>
+  [S]
+   Title = Name
+   Abstract = The name to display in the hello message
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The string created by service.
+   <LiteralOutput>
+     dataType = string
+    <Default />
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/hello.R
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/hello.R	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/hello.R	(revision 942)
@@ -0,0 +1,61 @@
+source("minimal.r")
+
+hellor <- function(a,b,c) {
+    # Create a useless graph
+    cars <- c(1,2,3,4,5)
+    filePath <- paste(a[["main"]][["tmpPath"]],paste("cars",zoo[["conf"]][["lenv"]][["usid"]],".png",sep=""),sep="/")
+    png(filePath)
+    plot(cars)
+    quartzFonts(avenir = c("Avenir Book", "Avenir Black", "Avenir Book Oblique", "Avenir Black Oblique"))
+    par(family = 'avenir')
+    title("Hello from R World!")
+    dev.off()
+    # Set the result
+    zoo[["outputs"]][["Result"]][["value"]] <<- paste("Hello",b[["S"]][["value"]],"from the R World! (plot ref:",filePath,")",sep=" ")
+    # Update the main conf settings
+    zoo[["conf"]][["lenv"]][["message"]] <<- "Running from R world!"
+    # Return SERVICE_SUCCEEDEED
+    return(zoo[["SERVICE_SUCCEEDEED"]])
+}
+
+failR <- function(conf,inputs,outputs){
+    zoo[["conf"]][["lenv"]][["message"]] <<- ZOOTranslate("Failed running from R world!")
+    return(zoo[["SERVICE_FAILED"]])
+}
+
+voronoipolygons <- function(x,poly) {
+  require(deldir)
+  if (.hasSlot(x, 'coords')) {
+    crds <- x@coords  
+  } else crds <- x
+  bb = bbox(poly)
+  rw = as.numeric(t(bb))
+  z <- deldir(crds[,1], crds[,2],rw=rw)
+  w <- tile.list(z)
+  polys <- vector(mode='list', length=length(w)) 
+  require(sp)
+  finalCoordinates <- c()
+  for (i in seq(along=polys)) {
+    pcrds <- cbind(w[[i]]$x, w[[i]]$y)
+    pcrds <- rbind(pcrds, pcrds[1,])
+    finalCoordinates[[i]] <- i
+    polys[[i]] <- Polygons(list(Polygon(pcrds)), ID=as.character(i))
+  }
+  SP <- SpatialPolygons(polys)
+  voronoi <- SpatialPolygonsDataFrame(SP, data=data.frame(identifier=finalCoordinates))
+  return(voronoi)
+}
+
+RVoronoi <- function(conf,inputs,outputs){
+    require(rgdal)
+    require(rgeos)
+    message(names(inputs[["InputPoints"]]))
+    message(inputs[["InputPoints"]])
+    myGeoData <- readOGR(inputs[["InputPoints"]][["cache_file"]],layer=ogrListLayers(inputs[["InputPoints"]][["cache_file"]])[1], verbose = FALSE);
+    voronoiData <- voronoipolygons(myGeoData,myGeoData)
+    filePath <- paste(conf[["main"]][["tmpPath"]],paste("RBuffer_",zoo[["conf"]][["lenv"]][["usid"]],".shp",sep=""),sep="/")
+    writeOGR(voronoiData, dsn=filePath, layer="Voronoi", driver="ESRI Shapefile", verbose = FALSE)
+    zoo[["outputs"]][["Result"]][["storage"]] <<- filePath
+    return(zoo[["SERVICE_SUCCEEDEED"]])
+}
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/hellor.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/hellor.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/hello-r/cgi-env/hellor.zcfg	(revision 942)
@@ -0,0 +1,28 @@
+[hellor]
+ Title = HelloWorld Service in R
+ Abstract = Output and Hello Wolrd string
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = hello.R
+ serviceType = R
+ <DataInputs>
+  [S]
+   Title = Name
+   Abstract = The name to display in the hello message
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The string created by service.
+   <LiteralOutput>
+     dataType = string
+    <Default />
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BoundaryPy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BoundaryPy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BoundaryPy.zcfg	(revision 942)
@@ -0,0 +1,56 @@
+[BoundaryPy]
+ Title = Computes boundary.
+ Abstract = A new geometry object is created and returned containing the boundary of the geometry on which the method is invoked. 
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to conpute boundary
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The geometry created
+   Abstract = The geometry containing the boundary of the geometry on which the method is invoked.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BufferPy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BufferPy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BufferPy.zcfg	(revision 942)
@@ -0,0 +1,68 @@
+[BufferPy]
+ Title = Creates a buffer around a polygon. 
+ Abstract = Creates a buffer around a single polygon. Accepts the polygon as GML and provides GML output for the buffered feature. 
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to be buffered
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     asReference = true	
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+  [BufferDistance]
+   Title = Buffer Distance
+   Abstract = Distance to be used to calculate buffer.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = float
+    <Default>
+     uom = meters
+     value = 1
+    </Default>
+    <Supported>
+     uom = feet
+    </Supported>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Buffered Polygon
+   Abstract = GML stream describing the buffered polygon feature.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/CentroidPy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/CentroidPy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/CentroidPy.zcfg	(revision 942)
@@ -0,0 +1,43 @@
+[Clean]
+ Title = Computes the centroid of a polygon 
+ Abstract = Computes the centroid of a polygon that have a valid geometry field.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <DataInputs>
+  [InputData]
+   Title = Polygon to get the centroid
+   Abstract = The centroid which is not necessarily within the geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The Centroid
+   Abstract = JSON String / GML Entity of the centroid
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/point.xsd
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ConvexHullPy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ConvexHullPy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ConvexHullPy.zcfg	(revision 942)
@@ -0,0 +1,51 @@
+[ConvexHullPy]
+ Title = Computes convex hull.
+ Abstract = A new geometry object is created and returned containing the convex hull of the geometry on which the method is invoked.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to compute convexhull
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+   title = Mon test
+   </MetaData>
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The convex hull of the geometry
+   Abstract = The convex hull of the geometry
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataOutputs> 
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/DifferencePy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/DifferencePy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/DifferencePy.zcfg	(revision 942)
@@ -0,0 +1,75 @@
+[DifferencePy]
+ Title = Computes difference. 
+ Abstract = Generates a new geometry which is the region of this geometry with the region of the other geometry removed.
+ Profile = urn:ogc:wps:1.0.0:difference
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The difference between two geometries
+   Abstract = The difference between the two geometries.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+      encoding = UTF-8
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/IntersectionPy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/IntersectionPy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/IntersectionPy.zcfg	(revision 942)
@@ -0,0 +1,75 @@
+[IntersectionPy]
+ Title = Computes intersection. 
+ Abstract = Generates a new geometry which is the region of intersection of the two geometries operated on.
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Intersection of the two geometries
+   Abstract = A new geometry representing the intersection or NULL if there is no intersection or an error occurs.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+      encoding = UTF-8
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/SymDifferencePy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/SymDifferencePy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/SymDifferencePy.zcfg	(revision 942)
@@ -0,0 +1,83 @@
+[SymDifferencePy]
+ Title = Computes symmetric difference. 
+ Abstract = Generates a new geometry which is the symmetric difference of this geometry and the other geometry.
+ Profile = urn:ogc:wps:1.0.0:symmetricdifference
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Supported>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The symmetric difference between two geometries
+   Abstract = The symmetric difference between the two geometries.
+   <MetaData>
+    title = Symmetric Difference  
+   </MetaData>   
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+      encoding = UTF-8
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/UnionPy.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/UnionPy.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/UnionPy.zcfg	(revision 942)
@@ -0,0 +1,73 @@
+[UnionPy]
+ Title = Computes union. 
+ Abstract = Generates a new geometry which is the region of union of the two geometries operated on.
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The union of two geometries
+   Abstract = The geometry representing the union of the two geometries.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      schema = http://schemas.opengis.net/gml/3.1.0/base/feature.xsd
+      encoding = UTF-8
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py	(revision 942)
@@ -0,0 +1,406 @@
+# -*- coding: utf-8 -*-
+#
+# Author : Gérald FENOY
+#
+# Copyright 2009-2013 GeoLabs SARL. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including with
+# out limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from osgeo import *
+import osgeo.ogr
+import osgeo.gdal
+import libxml2
+import os
+import sys
+import zoo
+
+def readFileFromBuffer(data,ext):
+    try:
+        geometry=[]
+        print >> sys.stderr,'/vsimem//temp1'+ext
+        #print >> sys.stderr,data
+        osgeo.gdal.FileFromMemBuffer('/vsimem//temp1'+ext,data)
+        ds = osgeo.ogr.Open('/vsimem//temp1'+ext)
+        lyr = ds.GetLayer(0)
+        feat = lyr.GetNextFeature()
+        while feat is not None:
+            geometry+=[feat.Clone()]
+            feat.Destroy()
+            feat = lyr.GetNextFeature()
+        ds.Destroy()
+        osgeo.gdal.Unlink('/vsimem//temp1'+ext)
+        return geometry
+    except Exception,e:
+        print >> sys.stderr,e
+        return []
+    
+def buildFeatureFromGeomtry(conf,geom,driverName,ext):
+    drv = osgeo.ogr.GetDriverByName( driverName )
+    ds = drv.CreateDataSource( "/vsimem//store"+conf["lenv"]["sid"]+"0."+ext )
+    lyr = ds.CreateLayer( "Result", None, osgeo.ogr.wkbUnknown )
+    field_defn = osgeo.ogr.FieldDefn( "Name", osgeo.ogr.OFTString )
+    field_defn.SetWidth( len("Result10000") )
+    lyr.CreateField ( field_defn )
+    feat = osgeo.ogr.Feature(lyr.GetLayerDefn())
+    feat.SetField( "Name", "Input0" )
+    feat.SetGeometry(geom)
+    lyr.CreateFeature(feat)
+    ds.Destroy()
+    return [feat]
+
+def createGeometryFromWFS(conf,my_wfs_response):
+    try:
+        geom=osgeo.ogr.CreateGeometryFromGML(my_wfs_response.replace('<?xml version="1.0" encoding="utf-8"?>\n','').replace('<?xml version=\'1.0\' encoding="utf-8"?>\n',''))
+    except Exception,e:
+        print >> sys.stderr,"**"
+        print >> sys.stderr,e
+        geom=None
+    try:
+        print >> sys.stderr,geom is None
+        if geom is None:
+            if not(conf["lenv"].has_key("cnt")):
+                conf["lenv"]["cnt"]=0
+            else:
+                conf["lenv"]["cnt"]+=1
+            return readFileFromBuffer(my_wfs_response,str(conf["lenv"]["cnt"]))
+        else:
+            return buildFeatureFromGeomtry(conf,geom,"GML","xml")
+    except:
+        print >> sys.stderr,"Unable to load file input data !!!\n\n\n"
+
+def createLayerFromJson(conf,obj):
+    geom=osgeo.ogr.CreateGeometryFromJson(obj)
+    if geom is None:
+        return readFileFromBuffer(obj,".json")
+    else:
+        return buildFeatureFromGeomtry(conf,geom,"GeoJSON","json")
+
+def extractInputs(conf,obj):
+    if obj.keys().count("cache_file"):
+        print >> sys.stderr,obj
+        geometry=[]
+        ds = osgeo.ogr.Open(obj["cache_file"])
+        lyr = ds.GetLayer(0)
+        feat = lyr.GetNextFeature()
+        while feat is not None:
+            geometry+=[feat.Clone()]
+            feat.Destroy()
+            feat = lyr.GetNextFeature()
+        ds.Destroy()
+        return geometry    
+    if obj["mimeType"]=="application/json":
+        return createLayerFromJson(conf,obj["value"])
+    else:
+        return createGeometryFromWFS(conf,obj["value"])
+    
+def outputResult(conf,obj,geom):
+    if obj["mimeType"].count("text/xml")>0:
+        driverName = "GML"
+        extension = [ ".xml" , ".xsd" ]
+        format_list = { "2.": 'GML2', "3.1.1": 'GML3', "3.1": 'GML3Deegree', "3.2": 'GML3.2' }
+        opts=['FORMAT=%s,GML3_LONGSRS=YES',format_list["3.2"]]
+        for i in format_list:
+            if obj["mimeType"].count(i)>0:
+                opts=['FORMAT=%s,GML3_LONGSRS=YES',format_list[i]]
+    if obj["mimeType"]=="application/json":
+        driverName = "GeoJSON"
+        extension = [ ".js" ]
+        opts=None
+    if obj.keys().count("schema")>0 and \
+            obj["schema"]=="http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd":
+        driverName = "KML"
+        extension = [ ".kml" ]
+        opts=None
+    drv = osgeo.ogr.GetDriverByName( driverName )
+    print >> sys.stderr,drv
+    # Create virtual file
+    ds = drv.CreateDataSource( "/vsimem/store"+conf["lenv"]["sid"]+extension[0],options = opts)
+    print >> sys.stderr,ds
+    lyr = ds.CreateLayer( "Result", None, osgeo.ogr.wkbUnknown )
+    print >> sys.stderr,lyr
+    i=0
+    print >> sys.stderr,driverName
+    print >> sys.stderr,extension
+    while i < len(geom):
+        if i==0 and driverName!="GeoJSON":
+            poDstFDefn=geom[i].GetDefnRef()
+            if poDstFDefn is not None:
+                nDstFieldCount = poDstFDefn.GetFieldCount()
+                for iField in range(nDstFieldCount):
+                    poSrcFieldDefn = poDstFDefn.GetFieldDefn(iField)
+                    oFieldDefn = osgeo.ogr.FieldDefn(poSrcFieldDefn.GetNameRef(),poSrcFieldDefn.GetType())
+                    oFieldDefn.SetWidth( poSrcFieldDefn.GetWidth() )
+                    oFieldDefn.SetPrecision( poSrcFieldDefn.GetPrecision() )
+                    lyr.CreateField( oFieldDefn )
+        try:
+            lyr.CreateFeature(geom[i])
+        except:
+            pass
+        geom[i].Destroy()
+        i+=1
+    ds.Destroy()
+    vsiFile=osgeo.gdal.VSIFOpenL("/vsimem/store"+conf["lenv"]["sid"]+extension[0],"r")
+    i=0
+    while osgeo.gdal.VSIFSeekL(vsiFile,0,os.SEEK_END)>0:
+        i+=1
+    fileSize=osgeo.gdal.VSIFTellL(vsiFile)
+    osgeo.gdal.VSIFSeekL(vsiFile,0,os.SEEK_SET)
+    obj["value"]=osgeo.gdal.VSIFReadL(fileSize,1,vsiFile)
+    osgeo.gdal.Unlink("/vsimem/store"+conf["lenv"]["sid"]+extension[0])
+
+def BufferPy(conf,inputs,outputs):
+    print >> sys.stderr, "Starting service ..."
+    try:
+        bdist=float(inputs["BufferDistance"]["value"])
+    except:
+        bdist=1
+    print >> sys.stderr, bdist
+    geometry=extractInputs(conf,inputs["InputPolygon"])
+    i=0
+    rgeometries=[]
+    while i < len(geometry):
+        tmp=geometry[i].Clone()
+        resg=geometry[i].GetGeometryRef().Buffer(bdist)
+        tmp.SetGeometryDirectly(resg)
+        rgeometries+=[tmp]
+        geometry[i].Destroy()
+        resg.thisown=False 
+        tmp.thisown=False
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    i=0
+    return zoo.SERVICE_SUCCEEDED
+
+def Clean(conf,inputs,outputs):
+    from shapely.wkb import loads
+    print >> sys.stderr, "Starting service ..."
+    features=extractInputs(conf,inputs["InputData"])
+    i=0
+    rgeometries=[]
+    while i < len(features):
+        tmp=features[i].Clone()
+        resg=features[i].GetGeometryRef()
+        if resg is not None:
+            geom = loads(resg.ExportToWkb())
+            if geom.is_valid:
+                tmp.SetGeometryDirectly(resg)
+                rgeometries+=[tmp]
+                print >> sys.stderr,"valid !"
+            else:
+                print >> sys.stderr,"invalid !"
+                print >> sys.stderr,geom.wkt[0:50]
+        features[i].Destroy()
+        resg.thisown=False 
+        tmp.thisown=False
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    i=0
+    print >> sys.stderr,"Return"
+    return zoo.SERVICE_SUCCEEDED
+
+def TransformService(conf,inputs,outputs):
+    from osgeo import osr
+    geometry=extractInputs(conf,inputs["InputData"])
+    sourceRef = osr.SpatialReference()
+    tmp=inputs["SourceCRS"]["value"].split(":")
+    sourceRef.ImportFromEPSG(int(tmp[len(tmp)-1]))
+    targetRef = osr.SpatialReference()    
+    tmp=inputs["TargetCRS"]["value"].split(":")
+    targetRef.ImportFromEPSG(int(tmp[len(tmp)-1]))
+    transform = osr.CoordinateTransformation(sourceRef, targetRef)
+    i=0
+    rgeometries=[]
+    while i < len(geometry):
+        tmp=geometry[i].Clone()
+        resg=geometry[i].GetGeometryRef()
+        resg.Transform(transform)
+        tmp.SetGeometryDirectly(resg.Clone())
+        rgeometries+=[tmp]
+        geometry[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["TransformedData"],rgeometries)
+    return zoo.SERVICE_SUCCEEDED
+
+def BoundaryPy(conf,inputs,outputs):
+    geometry=extractInputs(conf,inputs["InputPolygon"])
+    i=0
+    rgeometries=[]
+    while i < len(geometry):
+        tmp=geometry[i].Clone()
+        resg=geometry[i].GetGeometryRef()
+        resg=resg.GetBoundary()
+        tmp.SetGeometryDirectly(resg)
+        rgeometries+=[tmp]
+        geometry[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    return zoo.SERVICE_SUCCEEDED
+
+def CentroidPy(conf,inputs,outputs):
+    geometry=extractInputs(conf,inputs["InputPolygon"])
+    i=0
+    rgeometries=[]
+    while i < len(geometry):
+        tmp=geometry[i].Clone()
+        resg=geometry[i].GetGeometryRef()
+        if resg.GetGeometryType()!=3:
+            resg=resg.ConvexHull()
+        resg=resg.Centroid()
+        tmp.SetGeometryDirectly(resg)
+        rgeometries+=[tmp]
+        geometry[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    return zoo.SERVICE_SUCCEEDED
+
+def ConvexHullPy(conf,inputs,outputs):
+    geometry=extractInputs(conf,inputs["InputPolygon"])
+    i=0
+    rgeometries=[]
+    while i < len(geometry):
+        tmp=geometry[i].Clone()
+        resg=geometry[i].GetGeometryRef().ConvexHull()
+        tmp.SetGeometryDirectly(resg)
+        rgeometries+=[tmp]
+        geometry[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    return zoo.SERVICE_SUCCEEDED
+
+
+
+def EnvelopePy(conf,inputs,outputs):
+    print >> sys.stderr, inputs
+    try:
+        bdist=float(inputs["BufferDistance"]["value"])
+    except:
+        bdist=10
+    geometry=extractInputs(conf,inputs["InputPolygon"])
+    tmp=geometry[0].GetGeometryRef().GetEnvelope()
+    outputs["Result"]["value"]=str(tmp[0])+','+str(tmp[2])+','+str(tmp[1])+','+str(tmp[3])+','+'urn:ogc:def:crs:OGC:1.3:CRS84'
+    print >> sys.stderr,outputs["Result"]
+    return 3
+
+def UnionPy(conf,inputs,outputs):
+    geometry1=extractInputs(conf,inputs["InputEntity1"])
+    geometry2=extractInputs(conf,inputs["InputEntity2"])
+    rgeometries=[]
+    i=0
+    while i < len(geometry1):
+        j=0
+        while j < len(geometry2):
+            tmp=geometry1[i].Clone()
+            resg=geometry2[j].GetGeometryRef()
+            resg=resg.Union(geometry1[i].GetGeometryRef())
+            tmp.SetGeometryDirectly(resg)
+            if not(resg.IsEmpty()):
+                rgeometries+=[tmp]
+            j+=1
+        geometry1[i].Destroy()
+        i+=1
+    i=0
+    while i < len(geometry2):
+        geometry2[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    return 3
+
+def IntersectionPy(conf,inputs,outputs):
+
+    geometry1=extractInputs(conf,inputs["InputEntity1"])
+    geometry2=extractInputs(conf,inputs["InputEntity2"])
+
+    print >> sys.stderr,str(len(geometry1))+" "+str(len(geometry2))
+
+    rgeometries=[]
+    fids=[]
+    i=0
+    while i < len(geometry1):
+        j=0
+        while j < len(geometry2):
+            tmp=geometry2[j].Clone()
+            resg=geometry2[j].GetGeometryRef()
+            #resg=resg.Intersection(geometry1[i].GetGeometryRef())
+            resg=geometry1[i].GetGeometryRef().Intersection(resg)
+            tmp.SetGeometryDirectly(resg)
+            if resg is not None and not(resg.IsEmpty()) and fids.count(tmp.GetFID())==0:
+                rgeometries+=[tmp]
+                fids+=[tmp.GetFID()]
+            else:
+                tmp.Destroy()
+            j+=1
+        geometry1[i].Destroy()
+        i+=1
+    i=0
+    while i < len(geometry2):
+        geometry2[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    print >> sys.stderr,"/outputResult"
+    return 3
+
+def DifferencePy(conf,inputs,outputs):
+    geometry1=extractInputs(conf,inputs["InputEntity1"])
+    geometry2=extractInputs(conf,inputs["InputEntity2"])
+    rgeometries=[]
+    i=0
+    while i < len(geometry1):
+        j=0
+        while j < len(geometry2):
+            tmp=geometry2[j].Clone()
+            resg=geometry1[i].GetGeometryRef()
+            resg=resg.Difference(geometry2[i].GetGeometryRef())
+            tmp.SetGeometryDirectly(resg)
+            if not(resg.IsEmpty()):
+                rgeometries+=[tmp]
+            j+=1
+        geometry1[i].Destroy()
+        i+=1
+    i=0
+    while i < len(geometry2):
+        geometry2[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    return 3
+
+def SymDifferencePy(conf,inputs,outputs):
+    geometry1=extractInputs(conf,inputs["InputEntity1"])
+    geometry2=extractInputs(conf,inputs["InputEntity2"])
+    rgeometries=[]
+    i=0
+    while i < len(geometry1):
+        j=0
+        while j < len(geometry2):
+            tmp=geometry2[j].Clone()
+            resg=geometry1[i].GetGeometryRef()
+            resg=resg.SymmetricDifference(geometry2[i].GetGeometryRef())
+            tmp.SetGeometryDirectly(resg)
+            rgeometries+=[tmp]
+            j+=1
+        geometry1[i].Destroy()
+        i+=1
+    i=0
+    while i < len(geometry2):
+        geometry2[i].Destroy()
+        i+=1
+    outputResult(conf,outputs["Result"],rgeometries)
+    return 3
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/Makefile	(revision 942)
@@ -0,0 +1,19 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${ZOO_CFLAGS} ${JSCFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${GEOS_CFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+
+ifneq ($(MS_FILE),)
+	MS_FILES=${ZRPATH}/zoo-kernel/${MS_FILE} -lmapserver
+else
+	MS_FILES=
+endif
+
+cgi-env/ogr_service.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/ogr_service.zo ./service.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${GEOS_LDFLAGS} -lfcgi  -lpthread -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}/ogr/base-vect-ops
+	install cgi-env/* ${CGI_DIR}/ogr/base-vect-ops
+
+clean:
+	rm -f cgi-env/ogr_service.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg	(revision 942)
@@ -0,0 +1,60 @@
+[Boundary]
+ Title = Computes boundary.
+ Abstract = This service shall return a feature callection representing the combinatorial boundary of each geometry in the InputPolygon feature collection.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to compute boundary
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The geometry created
+   Abstract = The geometry containing the boundary of the geometry on which the method is invoked.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     extension = xml
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     extension = xml
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Buffer.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Buffer.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Buffer.zcfg	(revision 942)
@@ -0,0 +1,70 @@
+[Buffer]
+ Title = Create a buffer around a polygon. 
+ Abstract = This service shall return a feature collection representing the buffer of geometry InputPolygon at distance BufferDistance. The buffer of a geometry at distance d is the Polygon or MultiPolygon which contains all points within a distance d of the geometry.
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to be buffered
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     asReference = true	
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+  [BufferDistance]
+   Title = Buffer Distance
+   Abstract = Distance to be used to calculate buffer.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = float
+    <Default>
+     uom = meters
+     value = 10
+    </Default>
+    <Supported>
+     uom = feet
+    </Supported>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Buffered Polygon
+   Abstract = GML stream describing the buffered polygon feature.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     extension = xml
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Centroid.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Centroid.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Centroid.zcfg	(revision 942)
@@ -0,0 +1,55 @@
+[Centroid]
+ Title = Computes the centroid of a polygon. 
+ Abstract = This service shall return the point that is the geometric centre of gravity of the geometry InputPolygon.
+ Profile = urn:ogc:wps:1.0.0:centroid
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to get the centroid
+   Abstract = The centroid which is not necessarily within the geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The Centroid
+   Abstract = JSON String / GML Entity of the centroid
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/point.xsd
+     extension = xml
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Contains.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Contains.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Contains.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[Contains]
+ Title = Contains
+ Abstract = This service shall return a true value if and only if the geometry g2 lies in the closure (boundary union interior) of geometry g1 - the inverse of Within(g1: Geometry, g2: Geometry).
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Contains result
+   Abstract = A value true or false if the geometry1 contains the geometry2.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/ConvexHull.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/ConvexHull.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/ConvexHull.zcfg	(revision 942)
@@ -0,0 +1,54 @@
+[ConvexHull]
+ Title = Compute convex hull.
+ Abstract = This service shall return a feature collection that represents the convex hull of geometry InputPolygon. The convex hull is the smallest convex polygon that contains all points of the geometry. The convex Hull for a geometry of encoding data type Point is the point itself
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to compute convexhull
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+   title = Mon test
+   </MetaData>
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The convex hull of the geometry
+   Abstract = The convex hull of the geometry
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     extension = xml
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+    </Supported>
+   </ComplexData>
+ </DataOutputs> 
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Crosses.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Crosses.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Crosses.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[Crosses]
+ Title = Crosses test
+ Abstract = This service shall return a true value if and only if the geometries g1 and g2 share some but neither is containe in the other, and the dimension of the intersection is less than that of both of the geometries.
+ processVersion = 2
+ profile = urn:ogc:wps:1.0.0:union
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Disjoint result
+   Abstract = true if disjoint.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Difference.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Difference.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Difference.zcfg	(revision 942)
@@ -0,0 +1,75 @@
+[Difference]
+ Title = Compute difference. 
+ Abstract = This function shall return a bag of geometry values representing the closure of the set difference between the two geometries InputEntity1 and InputEntity2. The difference is the set of all points which lie on InputEntity1 but not on InputEntity2.
+ Profile = urn:ogc:wps:1.0.0:difference
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The difference between two geometries
+   Abstract = The difference between the two geometries.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      encoding = UTF-8
+      schema = http://fooa/gml/3.1.0/polygon.xsd
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Disjoint.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Disjoint.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Disjoint.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[Disjoint]
+ Title = Disjoint 
+ Abstract = This servuce shall return a true value if and only if the geometries g1 and g2 have no point in common.
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Disjoint result
+   Abstract = true if disjoint.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Distance.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Distance.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Distance.zcfg	(revision 942)
@@ -0,0 +1,71 @@
+[Distance]
+ Title = Compute the distance between two geometries
+ Abstract = Compute the distance between two geometries
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Distance]
+   Title = The distance between two geometries
+   Abstract = The shortest distance between the two geometries.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+     DataType = float
+     <Default>
+      uom = meters
+     </Default>
+     <Supported>
+      uom = feet
+     </Supported>
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Equals.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Equals.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Equals.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[Equals]
+ Title = Equals 
+ Abstract = This service shall return a true value if and only if the geometries g1 and g2 are equal
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Equals result
+   Abstract = Should be true if two geometries are equivalent..
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/GetArea.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/GetArea.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/GetArea.zcfg	(revision 942)
@@ -0,0 +1,50 @@
+[GetArea]
+ Title = Compute geometry area.
+ Abstract = Computes the area of a geometry
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to compute are
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+   title = Mon test
+   </MetaData>
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Area]
+   Title = Computed Area
+   Abstract = The Computed Area Value
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <LiteralData>
+    DataType = float
+    <Default>
+     uom = degree
+    </Default>
+    <Supported>
+     uom = meter
+    </Supported>
+   </LiteralData>
+ </DataOutputs> 
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersection.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersection.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersection.zcfg	(revision 942)
@@ -0,0 +1,75 @@
+[Intersection]
+ Title = Compute intersection. 
+ Abstract = This function SHALL return a bag of geometry values representing the Point set intersection of geometry InputEntity1 and geometry InputEntity2.
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Intersection of geometries
+   Abstract = A new geometry representing the intersection or NULL if there is no intersection or an error occurs.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      encoding = UTF-8
+      schema = http://fooa/gml/3.1.0/polygon.xsd
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersects.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersects.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersects.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[Intersects]
+ Title = Intersects test
+ Abstract = This service shall return a true value if and only if the geometries g1 and g2 have at least one boundary point in common, but no interior points.
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Contains result
+   Abstract = A value true or false if the geometry1 contains the geometry2.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/IsSimple.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/IsSimple.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/IsSimple.zcfg	(revision 942)
@@ -0,0 +1,37 @@
+[IsSimple]
+ Title = IsSimple test 
+ Abstract = This service shall return a true value if and only if geometry g has no anomalous geometric points, such as self intersection or self tangency. Simple curves intersect themselves only at their endpoints (only if they are also closed, see next function).
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputPolygon]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = IsSimple result
+   Abstract = The boolean result
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/IsValid.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/IsValid.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/IsValid.zcfg	(revision 942)
@@ -0,0 +1,37 @@
+[IsValid]
+ Title = IsValid test 
+ Abstract = This service shall return a TRUE value if and only if the geometry g is valid
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputPolygon]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Equals result
+   Abstract = Should be true if two geometries are equivalent..
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Simplify.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Simplify.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Simplify.zcfg	(revision 942)
@@ -0,0 +1,61 @@
+[Simplify]
+ Title = Simplifies polygons geometries. 
+ Abstract = This service shall return a feature collection representing all simplified geometries with all their vertices within the distance of the original geometry defined by the given tolerance.
+ Profile = urn:ogc:wps:1.0.0:buffer
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputPolygon]
+   Title = Polygon to be simplified
+   Abstract = URI to a set of GML that describes the polygon.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     asReference = true	
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+  [Tolerance]
+   Title = Buffer Distance
+   Abstract = Distance tolerance for the simplification.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = float
+    <Default>
+     uom = meters
+     value = 2
+    </Default>
+    <Supported>
+     uom = feet
+    </Supported>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Simplified features
+   Abstract = GML stream describing the simplified features.
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     extension = xml
+    </Default>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/SymDifference.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/SymDifference.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/SymDifference.zcfg	(revision 942)
@@ -0,0 +1,75 @@
+[SymDifference]
+ Title = Compute symmetric difference. 
+ Abstract = This service shall return a feature collection representing the closure of the symmetric difference of two Geometries. The symmetric difference is the set of points which lie on either InputEntity1 or InputEntity2 but not in both.
+ Profile = urn:ogc:wps:1.0.0:symmetricdifference
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting geometry
+   Abstract = The symmetric difference of two geometries
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      schema = http://fooa/gml/3.1.0/polygon.xsd
+      encoding = UTF-8
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Touches.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Touches.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Touches.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[Touches]
+ Title = Compute intersection. 
+ Abstract = Generates a new geometry which is the region of intersection of the two geometries operated on.
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Intersects result
+   Abstract = A value true or false if the geometry1 and geometry2 touches.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Union.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Union.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Union.zcfg	(revision 942)
@@ -0,0 +1,75 @@
+[Union]
+ Title = Compute union. 
+ Abstract = This service shall return a bag of geometry values representing a Point set union of geometry InputEntity1 with geometry InputEntity2.
+ profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <MetaData>
+   title = Demo
+ </MetaData>
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry to compare against.
+   minOccurs = 1
+   maxOccurs = 1
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The union of two geometries
+   Abstract = The geometry representing the union of the two geometries.
+   <MetaData>
+    title = Mon test  
+   </MetaData>
+    <ComplexData>
+     <Default>
+      mimeType = text/xml
+      schema = http://fooa/gml/3.1.0/polygon.xsd
+      encoding = UTF-8
+      extension = xml
+     </Default>
+     <Supported>
+      mimeType = application/json
+      encoding = UTF-8
+      extension = js
+     </Supported>
+    </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Within.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Within.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Within.zcfg	(revision 942)
@@ -0,0 +1,57 @@
+[Within]
+ Title = Within test
+ Abstract = This service shall return a true value if and only if the geometry InputEntity1 is spatially within geometry InputEntity2; that is if every point on InputEntity1 is also on InputEntity2.
+ Profile = urn:ogc:wps:1.0.0:union
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_service.zo
+ serviceType = C
+ <DataInputs>
+  [InputEntity1]
+   Title = the first geometry 
+   Abstract = the first geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+  [InputEntity2]
+   Title = the other geometry
+   Abstract = the other geometry.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     encoding = UTF-8
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+    </Supported>
+   </ComplexData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = Within result
+   Abstract = A value true or false if the geometry1 contains the geometry2.
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+    <LiteralData>
+      dataType=boolean
+      <Default />
+    </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/fr_FR.utf8.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/fr_FR.utf8.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/fr_FR.utf8.po	(revision 942)
@@ -0,0 +1,320 @@
+# French translations for PACKAGE package.
+# Copyright (C) 2010 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# root <gerald.fenoy@geolabs.fr>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: zoo-services\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-28 12:52+0200\n"
+"PO-Revision-Date: 2010-09-28 12:55+0200\n"
+"Last-Translator: root <gerald.fenoy@geolabs.fr>\n"
+"Language-Team: French\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: locale/.cache/my_service_string_to_translate.c:1
+msgid "Compute boundary."
+msgstr "Calcul le contour."
+
+#: locale/.cache/my_service_string_to_translate.c:2
+msgid "Polygon to compute boundary"
+msgstr "Le polygon à utiliser pour calculer le contour"
+
+#: locale/.cache/my_service_string_to_translate.c:3
+msgid "The geometry created"
+msgstr "La géométrie créée"
+
+#: locale/.cache/my_service_string_to_translate.c:4
+msgid ""
+"A new geometry object is created and returned containing the boundary of the "
+"geometry on which the method is invoked. "
+msgstr ""
+"Un nouvel objet géographique contenant le contour de la géométrie passée en "
+"paramètre est créé et retourné. "
+
+#: locale/.cache/my_service_string_to_translate.c:5
+#: locale/.cache/my_service_string_to_translate.c:12
+#: locale/.cache/my_service_string_to_translate.c:25
+#: locale/.cache/my_service_string_to_translate.c:47
+#: locale/.cache/my_service_string_to_translate.c:62
+msgid "URI to a set of GML that describes the polygon."
+msgstr "Le lien vers un fichier GML décrivant un polygone."
+
+#: locale/.cache/my_service_string_to_translate.c:6
+msgid ""
+"The geometry containing the boundary of the geometry on which the method is "
+"invoked."
+msgstr ""
+"La géométrie contenant le contour de la géométrie passée en paramètre."
+
+#: locale/.cache/my_service_string_to_translate.c:7
+msgid "Create a buffer around a polygon. "
+msgstr "Crée une zone tampon atour du polygone."
+
+#: locale/.cache/my_service_string_to_translate.c:8
+msgid "Polygon to be buffered"
+msgstr "Le Polygone à utiliser"
+
+#: locale/.cache/my_service_string_to_translate.c:9
+msgid "Buffer Distance"
+msgstr "La distance pour créer la zone tampon"
+
+#: locale/.cache/my_service_string_to_translate.c:10
+msgid "Buffered Polygon"
+msgstr "La zone tampon correspondant au polygone "
+
+#: locale/.cache/my_service_string_to_translate.c:11
+msgid ""
+"Create a buffer around a single polygon. Accepts the polygon as GML and "
+"provides GML output for the buffered feature. "
+msgstr ""
+"Crée une zone tampon autour d'un polygone. Prend en entrée un GML et fournit une "
+"chaîne GeoJSON de la zone tampon. "
+
+#: locale/.cache/my_service_string_to_translate.c:13
+msgid "Distance to be used to calculate buffer."
+msgstr "La distance à utiliser pour créer la zone tampon."
+
+#: locale/.cache/my_service_string_to_translate.c:14
+msgid "GML stream describing the buffered polygon feature."
+msgstr "Une chaîne GeoJSON contenant la zone tampon."
+
+#: locale/.cache/my_service_string_to_translate.c:15
+msgid "Get the centroid of a polygon. "
+msgstr "Renvoit le centroid d'un polygone"
+
+#: locale/.cache/my_service_string_to_translate.c:16
+msgid "Polygon to get the centroid"
+msgstr "Le polygone à utiliser pour calculer le centroid"
+
+#: locale/.cache/my_service_string_to_translate.c:17
+msgid "The Centroid"
+msgstr "Le centroid"
+
+#: locale/.cache/my_service_string_to_translate.c:18
+msgid "Compute the geometry centroid."
+msgstr "Calcul le centroid d'une géométrie"
+
+#: locale/.cache/my_service_string_to_translate.c:19
+msgid "The centroid which is not necessarily within the geometry."
+msgstr "Le centroid qui n'est pas nécessairement dans la géométrie."
+
+#: locale/.cache/my_service_string_to_translate.c:20
+msgid "JSON String / GML Entity of the centroid"
+msgstr "La chaîne GeoJSON ou l'entité GML du centroid"
+
+#: locale/.cache/my_service_string_to_translate.c:21
+msgid "Compute convex hull."
+msgstr "Calcul de la partie convexe"
+
+#: locale/.cache/my_service_string_to_translate.c:22
+msgid "Polygon to compute convexhull"
+msgstr "Polygone pour calculer la partie convexe"
+
+#: locale/.cache/my_service_string_to_translate.c:23
+#: locale/.cache/my_service_string_to_translate.c:26
+msgid "The convex hull of the geometry"
+msgstr "La partie convexe de la géométrie"
+
+#: locale/.cache/my_service_string_to_translate.c:24
+msgid ""
+"A new geometry object is created and returned containing the convex hull of "
+"the geometry on which the method is invoked."
+msgstr ""
+"Un nouvel objet géographique est créé et retourné. Il contient la partie convexe de la "
+"géométrie sur laquelle on a appliqué la méthode."
+
+#: locale/.cache/my_service_string_to_translate.c:27
+msgid "Compute difference. . "
+msgstr "Calcul de la différence."
+
+#: locale/.cache/my_service_string_to_translate.c:28
+#: locale/.cache/my_service_string_to_translate.c:36
+#: locale/.cache/my_service_string_to_translate.c:50
+#: locale/.cache/my_service_string_to_translate.c:66
+#: locale/.cache/my_service_string_to_translate.c:74
+msgid "the first geometry "
+msgstr "La première géométrie"
+
+#: locale/.cache/my_service_string_to_translate.c:29
+#: locale/.cache/my_service_string_to_translate.c:37
+#: locale/.cache/my_service_string_to_translate.c:51
+#: locale/.cache/my_service_string_to_translate.c:67
+#: locale/.cache/my_service_string_to_translate.c:75
+msgid "the other geometry"
+msgstr "L'autre géométrie"
+
+#: locale/.cache/my_service_string_to_translate.c:30
+msgid "The difference between two geometries"
+msgstr "La différence entre les deux géométries"
+
+#: locale/.cache/my_service_string_to_translate.c:31
+msgid ""
+"Generates a new geometry which is the region of this geometry with the "
+"region of the other geometry removed."
+msgstr ""
+"Génère une nouvelle géométrie qui contient la région de la géométrie dont on a "
+"supprimé l'autre géométrie."
+
+
+#: locale/.cache/my_service_string_to_translate.c:32
+#: locale/.cache/my_service_string_to_translate.c:40
+#: locale/.cache/my_service_string_to_translate.c:54
+#: locale/.cache/my_service_string_to_translate.c:70
+#: locale/.cache/my_service_string_to_translate.c:78
+msgid "the first geometry to compare against."
+msgstr "La première géométrie utilisée pour la comparaison"
+
+#: locale/.cache/my_service_string_to_translate.c:33
+#: locale/.cache/my_service_string_to_translate.c:41
+#: locale/.cache/my_service_string_to_translate.c:55
+#: locale/.cache/my_service_string_to_translate.c:71
+#: locale/.cache/my_service_string_to_translate.c:79
+msgid "the other geometry to compare against."
+msgstr "L'autre géométrie à comparer."
+
+#: locale/.cache/my_service_string_to_translate.c:34
+msgid "The difference between the two geometries."
+msgstr "La différence entre les deux géométries."
+
+#: locale/.cache/my_service_string_to_translate.c:35
+msgid "Calcul la distance entre deux entites geographique. "
+msgstr "Calcul de la distance entre deux objets géographiques."
+
+#: locale/.cache/my_service_string_to_translate.c:38
+msgid "The distance between two geometries"
+msgstr "La distance entre deux géométries"
+
+#: locale/.cache/my_service_string_to_translate.c:39
+msgid "Calcul de la distance entre deux entites geographique. "
+msgstr "Calcul de la distance entre deux entités géographiques."
+
+#: locale/.cache/my_service_string_to_translate.c:42
+msgid "The shortest distance between the two geometries."
+msgstr "La plus courte distance entre de géométries."
+
+#: locale/.cache/my_service_string_to_translate.c:43
+msgid "Compute geometry area."
+msgstr "Calcul l'aire de la géométrie."
+
+#: locale/.cache/my_service_string_to_translate.c:44
+msgid "Polygon to compute are"
+msgstr "Le polygone à utiliser"
+
+#: locale/.cache/my_service_string_to_translate.c:45
+msgid "Computed Area"
+msgstr "L'aire calculée"
+
+#: locale/.cache/my_service_string_to_translate.c:46
+msgid "Computes the area for a geometry"
+msgstr "Calcul de l'aire d'une géométrie"
+
+#: locale/.cache/my_service_string_to_translate.c:48
+msgid "The Computed Area Value"
+msgstr "La valeur de l'aire calculée"
+
+#: locale/.cache/my_service_string_to_translate.c:49
+msgid "Compute intersection. "
+msgstr "Calcul de l'intersection."
+
+#: locale/.cache/my_service_string_to_translate.c:52
+msgid "Intersection of geometries"
+msgstr "L'intersection des géométries."
+
+#: locale/.cache/my_service_string_to_translate.c:53
+msgid ""
+"Generates a new geometry which is the region of intersection of the two "
+"geometries operated on."
+msgstr ""
+"Crée une nouvelle géométrie qui représente l'intersection des deux géométries avec "
+"lesquelles le service est utilisé."
+
+#: locale/.cache/my_service_string_to_translate.c:56
+msgid ""
+"A new geometry representing the intersection or NULL if there is no "
+"intersection or an error occurs."
+msgstr ""
+"Une nouvelle géométrie représentant l'intersection ou NULL si l'intersection est vide "
+"si une erreur s'est produite."
+
+#: locale/.cache/my_service_string_to_translate.c:57
+msgid "Douglas-Peucker like algorithm"
+msgstr "Algorythme de simplification de type Douglas-Peucker"
+
+#: locale/.cache/my_service_string_to_translate.c:58
+msgid "Polygon to simplify"
+msgstr "Le polygone à simplifier"
+
+#: locale/.cache/my_service_string_to_translate.c:59
+msgid "Tolerance to use."
+msgstr "La tolérance à utliser."
+
+#: locale/.cache/my_service_string_to_translate.c:60
+msgid "The simplified geometry"
+msgstr "La géométrie simplifiée"
+
+#: locale/.cache/my_service_string_to_translate.c:61
+msgid ""
+"Simplifies a geometry, ensuring that the result is a valid geometry having "
+"the same dimension and number of components as the input. The simplification "
+"uses a maximum distance difference algorithm similar to the one used in the "
+"Douglas-Peucker algorithm."
+msgstr ""
+"Simplifie une géométrie, en s'assurant que le résultat soit une géométrie valide "
+"ayant la même dimension et le même nombre de composants que la donnée d'entrée. "
+"La simplification utilise un algorythme similaire à l'algorythme Douglas-Peucker."
+
+#: locale/.cache/my_service_string_to_translate.c:63
+msgid "The approximation tolerance to use."
+msgstr "La valeur approximative de la tolérance à utiliser."
+
+#: locale/.cache/my_service_string_to_translate.c:64
+msgid ""
+"The result has the same number of shells and holes (rings) as the input, in "
+"the same order. The result rings touch at no more than the number of "
+"touching point in the input (although they may touch at fewer points)."
+msgstr ""
+"Le résultat a le même nombre composant que l'entrée, dans le même ordre. "
+
+#: locale/.cache/my_service_string_to_translate.c:65
+msgid "Compute symmetric difference. "
+msgstr "Calcul de la différence symétrique."
+
+#: locale/.cache/my_service_string_to_translate.c:68
+msgid "The resulting geometry"
+msgstr "La géométrie résultat"
+
+#: locale/.cache/my_service_string_to_translate.c:69
+msgid ""
+"Generates a new geometry which is the symmetric difference of this geometry "
+"and the other geometry."
+msgstr ""
+"Crée une nouvelle géométrie qui est la difference symétrique des géométries."
+
+#: locale/.cache/my_service_string_to_translate.c:72
+msgid "The symmetric difference of two geometries"
+msgstr "La différence symmétrique de deux géométries"
+
+#: locale/.cache/my_service_string_to_translate.c:73
+msgid "Compute union. "
+msgstr "Cacul l'union."
+
+#: locale/.cache/my_service_string_to_translate.c:76
+msgid "The union of two geometries"
+msgstr "L'union de deux géométries"
+
+#: locale/.cache/my_service_string_to_translate.c:77
+msgid ""
+"Generates a new geometry which is the region of union of the two geometries "
+"operated on."
+msgstr ""
+"Génère une nouvelle géométrie qui est l'union des deux géométrie passées en "
+"paramètre."
+
+#: locale/.cache/my_service_string_to_translate.c:80
+msgid "The geometry representing the union of the two geometries."
+msgstr "La géométrie représentant l'union des deux géométries."
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/ja_JP.utf8.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/ja_JP.utf8.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/ja_JP.utf8.po	(revision 942)
@@ -0,0 +1,308 @@
+# Japanese translations for PACKAGE package.
+# Copyright (C) 2010 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the ZOO Services package.
+# Daisuke YOSHIDA <yoshida@la.tezuka-gu.ac.jp>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: zoo-services\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-28 12:52+0200\n"
+"PO-Revision-Date: 2010-09-28 12:55+0200\n"
+"Last-Translator: Daisuke YOSHIDA <yoshida@la.tezuka-gu.ac.jp>\n"
+"Language-Team: Japanese\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: locale/.cache/my_service_string_to_translate.c:1
+msgid "Compute boundary."
+msgstr "境界線を計算．"
+
+#: locale/.cache/my_service_string_to_translate.c:2
+msgid "Polygon to compute boundary"
+msgstr "境界線を計算するためのポリゴン．"
+
+#: locale/.cache/my_service_string_to_translate.c:3
+msgid "The geometry created"
+msgstr "ジオメトリが作成される．"
+
+#: locale/.cache/my_service_string_to_translate.c:4
+msgid ""
+"A new geometry object is created and returned containing the boundary of the "
+"geometry on which the method is invoked. "
+msgstr "新しいジオメトリオブジェクトは作成され，メソッド上に返答された境界面を含むジオメトリが，呼び出される．"
+
+
+#: locale/.cache/my_service_string_to_translate.c:5
+#: locale/.cache/my_service_string_to_translate.c:12
+#: locale/.cache/my_service_string_to_translate.c:25
+#: locale/.cache/my_service_string_to_translate.c:47
+#: locale/.cache/my_service_string_to_translate.c:62
+msgid "URI to a set of GML that describes the polygon."
+msgstr "ポリゴンが記述されているGMLセットへのURI．"
+
+#: locale/.cache/my_service_string_to_translate.c:6
+msgid ""
+"The geometry containing the boundary of the geometry on which the method is "
+"invoked."
+msgstr "メソッド上の地質境界面を含んでいるジオメトリを起動．"
+
+
+#: locale/.cache/my_service_string_to_translate.c:7
+msgid "Create a buffer around a polygon. "
+msgstr "ポリゴン周辺のバッファを作成．"
+
+#: locale/.cache/my_service_string_to_translate.c:8
+msgid "Polygon to be buffered"
+msgstr "バッファリングするポリゴン．"
+
+#: locale/.cache/my_service_string_to_translate.c:9
+msgid "Buffer Distance"
+msgstr "バッファ距離．"
+
+#: locale/.cache/my_service_string_to_translate.c:10
+msgid "Buffered Polygon"
+msgstr "バッファリングされたポリゴン． "
+
+#: locale/.cache/my_service_string_to_translate.c:11
+msgid ""
+"Create a buffer around a single polygon. Accepts the polygon as GML and "
+"provides GML output for the buffered feature. "
+msgstr "シングルポリゴン周辺のバッファの作成．GMLとしてポリゴンを許可し，バッファリングされたフィーチャーのためのGMLを提供．"
+
+#: locale/.cache/my_service_string_to_translate.c:13
+msgid "Distance to be used to calculate buffer."
+msgstr "バッファを計算するために使われる距離．"
+
+#: locale/.cache/my_service_string_to_translate.c:14
+msgid "GML stream describing the buffered polygon feature."
+msgstr "バッファリングされたポリゴンフィーチャーを記述するGML．"
+
+#: locale/.cache/my_service_string_to_translate.c:15
+msgid "Get the centroid of a polygon. "
+msgstr "ポリゴンの中心点を取得．"
+
+#: locale/.cache/my_service_string_to_translate.c:16
+msgid "Polygon to get the centroid"
+msgstr "中心点を取得するためのポリゴン．"
+
+#: locale/.cache/my_service_string_to_translate.c:17
+msgid "The Centroid"
+msgstr "中心点．"
+
+#: locale/.cache/my_service_string_to_translate.c:18
+msgid "Compute the geometry centroid."
+msgstr "ジオメトリの中心点を計算．"
+
+#: locale/.cache/my_service_string_to_translate.c:19
+msgid "The centroid which is not necessarily within the geometry."
+msgstr "ジオメトリに含まれる重要ではない中心点．"
+
+#: locale/.cache/my_service_string_to_translate.c:20
+msgid "JSON String / GML Entity of the centroid"
+msgstr "中心点のJSON文字列／GMLエンティティ．"
+
+#: locale/.cache/my_service_string_to_translate.c:21
+msgid "Compute convex hull."
+msgstr "凸包を計算．"
+
+#: locale/.cache/my_service_string_to_translate.c:22
+msgid "Polygon to compute convex hull"
+msgstr "凸包を計算するポリゴン．"
+
+#: locale/.cache/my_service_string_to_translate.c:23
+#: locale/.cache/my_service_string_to_translate.c:26
+msgid "The convex hull of the geometry"
+msgstr "ジオメトリの凸包．"
+
+#: locale/.cache/my_service_string_to_translate.c:24
+msgid ""
+"A new geometry object is created and returned containing the convex hull of "
+"the geometry on which the method is invoked."
+msgstr "新しいジオメトリオブジェクトは作成されメッソド上に返答され，凸包を含むジオメトリが呼び出される．"
+
+
+#: locale/.cache/my_service_string_to_translate.c:27
+msgid "Compute difference. . "
+msgstr "差分の計算．"
+
+#: locale/.cache/my_service_string_to_translate.c:28
+#: locale/.cache/my_service_string_to_translate.c:36
+#: locale/.cache/my_service_string_to_translate.c:50
+#: locale/.cache/my_service_string_to_translate.c:66
+#: locale/.cache/my_service_string_to_translate.c:74
+msgid "the first geometry "
+msgstr "最初のジオメトリ．"
+
+#: locale/.cache/my_service_string_to_translate.c:29
+#: locale/.cache/my_service_string_to_translate.c:37
+#: locale/.cache/my_service_string_to_translate.c:51
+#: locale/.cache/my_service_string_to_translate.c:67
+#: locale/.cache/my_service_string_to_translate.c:75
+msgid "the other geometry"
+msgstr "その他のジオメトリ．"
+
+#: locale/.cache/my_service_string_to_translate.c:30
+msgid "The difference between two geometries"
+msgstr "２つのジオメトリの差。"
+
+#: locale/.cache/my_service_string_to_translate.c:31
+msgid ""
+"Generates a new geometry which is the region of this geometry with the "
+"region of the other geometry removed."
+msgstr "他のジオメトリを削除した領域に，このジオメトリの領域の新しいジオメトリ"
+"を作成"
+
+
+#: locale/.cache/my_service_string_to_translate.c:32
+#: locale/.cache/my_service_string_to_translate.c:40
+#: locale/.cache/my_service_string_to_translate.c:54
+#: locale/.cache/my_service_string_to_translate.c:70
+#: locale/.cache/my_service_string_to_translate.c:78
+msgid "the first geometry to compare against."
+msgstr "対比比較する最初のジオメトリ．"
+
+#: locale/.cache/my_service_string_to_translate.c:33
+#: locale/.cache/my_service_string_to_translate.c:41
+#: locale/.cache/my_service_string_to_translate.c:55
+#: locale/.cache/my_service_string_to_translate.c:71
+#: locale/.cache/my_service_string_to_translate.c:79
+msgid "the other geometry to compare against."
+msgstr "対比比較するその他のジオメトリ．"
+
+#: locale/.cache/my_service_string_to_translate.c:34
+msgid "The difference between the two geometries."
+msgstr "2つのジオメトリの差分．"
+
+#: locale/.cache/my_service_string_to_translate.c:35
+msgid "Calcul la distance entre deux entites geographique. "
+msgstr "Calcul de la distance entre deux objets géographiques."
+
+#: locale/.cache/my_service_string_to_translate.c:38
+msgid "The distance between two geometries"
+msgstr "２つのジオメトリの距離．"
+
+#: locale/.cache/my_service_string_to_translate.c:39
+msgid "Calcul de la distance entre deux entites geographique. "
+msgstr "Calcul de la distance entre deux entités géographiques."
+
+#: locale/.cache/my_service_string_to_translate.c:42
+msgid "The shortest distance between the two geometries."
+msgstr "二つのジオメトリの最短距離."
+
+#: locale/.cache/my_service_string_to_translate.c:43
+msgid "Compute geometry area."
+msgstr "ジオメトリ面積の計算."
+
+#: locale/.cache/my_service_string_to_translate.c:44
+msgid "Polygon to compute area"
+msgstr "面積計算するためのポリゴン．"
+
+#: locale/.cache/my_service_string_to_translate.c:45
+msgid "Computed Area"
+msgstr "面積計算．"
+
+#: locale/.cache/my_service_string_to_translate.c:46
+msgid "Computes the area for a geometry"
+msgstr "ジオメトリの面積を計算する．"
+
+#: locale/.cache/my_service_string_to_translate.c:48
+msgid "The Computed Area Value"
+msgstr "計算された面積の値．"
+
+#: locale/.cache/my_service_string_to_translate.c:49
+msgid "Compute intersection. "
+msgstr "交点を計算する．"
+
+#: locale/.cache/my_service_string_to_translate.c:52
+msgid "Intersection of geometries"
+msgstr "ジオメトリの交点．"
+
+#: locale/.cache/my_service_string_to_translate.c:53
+msgid ""
+"Generates a new geometry which is the region of intersection of the two "
+"geometries operated on."
+msgstr "操作された２つのジオメトリの交点の領域の新しいジオメトリを作成．"
+
+
+#: locale/.cache/my_service_string_to_translate.c:56
+msgid ""
+"A new geometry representing the intersection or NULL if there is no "
+"intersection or an error occurs."
+msgstr "もし交点、またはエラーが起こっていない場合、交点またはNULLを表す新しいジオメトリ．"
+
+#: locale/.cache/my_service_string_to_translate.c:57
+msgid "Douglas-Peucker like algorithm"
+msgstr "Douglas-Peucker的アルゴリズム．"
+
+#: locale/.cache/my_service_string_to_translate.c:58
+msgid "Polygon to simplify"
+msgstr "単純化するためのポリゴン．"
+
+#: locale/.cache/my_service_string_to_translate.c:59
+msgid "Tolerance to use."
+msgstr "使用する許容値．"
+
+#: locale/.cache/my_service_string_to_translate.c:60
+msgid "The simplified geometry"
+msgstr "単純化されたジオメトリ．"
+
+#: locale/.cache/my_service_string_to_translate.c:61
+msgid ""
+"Simplifies a geometry, ensuring that the result is a valid geometry having "
+"the same dimension and number of components as the input. The simplification "
+"uses a maximum distance difference algorithm similar to the one used in the "
+"Douglas-Peucker algorithm."
+msgstr ""
+"ジオメトリを単純化"
+"結果がインプットとして同じ次元とコンポーネント数が等しい有効なジオメトリか確認．"
+"単純化では，Douglas-Peuckerアルゴリズムと類似した最大距離を使うアルゴリズムを使用．"
+
+#: locale/.cache/my_service_string_to_translate.c:63
+msgid "The approximation tolerance to use."
+msgstr "使用する許容値の概要．"
+
+#: locale/.cache/my_service_string_to_translate.c:64
+msgid ""
+"The result has the same number of shells and holes (rings) as the input, in "
+"the same order. The result rings touch at no more than the number of "
+"touching point in the input (although they may touch at fewer points)."
+msgstr "結果はインプットとしてshells とholes (rings）が共に等しい数，順序になる．"
+"結果のリングはインプットの中のタッチングポイントの数まで達しない．（しかし，より少ないポイントをタッチするかもしれない．"
+#: locale/.cache/my_service_string_to_translate.c:65
+msgid "Compute symmetric difference. "
+msgstr "対照的な差を計算．"
+
+#: locale/.cache/my_service_string_to_translate.c:68
+msgid "The resulting geometry"
+msgstr "ジオメトリの結果．"
+
+#: locale/.cache/my_service_string_to_translate.c:69
+msgid ""
+"Generates a new geometry which is the symmetric difference of this geometry "
+"and the other geometry."
+msgstr "このジオメトリと他のジオメトリで，対照的に異なった新しいジオメトリの作成"
+
+#: locale/.cache/my_service_string_to_translate.c:72
+msgid "The symmetric difference of two geometries"
+msgstr "2つのジオメトリの対照的違い．"
+
+#: locale/.cache/my_service_string_to_translate.c:73
+msgid "Compute union. "
+msgstr "結合の計算."
+
+#: locale/.cache/my_service_string_to_translate.c:76
+msgid "The union of two geometries"
+msgstr "2つのジオメトリの結合"
+
+#: locale/.cache/my_service_string_to_translate.c:77
+msgid ""
+"Generates a new geometry which is the region of union of the two geometries "
+"operated on."
+msgstr "操作された２つのジオメトリを結合した領域の新しいジオメトリの作成"
+
+#: locale/.cache/my_service_string_to_translate.c:80
+msgid "The geometry representing the union of the two geometries."
+msgstr "２つのジオメトリの結合を表すジオメトリ"
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/messages.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/messages.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/messages.po	(revision 942)
@@ -0,0 +1,299 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: zoo-services\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-28 12:52+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: GÃ©rald Fenoy <gerald.fenoy@geolabs.fr>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: locale/.cache/my_service_string_to_translate.c:1
+msgid "Compute boundary."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:2
+msgid "Polygon to compute boundary"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:3
+msgid "The geometry created"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:4
+msgid ""
+"A new geometry object is created and returned containing the boundary of the "
+"geometry on which the method is invoked. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:5
+#: locale/.cache/my_service_string_to_translate.c:12
+#: locale/.cache/my_service_string_to_translate.c:25
+#: locale/.cache/my_service_string_to_translate.c:47
+#: locale/.cache/my_service_string_to_translate.c:62
+msgid "URI to a set of GML that describes the polygon."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:6
+msgid ""
+"The geometry containing the boundary of the geometry on which the method is "
+"invoked."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:7
+msgid "Create a buffer around a polygon. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:8
+msgid "Polygon to be buffered"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:9
+msgid "Buffer Distance"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:10
+msgid "Buffered Polygon"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:11
+msgid ""
+"Create a buffer around a single polygon. Accepts the polygon as GML and "
+"provides GML output for the buffered feature. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:13
+msgid "Distance to be used to calculate buffer."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:14
+msgid "GML stream describing the buffered polygon feature."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:15
+msgid "Get the centroid of a polygon. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:16
+msgid "Polygon to get the centroid"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:17
+msgid "The Centroid"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:18
+msgid "Compute the geometry centroid."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:19
+msgid "The centroid which is not necessarily within the geometry."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:20
+msgid "JSON String / GML Entity of the centroid"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:21
+msgid "Compute convex hull."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:22
+msgid "Polygon to compute convexhull"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:23
+#: locale/.cache/my_service_string_to_translate.c:26
+msgid "The convex hull of the geometry"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:24
+msgid ""
+"A new geometry object is created and returned containing the convex hull of "
+"the geometry on which the method is invoked."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:27
+msgid "Compute difference. . "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:28
+#: locale/.cache/my_service_string_to_translate.c:36
+#: locale/.cache/my_service_string_to_translate.c:50
+#: locale/.cache/my_service_string_to_translate.c:66
+#: locale/.cache/my_service_string_to_translate.c:74
+msgid "the first geometry "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:29
+#: locale/.cache/my_service_string_to_translate.c:37
+#: locale/.cache/my_service_string_to_translate.c:51
+#: locale/.cache/my_service_string_to_translate.c:67
+#: locale/.cache/my_service_string_to_translate.c:75
+msgid "the other geometry"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:30
+msgid "The difference between two geometries"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:31
+msgid ""
+"Generates a new geometry which is the region of this geometry with the "
+"region of the other geometry removed."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:32
+#: locale/.cache/my_service_string_to_translate.c:40
+#: locale/.cache/my_service_string_to_translate.c:54
+#: locale/.cache/my_service_string_to_translate.c:70
+#: locale/.cache/my_service_string_to_translate.c:78
+msgid "the first geometry to compare against."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:33
+#: locale/.cache/my_service_string_to_translate.c:41
+#: locale/.cache/my_service_string_to_translate.c:55
+#: locale/.cache/my_service_string_to_translate.c:71
+#: locale/.cache/my_service_string_to_translate.c:79
+msgid "the other geometry to compare against."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:34
+msgid "The difference between the two geometries."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:35
+msgid "Calcul la distance entre deux entites geographique. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:38
+msgid "The distance between two geometries"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:39
+msgid "Calcul de la distance entre deux entites geographique. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:42
+msgid "The shortest distance between the two geometries."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:43
+msgid "Compute geometry area."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:44
+msgid "Polygon to compute are"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:45
+msgid "Computed Area"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:46
+msgid "Computes the area for a geometry"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:48
+msgid "The Computed Area Value"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:49
+msgid "Compute intersection. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:52
+msgid "Intersection of geometries"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:53
+msgid ""
+"Generates a new geometry which is the region of intersection of the two "
+"geometries operated on."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:56
+msgid ""
+"A new geometry representing the intersection or NULL if there is no "
+"intersection or an error occurs."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:57
+msgid "Douglas-Peucker like algorithm"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:58
+msgid "Polygon to simplify"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:59
+msgid "Tolerance to use."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:60
+msgid "The simplified geometry"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:61
+msgid ""
+"Simplifies a geometry, ensuring that the result is a valid geometry having "
+"the same dimension and number of components as the input. The simplification "
+"uses a maximum distance difference algorithm similar to the one used in the "
+"Douglas-Peucker algorithm."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:63
+msgid "The approximation tolerance to use."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:64
+msgid ""
+"The result has the same number of shells and holes (rings) as the input, in "
+"the same order. The result rings touch at no more than the number of "
+"touching point in the input (although they may touch at fewer points)."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:65
+msgid "Compute symmetric difference. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:68
+msgid "The resulting geometry"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:69
+msgid ""
+"Generates a new geometry which is the symmetric difference of this geometry "
+"and the other geometry."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:72
+msgid "The symmetric difference of two geometries"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:73
+msgid "Compute union. "
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:76
+msgid "The union of two geometries"
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:77
+msgid ""
+"Generates a new geometry which is the region of union of the two geometries "
+"operated on."
+msgstr ""
+
+#: locale/.cache/my_service_string_to_translate.c:80
+msgid "The geometry representing the union of the two geometries."
+msgstr ""
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/makefile.vc	(revision 942)
@@ -0,0 +1,12 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+cgi-env/ogr_service.zo: service.c
+	$(CPP)  /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE -I$(GDAL_DIR)/frmts/ $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/ogr_service.zo  ./service.obj $(FILES) $(LDFLAGS) $(GEOS_DIR)/lib/geos_c.lib /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\ogr_service.*
+
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/base-vect-ops/service.c	(revision 942)
@@ -0,0 +1,1918 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2008-2009 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "cpl_conv.h"
+#include "ogr_api.h"
+#include "ogr_geometry.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+
+#include "cpl_minixml.h"
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+
+#include "geos_c.h"
+#include "service.h"
+#include "service_internal.h"
+
+extern "C" {
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+/*#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+*/
+
+  void printExceptionReportResponse(maps*,map*);
+  char *base64(const char *input, int length);
+
+  OGRGeometryH createGeometryFromGML(maps* conf,char* inputStr){
+    xmlInitParser();
+    xmlDocPtr doc = xmlParseMemory(inputStr,strlen(inputStr));
+    xmlChar *xmlbuff;
+    int buffersize;
+    xmlXPathContextPtr xpathCtx;
+    xmlXPathObjectPtr xpathObj;
+    const char * xpathExpr="/*/*/*/*/*[local-name()='Polygon' or local-name()='MultiPolygon']";
+    xpathCtx = xmlXPathNewContext(doc);
+    xpathObj = xmlXPathEvalExpression(BAD_CAST xpathExpr,xpathCtx);
+    if(!xpathObj->nodesetval){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse Input Polygon"));
+      setMapInMaps(conf,"lenv","code","InvalidParameterValue");
+      return NULL;
+    }
+    int size = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0;
+    /**
+     * Create a temporary XML document
+     */
+    xmlDocPtr ndoc = xmlNewDoc(BAD_CAST "1.0");
+    /**
+     * Only one polygon should be provided so we use it as the root node.
+     */
+    for(int k=size-1;k>=0;k--){ 
+      xmlDocSetRootElement(ndoc, xpathObj->nodesetval->nodeTab[k]);
+    }
+    xmlDocDumpFormatMemory(ndoc, &xmlbuff, &buffersize, 1);
+    char *tmp=(char*)calloc((xmlStrlen(xmlStrstr(xmlbuff,BAD_CAST "?>"))-1),sizeof(char));
+    sprintf(tmp,"%s",xmlStrstr(xmlbuff,BAD_CAST "?>")+2);
+    xmlXPathFreeObject(xpathObj);
+    xmlXPathFreeContext(xpathCtx);
+    xmlFree(xmlbuff);
+    xmlFreeDoc(doc);
+    xmlFreeDoc(ndoc);
+#ifndef WIN32
+    xmlCleanupParser();
+#endif
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\n Loading the geometry from GML string ...");
+#endif
+    OGRGeometryH res=OGR_G_CreateFromGML(tmp);
+    free(tmp);
+    if(res==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to call OGR_G_CreatFromGML"));
+      return NULL;
+    }
+    else
+      return res;
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Simplify(maps*& conf,maps*& inputs,maps*& outputs){
+    OGRRegisterAll();
+
+    double tolerance;
+    map* tmp0=getMapFromMaps(inputs,"Tolerance","value");
+    if(tmp0==NULL){
+      tolerance=atof("2.0");
+    }
+    else
+      tolerance=atof(tmp0->value);
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry;
+    OGRGeometry *res;
+    OGRLayer *poDstLayer;
+    const char *oDriver1;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *poODS;
+#else
+    OGRDataSource *poODS;
+#endif
+    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+    if(!tmp){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse the input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    char filename[1024];
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+    const char *oDriver;
+    oDriver="GeoJSON";
+    sprintf(filename,"/vsimem/input_%d.json",getpid());
+    if(tmp1!=NULL){
+      if(strcmp(tmp1->value,"text/xml")==0){
+	sprintf(filename,"/vsimem/input_%d.xml",getpid());
+	oDriver="GML";
+      }
+    }
+    VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmp->value,strlen(tmp->value),FALSE);
+    VSIFCloseL(ifile);
+
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDataset *ipoDS =
+	(GDALDataset*) GDALOpenEx( filename,
+				   GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				   NULL, NULL, NULL );
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+#else
+      OGRDataSource* ipoDS = 
+	OGRSFDriverRegistrar::Open(filename,FALSE);
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+    char pszDestDataSource[100];
+    if( ipoDS == NULL )
+      {
+	fprintf( stderr, "FAILURE:\n"
+		 "Unable to open datasource `%s' with the following drivers.\n",
+		 filename );
+	
+	for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+	char tmp[1024];
+	sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+      }
+    for( int iLayer = 0; iLayer < ipoDS->GetLayerCount();
+	 iLayer++ )
+      {
+	OGRLayer        *poLayer = ipoDS->GetLayer(iLayer);
+	
+	if( poLayer == NULL )
+	  {
+	    fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		     iLayer );
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+	  }
+	
+	OGRFeature  *poFeature;
+
+	int                  iDriver;
+	
+	map* tmpMap=getMapFromMaps(outputs,"Result","mimeType");
+	oDriver1="GeoJSON";
+	sprintf(pszDestDataSource,"/vsimem/result_%d.json",getpid());
+	if(tmpMap!=NULL){
+	  if(strcmp(tmpMap->value,"text/xml")==0){
+	    sprintf(pszDestDataSource,"/vsimem/result_%d.xml",getpid());
+	    oDriver1="GML";
+	  }
+	}
+	
+	for( iDriver = 0;
+	     iDriver < poR->GetDriverCount() && poDriver == NULL;
+	     iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >=2
+	    if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),oDriver1) )
+#else
+	    if( EQUAL(poR->GetDriver(iDriver)->GetName(),oDriver1) )
+#endif
+	      {
+		poDriver = poR->GetDriver(iDriver);
+	      }
+	  }
+	
+	if( poDriver == NULL )
+	  {
+	    char emessage[8192];
+	    sprintf( emessage, "Unable to find driver `%s'.\n", oDriver );
+	    sprintf( emessage,  "%sThe following drivers are available:\n",emessage );
+	    
+	    for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	      {
+#if GDAL_VERSION_MAJOR >=2
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+#else
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+#endif
+	      }
+	    
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	    
+	  }
+	
+#if GDAL_VERSION_MAJOR >=2
+	if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+	if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+	  {
+	    char emessage[1024];
+	    sprintf( emessage,  "%s driver does not support data source creation.\n",
+	      "json" );
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	  }
+	
+	char **papszDSCO=NULL;
+#if GDAL_VERSION_MAJOR >=2
+        poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+	poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+	if( poODS == NULL ){
+	  char emessage[1024];      
+	  sprintf( emessage,  "%s driver failed to create %s\n", 
+		   "json", pszDestDataSource );
+	  setMapInMaps(conf,"lenv","message",emessage);
+	  return SERVICE_FAILED;
+	}
+	
+	if( !poODS->TestCapability( ODsCCreateLayer ) )
+	  {
+	    char emessage[1024];
+	    sprintf( emessage, 
+		     "Layer %s not found, and CreateLayer not supported by driver.", 
+		     "Result" );
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	  }
+	
+	poDstLayer = poODS->CreateLayer( "Result", NULL,wkbUnknown,NULL);
+	if( poDstLayer == NULL ){
+	  setMapInMaps(conf,"lenv","message","Layer creation failed.\n");
+	  return SERVICE_FAILED;
+	}
+	
+	OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
+	int iField;
+	int hasMmField=0;
+	
+	for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
+	  {
+	    OGRFieldDefn *tmp=poFDefn->GetFieldDefn(iField);
+            if (iField >= 0)
+                poDstLayer->CreateField( poFDefn->GetFieldDefn(iField) );
+            else
+            {
+                fprintf( stderr, "Field '%s' not found in source layer.\n", 
+                        iField );
+		return SERVICE_FAILED;
+            }
+	  }
+
+	while(TRUE){
+	  OGRFeature      *poDstFeature = NULL;
+	  poFeature = poLayer->GetNextFeature();
+	  if( poFeature == NULL )
+	    break;
+	  if(poFeature->GetGeometryRef() != NULL){
+	    poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+	    if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE )
+	      {
+		char tmpMsg[1024];
+		sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			 poFeature->GetFID(), poFDefn->GetName() );
+		
+		OGRFeature::DestroyFeature( poFeature );
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    geometry=poFeature->GetGeometryRef();
+#if GDAL_VERSION_MAJOR == 1 && GDAL_VERSION_MINOR < 11
+	    GEOSGeometry* ggeometry=((OGRGeometry *) geometry)->exportToGEOS();
+	    GEOSGeometry* gres=GEOSTopologyPreserveSimplify(ggeometry,tolerance);
+	    if(gres!=NULL)
+	      res=(OGRGeometry*)OGRGeometryFactory::createFromGEOS(gres);
+#else
+	    res=((OGRGeometry *) geometry)->SimplifyPreserveTopology(tolerance);
+#endif
+	    if(poDstFeature->SetGeometryDirectly(res) != OGRERR_NONE )
+	      {
+		char tmpMsg[1024];
+		sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			 poFeature->GetFID(), poFDefn->GetName() );
+		
+		OGRFeature::DestroyFeature( poFeature );
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRFeature::DestroyFeature( poFeature );
+	    if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE )
+	      {		
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRFeature::DestroyFeature( poDstFeature );
+#if GDAL_VERSION_MAJOR == 1 && GDAL_VERSION_MINOR < 11
+	    GEOSGeom_destroy( ggeometry);
+	    GEOSGeom_destroy( gres);
+#endif
+	  }
+	}
+      }
+
+    delete poODS;
+    delete ipoDS;
+
+    char *res1=readVSIFile(conf,pszDestDataSource);
+    if(res1==NULL)
+      return SERVICE_FAILED;
+    setMapInMaps(outputs,"Result","value",res1);
+    free(res1);
+
+    OGRCleanupAll();
+    dumpMaps(outputs);
+    return SERVICE_SUCCEEDED;
+
+}
+
+int applyOne(maps*& conf,maps*& inputs,maps*& outputs,OGRGeometry* (OGRGeometry::*myFunc)() const,const char* schema){
+    OGRRegisterAll();
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    OGRLayer *poDstLayer;
+    const char *oDriver1;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *poODS;
+#else
+    OGRDataSource *poODS;
+#endif
+    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+    if(!tmp){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse the input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    char filename[1024];
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+    const char *oDriver;
+    oDriver="GeoJSON";
+    sprintf(filename,"/vsimem/input_%d.json",getpid());
+    if(tmp1!=NULL){
+      if(strcmp(tmp1->value,"text/xml")==0){
+	sprintf(filename,"/vsimem/input_%d.xml",getpid());
+	oDriver="GML";
+      }
+    }
+    VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmp->value,strlen(tmp->value),FALSE);
+    VSIFCloseL(ifile);
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *ipoDS =
+      (GDALDataset*) GDALOpenEx( filename,
+				 GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				 NULL, NULL, NULL );
+    GDALDriverManager* poR=GetGDALDriverManager();
+    GDALDriver          *poDriver = NULL;
+#else
+    OGRDataSource* ipoDS = 
+      OGRSFDriverRegistrar::Open(filename,FALSE);
+    OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+    OGRSFDriver          *poDriver = NULL;
+#endif
+    char pszDestDataSource[100];
+    if( ipoDS == NULL )
+      {
+	fprintf( stderr, "FAILURE:\n"
+		 "Unable to open datasource `%s' with the following drivers.\n",
+		 filename );
+	char emessage[1024];	
+	for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >=2
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+		fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+		fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+	char tmp[1024];
+	sprintf(tmp,"Unable to open datasource `%s' with the following drivers.\n%s",filename,emessage);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+      }
+
+    for( int iLayer = 0; iLayer < ipoDS->GetLayerCount();
+	 iLayer++ )
+      {
+	OGRLayer        *poLayer = ipoDS->GetLayer(iLayer);
+	
+	if( poLayer == NULL )
+	  {
+	    fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		     iLayer );
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+	  }
+	
+	OGRFeature  *poFeature;
+
+	/* -------------------------------------------------------------------- */
+	/*      Try opening the output datasource as an existing, writable      */
+	/* -------------------------------------------------------------------- */
+	
+	int                  iDriver;
+	
+	map* tmpMap=getMapFromMaps(outputs,"Result","mimeType");
+	oDriver1="GeoJSON";
+	sprintf(pszDestDataSource,"/vsimem/result_%d.json",getpid());
+	if(tmpMap!=NULL){
+	  if(strcmp(tmpMap->value,"text/xml")==0){
+	    sprintf(pszDestDataSource,"/vsimem/result_%d.xml",getpid());
+	    oDriver1="GML";
+	  }
+	}
+	
+	for( iDriver = 0;
+	     iDriver < poR->GetDriverCount() && poDriver == NULL;
+	     iDriver++ )
+	  {
+
+	    if( 
+#if GDAL_VERSION_MAJOR >=2
+		EQUAL(poR->GetDriver(iDriver)->GetDescription(),oDriver1)
+#else
+		EQUAL(poR->GetDriver(iDriver)->GetName(),oDriver1)
+#endif
+		)
+	      {
+		poDriver = poR->GetDriver(iDriver);
+	      }
+	  }
+	
+	if( poDriver == NULL )
+	  {
+	    char emessage[8192];
+	    sprintf( emessage, "Unable to find driver `%s'.\n", oDriver );
+	    sprintf( emessage,  "%sThe following drivers are available:\n",emessage );
+	    for( iDriver = 0;iDriver < poR->GetDriverCount();iDriver++ )	    
+	      {
+#if GDAL_VERSION_MAJOR >=2
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+#else
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+#endif
+	      }
+	    
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	    
+	  }
+	
+#if GDAL_VERSION_MAJOR >=2
+	if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+	if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+	{
+	  char emessage[1024];
+	  sprintf( emessage,  "%s driver does not support data source creation.\n",
+		   "json" );
+	  setMapInMaps(conf,"lenv","message",emessage);
+	  return SERVICE_FAILED;
+	}
+	
+	/* -------------------------------------------------------------------- */
+	/*      Create the output data source.                                  */
+	/* -------------------------------------------------------------------- */
+	//map* tpath=getMapFromMaps(conf,"main","tmpPath");
+	char **papszDSCO=NULL;
+#if GDAL_VERSION_MAJOR >=2
+        poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+	poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+	if( poODS == NULL ){
+	  char emessage[1024];      
+	  sprintf( emessage,  "%s driver failed to create %s\n", 
+		   "json", pszDestDataSource );
+	  setMapInMaps(conf,"lenv","message",emessage);
+	  return SERVICE_FAILED;
+	}
+	
+	/* -------------------------------------------------------------------- */
+	/*      Create the layer.                                               */
+	/* -------------------------------------------------------------------- */
+	if( !poODS->TestCapability( ODsCCreateLayer ) )
+	  {
+	    char emessage[1024];
+	    sprintf( emessage, 
+		     "Layer %s not found, and CreateLayer not supported by driver.", 
+		     "Result" );
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	  }
+	
+	
+	poDstLayer = poODS->CreateLayer( "Result", NULL,wkbUnknown,NULL);
+	if( poDstLayer == NULL ){
+	  setMapInMaps(conf,"lenv","message","Layer creation failed.\n");
+	  return SERVICE_FAILED;
+	}
+	
+	OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
+	int iField;
+	int hasMmField=0;
+	
+	for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
+	  {
+	    OGRFieldDefn *tmp=poFDefn->GetFieldDefn(iField);
+            if (iField >= 0)
+                poDstLayer->CreateField( poFDefn->GetFieldDefn(iField) );
+            else
+            {
+                fprintf( stderr, "Field '%s' not found in source layer.\n", 
+                        iField );
+		return SERVICE_FAILED;
+            }
+	  }
+
+	while(TRUE){
+	  OGRFeature      *poDstFeature = NULL;
+	  poFeature = poLayer->GetNextFeature();
+	  if( poFeature == NULL )
+	    break;
+	  if(poFeature->GetGeometryRef() != NULL){
+	    poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+	    if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE )
+	      {
+		char tmpMsg[1024];
+		sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			 poFeature->GetFID(), poFDefn->GetName() );
+		
+		OGRFeature::DestroyFeature( poFeature );
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    if(poDstFeature->SetGeometryDirectly((poDstFeature->GetGeometryRef()->*myFunc)()) != OGRERR_NONE )
+	      {
+		char tmpMsg[1024];
+		sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			 poFeature->GetFID(), poFDefn->GetName() );
+		
+		OGRFeature::DestroyFeature( poFeature );
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRFeature::DestroyFeature( poFeature );
+	    if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE )
+	      {		
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRFeature::DestroyFeature( poDstFeature );
+	  }
+	}
+
+      }
+
+    delete poODS;
+    delete ipoDS;
+
+    char *res1=readVSIFile(conf,pszDestDataSource);
+    if(res1==NULL)
+      return SERVICE_FAILED;
+    setMapInMaps(outputs,"Result","value",res1);
+    free(res1);
+
+    OGRCleanupAll();
+    return SERVICE_SUCCEEDED;
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+int Buffer(maps*& conf,maps*& inputs,maps*& outputs){
+    OGRRegisterAll();
+
+    double bufferDistance;
+    map* tmp0=getMapFromMaps(inputs,"BufferDistance","value");
+    if(tmp0==NULL){
+      bufferDistance=atof("10.0");
+    }
+    else
+      bufferDistance=atof(tmp0->value);
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    OGRLayer *poDstLayer;
+    const char *oDriver1;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *poODS;
+#else
+    OGRDataSource *poODS;
+#endif
+    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+    if(!tmp){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse the input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    char filename[1024];
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+    const char *oDriver;
+    oDriver="GeoJSON";
+    sprintf(filename,"/vsimem/input_%d.json",getpid());
+    if(tmp1!=NULL){
+      if(strcmp(tmp1->value,"text/xml")==0){
+	sprintf(filename,"/vsimem/input_%d.xml",getpid());
+	oDriver="GML";
+      }
+    }
+    VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmp->value,strlen(tmp->value),FALSE);
+    VSIFCloseL(ifile);
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDataset *ipoDS =
+	(GDALDataset*) GDALOpenEx( filename,
+				   GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				   NULL, NULL, NULL );
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+#else
+      OGRDataSource* ipoDS = 
+	OGRSFDriverRegistrar::Open(filename,FALSE);
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+    char pszDestDataSource[100];
+    if( ipoDS == NULL )
+      {
+	
+	fprintf( stderr, "FAILURE:\n"
+		 "Unable to open datasource `%s' with the following drivers.\n",
+		 filename );
+	
+	for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+	char tmp[1024];
+	sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+      }
+    for( int iLayer = 0; iLayer < ipoDS->GetLayerCount();
+	 iLayer++ )
+      {
+	OGRLayer        *poLayer = ipoDS->GetLayer(iLayer);
+	
+	if( poLayer == NULL )
+	  {
+	    fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		     iLayer );
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+	  }
+	
+	OGRFeature  *poFeature;
+
+	/* -------------------------------------------------------------------- */
+	/*      Try opening the output datasource as an existing, writable      */
+	/* -------------------------------------------------------------------- */
+	
+	int                  iDriver;
+	
+	map* tmpMap=getMapFromMaps(outputs,"Result","mimeType");
+	oDriver1="GeoJSON";
+	sprintf(pszDestDataSource,"/vsimem/result_%d.json",getpid());
+	if(tmpMap!=NULL){
+	  if(strcmp(tmpMap->value,"text/xml")==0){
+	    sprintf(pszDestDataSource,"/vsimem/result_%d.xml",getpid());
+	    oDriver1="GML";
+	  }
+	}
+	
+	for( iDriver = 0;
+	     iDriver < poR->GetDriverCount() && poDriver == NULL;
+	     iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >=2
+	    if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),oDriver1) )
+#else
+	    if( EQUAL(poR->GetDriver(iDriver)->GetName(),oDriver1) )
+#endif
+	      {
+		poDriver = poR->GetDriver(iDriver);
+	      }
+	  }
+	
+	if( poDriver == NULL )
+	  {
+	    char emessage[8192];
+	    sprintf( emessage, "Unable to find driver `%s'.\n", oDriver );
+	    sprintf( emessage,  "%sThe following drivers are available:\n",emessage );
+	    
+	    for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	      {
+#if GDAL_VERSION_MAJOR >=2
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+#else
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+#endif
+	      }
+	    
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	    
+	  }
+	
+#if GDAL_VERSION_MAJOR >=2
+	if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+	if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+	{
+	  char emessage[1024];
+	  sprintf( emessage,  "%s driver does not support data source creation.\n",
+		   "json" );
+	  setMapInMaps(conf,"lenv","message",emessage);
+	  return SERVICE_FAILED;
+	}
+	
+	/* -------------------------------------------------------------------- */
+	/*      Create the output data source.                                  */
+	/* -------------------------------------------------------------------- */
+	//map* tpath=getMapFromMaps(conf,"main","tmpPath");
+	char **papszDSCO=NULL;
+#if GDAL_VERSION_MAJOR >=2
+        poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+	poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+	if( poODS == NULL ){
+	  char emessage[1024];      
+	  sprintf( emessage,  "%s driver failed to create %s\n", 
+		   "json", pszDestDataSource );
+	  setMapInMaps(conf,"lenv","message",emessage);
+	  return SERVICE_FAILED;
+	}
+	
+	/* -------------------------------------------------------------------- */
+	/*      Create the layer.                                               */
+	/* -------------------------------------------------------------------- */
+	if( !poODS->TestCapability( ODsCCreateLayer ) )
+	  {
+	    char emessage[1024];
+	    sprintf( emessage, 
+		     "Layer %s not found, and CreateLayer not supported by driver.", 
+		     "Result" );
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	  }
+
+	poDstLayer = poODS->CreateLayer( "Result", NULL,wkbUnknown,NULL);
+	if( poDstLayer == NULL ){
+	  setMapInMaps(conf,"lenv","message","Layer creation failed.\n");
+	  return SERVICE_FAILED;
+	}
+	
+	OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
+	int iField;
+	int hasMmField=0;
+	
+	for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
+	  {
+	    OGRFieldDefn *tmp=poFDefn->GetFieldDefn(iField);
+            if (iField >= 0)
+                poDstLayer->CreateField( poFDefn->GetFieldDefn(iField) );
+            else
+            {
+                fprintf( stderr, "Field '%s' not found in source layer.\n", 
+                        iField );
+		return SERVICE_FAILED;
+            }
+	  }
+
+	while(TRUE){
+	  OGRFeature      *poDstFeature = NULL;
+	  poFeature = poLayer->GetNextFeature();
+	  if( poFeature == NULL )
+	    break;
+	  if(poFeature->GetGeometryRef() != NULL){
+	    poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+	    if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE )
+	      {
+		char tmpMsg[1024];
+		sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			 poFeature->GetFID(), poFDefn->GetName() );
+		
+		OGRFeature::DestroyFeature( poFeature );
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    if(poDstFeature->SetGeometryDirectly(poDstFeature->GetGeometryRef()->Buffer(bufferDistance,30)) != OGRERR_NONE )
+	      {
+		char tmpMsg[1024];
+		sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			 poFeature->GetFID(), poFDefn->GetName() );
+		
+		OGRFeature::DestroyFeature( poFeature );
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRFeature::DestroyFeature( poFeature );
+	    if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE )
+	      {		
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRFeature::DestroyFeature( poDstFeature );
+	  }
+	}
+
+      }
+
+    delete poODS;
+    delete ipoDS;
+
+    char *res1=readVSIFile(conf,pszDestDataSource);
+    if(res1==NULL)
+      return SERVICE_FAILED;
+    setMapInMaps(outputs,"Result","value",res1);
+    free(res1);
+
+    OGRCleanupAll();
+    return SERVICE_SUCCEEDED;
+
+}
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+int Centroid(maps*& conf,maps*& inputs,maps*& outputs){
+    OGRRegisterAll();
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    OGRLayer *poDstLayer;
+    const char *oDriver1;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *poODS;
+#else
+    OGRDataSource *poODS;
+#endif
+    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+    if(!tmp){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse the input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    char filename[1024];
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+    const char *oDriver;
+    oDriver="GeoJSON";
+    sprintf(filename,"/vsimem/input_%d.json",getpid());
+    if(tmp1!=NULL){
+      if(strcmp(tmp1->value,"text/xml")==0){
+	sprintf(filename,"/vsimem/input_%d.xml",getpid());
+	oDriver="GML";
+      }
+    }
+    VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmp->value,strlen(tmp->value),FALSE);
+    VSIFCloseL(ifile);
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDataset *ipoDS =
+	(GDALDataset*) GDALOpenEx( filename,
+				   GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				   NULL, NULL, NULL );
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+#else
+      OGRDataSource* ipoDS = 
+	OGRSFDriverRegistrar::Open(filename,FALSE);
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+    char pszDestDataSource[100];
+    if( ipoDS == NULL )
+      {
+	
+	fprintf( stderr, "FAILURE:\n"
+		 "Unable to open datasource `%s' with the following drivers.\n",
+		 filename );
+	
+	for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+	char tmp[1024];
+	sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+      }
+    for( int iLayer = 0; iLayer < ipoDS->GetLayerCount();
+	 iLayer++ )
+      {
+	OGRLayer        *poLayer = ipoDS->GetLayer(iLayer);
+	
+	if( poLayer == NULL )
+	  {
+	    fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		     iLayer );
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+	  }
+	
+	OGRFeature  *poFeature;
+
+	/* -------------------------------------------------------------------- */
+	/*      Try opening the output datasource as an existing, writable      */
+	/* -------------------------------------------------------------------- */
+	
+	int                  iDriver;
+	
+	map* tmpMap=getMapFromMaps(outputs,"Result","mimeType");
+	oDriver1="GeoJSON";
+	sprintf(pszDestDataSource,"/vsimem/result_%d.json",getpid());
+	if(tmpMap!=NULL){
+	  if(strcmp(tmpMap->value,"text/xml")==0){
+	    sprintf(pszDestDataSource,"/vsimem/result_%d.xml",getpid());
+	    oDriver1="GML";
+	  }
+	}
+	
+	for( iDriver = 0;
+	     iDriver < poR->GetDriverCount() && poDriver == NULL;
+	     iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >=2
+	    if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),oDriver1) )
+#else
+	    if( EQUAL(poR->GetDriver(iDriver)->GetName(),oDriver1) )
+#endif
+	      {
+		poDriver = poR->GetDriver(iDriver);
+	      }
+	  }
+	
+	if( poDriver == NULL )
+	  {
+	    char emessage[8192];
+	    sprintf( emessage, "Unable to find driver `%s'.\n", oDriver );
+	    sprintf( emessage,  "%sThe following drivers are available:\n",emessage );
+	    
+	    for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	      {
+#if GDAL_VERSION_MAJOR >=2
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+#else
+		sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+#endif
+	      }
+	    
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	    
+	  }
+	
+#if GDAL_VERSION_MAJOR >=2
+	if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+	if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+	{
+	  char emessage[1024];
+	  sprintf( emessage,  "%s driver does not support data source creation.\n",
+		   "json" );
+	  setMapInMaps(conf,"lenv","message",emessage);
+	  return SERVICE_FAILED;
+	}
+	
+	/* -------------------------------------------------------------------- */
+	/*      Create the output data source.                                  */
+	/* -------------------------------------------------------------------- */
+	//map* tpath=getMapFromMaps(conf,"main","tmpPath");
+	char **papszDSCO=NULL;
+#if GDAL_VERSION_MAJOR >=2
+        poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+	poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+	if( poODS == NULL ){
+	  char emessage[1024];      
+	  sprintf( emessage,  "%s driver failed to create %s\n", 
+		   "json", pszDestDataSource );
+	  setMapInMaps(conf,"lenv","message",emessage);
+	  return SERVICE_FAILED;
+	}
+	
+	/* -------------------------------------------------------------------- */
+	/*      Create the layer.                                               */
+	/* -------------------------------------------------------------------- */
+	if( !poODS->TestCapability( ODsCCreateLayer ) )
+	  {
+	    char emessage[1024];
+	    sprintf( emessage, 
+		     "Layer %s not found, and CreateLayer not supported by driver.", 
+		     "Result" );
+	    setMapInMaps(conf,"lenv","message",emessage);
+	    return SERVICE_FAILED;
+	  }
+
+	poDstLayer = poODS->CreateLayer( "Result", NULL,wkbUnknown,NULL);
+	if( poDstLayer == NULL ){
+	  setMapInMaps(conf,"lenv","message","Layer creation failed.\n");
+	  return SERVICE_FAILED;
+	}
+	
+	OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
+	int iField;
+	int hasMmField=0;
+	
+	for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
+	  {
+	    OGRFieldDefn *tmp=poFDefn->GetFieldDefn(iField);
+            if (iField >= 0)
+                poDstLayer->CreateField( poFDefn->GetFieldDefn(iField) );
+            else
+            {
+                fprintf( stderr, "Field '%s' not found in source layer.\n", 
+                        iField );
+		return SERVICE_FAILED;
+            }
+	  }
+
+	while(TRUE){
+	  OGRFeature      *poDstFeature = NULL;
+	  poFeature = poLayer->GetNextFeature();
+	  if( poFeature == NULL )
+	    break;
+	  if(poFeature->GetGeometryRef() != NULL){
+	    poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+	    if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE )
+	      {
+		char tmpMsg[1024];
+		sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			 poFeature->GetFID(), poFDefn->GetName() );
+		
+		OGRFeature::DestroyFeature( poFeature );
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRPoint* poPoint=new OGRPoint();
+	    poDstFeature->GetGeometryRef()->Centroid(poPoint);
+	    if(poDstFeature->SetGeometryDirectly(poPoint)!= OGRERR_NONE ){
+	      char tmpMsg[1024];
+	      sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+		       poFeature->GetFID(), poFDefn->GetName() );
+	      
+	      OGRFeature::DestroyFeature( poFeature );
+	      OGRFeature::DestroyFeature( poDstFeature );
+	      return SERVICE_FAILED;
+	    }
+	    OGRFeature::DestroyFeature( poFeature );
+	    if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE )
+	      {		
+		OGRFeature::DestroyFeature( poDstFeature );
+		return SERVICE_FAILED;
+	      }
+	    OGRFeature::DestroyFeature( poDstFeature );
+	  }
+	}
+
+      }
+
+    delete poODS;
+    delete ipoDS;
+
+    char *res1=readVSIFile(conf,pszDestDataSource);
+    if(res1==NULL)
+      return SERVICE_FAILED;
+    setMapInMaps(outputs,"Result","value",res1);
+    free(res1);
+
+    OGRCleanupAll();
+    return SERVICE_SUCCEEDED;
+
+}
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Boundary(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyOne(conf,inputs,outputs,&OGRGeometry::Boundary,"http://fooa/gml/3.1.0/polygon.xsd");
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int ConvexHull(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyOne(conf,inputs,outputs,&OGRGeometry::ConvexHull,"http://fooa/gml/3.1.0/polygon.xsd");
+  }
+
+#if GDAL_VERSION_MAJOR >= 2
+GDALDataset*
+#else
+OGRDataSource* 
+#endif
+  loadEntity(maps* conf,maps* inputs,char **filename,const char **oDriver,const char *entity,int iter){
+    map* tmp=getMapFromMaps(inputs,entity,"value");
+    map* tmp1=getMapFromMaps(inputs,entity,"mimeType");
+    *oDriver="GeoJSON";
+    sprintf(*filename,"/vsimem/input_%d.json",getpid()+iter);
+    if(tmp1!=NULL){
+      if(strcmp(tmp1->value,"text/xml")==0){
+	sprintf(*filename,"/vsimem/input_%d.xml",getpid()+iter);
+	*oDriver="GML";
+      }
+    }
+    VSILFILE *ifile=VSIFileFromMemBuffer(*filename,(GByte*)tmp->value,strlen(tmp->value),FALSE);
+    VSIFCloseL(ifile);
+#if GDAL_VERSION_MAJOR >= 2
+    return (GDALDataset*) GDALOpenEx( *filename,
+				      GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				      NULL, NULL, NULL );
+#else
+    return OGRSFDriverRegistrar::Open(*filename,FALSE);    
+#endif
+  }
+
+  int applyOneBool(maps*& conf,maps*& inputs,maps*& outputs,OGRBoolean (OGRGeometry::*myFunc)() const){
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\n");
+#endif
+    OGRRegisterAll();
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    OGRLayer *poDstLayer;
+    const char *oDriver1;
+    OGRDataSource       *poODS;
+#ifdef DEBUG
+    dumpMaps(cursor);
+#endif
+    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+    if(!tmp){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse the input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    char filename[1024];
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+    const char *oDriver;
+    oDriver="GeoJSON";
+    sprintf(filename,"/vsimem/input_%d.json",getpid());
+    if(tmp1!=NULL){
+      if(strcmp(tmp1->value,"text/xml")==0){
+	sprintf(filename,"/vsimem/input_%d.xml",getpid());
+	oDriver="GML";
+      }
+    }
+    VSILFILE *ifile=VSIFileFromMemBuffer(filename,(GByte*)tmp->value,strlen(tmp->value),FALSE);
+    VSIFCloseL(ifile);
+
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDataset *ipoDS =
+	(GDALDataset*) GDALOpenEx( filename,
+				   GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				   NULL, NULL, NULL );
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+#else
+      OGRDataSource* ipoDS = 
+	OGRSFDriverRegistrar::Open(filename,FALSE);
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+    char pszDestDataSource[100];
+    if( ipoDS == NULL )
+      {	
+	fprintf( stderr, "FAILURE:\n"
+		 "Unable to open datasource `%s' with the following drivers.\n",
+		 filename );
+	
+	for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+	char tmp[1024];
+	sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+      }
+    for( int iLayer = 0; iLayer < ipoDS->GetLayerCount();
+	 iLayer++ )
+      {
+	OGRLayer        *poLayer = ipoDS->GetLayer(iLayer);
+	
+	if( poLayer == NULL )
+	  {
+	    fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		     iLayer );
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+	  }
+	
+	OGRFeature  *poFeature;
+
+
+	while(TRUE){
+	  OGRFeature      *poDstFeature = NULL;
+	  poFeature = poLayer->GetNextFeature();
+	  if( poFeature == NULL )
+	    break;
+	  if(poFeature->GetGeometryRef() != NULL){
+	    if((poFeature->GetGeometryRef()->*myFunc)()==0){
+	      setMapInMaps(outputs,"Result","value","false");
+	      OGRFeature::DestroyFeature( poFeature );
+	      delete ipoDS;
+	      return SERVICE_SUCCEEDED;
+	    }
+	  }
+	  OGRFeature::DestroyFeature( poFeature );
+	}
+
+      }
+
+    delete ipoDS;
+    setMapInMaps(outputs,"Result","value","true");
+
+    OGRCleanupAll();
+    return SERVICE_SUCCEEDED;
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int IsSimple(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyOneBool(conf,inputs,outputs,&OGRGeometry::IsSimple);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int IsClosed(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyOneBool(conf,inputs,outputs,&OGRGeometry::IsRing);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int IsValid(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyOneBool(conf,inputs,outputs,&OGRGeometry::IsValid);
+  }
+
+  
+  int applyTwo(maps*& conf,maps*& inputs,maps*& outputs,OGRGeometry* (OGRGeometry::*myFunc)(const OGRGeometry*) const){
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\n");
+#endif
+    OGRRegisterAll();
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    OGRLayer *poDstLayer;
+    //const char *oDriver1;
+#ifdef DEBUG
+    dumpMaps(cursor);
+#endif
+
+    char *filename=(char*)malloc(1024*sizeof(char));
+    const char *oDriver1;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset*
+#else
+    OGRDataSource* 
+#endif
+      ipoDS1 = loadEntity(conf,inputs,&filename,&oDriver1,"InputEntity1",1);
+    char *filename1=(char*)malloc(1024*sizeof(char));
+    const char *oDriver2;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset*
+#else
+    OGRDataSource* 
+#endif
+      ipoDS2 = loadEntity(conf,inputs,&filename1,&oDriver2,"InputEntity2",2);
+    const char *oDriver3;
+    char pszDestDataSource[100];
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+      GDALDataset *poODS;
+#else
+      OGRDataSource       *poODS;
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+    if( ipoDS1 == NULL || ipoDS2 == NULL )
+      {
+	
+	fprintf( stderr, "FAILURE:\n"
+		 "Unable to open datasource `%s' with the following drivers.\n",
+		 filename );
+	
+	for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+	char tmp[1024];
+	if( ipoDS1 == NULL )
+	  sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename);
+	if( ipoDS2 == NULL )
+	  sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename1);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+      }
+    for( int iLayer = 0; iLayer < ipoDS1->GetLayerCount();
+	 iLayer++ )
+      {
+	OGRLayer        *poLayer1 = ipoDS1->GetLayer(iLayer);
+	
+	if( poLayer1 == NULL )
+	  {
+	    fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		     iLayer );
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+	  }
+
+	for( int iLayer1 = 0; iLayer1 < ipoDS2->GetLayerCount();
+	     iLayer1++ )
+	  {
+	    OGRLayer        *poLayer2 = ipoDS2->GetLayer(iLayer1);
+	    
+	    if( poLayer1 == NULL )
+	      {
+		fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+			 iLayer1 );
+		char tmp[1024];
+		sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer1);
+		setMapInMaps(conf,"lenv","message",tmp);
+		return SERVICE_FAILED;
+	      }
+	
+	    OGRFeature  *poFeature1,*poFeature2;
+
+	    /* -------------------------------------------------------------------- */
+	    /*      Try opening the output datasource as an existing, writable      */
+	    /* -------------------------------------------------------------------- */
+	    
+	    int                  iDriver;
+	    
+	    map* tmpMap=getMapFromMaps(outputs,"Result","mimeType");
+	    oDriver3="GeoJSON";
+	    sprintf(pszDestDataSource,"/vsimem/result_%d.json",getpid());
+	    if(tmpMap!=NULL){
+	      if(strcmp(tmpMap->value,"text/xml")==0){
+		sprintf(pszDestDataSource,"/vsimem/result_%d.xml",getpid());
+		oDriver3="GML";
+	      }
+	    }
+
+	    for( iDriver = 0;
+		 iDriver < poR->GetDriverCount() && poDriver == NULL;
+		 iDriver++ )
+	      {
+#if GDAL_VERSION_MAJOR >=2
+		if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),oDriver3) )
+#else
+		if( EQUAL(poR->GetDriver(iDriver)->GetName(),oDriver3) )
+#endif
+		  {
+		    poDriver = poR->GetDriver(iDriver);
+		  }
+	      }
+	    
+	    if( poDriver == NULL )
+	      {
+		char emessage[8192];
+		sprintf( emessage, "Unable to find driver `%s'.\n", oDriver1 );
+		sprintf( emessage,  "%sThe following drivers are available:\n",emessage );
+		
+		for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+		  {
+#if GDAL_VERSION_MAJOR >= 2
+		    sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetDescription() );
+#else
+		    sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+#endif
+		  }
+		
+		setMapInMaps(conf,"lenv","message",emessage);
+		return SERVICE_FAILED;
+		
+	      }
+	    
+#if GDAL_VERSION_MAJOR >= 2
+	    if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+	    if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+	      {
+		char emessage[1024];
+		sprintf( emessage,  "%s driver does not support data source creation.\n",
+			 "json" );
+		setMapInMaps(conf,"lenv","message",emessage);
+		return SERVICE_FAILED;
+	      }
+	    
+	    /* -------------------------------------------------------------------- */
+	    /*      Create the output data source.                                  */
+	    /* -------------------------------------------------------------------- */
+	    //map* tpath=getMapFromMaps(conf,"main","tmpPath");
+	    char **papszDSCO=NULL;
+#if GDAL_VERSION_MAJOR >= 2
+	    poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+	    poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+	    if( poODS == NULL ){
+	      char emessage[1024];      
+	      sprintf( emessage,  "%s driver failed to create %s\n", 
+		       "json", pszDestDataSource );
+	      setMapInMaps(conf,"lenv","message",emessage);
+	      return SERVICE_FAILED;
+	    }
+	    
+	    /* -------------------------------------------------------------------- */
+	    /*      Create the layer.                                               */
+	    /* -------------------------------------------------------------------- */
+	    if( !poODS->TestCapability( ODsCCreateLayer ) )
+	      {
+		char emessage[1024];
+		sprintf( emessage, 
+			 "Layer %s not found, and CreateLayer not supported by driver.", 
+			 "Result" );
+		setMapInMaps(conf,"lenv","message",emessage);
+		return SERVICE_FAILED;
+	      }
+	    
+	    //CPLErrorReset();
+	    
+	    poDstLayer = poODS->CreateLayer( "Result", NULL,wkbUnknown,NULL);
+	    if( poDstLayer == NULL ){
+	      setMapInMaps(conf,"lenv","message","Layer creation failed.\n");
+	      return SERVICE_FAILED;
+	    }
+	    
+	    OGRFeatureDefn *poFDefn = poLayer2->GetLayerDefn();
+	    int iField;
+	    int hasMmField=0;
+	    
+	    for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
+	      {
+		OGRFieldDefn *tmp=poFDefn->GetFieldDefn(iField);
+		if (iField >= 0)
+		  poDstLayer->CreateField( poFDefn->GetFieldDefn(iField) );
+		else
+		  {
+		    fprintf( stderr, "Field '%s' not found in source layer.\n", 
+			     iField );
+		    return SERVICE_FAILED;
+		  }
+	      }
+	    
+	    while(TRUE){
+	      OGRFeature      *poDstFeature = NULL;
+	      poFeature1 = poLayer1->GetNextFeature();
+	      if( poFeature1 == NULL )
+		break;
+	      while(TRUE){
+		poFeature2 = poLayer2->GetNextFeature();
+		if( poFeature2 == NULL )
+		  break;
+
+		if(poFeature1->GetGeometryRef() != NULL && poFeature2->GetGeometryRef() != NULL){
+		  poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+		  if( poDstFeature->SetFrom( poFeature2, TRUE ) != OGRERR_NONE )
+		    {
+		      char tmpMsg[1024];
+		      sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			       poFeature2->GetFID(), poFDefn->GetName() );
+		      
+		      OGRFeature::DestroyFeature( poFeature1 );
+		      OGRFeature::DestroyFeature( poFeature2 );
+		      OGRFeature::DestroyFeature( poDstFeature );
+		      return SERVICE_FAILED;
+		    }
+		  if(poDstFeature->SetGeometryDirectly((poFeature1->GetGeometryRef()->*myFunc)(poFeature2->GetGeometryRef())) != OGRERR_NONE )
+		    {
+		      char tmpMsg[1024];
+		      sprintf( tmpMsg,"Unable to translate feature %ld from layer %s.\n",
+			       poFeature2->GetFID(), poFDefn->GetName() );
+		      
+		      OGRFeature::DestroyFeature( poFeature1 );
+		      OGRFeature::DestroyFeature( poFeature2 );
+		      OGRFeature::DestroyFeature( poDstFeature );
+		      return SERVICE_FAILED;
+		    }
+		  OGRFeature::DestroyFeature( poFeature2 );
+		  if(!poDstFeature->GetGeometryRef()->IsEmpty())
+		    if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE )
+		      {		
+			OGRFeature::DestroyFeature( poDstFeature );
+			return SERVICE_FAILED;
+		      }
+		  OGRFeature::DestroyFeature( poDstFeature );
+		}
+	      }
+	    }
+	    OGRFeature::DestroyFeature( poFeature1 );
+	  }
+      }
+
+    delete poODS;
+    delete ipoDS1;
+    delete ipoDS2;
+    free(filename);
+    free(filename1);
+
+    char *res1=readVSIFile(conf,pszDestDataSource);
+    if(res1==NULL)
+      return SERVICE_FAILED;
+    setMapInMaps(outputs,"Result","value",res1);
+    free(res1);
+    OGRCleanupAll();
+    return SERVICE_SUCCEEDED;
+  }
+  
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Difference(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGRGeometry::Difference);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int SymDifference(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGRGeometry::SymDifference);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Intersection(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGRGeometry::Intersection);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Union(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGRGeometry::Union);
+  }
+
+  int applyTwoBool(maps*& conf,maps*& inputs,maps*& outputs,OGRBoolean (OGRGeometry::*myFunc)(const OGRGeometry*) const){
+    OGRRegisterAll();
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    OGRLayer *poDstLayer;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset *poODS;
+#else
+    OGRDataSource *poODS;
+#endif
+
+    char *filename=(char*)malloc(1024*sizeof(char));
+    const char *oDriver1;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset*
+#else
+    OGRDataSource*
+#endif
+      ipoDS1 = loadEntity(conf,inputs,&filename,&oDriver1,"InputEntity1",1);
+
+    char *filename1=(char*)malloc(1024*sizeof(char));
+    const char *oDriver2;
+#if GDAL_VERSION_MAJOR >= 2
+    GDALDataset*
+#else
+    OGRDataSource*
+#endif
+      ipoDS2 = loadEntity(conf,inputs,&filename1,&oDriver2,"InputEntity2",2);
+    const char *oDriver3;
+    char pszDestDataSource[100];
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+#else
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+
+    if( ipoDS1 == NULL || ipoDS2 == NULL )
+      {
+	fprintf( stderr, "FAILURE:\n"
+		 "Unable to open datasource `%s' with the following drivers.\n",
+		 filename );
+	
+	for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+	  {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+	  }
+	char tmp[1024];
+	if( ipoDS1 == NULL )
+	  sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename);
+	if( ipoDS2 == NULL )
+	  sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",filename1);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+      }
+    for( int iLayer = 0; iLayer < ipoDS1->GetLayerCount();
+	 iLayer++ )
+      {
+	OGRLayer        *poLayer1 = ipoDS1->GetLayer(iLayer);
+	
+	if( poLayer1 == NULL )
+	  {
+	    fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+		     iLayer );
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+	  }
+
+	for( int iLayer1 = 0; iLayer1 < ipoDS2->GetLayerCount();
+	     iLayer1++ )
+	  {
+	    OGRLayer        *poLayer2 = ipoDS2->GetLayer(iLayer1);
+	    
+	    if( poLayer1 == NULL )
+	      {
+		fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+			 iLayer1 );
+		char tmp[1024];
+		sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer1);
+		setMapInMaps(conf,"lenv","message",tmp);
+		return SERVICE_FAILED;
+	      }
+	
+	    OGRFeature  *poFeature1,*poFeature2;
+
+
+	    while(TRUE){
+	      OGRFeature      *poDstFeature = NULL;
+	      poFeature1 = poLayer1->GetNextFeature();
+	      if( poFeature1 == NULL )
+		break;
+	      while(TRUE){
+		poFeature2 = poLayer2->GetNextFeature();
+		if( poFeature2 == NULL )
+		  break;
+		if(poFeature1->GetGeometryRef() != NULL && poFeature2->GetGeometryRef() != NULL){
+		  if((poFeature1->GetGeometryRef()->*myFunc)(poFeature2->GetGeometryRef())==0){
+		    setMapInMaps(outputs,"Result","value","false");
+		    OGRFeature::DestroyFeature( poFeature1 );
+		    OGRFeature::DestroyFeature( poFeature2 );
+		    delete ipoDS1;
+		    delete ipoDS2;
+		    free(filename);
+		    free(filename1);
+		    return SERVICE_SUCCEEDED;
+		  }
+		}
+		OGRFeature::DestroyFeature( poFeature2 );
+	      }
+	      OGRFeature::DestroyFeature( poFeature1 );
+	    }
+	  }
+      }
+
+    delete ipoDS1;
+    delete ipoDS2;
+    free(filename);
+    free(filename1);
+
+    setMapInMaps(outputs,"Result","value","true");
+
+    OGRCleanupAll();
+    return SERVICE_SUCCEEDED;
+  }
+
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Equals(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,(OGRBoolean (OGRGeometry::*)(const OGRGeometry *) const)&OGRGeometry::Equals);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Disjoint(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,&OGRGeometry::Disjoint);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Touches(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,&OGRGeometry::Touches);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Crosses(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,&OGRGeometry::Crosses);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Within(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,&OGRGeometry::Within);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Contains(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,&OGRGeometry::Contains);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Overlaps(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,&OGRGeometry::Overlaps);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Intersects(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwoBool(conf,inputs,outputs,(OGRBoolean (OGRGeometry::*)(const OGRGeometry *) const)&OGRGeometry::Intersects);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Distance(maps*& conf,maps*& inputs,maps*& outputs){
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print1\n");
+#endif
+    fflush(stderr);
+    maps* cursor=inputs;
+    OGRGeometryH geometry1,geometry2;
+    double res;
+    {
+      map* tmp=getMapFromMaps(inputs,"InputEntity1","value");
+      map* tmp1=getMapFromMaps(inputs,"InputEntity1","mimeType");
+#ifdef DEBUG
+      fprintf(stderr,"MY MAP\n");
+      dumpMap(tmp1);
+      dumpMaps(inputs);
+      fprintf(stderr,"MY MAP\n");
+#endif
+      if(tmp1!=NULL){
+        if(strncmp(tmp1->value,"application/json",16)==0)
+      	  geometry1=OGR_G_CreateGeometryFromJson(tmp->value);
+	else
+	  geometry1=createGeometryFromGML(conf,tmp->value);
+      }
+      else
+      	geometry1=createGeometryFromGML(conf,tmp->value);
+    }
+    if(geometry1==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse input geometry for InputEntity1."));
+      fprintf(stderr,"SERVICE FAILED !\n");
+      return SERVICE_FAILED;
+    }
+    {
+      map* tmp=getMapFromMaps(inputs,"InputEntity2","value");
+      map* tmp1=getMapFromMaps(inputs,"InputEntity2","mimeType");
+#ifdef DEBUG
+      fprintf(stderr,"MY MAP\n");
+      dumpMap(tmp1);
+      dumpMaps(inputs);
+      fprintf(stderr,"MY MAP\n");
+#endif
+      if(tmp1!=NULL){
+        if(strncmp(tmp1->value,"application/json",16)==0)
+      	  geometry2=OGR_G_CreateGeometryFromJson(tmp->value);
+	else
+	  geometry2=createGeometryFromGML(conf,tmp->value);
+      }
+      else
+      	geometry2=createGeometryFromGML(conf,tmp->value);
+    }
+    if(geometry2==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse input geometry for InputEntity2."));
+      fprintf(stderr,"SERVICE FAILED !\n");
+      return SERVICE_FAILED;
+    }
+    res=OGR_G_Distance(geometry1,geometry2);    
+    char tmpres[100];
+    sprintf(tmpres,"%f",res);
+    setMapInMaps(outputs,"Distance","value",tmpres);
+    setMapInMaps(outputs,"Distance","dataType","float");
+#ifdef DEBUG
+    dumpMaps(outputs);
+    fprintf(stderr,"\nService internal print\n===\n");
+#endif
+    return SERVICE_SUCCEEDED;
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int GetArea(maps*& conf,maps*& inputs,maps*& outputs){
+    fprintf(stderr,"GETAREA \n");
+    double res;
+    /**
+     * Extract Geometry from the InputPolygon value
+     */
+    OGRGeometryH geometry;
+    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+    if(tmp==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    fprintf(stderr,"geometry creation %s \n",tmp->value);
+    geometry=createGeometryFromGML(conf,tmp->value);
+    if(geometry==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    fprintf(stderr,"geometry created %s \n",tmp->value);
+    res=OGR_G_Area(geometry);
+    fprintf(stderr,"area %d \n",res);
+    /**
+     * Filling the outputs
+     */
+    char tmp1[100];
+    sprintf(tmp1,"%f",res);
+    setMapInMaps(outputs,"Area","value",tmp1);
+    setMapInMaps(outputs,"Area","dataType","float");
+#ifdef DEBUG
+    dumpMaps(outputs);
+#endif
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/Makefile	(revision 942)
@@ -0,0 +1,14 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-DZOO_SERVICE -I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/ogr2ogr_service.zo: service.c $(DEP_LIBS)
+	g++ $(CFLAGS) $(CPPFLAGS) -shared -fpic $<  -o $@ ${GDAL_LIBS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}/ogr/ogr2ogr
+	install cgi-env/* ${CGI_DIR}/ogr/ogr2ogr
+
+clean:
+	rm -f cgi-env/*zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/cgi-env/Ogr2Ogr.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/cgi-env/Ogr2Ogr.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/cgi-env/Ogr2Ogr.zcfg	(revision 942)
@@ -0,0 +1,62 @@
+[Ogr2Ogr]
+ Title = Converts vector data from one format to another. 
+ Abstract = http://www.gdal.org/ogr2ogr.html
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = ogr2ogr_service.zo
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [F]
+   Title = Format of the output data
+   Abstract = Select the output format.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = ESRI ShapeFile
+    </Default>
+    <Supported>
+    </Supported>
+   </LiteralData>
+  [InputDSN]
+   Title = The input data source name
+   Abstract = The input data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+    <Supported>
+    </Supported>
+   </LiteralData>
+  [OutputDSN]
+   Title = The output data source name
+   Abstract = The output data name.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+    <Supported>
+    </Supported>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [OutputedDataSourceName]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+    <Supported>
+    </Supported>
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/makefile.vc	(revision 942)
@@ -0,0 +1,14 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib
+
+CFLAGS=-I$(GEODIR)/include -I$(TOOLS)/include -I../../../zoo-kernel/ -I./ -DGDAL_1_5_0 -DZOO_SERVICE -DLINUX_FREE_ISSUE -DDEBUG
+CPP=cl /TP 
+
+cgi-env/ogr2ogr_service.zo: service.c
+	$(CPP) $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/ogr2ogr_service.zo ./service.obj  $(FILES) $(LDFLAGS)
+
+clean:
+	rm -f cgi-env/ogr2ogr_service.zso
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/ogr2ogr/service.c	(revision 942)
@@ -0,0 +1,1406 @@
+/******************************************************************************
+ * $Id: ogr2ogr.cpp 15473 2008-10-07 20:59:24Z warmerdam $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  Simple client for translating between formats.
+ * Author:   Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, Frank Warmerdam
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "ogr_api.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include <gdal_priv.h>
+#endif
+#ifdef ZOO_SERVICE
+#include "service.h"
+#endif
+
+CPL_CVSID("$Id: ogr2ogr.cpp 15473 2008-10-07 20:59:24Z warmerdam $");
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp 
+#endif
+
+#ifdef ZOO_SERVICE
+extern "C" {
+#endif
+
+static void Usage();
+
+static int TranslateLayer(
+#if GDAL_VERSION_MAJOR >= 2
+			  GDALDataset
+#else 
+			  OGRDataSource 
+#endif
+			  *poSrcDS, 
+			  OGRLayer * poSrcLayer,
+#if GDAL_VERSION_MAJOR >= 2
+			  GDALDataset
+#else 
+			  OGRDataSource 
+#endif
+			  *poDstDS,
+			  char ** papszLSCO,
+			  const char *pszNewLayerName,
+			  int bTransform, 
+			  OGRSpatialReference *poOutputSRS,
+			  OGRSpatialReference *poSourceSRS,
+			  char **papszSelFields,
+			  int bAppend, int eGType,
+			  int bOverwrite,
+			  double dfMaxSegmentLength
+			   );
+  
+static int bSkipFailures = FALSE;
+static int nGroupTransactions = 200;
+static int bPreserveFID = TRUE;
+static int nFIDToFetch = OGRNullFID;
+
+/************************************************************************/
+/*                                main()                                */
+/************************************************************************/
+
+#ifdef ZOO_SERVICE
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int Ogr2Ogr(maps*& conf,maps*& inputs,maps*& outputs)
+#else
+int main( int nArgc, char ** papszArgv )
+#endif
+{
+    char  *pszDialect = NULL;
+    const char  *pszFormat = "ESRI Shapefile";
+    const char  *pszDataSource = NULL;
+    const char  *pszDestDataSource = NULL;
+    const char  *pszwebDestData = NULL;
+    char        **papszLayers = NULL;
+    char        **papszDSCO = NULL, **papszLCO = NULL;
+    int         bTransform = FALSE;
+    int         bAppend = FALSE, bUpdate = FALSE, bOverwrite = FALSE;
+    const char  *pszOutputSRSDef = NULL;
+    const char  *pszSourceSRSDef = NULL;
+    OGRSpatialReference *poOutputSRS = NULL;
+    OGRSpatialReference *poSourceSRS = NULL;
+    const char  *pszNewLayerName = NULL;
+    const char  *pszWHERE = NULL;
+    OGRGeometry *poSpatialFilter = NULL;
+    const char  *pszSelect;
+    char        **papszSelFields = NULL;
+    const char  *pszSQLStatement = NULL;
+    int         eGType = -2;
+    double      dfMaxSegmentLength = 0;
+
+#ifdef ZOO_SERVICE
+    dumpMaps(inputs);
+#endif
+    /* Check strict compilation and runtime library version as we use C++ API */
+    if (! GDAL_CHECK_VERSION("ogr2ogr"))
+#ifdef ZOO_SERVICE
+	{
+		fprintf(stderr,"Not correct version of the gdal library\n");
+		setMapInMaps(conf,"lenv","message","Unable to check gdal version for ogr2ogr_service.zo");
+		return SERVICE_FAILED;
+	}
+#else
+        exit(1);
+#endif
+/* -------------------------------------------------------------------- */
+/*      Register format(s).                                             */
+/* -------------------------------------------------------------------- */
+    OGRRegisterAll();
+
+#ifdef ZOO_SERVICE
+    map *tmpMap=NULL;
+    char dataPath[1024];
+    tmpMap=getMapFromMaps(conf,"main","dataPath");
+    if(tmpMap!=NULL)
+      sprintf(dataPath,"%s",tmpMap->value);
+    tmpMap=NULL;
+    char tempPath[1024];
+    tmpMap=getMapFromMaps(conf,"main","tmpPath");
+    if(tmpMap!=NULL){
+      sprintf(tempPath,"%s",tmpMap->value);
+    }
+    
+    tmpMap=NULL;
+    char serverAddress[1024];
+    tmpMap=getMapFromMaps(conf,"main","serverAddress");
+    if(tmpMap!=NULL){
+      sprintf(serverAddress,"%s",tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    char tmpurl[1024];
+    tmpMap=getMapFromMaps(conf,"main","tmpurl");
+    if(tmpMap!=NULL){
+      sprintf(tmpurl,"%s",tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"F","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      pszFormat=tmpMap->value;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"DSCO","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  papszDSCO = CSLAddString(papszDSCO, tmpMap->value );
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"LCO","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  papszLCO = CSLAddString(papszLCO, tmpMap->value );
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"preserve_fid","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  bPreserveFID = TRUE;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"skipfailure","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      bSkipFailures = TRUE;
+      nGroupTransactions = 1; /* #2409 */
+    }
+
+    /* if exist, overwrite the data with the same name */
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"overwrite","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      bOverwrite = TRUE;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"append","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0){
+      bAppend = TRUE;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"update","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"TRUE",4)==0){
+      bUpdate = TRUE;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"fid","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      nFIDToFetch = atoi(tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"sql","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      pszSQLStatement = tmpMap->value;
+    }
+
+    tmpMap=getMapFromMaps(inputs,"dialect","value");
+    if(tmpMap!=NULL){
+      pszDialect=strdup(tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"nln","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  pszNewLayerName = tmpMap->value;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"nlt","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  pszNewLayerName = tmpMap->value;
+	  if( EQUAL(tmpMap->value,"NONE") )
+		  eGType = wkbNone;
+	  else if( EQUAL(tmpMap->value,"GEOMETRY") )
+		  eGType = wkbUnknown;
+	  else if( EQUAL(tmpMap->value,"POINT") )
+		  eGType = wkbPoint;
+	  else if( EQUAL(tmpMap->value,"LINESTRING") )
+		  eGType = wkbLineString;
+	  else if( EQUAL(tmpMap->value,"POLYGON") )
+		  eGType = wkbPolygon;
+	  else if( EQUAL(tmpMap->value,"GEOMETRYCOLLECTION") )
+		  eGType = wkbGeometryCollection;
+	  else if( EQUAL(tmpMap->value,"MULTIPOINT") )
+		  eGType = wkbMultiPoint;
+	  else if( EQUAL(tmpMap->value,"MULTILINESTRING") )
+		  eGType = wkbMultiLineString;
+	  else if( EQUAL(tmpMap->value,"MULTIPOLYGON") )
+		  eGType = wkbMultiPolygon;
+	  else if( EQUAL(tmpMap->value,"GEOMETRY25D") )
+		  eGType = wkbUnknown | wkb25DBit;
+	  else if( EQUAL(tmpMap->value,"POINT25D") )
+		  eGType = wkbPoint25D;
+	  else if( EQUAL(tmpMap->value,"LINESTRING25D") )
+		  eGType = wkbLineString25D;
+	  else if( EQUAL(tmpMap->value,"POLYGON25D") )
+		  eGType = wkbPolygon25D;
+	  else if( EQUAL(tmpMap->value,"GEOMETRYCOLLECTION25D") )
+		  eGType = wkbGeometryCollection25D;
+	  else if( EQUAL(tmpMap->value,"MULTIPOINT25D") )
+		  eGType = wkbMultiPoint25D;
+	  else if( EQUAL(tmpMap->value,"MULTILINESTRING25D") )
+		  eGType = wkbMultiLineString25D;
+	  else if( EQUAL(tmpMap->value,"MULTIPOLYGON25D") )
+		  eGType = wkbMultiPolygon25D;
+	  else	  
+	  {
+		  fprintf( stderr, "-nlt %s: type not recognised.\n", 
+			  tmpMap->value );
+		  exit( 1 );
+	  }
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"tg","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  nGroupTransactions = atoi(tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"s_srs","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      pszSourceSRSDef = strdup(tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"a_srs","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      pszOutputSRSDef = strdup(tmpMap->value);
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"t_srs","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      pszOutputSRSDef = strdup(tmpMap->value);
+      bTransform = TRUE;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"SPAT","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      char *tmp=tmpMap->value;
+      char *t=strtok(tmp,",");
+      int cnt=0;
+      double dfULX, dfULY, dfLRX, dfLRY;
+      while(t!=NULL){
+        switch(cnt){
+        case 0:
+          dfULX = atof(t);
+          break;
+        case 1:
+          dfULY = atof(t);
+          break;
+        case 2:
+          dfLRX = atof(t);
+          break;
+        case 3:
+          dfLRY = atof(t);
+          break;
+        }
+        fprintf(stderr,"%s\n\n",t);
+        fprintf(stderr,"%f - %f - %f - %f\n\n",dfULX,dfULY,dfLRX,dfLRY);
+        t=strtok(NULL,",");
+        cnt++;
+      }
+
+      OGRLinearRing  oRing;
+      
+      oRing.addPoint( dfULX, dfULY );
+      oRing.addPoint( dfULX, dfLRY );
+      oRing.addPoint( dfLRX, dfLRY );
+      oRing.addPoint( dfLRX, dfULY );
+      oRing.addPoint( dfULX, dfULY );
+      poSpatialFilter = new OGRPolygon();
+      ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"where","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  pszWHERE = tmpMap->value;
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"select","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  pszSelect = tmpMap->value;
+	  papszSelFields = CSLTokenizeStringComplex(pszSelect, " ,", 
+		  FALSE, FALSE );
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"segmentize","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+	  dfMaxSegmentLength = atof(tmpMap->value);
+    }
+   
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"InputDSN","value");
+    if(tmpMap!=NULL && strncasecmp(tmpMap->value,"NULL",4)!=0){
+      if(strncasecmp(tmpMap->value,"PG",2)!=0 &&
+	 strncasecmp(tmpMap->value,"My",2)!=0 &&
+	 strncasecmp(tmpMap->value,"OCI",3)!=0 ){
+	if(strncasecmp(dataPath,tmpMap->value,strlen(dataPath))==0 ||
+	   strncasecmp(tempPath,tmpMap->value,strlen(tempPath))==0){
+	  pszDataSource=strdup(tmpMap->value);
+	}else{
+	  pszDataSource=(char*)malloc(sizeof(char)*(strlen(dataPath)+strlen(tmpMap->value)+2));
+	  sprintf((char*)pszDataSource,"%s/%s",dataPath,tmpMap->value);
+	}
+      }else{
+	pszDataSource=(char*)malloc(sizeof(char)*(strlen(tmpMap->value)+1));
+	sprintf((char*)pszDataSource,"%s",tmpMap->value);	
+      }
+    }
+
+    tmpMap=NULL;
+    tmpMap=getMapFromMaps(inputs,"OutputDSN","value");
+    if(tmpMap!=NULL){
+      if(strncasecmp(tmpMap->value,"PG",2)!=0 &&
+	 strncasecmp(tmpMap->value,"MY",2)!=0 &&
+	 strncasecmp(tmpMap->value,"OCI",3)!=0){
+	pszDestDataSource=(char*)malloc(sizeof(char)*(strlen(tempPath)+strlen(tmpMap->value)+4));
+	sprintf((char*)pszDestDataSource,"%s/%s",tempPath,tmpMap->value/*,ext*/);
+	pszwebDestData=(char*)malloc(sizeof(char)*(strlen(serverAddress)+strlen(tmpurl)+strlen(tmpMap->value)+4));
+	sprintf((char*)pszwebDestData,"%s%s/%s",serverAddress,tmpurl,tmpMap->value/*,ext*/);
+      }
+      else{
+	pszDestDataSource=(char*)malloc(sizeof(char)*(strlen(tmpMap->value)+1));
+	sprintf((char*)pszDestDataSource,"%s",tmpMap->value/*,ext*/);
+	pszwebDestData=(char*)malloc(sizeof(char)*(strlen(serverAddress)+strlen(tmpurl)+strlen(tmpMap->value)+4));
+	sprintf((char*)pszwebDestData,"%s%s/%s",serverAddress,tmpurl,tmpMap->value/*,ext*/);
+      }
+    }
+
+    fprintf(stderr,"Message %s\n",pszDestDataSource);
+#else
+/* -------------------------------------------------------------------- */
+/*      Processing command line arguments.                              */
+/* -------------------------------------------------------------------- */
+    nArgc = OGRGeneralCmdLineProcessor( nArgc, &papszArgv, 0 );
+    
+    if( nArgc < 1 )
+        exit( -nArgc );
+
+    for( int iArg = 1; iArg < nArgc; iArg++ )
+    {
+        if( EQUAL(papszArgv[iArg], "--utility_version") )
+        {
+				printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
+                   papszArgv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
+            return 0;
+        }
+        else if( EQUAL(papszArgv[iArg],"-f") && iArg < nArgc-1 )
+        {
+            pszFormat = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-dsco") && iArg < nArgc-1 )
+        {
+            papszDSCO = CSLAddString(papszDSCO, papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg],"-lco") && iArg < nArgc-1 )
+        {
+            papszLCO = CSLAddString(papszLCO, papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg],"-preserve_fid") )
+        {
+            bPreserveFID = TRUE;
+        }
+        else if( EQUALN(papszArgv[iArg],"-skip",5) )
+        {
+            bSkipFailures = TRUE;
+            nGroupTransactions = 1; /* #2409 */
+        }
+        else if( EQUAL(papszArgv[iArg],"-append") )
+        {
+            bAppend = TRUE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-overwrite") )
+        {
+            bOverwrite = TRUE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-update") )
+        {
+            bUpdate = TRUE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-fid") && papszArgv[iArg+1] != NULL )
+        {
+            nFIDToFetch = atoi(papszArgv[++iArg]);
+        }
+        else if( EQUAL(papszArgv[iArg],"-sql") && papszArgv[iArg+1] != NULL )
+        {
+            pszSQLStatement = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-nln") && iArg < nArgc-1 )
+        {
+            pszNewLayerName = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-nlt") && iArg < nArgc-1 )
+        {
+            if( EQUAL(papszArgv[iArg+1],"NONE") )
+                eGType = wkbNone;
+            else if( EQUAL(papszArgv[iArg+1],"GEOMETRY") )
+                eGType = wkbUnknown;
+            else if( EQUAL(papszArgv[iArg+1],"POINT") )
+                eGType = wkbPoint;
+            else if( EQUAL(papszArgv[iArg+1],"LINESTRING") )
+                eGType = wkbLineString;
+            else if( EQUAL(papszArgv[iArg+1],"POLYGON") )
+                eGType = wkbPolygon;
+            else if( EQUAL(papszArgv[iArg+1],"GEOMETRYCOLLECTION") )
+                eGType = wkbGeometryCollection;
+            else if( EQUAL(papszArgv[iArg+1],"MULTIPOINT") )
+                eGType = wkbMultiPoint;
+            else if( EQUAL(papszArgv[iArg+1],"MULTILINESTRING") )
+                eGType = wkbMultiLineString;
+            else if( EQUAL(papszArgv[iArg+1],"MULTIPOLYGON") )
+                eGType = wkbMultiPolygon;
+            else if( EQUAL(papszArgv[iArg+1],"GEOMETRY25D") )
+                eGType = wkbUnknown | wkb25DBit;
+            else if( EQUAL(papszArgv[iArg+1],"POINT25D") )
+                eGType = wkbPoint25D;
+            else if( EQUAL(papszArgv[iArg+1],"LINESTRING25D") )
+                eGType = wkbLineString25D;
+            else if( EQUAL(papszArgv[iArg+1],"POLYGON25D") )
+                eGType = wkbPolygon25D;
+            else if( EQUAL(papszArgv[iArg+1],"GEOMETRYCOLLECTION25D") )
+                eGType = wkbGeometryCollection25D;
+            else if( EQUAL(papszArgv[iArg+1],"MULTIPOINT25D") )
+                eGType = wkbMultiPoint25D;
+            else if( EQUAL(papszArgv[iArg+1],"MULTILINESTRING25D") )
+                eGType = wkbMultiLineString25D;
+            else if( EQUAL(papszArgv[iArg+1],"MULTIPOLYGON25D") )
+                eGType = wkbMultiPolygon25D;
+            else
+            {
+                fprintf( stderr, "-nlt %s: type not recognised.\n", 
+                         papszArgv[iArg+1] );
+                exit( 1 );
+            }
+            iArg++;
+        }
+        else if( (EQUAL(papszArgv[iArg],"-tg") ||
+                  EQUAL(papszArgv[iArg],"-gt")) && iArg < nArgc-1 )
+        {
+            nGroupTransactions = atoi(papszArgv[++iArg]);
+        }
+        else if( EQUAL(papszArgv[iArg],"-s_srs") && iArg < nArgc-1 )
+        {
+            pszSourceSRSDef = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-a_srs") && iArg < nArgc-1 )
+        {
+            pszOutputSRSDef = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-t_srs") && iArg < nArgc-1 )
+        {
+            pszOutputSRSDef = papszArgv[++iArg];
+            bTransform = TRUE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-spat") 
+                 && papszArgv[iArg+1] != NULL 
+                 && papszArgv[iArg+2] != NULL 
+                 && papszArgv[iArg+3] != NULL 
+                 && papszArgv[iArg+4] != NULL )
+        {
+            OGRLinearRing  oRing;
+
+            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
+            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+4]) );
+            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+4]) );
+            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+2]) );
+            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
+
+            poSpatialFilter = new OGRPolygon();
+            ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
+            iArg += 4;
+        }
+        else if( EQUAL(papszArgv[iArg],"-where") && papszArgv[iArg+1] != NULL )
+        {
+            pszWHERE = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-select") && papszArgv[iArg+1] != NULL)
+        {
+            pszSelect = papszArgv[++iArg];
+            papszSelFields = CSLTokenizeStringComplex(pszSelect, " ,", 
+                                                      FALSE, FALSE );
+        }
+        else if( EQUAL(papszArgv[iArg],"-segmentize") && iArg < nArgc-1 )
+        {
+            dfMaxSegmentLength = atof(papszArgv[++iArg]);
+        }
+        else if( papszArgv[iArg][0] == '-' )
+        {
+            Usage();
+        }
+        else if( pszDestDataSource == NULL )
+            pszDestDataSource = papszArgv[iArg];
+        else if( pszDataSource == NULL )
+            pszDataSource = papszArgv[iArg];
+        else
+            papszLayers = CSLAddString( papszLayers, papszArgv[iArg] );
+    }
+#endif
+
+    if( pszDataSource == NULL )
+#ifdef ZOO_SERVICE
+	{
+#else
+	  Usage();
+#endif
+#ifdef ZOO_SERVICE
+	  setMapInMaps(conf,"lenv","message","Wrong parameter");
+	  return SERVICE_FAILED;
+	}
+#endif
+
+/* -------------------------------------------------------------------- */
+/*      Open data source.                                               */
+/* -------------------------------------------------------------------- */
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDataset *poDS
+	= (GDALDataset*) GDALOpenEx( pszDataSource,
+				     GDAL_OF_READONLY | GDAL_OF_VECTOR,
+				     NULL, NULL, NULL );
+      GDALDataset *poODS;
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+#else
+      OGRDataSource* poDS
+	= OGRSFDriverRegistrar::Open( pszDataSource, FALSE );
+      OGRDataSource *poODS;
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+
+/* -------------------------------------------------------------------- */
+/*      Report failure                                                  */
+/* -------------------------------------------------------------------- */
+    if( poDS == NULL )
+    {
+        fprintf( stderr, "FAILURE:\n"
+                "Unable to open datasource `%s' with the following drivers.\n",
+                pszDataSource );
+
+        for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+        {
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+        }
+#ifdef ZOO_SERVICE
+	char tmp[1024];
+	sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",pszDataSource);
+	setMapInMaps(conf,"lenv","message",tmp);
+	return SERVICE_FAILED;
+#else
+        exit( 1 );
+#endif
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Try opening the output datasource as an existing, writable      */
+/* -------------------------------------------------------------------- */
+    if( bUpdate )
+    {
+        poODS = 
+#if GDAL_VERSION_MAJOR >= 2
+	  (GDALDataset*) GDALOpenEx( pszDestDataSource,
+				     GDAL_OF_UPDATE | GDAL_OF_VECTOR,
+				     NULL, NULL, NULL )
+#else
+	  OGRSFDriverRegistrar::Open( pszDestDataSource, TRUE )
+#endif
+	  ;
+        if( poODS == NULL )
+        {
+            fprintf( stderr, "FAILURE:\n"
+                    "Unable to open existing output datasource `%s'.\n",
+                    pszDestDataSource );
+#ifdef ZOO_SERVICE
+	    char tmp[1024];
+	    sprintf(tmp,"Unable to open existing output datasource `%s'.",pszDestDataSource);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+#else
+        exit( 1 );
+#endif
+        }
+
+        if( CSLCount(papszDSCO) > 0 )
+        {
+            fprintf( stderr, "WARNING: Datasource creation options ignored since an existing datasource\n"
+                    "         being updated.\n" );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the output driver.                                         */
+/* -------------------------------------------------------------------- */
+    else
+    {
+        int                  iDriver;
+
+        for( iDriver = 0;
+             iDriver < poR->GetDriverCount() && poDriver == NULL;
+             iDriver++ )
+        {
+#if GDAL_VERSION_MAJOR >=2
+	    if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),pszFormat) )
+#else
+	    if( EQUAL(poR->GetDriver(iDriver)->GetName(),pszFormat) )
+#endif
+            {
+                poDriver = poR->GetDriver(iDriver);
+            }
+        }
+
+        if( poDriver == NULL )
+        {
+            fprintf( stderr, "Unable to find driver `%s'.\n", pszFormat );
+            fprintf( stderr,  "The following drivers are available:\n" );
+        
+            for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+            {
+#if GDAL_VERSION_MAJOR >= 2
+	      fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
+#else
+	      fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+#endif
+            }
+#ifdef ZOO_SERVICE
+	    char tmp[1024];
+	    sprintf(tmp,"Unable to find driver `%s'.",pszFormat);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+
+#if GDAL_VERSION_MAJOR >=2
+	if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+	if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+        {
+            fprintf( stderr,  "%s driver does not support data source creation.\n",
+                    pszFormat );
+#ifdef ZOO_SERVICE
+	    char tmp[1024];
+	    sprintf(tmp,"%s driver does not support data source creation.",pszFormat);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Create the output data source.                                  */
+/* -------------------------------------------------------------------- */
+#if GDAL_VERSION_MAJOR >=2
+        poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
+#else
+	poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+#endif
+        if( poODS == NULL )
+        {
+	  poODS = 
+#if GDAL_VERSION_MAJOR >= 2
+	    (GDALDataset*) GDALOpenEx( pszDestDataSource,
+				       GDAL_OF_UPDATE | GDAL_OF_VECTOR,
+				       NULL, NULL, NULL )
+#else
+	    OGRSFDriverRegistrar::Open( pszDestDataSource, TRUE )
+#endif
+	    ;
+	  if( poODS == NULL )
+	    {
+	      fprintf( stderr, "FAILURE:\n"
+		       "Unable to open existing output datasource `%s'.\n",
+		       pszDestDataSource );
+#ifdef ZOO_SERVICE
+	      char tmp[1024];
+	      sprintf(tmp,"Unable to open existing output datasource `%s'.",pszDestDataSource);
+	      setMapInMaps(conf,"lenv","message",tmp);
+	      return SERVICE_FAILED;
+#else
+	      exit( 1 );
+#endif
+
+            fprintf( stderr,  "%s driver failed to create %s\n", 
+                    pszFormat, pszDestDataSource );
+	    }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Parse the output SRS definition if possible.                    */
+/* -------------------------------------------------------------------- */
+    if( pszOutputSRSDef != NULL )
+    {
+        poOutputSRS = new OGRSpatialReference();
+        if( poOutputSRS->SetFromUserInput( pszOutputSRSDef ) != OGRERR_NONE )
+        {
+            fprintf( stderr,  "Failed to process SRS definition: %s\n", 
+                    pszOutputSRSDef );
+#ifdef ZOO_SERVICE
+	    char tmp[1024];
+	    sprintf(tmp,"Failed to process SRS definition: %s",pszOutputSRSDef);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Parse the source SRS definition if possible.                    */
+/* -------------------------------------------------------------------- */
+    if( pszSourceSRSDef != NULL )
+    {
+        poSourceSRS = new OGRSpatialReference();
+        if( poSourceSRS->SetFromUserInput( pszSourceSRSDef ) != OGRERR_NONE )
+        {
+            fprintf( stderr,  "Failed to process SRS definition: %s\n", 
+                    pszSourceSRSDef );
+#ifdef ZOO_SERVICE
+	    char tmp[1024];
+	    sprintf(tmp,"Failed to process SRS definition: %s",pszOutputSRSDef);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Special case for -sql clause.  No source layers required.       */
+/* -------------------------------------------------------------------- */
+    if( pszSQLStatement != NULL )
+    {
+        OGRLayer *poResultSet;
+
+        if( pszWHERE != NULL )
+            fprintf( stderr,  "-where clause ignored in combination with -sql.\n" );
+        if( CSLCount(papszLayers) > 0 )
+	  fprintf( stderr,  "layer names ignored in combination with -sql. (%s)\n", pszSQLStatement);
+        
+        poResultSet = poDS->ExecuteSQL( pszSQLStatement, poSpatialFilter, 
+                                        pszDialect );
+
+        if( poResultSet != NULL )
+        {
+            if( !TranslateLayer( poDS, poResultSet, poODS, papszLCO, 
+                                 pszNewLayerName, bTransform, poOutputSRS,
+                                 poSourceSRS, papszSelFields, bAppend, eGType,
+                                 bOverwrite, dfMaxSegmentLength ))
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, 
+                          "Terminating translation prematurely after failed\n"
+                          "translation from sql statement." );
+
+                exit( 1 );
+            }
+            poDS->ReleaseResultSet( poResultSet );
+        }else{
+	  setMapInMaps(conf,"lenv","message","There was an error when running yoru SQL query.");
+	  if(pszDialect!=NULL)
+	    free(pszDialect);
+	  return SERVICE_FAILED;
+	}
+    }
+    if(pszDialect!=NULL)
+      free(pszDialect);
+
+/* -------------------------------------------------------------------- */
+/*      Process each data source layer.                                 */
+/* -------------------------------------------------------------------- */
+    for( int iLayer = 0; 
+         pszSQLStatement == NULL && iLayer < poDS->GetLayerCount(); 
+         iLayer++ )
+    {
+        OGRLayer        *poLayer = poDS->GetLayer(iLayer);
+
+        if( poLayer == NULL )
+        {
+            fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
+                    iLayer );
+#ifdef ZOO_SERVICE
+	    char tmp[1024];
+	    sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+#else
+	    exit( 1 );
+#endif
+        }
+
+        if( CSLCount(papszLayers) == 0
+            || CSLFindString( papszLayers,
+                              poLayer->GetLayerDefn()->GetName() ) != -1 )
+        {
+            if( pszWHERE != NULL )
+                poLayer->SetAttributeFilter( pszWHERE );
+            
+            if( poSpatialFilter != NULL )
+                poLayer->SetSpatialFilter( poSpatialFilter );
+            
+            if( !TranslateLayer( poDS, poLayer, poODS, papszLCO, 
+                                 pszNewLayerName, bTransform, poOutputSRS,
+                                 poSourceSRS, papszSelFields, bAppend, eGType,
+                                 bOverwrite, dfMaxSegmentLength ) 
+                && !bSkipFailures )
+            {
+#ifdef ZOO_SERVICE
+		char tmp[1024];
+		sprintf(tmp,"Terminating translation prematurely after failed of layer %s",poLayer->GetLayerDefn()->GetName() );
+		setMapInMaps(conf,"lenv","message",tmp);
+		return SERVICE_FAILED;
+#else
+                CPLError( CE_Failure, CPLE_AppDefined, 
+                          "Terminating translation prematurely after failed\n"
+                          "translation of layer %s (use -skipfailures to skip errors)\n", 
+                          poLayer->GetLayerDefn()->GetName() );
+
+                exit( 1 );
+#endif
+            }
+        }
+    }
+
+#ifdef ZOO_SERVICE
+    setMapInMaps(outputs,"OutputedDataSourceName","value",(char*)pszwebDestData);
+    //outputs->content=createMap("value",(char*)pszwebDestData);
+#endif
+
+/* -------------------------------------------------------------------- */
+/*      Close down.                                                     */
+/* -------------------------------------------------------------------- */
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+    delete poOutputSRS;
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+    delete poSourceSRS;
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+    delete poODS;
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+    delete poDS;
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+
+#ifndef ZOO_SERVICE
+    CSLDestroy(papszSelFields);
+    CSLDestroy( papszArgv );
+#endif
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+    CSLDestroy( papszLayers );
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+#ifndef ZOO_SERVICE
+    CSLDestroy( papszDSCO );
+    CSLDestroy( papszLCO );
+#endif
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+
+    //OGRCleanupAll();
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+
+#ifdef DBMALLOC
+    malloc_dump(1);
+#endif
+    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
+    
+#ifdef ZOO_SERVICE
+    //sleep(10);
+    return SERVICE_SUCCEEDED;
+#else
+    return 0;
+#endif
+}
+
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage()
+
+{
+#if GDAL_VERSION_MAJOR >= 2
+      GDALDataset *poDS;
+      GDALDataset *poODS;
+      GDALDriverManager* poR=GetGDALDriverManager();
+      GDALDriver          *poDriver = NULL;
+#else
+      OGRDataSource* poDS;
+      OGRDataSource *poODS;
+      OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+      OGRSFDriver          *poDriver = NULL;
+#endif
+
+#ifdef ZOO_SERVICE
+	fprintf(stderr,
+#else
+	printf(
+#endif
+		"Usage: ogr2ogr [--help-general] [-skipfailures] [-append] [-update] [-gt n]\n"
+		"               [-select field_list] [-where restricted_where] \n"
+		"               [-sql <sql statement>] \n" 
+		"               [-spat xmin ymin xmax ymax] [-preserve_fid] [-fid FID]\n"
+		"               [-a_srs srs_def] [-t_srs srs_def] [-s_srs srs_def]\n"
+		"               [-f format_name] [-overwrite] [[-dsco NAME=VALUE] ...]\n"
+		"               [-segmentize max_dist]\n"
+		"               dst_datasource_name src_datasource_name\n"
+		"               [-lco NAME=VALUE] [-nln name] [-nlt type] [layer [layer ...]]\n"
+		"\n"
+		" -f format_name: output file format name, possible values are:\n");
+    
+    for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+    {
+        poDriver = poR->GetDriver(iDriver);
+
+#if GDAL_VERSION_MAJOR >=2
+	if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+#else
+	if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+#endif
+#if GDAL_VERSION_MAJOR >= 2
+	    fprintf( stderr, "  -> %s\n", poDriver->GetDescription() );
+#else
+	    fprintf( stderr, "  -> %s\n", poDriver->GetName() );
+#endif
+    }
+
+#ifdef ZOO_SERVICE
+	fprintf(stderr,
+#else
+	printf(
+#endif
+		" -append: Append to existing layer instead of creating new if it exists\n"
+		" -overwrite: delete the output layer and recreate it empty\n"
+		" -update: Open existing output datasource in update mode\n"
+		" -select field_list: Comma-delimited list of fields from input layer to\n"
+		"                     copy to the new layer (defaults to all)\n" 
+		" -where restricted_where: Attribute query (like SQL WHERE)\n" 
+		" -sql statement: Execute given SQL statement and save result.\n"
+		" -skipfailures: skip features or layers that fail to convert\n"
+		" -gt n: group n features per transaction (default 200)\n"
+		" -spat xmin ymin xmax ymax: spatial query extents\n"
+		" -segmentize max_dist: maximum distance between 2 nodes.\n"
+		"                       Used to create intermediate points\n"
+		" -dsco NAME=VALUE: Dataset creation option (format specific)\n"
+		" -lco  NAME=VALUE: Layer creation option (format specific)\n"
+		" -nln name: Assign an alternate name to the new layer\n"
+		" -nlt type: Force a geometry type for new layer.  One of NONE, GEOMETRY,\n"
+		"      POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, MULTIPOINT,\n"
+		"      MULTIPOLYGON, or MULTILINESTRING.  Add \"25D\" for 3D layers.\n"
+		"      Default is type of source layer.\n" );
+
+#ifdef ZOO_SERVICE
+	fprintf(stderr,
+#else
+	printf(
+#endif
+		" -a_srs srs_def: Assign an output SRS\n"
+		" -t_srs srs_def: Reproject/transform to this SRS on output\n"
+		" -s_srs srs_def: Override source SRS\n"
+		"\n" 
+		" Srs_def can be a full WKT definition (hard to escape properly),\n"
+		" or a well known definition (ie. EPSG:4326) or a file with a WKT\n"
+		" definition.\n" );
+
+
+#ifndef ZOO_SERVICE
+	exit( 1 );
+#endif
+}
+
+/************************************************************************/
+/*                           TranslateLayer()                           */
+/************************************************************************/
+
+static int TranslateLayer(
+#if GDAL_VERSION_MAJOR >= 2
+			  GDALDataset
+#else 
+			  OGRDataSource 
+#endif
+			  *poSrcDS, 
+			  OGRLayer * poSrcLayer,
+#if GDAL_VERSION_MAJOR >= 2
+			  GDALDataset
+#else 
+			  OGRDataSource 
+#endif
+			  *poDstDS,
+			  char **papszLCO,
+			  const char *pszNewLayerName,
+			  int bTransform, 
+			  OGRSpatialReference *poOutputSRS,
+			  OGRSpatialReference *poSourceSRS,
+			  char **papszSelFields,
+			  int bAppend, int eGType, int bOverwrite,
+			  double dfMaxSegmentLength)
+		
+{
+    OGRLayer    *poDstLayer;
+    OGRFeatureDefn *poFDefn;
+    OGRErr      eErr;
+    int         bForceToPolygon = FALSE;
+    int         bForceToMultiPolygon = FALSE;
+
+    if( pszNewLayerName == NULL )
+        pszNewLayerName = poSrcLayer->GetLayerDefn()->GetName();
+
+    if( wkbFlatten(eGType) == wkbPolygon )
+        bForceToPolygon = TRUE;
+    else if( wkbFlatten(eGType) == wkbMultiPolygon )
+        bForceToMultiPolygon = TRUE;
+
+/* -------------------------------------------------------------------- */
+/*      Setup coordinate transformation if we need it.                  */
+/* -------------------------------------------------------------------- */
+    OGRCoordinateTransformation *poCT = NULL;
+
+    if( bTransform )
+    {
+        if( poSourceSRS == NULL )
+            poSourceSRS = poSrcLayer->GetSpatialRef();
+
+        if( poSourceSRS == NULL )
+        {
+            fprintf( stderr, "Can't transform coordinates, source layer has no\n"
+                    "coordinate system.  Use -s_srs to set one.\n" );
+#ifdef ZOO_SERVICE
+            return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+
+        CPLAssert( NULL != poSourceSRS );
+        CPLAssert( NULL != poOutputSRS );
+
+        poCT = OGRCreateCoordinateTransformation( poSourceSRS, poOutputSRS );
+        if( poCT == NULL )
+        {
+            char        *pszWKT = NULL;
+
+            fprintf( stderr, "Failed to create coordinate transformation between the\n"
+                   "following coordinate systems.  This may be because they\n"
+                   "are not transformable, or because projection services\n"
+                   "(PROJ.4 DLL/.so) could not be loaded.\n" );
+            
+            poSourceSRS->exportToPrettyWkt( &pszWKT, FALSE );
+            fprintf( stderr,  "Source:\n%s\n", pszWKT );
+            
+            poOutputSRS->exportToPrettyWkt( &pszWKT, FALSE );
+            fprintf( stderr,  "Target:\n%s\n", pszWKT );
+#ifdef ZOO_SERVICE
+            return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Get other info.                                                 */
+/* -------------------------------------------------------------------- */
+    poFDefn = poSrcLayer->GetLayerDefn();
+    
+    if( poOutputSRS == NULL )
+        poOutputSRS = poSrcLayer->GetSpatialRef();
+
+/* -------------------------------------------------------------------- */
+/*      Find the layer.                                                 */
+/* -------------------------------------------------------------------- */
+    int iLayer = -1;
+    poDstLayer = NULL;
+
+    for( iLayer = 0; iLayer < poDstDS->GetLayerCount(); iLayer++ )
+    {
+        OGRLayer        *poLayer = poDstDS->GetLayer(iLayer);
+
+        if( poLayer != NULL 
+            && EQUAL(poLayer->GetLayerDefn()->GetName(),pszNewLayerName) )
+        {
+            poDstLayer = poLayer;
+            break;
+        }
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      If the user requested overwrite, and we have the layer in       */
+/*      question we need to delete it now so it will get recreated      */
+/*      (overwritten).                                                  */
+/* -------------------------------------------------------------------- */
+    if( poDstLayer != NULL && bOverwrite )
+    {
+        if( poDstDS->DeleteLayer( iLayer ) != OGRERR_NONE )
+        {
+            fprintf( stderr, 
+                     "DeleteLayer() failed when overwrite requested.\n" );
+            return FALSE;
+        }
+        poDstLayer = NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If the layer does not exist, then create it.                    */
+/* -------------------------------------------------------------------- */
+    if( poDstLayer == NULL )
+    {
+        if( eGType == -2 )
+            eGType = poFDefn->GetGeomType();
+
+        if( !poDstDS->TestCapability( ODsCCreateLayer ) )
+        {
+            fprintf( stderr, 
+              "Layer %s not found, and CreateLayer not supported by driver.", 
+                     pszNewLayerName );
+            return FALSE;
+        }
+
+        CPLErrorReset();
+
+        poDstLayer = poDstDS->CreateLayer( pszNewLayerName, poOutputSRS,
+                                           (OGRwkbGeometryType) eGType, 
+                                           papszLCO );
+
+        if( poDstLayer == NULL )
+            return FALSE;
+
+        bAppend = FALSE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Otherwise we will append to it, if append was requested.        */
+/* -------------------------------------------------------------------- */
+    else if( !bAppend )
+    {
+        fprintf( stderr, "FAILED: Layer %s already exists, and -append not specified.\n"
+                "        Consider using -append, or -overwrite.\n",
+                pszNewLayerName );
+        return FALSE;
+    }
+    else
+    {
+        if( CSLCount(papszLCO) > 0 )
+        {
+            fprintf( stderr, "WARNING: Layer creation options ignored since an existing layer is\n"
+                    "         being appended to.\n" );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Add fields.  Default to copy all field.                         */
+/*      If only a subset of all fields requested, then output only      */
+/*      the selected fields, and in the order that they were            */
+/*      selected.                                                       */
+/* -------------------------------------------------------------------- */
+    int         iField;
+    int hasMmField=-1;
+
+    if (papszSelFields && !bAppend )
+    {
+        for( iField=0; papszSelFields[iField] != NULL; iField++)
+        {
+            int iSrcField = poFDefn->GetFieldIndex(papszSelFields[iField]);
+	    OGRFieldDefn *tmp=poFDefn->GetFieldDefn(iSrcField);
+	    fprintf(stderr,"NAME: %s\n",tmp->GetNameRef());
+	    fflush(stderr);
+	    if(tmp!=NULL && strncasecmp(tmp->GetNameRef(),"MMID",4)==0)
+	      hasMmField=1;
+            if (iSrcField >= 0)
+                poDstLayer->CreateField( poFDefn->GetFieldDefn(iSrcField) );
+            else
+            {
+                fprintf( stderr, "Field '%s' not found in source layer.\n", 
+                        papszSelFields[iField] );
+                if( !bSkipFailures )
+                    return FALSE;
+            }
+        }
+
+    }
+    else if( !bAppend )
+    {
+      for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ ){
+            poDstLayer->CreateField( poFDefn->GetFieldDefn(iField) );
+	    OGRFieldDefn *tmp=poFDefn->GetFieldDefn(iField);
+	    if(tmp!=NULL && strncasecmp(tmp->GetNameRef(),"MMID",4)==0)
+	      hasMmField=1;
+	    fprintf(stderr,"NAME: %s\n",tmp->GetNameRef());
+      }
+    }
+    /*if(hasMmField<0){
+      OGRFieldDefn oField( "MMID", OFTInteger );
+      poDstLayer->CreateField( &oField );
+      }*/
+
+/* -------------------------------------------------------------------- */
+/*      Transfer features.                                              */
+/* -------------------------------------------------------------------- */
+    OGRFeature  *poFeature;
+    int         nFeaturesInTransaction = 0;
+    int fCount=0;
+    poSrcLayer->ResetReading();
+
+    if( nGroupTransactions )
+        poDstLayer->StartTransaction();
+
+    while( TRUE )
+    {
+        OGRFeature      *poDstFeature = NULL;
+
+        if( nFIDToFetch != OGRNullFID )
+        {
+            // Only fetch feature on first pass.
+            if( nFeaturesInTransaction == 0 )
+                poFeature = poSrcLayer->GetFeature(nFIDToFetch);
+            else
+                poFeature = NULL;
+        }
+        else
+            poFeature = poSrcLayer->GetNextFeature();
+
+        if( poFeature == NULL )
+            break;
+
+	//poFeature->SetField((poFeature->GetFieldCount()-1),fCount);
+
+        if( ++nFeaturesInTransaction == nGroupTransactions )
+        {
+            poDstLayer->CommitTransaction();
+            poDstLayer->StartTransaction();
+            nFeaturesInTransaction = 0;
+        }
+
+        CPLErrorReset();
+        poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+
+        if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE )
+        {
+            if( nGroupTransactions )
+                poDstLayer->CommitTransaction();
+            
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Unable to translate feature %ld from layer %s.\n",
+                      poFeature->GetFID(), poFDefn->GetName() );
+            
+            OGRFeature::DestroyFeature( poFeature );
+            OGRFeature::DestroyFeature( poDstFeature );
+            return FALSE;
+        }
+
+        if( bPreserveFID )
+            poDstFeature->SetFID( poFeature->GetFID() );
+
+	/*if(hasMmField<0){
+	  poDstFeature->SetField((poDstFeature->GetFieldCount()-1),fCount);
+	  fCount++;
+	}*/
+
+#ifndef GDAL_1_5_0
+        if (poDstFeature->GetGeometryRef() != NULL && dfMaxSegmentLength > 0)
+            poDstFeature->GetGeometryRef()->segmentize(dfMaxSegmentLength);
+#endif
+
+        if( poCT && poDstFeature->GetGeometryRef() != NULL )
+        {
+            eErr = poDstFeature->GetGeometryRef()->transform( poCT );
+            if( eErr != OGRERR_NONE )
+            {
+                if( nGroupTransactions )
+                    poDstLayer->CommitTransaction();
+
+                fprintf( stderr, "Failed to reproject feature %d (geometry probably out of source or destination SRS).\n", 
+                        (int) poFeature->GetFID() );
+                if( !bSkipFailures )
+                {
+                    OGRFeature::DestroyFeature( poFeature );
+                    OGRFeature::DestroyFeature( poDstFeature );
+                    return FALSE;
+                }
+            }
+        }
+
+        if( poDstFeature->GetGeometryRef() != NULL && bForceToPolygon )
+        {
+            poDstFeature->SetGeometryDirectly( 
+                OGRGeometryFactory::forceToPolygon(
+                    poDstFeature->StealGeometry() ) );
+        }
+                    
+        if( poDstFeature->GetGeometryRef() != NULL && bForceToMultiPolygon )
+        {
+            poDstFeature->SetGeometryDirectly( 
+                OGRGeometryFactory::forceToMultiPolygon(
+                    poDstFeature->StealGeometry() ) );
+        }
+                    
+        OGRFeature::DestroyFeature( poFeature );
+
+        CPLErrorReset();
+        if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE 
+            && !bSkipFailures )
+        {
+            if( nGroupTransactions )
+                poDstLayer->RollbackTransaction();
+
+            OGRFeature::DestroyFeature( poDstFeature );
+            return FALSE;
+        }
+
+        OGRFeature::DestroyFeature( poDstFeature );
+    }
+
+    if( nGroupTransactions )
+        poDstLayer->CommitTransaction();
+
+/* -------------------------------------------------------------------- */
+/*      Cleaning                                                        */
+/* -------------------------------------------------------------------- */
+    delete poCT;
+
+    return TRUE;
+}
+
+#ifdef ZOO_SERVICE
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/Makefile	(revision 942)
@@ -0,0 +1,14 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-DZOO_SERVICE ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/ogrtindex_service.zo: service.c $(DEP_LIBS)
+	g++ $(CFLAGS) $(CPPFLAGS) -shared -fpic $<  -o $@ ${GDAL_LIBS} -L${ZRPATH}/zoo-kernel/ -lzoo_service -lfcgi -L/usr/local/Cellar/gettext/0.19.8.1/lib/ -lintl
+
+install:
+	install -d ${CGI_DIR}/ogr/
+	install cgi-env/* ${CGI_DIR}/ogr/
+
+clean:
+	rm -f cgi-env/*zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/cgi-env/Ogrtindex.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/cgi-env/Ogrtindex.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/cgi-env/Ogrtindex.zcfg	(revision 942)
@@ -0,0 +1,67 @@
+[Ogrtindex]
+ Title = Create a tileindex. 
+ Abstract = http://www.gdal.org/ogrtindex.html
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = ogrtindex_service.zo
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [f]
+   Title = Format of the output data
+   Abstract = Select the output format.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = ESRI ShapeFile
+     AllowedValues = KML,geojson,ESRI Shapefile,csv
+    </Default>
+   </LiteralData>
+  [of]
+   Title = Format of the output data
+   Abstract = Select the output format.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+     value = ESRI ShapeFile     
+     AllowedValues = KML,geojson,ESRI Shapefile,csv
+    </Default>
+    <Supported>
+     value = KML
+    </Supported>
+   </LiteralData>
+  [files]
+   Title = The input data source name
+   Abstract = The input data source name to use as source for convertion.
+   minOccurs = 1
+   maxOccurs = 1024
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+  [OutputName]
+   Title = The output data source name
+   Abstract = The output data name.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default />
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/ogr/tindex/service.c	(revision 942)
@@ -0,0 +1,1102 @@
+/******************************************************************************
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  Program to generate a UMN MapServer compatible tile index for a
+ *           set of OGR data sources.
+ * Author:   Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2002, Frank Warmerdam
+ * Copyright (c) 2007-2010, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "cpl_port.h"
+
+#include <cassert>
+#include <vector>
+
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "ogr_api.h"
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+#include "gdal_version.h"
+//#include "commonutils.h"
+#if GDAL_VERSION_MAJOR >= 2
+#include "gdal.h"
+#include "gdal_priv.h"
+#endif
+#ifdef ZOO_SERVICE
+#include "service.h"
+#include "service_internal.h"
+#endif
+
+CPL_CVSID("$Id$")
+
+#ifdef ZOO_SERVICE
+extern "C" {
+#endif
+
+typedef enum
+{
+    FORMAT_AUTO,
+    FORMAT_WKT,
+    FORMAT_EPSG,
+    FORMAT_PROJ
+} SrcSRSFormat;
+
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage()
+
+{
+    printf("Usage: ogrtindex [-lnum n]... [-lname name]... [-f output_format]\n"
+           "                 [-write_absolute_path] [-skip_different_projection]\n"
+           "                 [-t_srs target_srs]\n"
+           "                 [-src_srs_name field_name] [-src_srs_format [AUTO|WKT|EPSG|PROJ]\n"
+           "                 [-accept_different_schemas]\n"
+           "                 output_dataset src_dataset...\n");
+    printf("\n");
+    printf("  -lnum n: Add layer number 'n' from each source file\n"
+           "           in the tile index.\n");
+    printf("  -lname name: Add the layer named 'name' from each source file\n"
+           "               in the tile index.\n");
+    printf("  -f output_format: Select an output format name.\n");
+    printf("  -tileindex field_name: The name to use for the dataset name.\n"
+           "                         Defaults to LOCATION.\n");
+    printf("  -write_absolute_path: Filenames are written with absolute paths.\n");
+    printf("  -skip_different_projection: Only layers with same projection ref \n"
+           "        as layers already inserted in the tileindex will be inserted.\n");
+    printf("  -accept_different_schemas: by default ogrtindex checks that all layers inserted\n"
+           "                             into the index have the same attribute schemas. If you\n"
+           "                             specify this option, this test will be disabled. Be aware that\n"
+           "                             resulting index may be incompatible with MapServer!\n");
+    printf(
+           "  - If -t_srs is specified, geometries of input files will be transformed to the desired\n"
+           "    target coordinate reference system.\n"
+           "    Note that using this option generates files that are NOT compatible with MapServer < 7.2.\n"
+           "  - Simple rectangular polygons are generated in the same coordinate reference system\n"
+           "    as the vectors, or in target reference system if the -t_srs option is used.\n");
+    printf("\n");
+    printf("If no -lnum or -lname arguments are given it is assumed that\n"
+           "all layers in source datasets should be added to the tile index\n"
+           "as independent records.\n");
+    exit(1);
+}
+
+/************************************************************************/
+/*                                main()                                */
+/************************************************************************/
+
+#ifdef ZOO_SERVICE
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Ogrtindex(maps*& conf,maps*& inputs,maps*& outputs)
+#else
+  MAIN_START(nArgc, papszArgv)
+#endif
+{
+  FILE* log=fopen("/tmp/error.log","w+");
+  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+  fflush(log);
+  //return SERVICE_FAILED;
+    // Check strict compilation and runtime library version as we use C++ API.
+#ifdef ZOO_SERVICE
+  if( !GDAL_CHECK_VERSION("ogrtindex") )
+      {
+	setMapInMaps(conf,"lenv","message",_("Compilation and runtime library versions differ"));
+	return SERVICE_FAILED;
+      }
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+#else
+    if( !GDAL_CHECK_VERSION(papszArgv[0]) )
+      exit(1);
+#endif
+/* -------------------------------------------------------------------- */
+/*      Register format(s).                                             */
+/* -------------------------------------------------------------------- */
+    OGRRegisterAll();
+
+/* -------------------------------------------------------------------- */
+/*      Processing command line arguments.                              */
+/* -------------------------------------------------------------------- */
+    int nFirstSourceDataset = -1;
+    bool bLayersWildcarded = true;
+    const char *pszFormat = nullptr;
+    const char *pszTileIndexField = "LOCATION";
+    const char *pszOutputName = nullptr;
+    bool write_absolute_path = false;
+    bool skip_different_projection = false;
+    char* current_path = nullptr;
+    bool accept_different_schemas = false;
+    bool bFirstWarningForNonMatchingAttributes = true;
+    const char *pszTargetSRS = "";
+    bool bSetTargetSRS = false;
+    const char* pszSrcSRSName = nullptr;
+    int i_SrcSRSName = -1;
+    bool bSrcSRSFormatSpecified = false;
+    SrcSRSFormat eSrcSRSFormat = FORMAT_AUTO;
+    size_t nMaxFieldSize = 254;
+
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+#ifdef ZOO_SERVICE
+      // f / of
+      map* tmpMap=getMapFromMaps(inputs,"f","value");
+      if(tmpMap==NULL)
+	tmpMap=getMapFromMaps(inputs,"of","value");
+      if(tmpMap!=NULL)
+	pszFormat = zStrdup(tmpMap->value);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+
+      // write_absolute_path
+      tmpMap=getMapFromMaps(inputs,"write_absolute_path","value");
+      if(tmpMap!=NULL && strncasecmp(tmpMap->value,"true",4)==0)
+	write_absolute_path = true;
+      // skip_different_projection
+      tmpMap=getMapFromMaps(inputs,"skip_different_projection","value");
+      if(tmpMap!=NULL && strncasecmp(tmpMap->value,"true",4)==0)
+	skip_different_projection = true;
+      // accept_different_schemas
+      tmpMap=getMapFromMaps(inputs,"accept_different_schemas","value");
+      if(tmpMap!=NULL && strncasecmp(tmpMap->value,"true",4)==0)
+	accept_different_schemas = true;
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // tileindex
+      tmpMap=getMapFromMaps(inputs,"tileindex","value");
+      if(tmpMap!=NULL)
+	pszTileIndexField = zStrdup(tmpMap->value);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // lname / lnum
+      tmpMap=getMapFromMaps(inputs,"lname","value");
+      if(tmpMap==NULL)
+	tmpMap=getMapFromMaps(inputs,"lnum","value");
+      if(tmpMap!=NULL)
+	bLayersWildcarded = false;
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      //dumpMaps(inputs);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // t_srs
+      tmpMap=getMapFromMaps(inputs,"t_srs","value");
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      if(tmpMap!=NULL){
+	pszTargetSRS = zStrdup(tmpMap->value);
+	bSetTargetSRS = true;
+      }
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // src_srs_name
+      //dumpMaps(inputs);
+      tmpMap=getMapFromMaps(inputs,"src_srs_name","value");
+      if(tmpMap!=NULL){
+	pszSrcSRSName = zStrdup(tmpMap->value);
+      }
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // src_srs_format
+      tmpMap=getMapFromMaps(inputs,"src_srs_format","value");
+      if(tmpMap!=NULL){
+	bSrcSRSFormatSpecified = true;
+	const char* pszSRSFormat = zStrdup(tmpMap->value);
+	if( EQUAL(pszSRSFormat, "AUTO") )
+	  eSrcSRSFormat = FORMAT_AUTO;
+	else if( EQUAL(pszSRSFormat, "WKT") )
+	  eSrcSRSFormat = FORMAT_WKT;
+	else if( EQUAL(pszSRSFormat, "EPSG") )
+	  eSrcSRSFormat = FORMAT_EPSG;
+	else if( EQUAL(pszSRSFormat, "PROJ") )
+	  eSrcSRSFormat = FORMAT_PROJ;	
+      }
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      // OutputName
+      tmpMap=getMapFromMaps(inputs,"OutputName","value");
+      if(tmpMap!=NULL){
+	pszOutputName = zStrdup(tmpMap->value);
+      }
+      nFirstSourceDataset = 0;
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+#else      
+    for( int iArg = 1; iArg < nArgc; iArg++ )
+    {
+        if( EQUAL(papszArgv[iArg], "--utility_version") )
+        {
+            printf("%s was compiled against GDAL %s and "
+                   "is running against GDAL %s\n",
+                   papszArgv[0], GDAL_RELEASE_NAME,
+                   GDALVersionInfo("RELEASE_NAME"));
+            return 0;
+        }
+        else if( iArg < nArgc-1 &&
+                 (EQUAL(papszArgv[iArg],"-f") || EQUAL(papszArgv[iArg],"-of")) )
+        {
+            pszFormat = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-write_absolute_path"))
+        {
+            write_absolute_path = true;
+        }
+        else if( EQUAL(papszArgv[iArg],"-skip_different_projection"))
+        {
+            skip_different_projection = true;
+        }
+        else if( EQUAL(papszArgv[iArg],"-accept_different_schemas"))
+        {
+            accept_different_schemas = true;
+        }
+        else if( iArg < nArgc-1 && EQUAL(papszArgv[iArg],"-tileindex") )
+        {
+            pszTileIndexField = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-lnum")
+                 || EQUAL(papszArgv[iArg],"-lname") )
+        {
+            iArg++;
+            bLayersWildcarded = false;
+        }
+        else if( iArg < nArgc-1 && strcmp(papszArgv[iArg],"-t_srs") == 0 )
+        {
+            pszTargetSRS = papszArgv[++iArg];
+            bSetTargetSRS = true;
+        }
+        else if( iArg < nArgc-1 &&
+                 strcmp(papszArgv[iArg], "-src_srs_name") == 0 )
+        {
+            pszSrcSRSName = papszArgv[++iArg];
+        }
+        else if( iArg < nArgc-1 &&
+                 strcmp(papszArgv[iArg], "-src_srs_format") == 0 )
+        {
+            bSrcSRSFormatSpecified = true;
+            const char* pszSRSFormat = papszArgv[++iArg];
+            if( EQUAL(pszSRSFormat, "AUTO") )
+                eSrcSRSFormat = FORMAT_AUTO;
+            else if( EQUAL(pszSRSFormat, "WKT") )
+                eSrcSRSFormat = FORMAT_WKT;
+            else if( EQUAL(pszSRSFormat, "EPSG") )
+                eSrcSRSFormat = FORMAT_EPSG;
+            else if( EQUAL(pszSRSFormat, "PROJ") )
+                eSrcSRSFormat = FORMAT_PROJ;
+        }
+        else if( papszArgv[iArg][0] == '-' )
+        {
+            Usage();
+        }
+        else if( pszOutputName == nullptr )
+        {
+            pszOutputName = papszArgv[iArg];
+        }
+        else if( nFirstSourceDataset == -1 )
+        {
+            nFirstSourceDataset = iArg;
+        }
+    }
+#endif
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+    if( pszOutputName == nullptr || nFirstSourceDataset == -1 )
+        Usage();
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+    if( bSrcSRSFormatSpecified && pszSrcSRSName == nullptr )
+    {
+        fprintf(log,
+                "-src_srs_name must be specified when -src_srs_format is "
+                "specified.\n");
+        Usage();
+    }
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      Create and validate target SRS if given.                        */
+/* -------------------------------------------------------------------- */
+    OGRSpatialReference* poTargetSRS = nullptr;
+    if( bSetTargetSRS )
+    {
+        if( skip_different_projection )
+        {
+            fprintf(log,
+                    "Warning : -skip_different_projection does not apply "
+                    "when -t_srs is requested.\n");
+        }
+        poTargetSRS = new OGRSpatialReference();
+        // coverity[tainted_data]
+        if( poTargetSRS->SetFromUserInput( pszTargetSRS ) != CE_None )
+        {
+            delete poTargetSRS;
+            fprintf(log, "Invalid target SRS `%s'.\n",
+                    pszTargetSRS);
+            exit(1);
+        }
+    }
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      Try to open as an existing dataset for update access.           */
+/* -------------------------------------------------------------------- */
+    GDALDataset *poDstDS = reinterpret_cast<GDALDataset*>(
+        OGROpen(pszOutputName, TRUE, nullptr));
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      If that failed, find the driver so we can create the tile index.*/
+/* -------------------------------------------------------------------- */
+    OGRLayer *poDstLayer = nullptr;
+    int                      nArgc;
+
+    fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+    fflush(log);
+    if( poDstDS == nullptr )
+    {
+        CPLString osFormat;
+	
+	OGRSFDriverRegistrar     *poR = OGRSFDriverRegistrar::GetRegistrar();
+        GDALDriver              *poDriver = NULL;
+        int                      iDriver;
+	
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+        for( iDriver = 0;
+             iDriver < poR->GetDriverCount() && poDriver == NULL;
+             iDriver++ )
+        {
+            if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),pszFormat) )
+            {
+	      osFormat=pszFormat;
+                poDriver = poR->GetDriver(iDriver);
+            }
+        }
+
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+        if( poDriver == NULL )
+        {
+            fprintf( log, "Unable to find driver `%s'.\n", pszFormat );
+            fprintf( log, "The following drivers are available:\n" );
+
+            for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+            {
+                fprintf( log, "  -> `%s'\n", poR->GetDriver(iDriver)->GetDescription() );
+            }
+#ifdef ZOO_SERVICE
+	    setMapInMaps(conf,"lenv","message",_("Unable to find driver!"));	    
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+	/*        if( !CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+        {
+            fprintf( log, "%s driver does not support data source creation.\n",
+                    pszFormat );
+#ifdef ZOO_SERVICE
+	    setMapInMaps(conf,"lenv","message",_("This driver does not support data source creation!"));	    
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+}*/
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+/* -------------------------------------------------------------------- */
+/*      Now create it.                                                  */
+/* -------------------------------------------------------------------- */
+
+        poDstDS = reinterpret_cast<GDALDataset*>(
+            GDALCreate(poDriver, pszOutputName, 0, 0, 0, GDT_Unknown, nullptr));
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+        if( poDstDS == nullptr )
+        {
+            fprintf(log, "%s driver failed to create %s\n",
+                    osFormat.c_str(), pszOutputName);
+#ifdef ZOO_SERVICE
+	    setMapInMaps(conf,"lenv","message",_("This driver failed to create!"));
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+        if( poDstDS->GetLayerCount() == 0 )
+        {
+#ifndef ZOO_SERVICE
+	  if( nFirstSourceDataset < nArgc &&
+	      papszArgv[nFirstSourceDataset][0] == '-' )
+            {
+	      nFirstSourceDataset++;
+	    }
+#else
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+	  map* lengthMap=getMapFromMaps(inputs,"files","length");
+	  maps* tmpMaps=getMaps(inputs,"files");
+	  if(lengthMap!=NULL)
+	    nArgc=atoi(lengthMap->value);
+	  else
+	    nArgc=1;
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+#endif	  
+            OGRSpatialReference* poSrcSpatialRef = nullptr;
+            if( bSetTargetSRS )
+            {
+                // Fetches the SRS from target SRS (if set), or from the SRS of
+                // the first layer and use it when creating the
+                // tileindex layer.
+                poSrcSpatialRef = poTargetSRS->Clone();
+            }
+            else if( nFirstSourceDataset < nArgc )
+            {
+#ifdef ZOO_SERVICE
+	  fprintf(log,"**** %s %d %s \n",__FILE__,__LINE__,nFirstSourceDataset);
+	  fflush(log);
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+	  tmpMap=getMapArray(tmpMaps->content,"value",0);
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+	  //dumpMap(tmpMap);
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+#endif
+	  GDALDataset* poDS =
+	    reinterpret_cast<GDALDataset*>(
+#ifndef ZOO_SERVICE
+                    OGROpen(papszArgv[nFirstSourceDataset], FALSE, nullptr)
+#else
+                    OGROpen(tmpMap->value, FALSE, nullptr)
+#endif
+	    );
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+                if( poDS != nullptr )
+                {
+                    for( int iLayer = 0;
+                         iLayer < poDS->GetLayerCount();
+                         iLayer++ )
+                    {
+                        bool bRequested = bLayersWildcarded;
+                        OGRLayer *poLayer = poDS->GetLayer(iLayer);
+
+                        if( !bRequested )
+                            continue;
+
+                        if( poLayer->GetSpatialRef() )
+                            poSrcSpatialRef = poLayer->GetSpatialRef()->Clone();
+                        break;
+                    }
+                }
+
+                GDALClose(poDS);
+            }
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+
+            poDstLayer = poDstDS->CreateLayer("tileindex", poSrcSpatialRef);
+
+            OGRFieldDefn oLocation(pszTileIndexField, OFTString);
+            oLocation.SetWidth(200);
+            poDstLayer->CreateField(&oLocation);
+
+            if( pszSrcSRSName != nullptr )
+            {
+                OGRFieldDefn oSrcSRSNameField(pszSrcSRSName, OFTString);
+                poDstLayer->CreateField(&oSrcSRSNameField);
+            }
+
+            if( poSrcSpatialRef )
+                poSrcSpatialRef->Release();
+	  fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	  fflush(log);
+        }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Identify target layer and field.                                */
+/* -------------------------------------------------------------------- */
+
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+    poDstLayer = poDstDS->GetLayer(0);
+    if( poDstLayer == nullptr )
+    {
+        fprintf(log, "Can't find any layer in output tileindex!\n");
+        exit(1);
+    }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+    const int iTileIndexField =
+        poDstLayer->GetLayerDefn()->GetFieldIndex(pszTileIndexField);
+    if( iTileIndexField == -1 )
+    {
+        fprintf(log, "Can't find %s field in tile index dataset.\n",
+                pszTileIndexField);
+        exit(1);
+    }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+
+    if( pszSrcSRSName != nullptr )
+        i_SrcSRSName = poDstLayer->GetLayerDefn()->GetFieldIndex(pszSrcSRSName);
+
+    OGRFeatureDefn* poFeatureDefn = nullptr;
+
+    // Load in memory existing file names in SHP.
+    char **existingLayersTab = nullptr;
+    OGRSpatialReference* alreadyExistingSpatialRef = nullptr;
+    bool alreadyExistingSpatialRefValid = false;
+    const int nExistingLayers = static_cast<int>(poDstLayer->GetFeatureCount());
+    if( nExistingLayers )
+    {
+        existingLayersTab = static_cast<char **>(
+            CPLMalloc(nExistingLayers * sizeof(char*)));
+        for( int i = 0; i < nExistingLayers; i++ )
+        {
+            OGRFeature* feature = poDstLayer->GetNextFeature();
+            existingLayersTab[i] =
+                CPLStrdup(feature->GetFieldAsString( iTileIndexField));
+            if( i == 0 )
+            {
+                char* filename = CPLStrdup(existingLayersTab[i]);
+                // j used after for.
+                int j = static_cast<int>(strlen(filename)) - 1;
+                for( ; j >= 0; j-- )
+                {
+                    if( filename[j] == ',' )
+                        break;
+                }
+                GDALDataset *poDS = nullptr;
+                if( j >= 0 )
+                {
+                    const int iLayer = atoi(filename + j + 1);
+                    filename[j] = 0;
+                    poDS = reinterpret_cast<GDALDataset *>(
+                        OGROpen(filename, FALSE, nullptr));
+                    if( poDS != nullptr )
+                    {
+                        OGRLayer *poLayer = poDS->GetLayer(iLayer);
+                        if( poLayer )
+                        {
+                            alreadyExistingSpatialRefValid = true;
+                            alreadyExistingSpatialRef =
+                                poLayer->GetSpatialRef() ?
+                                poLayer->GetSpatialRef()->Clone() : nullptr;
+
+                            if( poFeatureDefn == nullptr )
+                                poFeatureDefn =
+                                    poLayer->GetLayerDefn()->Clone();
+                        }
+                        GDALClose(poDS);
+                    }
+                }
+            }
+        }
+    }
+
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+    if( write_absolute_path )
+    {
+        current_path = CPLGetCurrentDir();
+        if( current_path == nullptr )
+        {
+            fprintf(log,
+                    "This system does not support the CPLGetCurrentDir call. "
+                    "The option -write_absolute_path will have no effect\n");
+            write_absolute_path = false;
+        }
+    }
+	fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+	fflush(log);
+/* ==================================================================== */
+/*      Process each input datasource in turn.                          */
+/* ==================================================================== */
+#ifdef ZOO_SERVICE
+    maps* tmpMaps=getMaps(inputs,"files");
+    nFirstSourceDataset=0;
+#endif
+    for( ; nFirstSourceDataset < nArgc; nFirstSourceDataset++ )
+    {
+#ifndef ZOO_SERVICE
+      if( papszArgv[nFirstSourceDataset][0] == '-' )
+        {
+            nFirstSourceDataset++;
+            continue;
+        }
+#else
+      tmpMap=getMapArray(tmpMaps->content,"value",nFirstSourceDataset);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+      //dumpMap(tmpMap);
+      fprintf(log,"**** %s %d \n",__FILE__,__LINE__);
+      fflush(log);
+
+#endif
+      char* fileNameToWrite = nullptr;
+      VSIStatBuf sStatBuf;
+      if( write_absolute_path &&
+#ifdef ZOO_SERVICE
+            CPLIsFilenameRelative( tmpMap->value ) &&
+            VSIStat( tmpMap->value, &sStatBuf ) == 0
+#else
+            CPLIsFilenameRelative( papszArgv[nFirstSourceDataset] ) &&
+            VSIStat( papszArgv[nFirstSourceDataset], &sStatBuf ) == 0	    
+#endif
+	    )
+        {
+            fileNameToWrite =
+                CPLStrdup(CPLProjectRelativeFilename(
+						     current_path,
+#ifdef ZOO_SERVICE
+						     tmpMap->value
+#else
+						     papszArgv[nFirstSourceDataset]
+#endif
+						     ));
+        }
+        else
+        {
+#ifdef ZOO_SERVICE
+	  fileNameToWrite = CPLStrdup(tmpMap->value);
+#else
+	  fileNameToWrite = CPLStrdup(papszArgv[nFirstSourceDataset]);
+#endif
+        }
+
+        GDALDataset *poDS = reinterpret_cast<GDALDataset*>(
+							   OGROpen(
+#ifdef ZOO_SERVICE
+								   tmpMap->value
+#else
+								   papszArgv[nFirstSourceDataset]
+#endif		    
+								   ,
+								   FALSE,
+								   nullptr )
+							   );
+
+        if( poDS == nullptr )
+        {
+	  fprintf(log, "Failed to open dataset %s, skipping.\n",
+#ifndef ZOO_SERVICE
+		  papszArgv[nFirstSourceDataset]
+#else
+		  tmpMap->value
+#endif
+		  );
+            CPLFree(fileNameToWrite);
+            continue;
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Check all layers, and see if they match requests.               */
+/* -------------------------------------------------------------------- */
+        for( int iLayer = 0; iLayer < poDS->GetLayerCount(); iLayer++ )
+        {
+            bool bRequested = bLayersWildcarded;
+            OGRLayer *poLayer = poDS->GetLayer(iLayer);
+
+#ifndef ZOO_SERVICE
+            for( int iArg = 1; iArg < nArgc && !bRequested; iArg++ )
+            {
+                if( EQUAL(papszArgv[iArg], "-lnum")
+                    && atoi(papszArgv[iArg+1]) == iLayer )
+                    bRequested = true;
+                else if( EQUAL(papszArgv[iArg], "-lname" )
+                         && EQUAL(papszArgv[iArg+1],
+                                  poLayer->GetLayerDefn()->GetName()) )
+                    bRequested = true;
+            }
+#endif
+	    
+            if( !bRequested )
+                continue;
+
+            // Checks that the layer is not already in tileindex.
+            int i = 0;  // Used after for.
+            for( ; i < nExistingLayers; i++ )
+            {
+                // TODO(schwehr): Move this off of the stack.
+                char szLocation[5000] = {};
+                snprintf(szLocation, sizeof(szLocation), "%s,%d",
+                         fileNameToWrite, iLayer);
+                if( EQUAL(szLocation, existingLayersTab[i]) )
+                {
+                    fprintf(log, "Layer %d of %s is already in tileindex. "
+                            "Skipping it.\n",
+                            iLayer, szLocation);
+                    break;
+                }
+            }
+            if( i != nExistingLayers )
+            {
+                continue;
+            }
+
+            OGRSpatialReference* spatialRef = poLayer->GetSpatialRef();
+            // If not set target srs, test that the current file uses same
+            // projection as others.
+            if( !bSetTargetSRS )
+            {
+                if( alreadyExistingSpatialRefValid )
+                {
+                    if( (spatialRef != nullptr &&
+                         alreadyExistingSpatialRef != nullptr &&
+                        spatialRef->IsSame(alreadyExistingSpatialRef) ==
+                          FALSE) ||
+                        ((spatialRef != nullptr) !=
+                        (alreadyExistingSpatialRef != nullptr)) )
+                    {
+                        fprintf(
+                            log,
+                            "Warning : layer %d of %s is not using the same "
+                            "projection system as other files in the "
+                            "tileindex. This may cause problems when using it "
+                            "in MapServer for example.%s\n",
+                            iLayer,
+#ifdef ZOO_SERVICE
+			    tmpMap->value
+#else
+			    papszArgv[nFirstSourceDataset]
+#endif
+			    ,
+                            skip_different_projection ? " Skipping it" : "");
+                        if( skip_different_projection )
+                        {
+                            continue;
+                        }
+                    }
+                }
+                else
+                {
+                    alreadyExistingSpatialRefValid = true;
+                    alreadyExistingSpatialRef =
+                        spatialRef ? spatialRef->Clone() : nullptr;
+                }
+            }
+
+/* -------------------------------------------------------------------- */
+/*      Check if all layers in dataset have the same attributes schema. */
+/* -------------------------------------------------------------------- */
+            if( poFeatureDefn == nullptr )
+            {
+                poFeatureDefn = poLayer->GetLayerDefn()->Clone();
+            }
+            else if( !accept_different_schemas )
+            {
+                OGRFeatureDefn* poFeatureDefnCur = poLayer->GetLayerDefn();
+                assert(nullptr != poFeatureDefnCur);
+
+                const int fieldCount = poFeatureDefnCur->GetFieldCount();
+
+                if( fieldCount != poFeatureDefn->GetFieldCount())
+                {
+                    fprintf( log, "Number of attributes of layer %s of %s "
+                             "does not match ... skipping it.\n",
+                             poLayer->GetLayerDefn()->GetName(),
+#ifdef ZOO_SERVICE
+			     tmpMap->value
+#else		     
+                             papszArgv[nFirstSourceDataset]
+#endif			     
+			     );
+                    if( bFirstWarningForNonMatchingAttributes )
+                    {
+                        fprintf(
+                            log, "Note : you can override this "
+                            "behaviour with -accept_different_schemas option\n"
+                            "but this may result in a tileindex incompatible "
+                            "with MapServer\n");
+                        bFirstWarningForNonMatchingAttributes = false;
+                    }
+                    continue;
+                }
+
+                bool bSkip = false;
+                for( int fn = 0; fn < poFeatureDefnCur->GetFieldCount(); fn++ )
+                {
+                    OGRFieldDefn* poField = poFeatureDefn->GetFieldDefn(fn);
+                    OGRFieldDefn* poFieldCur =
+                        poFeatureDefnCur->GetFieldDefn(fn);
+
+                    // XXX - Should those pointers be checked against NULL?
+                    assert(nullptr != poField);
+                    assert(nullptr != poFieldCur);
+
+                    if( poField->GetType() != poFieldCur->GetType()
+                        || poField->GetWidth() != poFieldCur->GetWidth()
+                        || poField->GetPrecision() != poFieldCur->GetPrecision()
+                        || !EQUAL( poField->GetNameRef(),
+                                   poFieldCur->GetNameRef() ) )
+                    {
+                        fprintf(
+                            log, "Schema of attributes of layer %s of %s "
+                            "does not match. Skipping it.\n",
+                            poLayer->GetLayerDefn()->GetName(),
+#ifdef ZOO_SERVICE
+			    tmpMap->value
+#else		     
+			    papszArgv[nFirstSourceDataset]
+#endif
+				);
+                        if( bFirstWarningForNonMatchingAttributes )
+                        {
+                            fprintf(
+                                log, "Note : you can override this "
+                                "behaviour with -accept_different_schemas "
+                                "option,\nbut this may result in a tileindex "
+                                "incompatible with MapServer\n");
+                            bFirstWarningForNonMatchingAttributes = false;
+                        }
+                        bSkip = true;
+                        break;
+                    }
+                }
+
+                if( bSkip )
+                    continue;
+            }
+
+/* -------------------------------------------------------------------- */
+/*      Get layer extents, and create a corresponding polygon           */
+/*      geometry.                                                       */
+/* -------------------------------------------------------------------- */
+            OGREnvelope sExtents;
+
+            if( poLayer->GetExtent( &sExtents, TRUE ) != OGRERR_NONE )
+            {
+                fprintf(log,
+                        "GetExtent() failed on layer %s of %s, skipping.\n",
+                        poLayer->GetLayerDefn()->GetName(),
+#ifdef ZOO_SERVICE
+			tmpMap->value
+#else		     
+			papszArgv[nFirstSourceDataset]
+#endif
+			);
+                continue;
+            }
+
+            OGRLinearRing oRing;
+            oRing.addPoint(sExtents.MinX, sExtents.MinY);
+            oRing.addPoint(sExtents.MinX, sExtents.MaxY);
+            oRing.addPoint(sExtents.MaxX, sExtents.MaxY);
+            oRing.addPoint(sExtents.MaxX, sExtents.MinY);
+            oRing.addPoint(sExtents.MinX, sExtents.MinY);
+
+            OGRPolygon oRegion;
+            oRegion.addRing(&oRing);
+
+            // If set target srs, do the forward transformation of all points.
+            if( bSetTargetSRS && spatialRef != nullptr )
+            {
+                OGRCoordinateTransformation* poCT = nullptr;
+                if( !spatialRef->IsSame(poTargetSRS) )
+                {
+                    poCT = OGRCreateCoordinateTransformation(spatialRef,
+                                                             poTargetSRS);
+                    if( poCT == nullptr ||
+                        oRegion.transform(poCT) == OGRERR_FAILURE )
+                    {
+                        char* pszSourceWKT = nullptr;
+                        spatialRef->exportToWkt(&pszSourceWKT);
+                        fprintf(
+                            log,
+                            "Warning : unable to transform points from source "
+                            "SRS `%s' to target SRS `%s'\n"
+                            "for file `%s' - file skipped\n",
+                            pszSourceWKT, pszTargetSRS,
+#ifdef ZOO_SERVICE
+			    tmpMap->value
+#else		     
+			    papszArgv[nFirstSourceDataset]
+#endif
+				);
+                        CPLFree(pszSourceWKT);
+                        delete poCT;
+                        continue;
+                    }
+                    delete poCT;
+                }
+            }
+
+/* -------------------------------------------------------------------- */
+/*      Add layer to tileindex.                                         */
+/* -------------------------------------------------------------------- */
+            OGRFeature oTileFeat(poDstLayer->GetLayerDefn());
+
+            // TODO(schwehr): Move this off of the stack.
+            char szLocation[5000] = {};
+            snprintf(szLocation, sizeof(szLocation), "%s,%d",
+                     fileNameToWrite, iLayer);
+            oTileFeat.SetGeometry(&oRegion);
+            oTileFeat.SetField(iTileIndexField, szLocation);
+
+            if( i_SrcSRSName >= 0 && spatialRef != nullptr )
+            {
+                const char* pszAuthorityCode =
+                    spatialRef->GetAuthorityCode(nullptr);
+                const char* pszAuthorityName =
+                    spatialRef->GetAuthorityName(nullptr);
+                char* pszWKT = nullptr;
+                spatialRef->exportToWkt(&pszWKT);
+                if( eSrcSRSFormat == FORMAT_AUTO )
+                {
+                    if( pszAuthorityName != nullptr &&
+                        pszAuthorityCode != nullptr )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName,
+                            CPLSPrintf("%s:%s",
+                                       pszAuthorityName, pszAuthorityCode));
+                    }
+                    else if( nMaxFieldSize == 0 ||
+                            strlen(pszWKT) <= nMaxFieldSize )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName, pszWKT);
+                    }
+                    else
+                    {
+                        char* pszProj4 = nullptr;
+                        if( spatialRef->exportToProj4(&pszProj4) ==
+                              OGRERR_NONE )
+                        {
+                            oTileFeat.SetField(i_SrcSRSName, pszProj4);
+                            CPLFree(pszProj4);
+                        }
+                        else
+                        {
+                            oTileFeat.SetField(i_SrcSRSName, pszWKT);
+                        }
+                    }
+                }
+                else if( eSrcSRSFormat == FORMAT_WKT )
+                {
+                    if( nMaxFieldSize == 0 ||
+                        strlen(pszWKT) <= nMaxFieldSize )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName, pszWKT);
+                    }
+                    else
+                    {
+                        fprintf(
+                            log,
+                            "Cannot write WKT for file %s as it is too long!\n",
+                            fileNameToWrite);
+                    }
+                }
+                else if( eSrcSRSFormat == FORMAT_PROJ )
+                {
+                    char* pszProj4 = nullptr;
+                    if( spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE )
+                    {
+                        oTileFeat.SetField(i_SrcSRSName, pszProj4);
+                        CPLFree(pszProj4);
+                    }
+                }
+                else if( eSrcSRSFormat == FORMAT_EPSG )
+                {
+                    if( pszAuthorityName != nullptr &&
+                        pszAuthorityCode != nullptr )
+                        oTileFeat.SetField(i_SrcSRSName,
+                            CPLSPrintf("%s:%s",
+                                       pszAuthorityName, pszAuthorityCode));
+                }
+                CPLFree(pszWKT);
+            }
+            if( poDstLayer->CreateFeature(&oTileFeat) != OGRERR_NONE )
+            {
+                fprintf(log,
+                        "Failed to create feature on tile index. "
+                        "Terminating.");
+                GDALClose(poDstDS);
+                exit(1);
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Cleanup this data source.                                       */
+/* -------------------------------------------------------------------- */
+        CPLFree(fileNameToWrite);
+        GDALClose(poDS);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Close tile index and clear buffers.                             */
+/* -------------------------------------------------------------------- */
+    GDALClose(poDstDS);
+    OGRFeatureDefn::DestroyFeatureDefn(poFeatureDefn);
+
+    if( alreadyExistingSpatialRef != nullptr )
+        alreadyExistingSpatialRef->Release();
+    delete poTargetSRS;
+
+    CPLFree(current_path);
+
+    if( nExistingLayers )
+    {
+        for( int i = 0; i < nExistingLayers; i++ )
+        {
+            CPLFree(existingLayersTab[i]);
+        }
+        CPLFree(existingLayersTab);
+    }
+
+    OGRCleanupAll();
+#ifdef ZOO_SERVICE
+    //setMapInMaps(outputs,"Result","generated_file",pszOutputName);
+    setMapInMaps(outputs,"Result","value",pszOutputName);
+    return  SERVICE_SUCCEEDED;
+#else
+    return 0;
+#endif
+}
+#ifndef ZOO_SERVICE
+MAIN_END
+#endif
+  
+#ifdef ZOO_SERVICE
+}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/Exporter.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/Exporter.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/Exporter.py	(revision 942)
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+#
+# Author : Gérald FENOY
+#
+# Copyright 2008-2013 GeoLabs SARL. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including with
+# out limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+import uno
+import getopt, sys
+
+from unohelper import Base, systemPathToFileUrl, absolutize
+
+from com.sun.star.beans import PropertyValue
+from com.sun.star.script import CannotConvertException
+from com.sun.star.lang import IllegalArgumentException
+from com.sun.star.task import ErrorCodeIOException
+from com.sun.star.io import IOException, XOutputStream
+
+class OutputStream( Base, XOutputStream ):
+    def __init__( self ):
+        self.closed = 0
+    def closeOutput(self):
+        self.closed = 1
+    def writeBytes( self, seq ):
+        sys.stdout.write( seq.value )
+    def flush( self ):
+        pass
+
+def OdtConverter(conf,inputs,outputs):
+	# get the uno component context from the PyUNO runtime  
+	localContext = uno.getComponentContext()
+
+	# create the UnoUrlResolver 
+	# on a single line
+	resolver = 	localContext.ServiceManager.createInstanceWithContext	("com.sun.star.bridge.UnoUrlResolver", localContext )
+
+	# connect to the running office                                 
+	ctx = resolver.resolve( conf["oo"]["server"].replace("::","=")+";urp;StarOffice.ComponentContext" )
+	smgr = ctx.ServiceManager
+
+	# get the central desktop object
+	desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
+
+	# get the file name
+	adressDoc=systemPathToFileUrl(conf["main"]["dataPath"]+"/"+inputs["InputDoc"]["value"])
+
+	propFich=PropertyValue("Hidden", 0, True, 0),
+
+	myDocument=0
+	try:
+	    myDocument = desktop.loadComponentFromURL(adressDoc,"_blank",0,propFich)
+	except CannotConvertException, e:
+	    print >> sys.stderr,  'Impossible de convertir le fichier pour les raisons suivantes : \n'
+	    print >> sys.stderr,  e
+	    sys.exit(0)
+	except IllegalArgumentException, e:
+	    print >> sys.stderr,  'Impossible de convertir le fichier pour les 	raisons suivantes : \n'
+	    print >> sys.stderr,  e
+	    sys.exit(0)
+
+	outputDoc=systemPathToFileUrl(conf["main"]["tmpPath"]+"/"+inputs["OutputDoc"]["value"])
+
+	tmp=inputs["OutputDoc"]["value"].split('.');
+
+	outputFormat={"pdf": "writer_pdf_Export", "html": "HTML (StarWriter)","odt": "writer8","doc": "MS Word 97","rtf": "Rich Text Format"}
+
+	for i in range(len(outputFormat)) :
+	    if tmp[1]==outputFormat.keys()[i] :
+	        filterName=outputFormat[tmp[1]]
+	        prop1Fich = (
+	            PropertyValue( "FilterName" , 0, filterName , 0 ),
+		        PropertyValue( "Overwrite" , 0, True , 0 )
+	        )
+	        break
+
+	myDocument.storeToURL(outputDoc,prop1Fich)
+	myDocument.close(True)
+	ctx.ServiceManager
+	outputs["OutputedDocument"]={"value": inputs["OutputDoc"]["value"],"dataType": "string"}
+	return 3
Index: /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/OdtConverter.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/OdtConverter.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/OdtConverter.zcfg	(revision 942)
@@ -0,0 +1,43 @@
+[OdtConverter]
+ Title = Converts Open Documents. 
+ Abstract = Converts open documents.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = Python
+ serviceProvider = Exporter
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [InputDoc]
+   Title = The input data source name
+   Abstract = The input data source name
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+   </LiteralData>
+  [OutputDoc]
+   Title = The output data source name
+   Abstract = The output data source name to use as source.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [OutputedDoc]
+   Title = The resulting converted file
+   Abstract = The file name resulting of the convertion
+   <LiteralData>
+    DataType = string
+    <Default>
+    </Default>	
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/Xml2Pdf.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/Xml2Pdf.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/Xml2Pdf.zcfg	(revision 942)
@@ -0,0 +1,39 @@
+[Xml2Pdf]
+ Title = Convert XML and Open Document to PDF format. 
+ Abstract = Converts XML to PDF format.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = Python
+ serviceProvider = oo_service
+ <DataInputs>
+  [doc]
+   Title = The input Open Document Text
+   Abstract = The input Open Document Text including all required Styles
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default/>
+   </LiteralData>
+  [xml]
+   Title = The input XML file
+   Abstract = The input XML file to convert.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default/>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Document]
+   Title = The resulting file
+   Abstract = The file content resulting of the convertion from XML to PDF
+   <ComplexData>
+    <Default>
+     mimeType=application/pdf
+     extension=pdf
+    </Default>	
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/oo_service.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/oo_service.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/openoffice/cgi-env/oo_service.py	(revision 942)
@@ -0,0 +1,144 @@
+#
+# Author : Gérald FENOY
+#
+# Copyright 2008-2013 GeoLabs SARL. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+import uno
+import getopt, sys, os
+
+from unohelper import Base, systemPathToFileUrl, absolutize
+
+from com.sun.star.beans import PropertyValue
+from com.sun.star.script import CannotConvertException
+from com.sun.star.lang import IllegalArgumentException
+from com.sun.star.task import ErrorCodeIOException
+from com.sun.star.io import IOException, XOutputStream
+from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER
+from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
+
+from xml.dom import minidom 
+import sys 
+
+keep_trace=''
+
+def addToText(cursor,text,level,value):
+    if level==1:
+        cursor.NumberingStyleName = "NONE"
+        cursor.ParaStyleName="Heading 1"
+        text.insertString( cursor, value , 0 )
+        text.insertControlCharacter( cursor, PARAGRAPH_BREAK , 0 )
+        #print  >> sys.stderr,' * Main Title : ' + value
+    else:
+        i=0
+        prefix=''
+        while i < level-1:
+            prefix+=' '
+            i+=1
+        cursor.NumberingStyleName="List "+str(level-1)
+        text.insertString( cursor, prefix+value , 0 )
+        text.insertControlCharacter( cursor, PARAGRAPH_BREAK , 0 )
+        cursor.NumberingStyleName = "NONE"
+	#print  >> sys.stderr,dir(sys.stderr)
+        #print >> sys.stderr,prefix+' * NumberingStyleName '+str(level-1)+' '+value.encode('iso-8859-15')
+
+def printChildren(cursor,text,node,level,keep_trace):
+    if node.nodeType==3:
+        level-=1
+
+    if not(node.nodeValue!=None and len(node.nodeValue.replace(' ',''))!=1 and keep_trace!='' and keep_trace!=None):
+        if keep_trace!='':
+            addToText(cursor,text,level-1,keep_trace)
+        keep_trace=node.nodeName
+
+    if node.hasChildNodes():
+        for i in node.childNodes:
+            printChildren(cursor,text,i,level+1,keep_trace)
+            keep_trace=''
+    else:
+        if node.nodeValue != None and len(node.nodeValue.replace(' ',''))>1:
+            addToText(cursor,text,level-1,keep_trace+' : '+node.nodeValue)
+            keep_trace=''
+        else:
+            if node.nodeValue != None and len(node.nodeValue.replace(' ',''))>1:
+                addToText(cursor,text,level-1,keep_trace+' : '+node.nodeValue)
+                keep_trace=''
+            else:
+                if keep_trace!='#text':
+                    addToText(cursor,text,level-1,keep_trace)
+                    keep_trace=''
+
+    if node.nodeType==1 and node.hasAttributes():
+        i=0
+        while i<node.attributes.length:
+            addToText(cursor,text,level,'(attr) '+node.attributes.keys()[i] + ' : ' + node.attributes[node.attributes.keys()[i]].value)
+            i+=1
+
+        
+
+def Xml2Pdf(conf,input,output):
+    localContext = uno.getComponentContext()
+    resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
+    ctx = resolver.resolve( "uno:socket,host=127.0.0.1,port=3662;urp;StarOffice.ComponentContext" )
+    smgr = ctx.ServiceManager
+    desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
+    adressDoc=systemPathToFileUrl(input["doc"]["value"])
+    propFich=PropertyValue("Hidden", 0, True, 0),
+    try:
+        myDocument = desktop.loadComponentFromURL(adressDoc,"_blank",0,propFich)
+	#Prefer to create a new document without any style ?
+        #myDocument = desktop.loadComponentFromURL("private:factory/writer","_blank",0,propFich)
+    except:
+        conf["lenv"]["message"]='Unable to load input document'
+	return 4
+    text = myDocument.Text
+    cursor = text.createTextCursor()
+    cursor.gotoStart(0)
+    cursor.gotoEnd(1)
+    xmldoc = minidom.parseString(input['xml']['value'])
+
+    if xmldoc.hasChildNodes():
+        for i in xmldoc.childNodes:
+            if i.nodeType==1:
+                cursor.ParaStyleName="Title"
+                text.insertString( cursor, i.nodeName , 0 )
+                text.insertControlCharacter( cursor, PARAGRAPH_BREAK , 0 )
+                #print >> sys.stderr,' * 1st level' + i.nodeName
+                if i.hasChildNodes():
+                    for j in i.childNodes:
+                        printChildren(cursor,text,j,2,'')
+
+    tmp=myDocument.StyleFamilies.getByName("NumberingStyles")
+
+    tmp1=tmp.getByName("Puce 1")
+
+    prop1Fich = ( PropertyValue( "FilterName" , 0, "writer_pdf_Export", 0 ),PropertyValue( "Overwrite" , 0, True , 0 ) )
+    outputDoc=systemPathToFileUrl("/tmp/output.pdf")
+    myDocument.storeToURL(outputDoc,prop1Fich)
+
+    myDocument.close(True)
+    ctx.ServiceManager
+    output["Document"]["value"]= open('/tmp/output.pdf', 'r').read()
+    print >> sys.stderr,len(output["Document"]["value"])
+    return 3
+
+#To run test from command line uncomment the following line:
+#xml2pdf({},{"file":{"value":"/tmp/demo.xml"},"doc":{"value":"/tmp/demo.odt"}},{})
Index: /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/Makefile	(revision 942)
@@ -0,0 +1,10 @@
+ZRPATH=../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/qrencode.zo: qrenc-service.c
+	g++ -DZOO_SERVICE_PROVIDER ${CFLAGS} -shared -fpic -o cgi-env/qrencode.zo ./qrenc-service.c -lqrencode ${GDAL_LIBS} -lpng ${MACOS_LD_FLAGS} -L${INST_LIB} -lzoo_service
+
+clean:
+	rm -f cgi-env/*.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/cgi-env/QREncode.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/cgi-env/QREncode.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/cgi-env/QREncode.zcfg	(revision 942)
@@ -0,0 +1,69 @@
+[QREncode]
+ Title = Encode a string into a QR Code
+ Abstract = Multiply two values and store the result in Result.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = qrencode.zo
+ serviceType = C
+ <DataInputs>
+  [Text]
+   Title = the input string
+   Abstract = The string to encode using QREncode.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+     uom = meters
+    </Default>
+    <Supported>
+     uom = feet
+    </Supported>
+   </LiteralData>
+  [fgcolor]
+   Title = the input string
+   Abstract = The string (RRGGBBAA) for for foreground color.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+     value=000000
+    </Default>
+   </LiteralData>
+  [bgcolor]
+   Title = the input string
+   Abstract = The string (RRGGBBAA) for for background color.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+     value=ffffff
+    </Default>
+   </LiteralData>
+  [size]
+   Title = the image size
+   Abstract = The generated image size.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = integer
+    <Default>
+     value=3
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [QR]
+   Title = the QR Code image 
+   Abstract = The QRCode corresponding to the string encoded.
+   minOccurs = 1
+   maxOccurs = 1
+   <ComplexData>
+       <Default>
+            mimeType = image/png
+       </Default>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/makefile.vc	(revision 942)
@@ -0,0 +1,23 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/service_internal.obj $(ZOOK_DIR)/ulinet.obj 
+!IFDEF JS_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(JS_FILE)
+!ENDIF
+!IFDEF JDK_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(JAVA_FILE)
+!ENDIF
+!IFDEF PY_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(PY_FILE)
+!ENDIF
+!IFDEF MS_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(MS_FILE)
+!ENDIF
+
+qrencode.zo: qrenc-service.c
+	$(CPP) -Ivc8\qrcode /DOGR_ENABLED /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE_PROVIDER -I$(GDAL_DIR)/frmts/ -I$(GDAL_DIR)/alg/ $(CFLAGS) -I$(PNG_DIR) /c qrenc-service.c
+	link /dll /out:cgi-env/qrencode.zo  $(FILES) ./qrenc-service.obj $(LDFLAGS) $(PNG_DIR)/libpng15.lib $(QRENCODE_DIR)vc8/.build/Release-Lib/qrcodelib.lib /FORCE:MULTIPLE /NODEFAULTLIB:library
+
+clean:
+	erase qrencode.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/qrenc-service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/qrenc-service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/qrencode/qrenc-service.c	(revision 942)
@@ -0,0 +1,1216 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: t -*-*/
+
+/**
+ * qrencode - QR Code encoder
+ *
+ * QR Code encoding tool
+ * Copyright (C) 2006-2012 Kentaro Fukuchi <kentaro@fukuchi.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "string.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+#include <getopt.h>
+#include "qrencode.h"
+
+#ifdef ZOO_SERVICE_PROVIDER
+#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
+#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)
+#ifdef WIN32
+#include "windows.h"
+#endif
+#include "service.h"
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+
+#define INCHES_PER_METER (100.0/2.54)
+
+static int casesensitive = 1;
+static int eightbit = 0;
+static int version = 0;
+static int size = 3;
+static int margin = -1;
+static int dpi = 72;
+static int structured = 0;
+static int micro = 0;
+static QRecLevel level = QR_ECLEVEL_L;
+static QRencodeMode hint = QR_MODE_8;
+static unsigned int fg_color[4] = {0, 0, 0, 255};
+static unsigned int bg_color[4] = {255, 255, 255, 255};
+
+enum imageType {
+	PNG_TYPE,
+	EPS_TYPE,
+	SVG_TYPE,
+	ANSI_TYPE,
+	ANSI256_TYPE,
+	ASCII_TYPE,
+	ASCIIi_TYPE,
+	UTF8_TYPE,
+	ANSIUTF8_TYPE
+};
+
+static enum imageType image_type = PNG_TYPE;
+
+static const struct option options[] = {
+	{"help"         , no_argument      , NULL, 'h'},
+	{"output"       , required_argument, NULL, 'o'},
+	{"level"        , required_argument, NULL, 'l'},
+	{"size"         , required_argument, NULL, 's'},
+	{"symversion"   , required_argument, NULL, 'v'},
+	{"margin"       , required_argument, NULL, 'm'},
+	{"dpi"          , required_argument, NULL, 'd'},
+	{"type"         , required_argument, NULL, 't'},
+	{"structured"   , no_argument      , NULL, 'S'},
+	{"kanji"        , no_argument      , NULL, 'k'},
+	{"casesensitive", no_argument      , NULL, 'c'},
+	{"ignorecase"   , no_argument      , NULL, 'i'},
+	{"8bit"         , no_argument      , NULL, '8'},
+	{"micro"        , no_argument      , NULL, 'M'},
+	{"foreground"	, required_argument, NULL, 'f'},
+	{"background"	, required_argument, NULL, 'b'},
+	{"version"      , no_argument      , NULL, 'V'},
+	{NULL, 0, NULL, 0}
+};
+
+static char *optstring = "ho:l:s:v:m:d:t:Skci8MV";
+
+static void usage(int help, int longopt)
+{
+	fprintf(stderr,
+"qrencode version %s\n"
+"Copyright (C) 2006-2012 Kentaro Fukuchi\n", QRcode_APIVersionString());
+	if(help) {
+		if(longopt) {
+			fprintf(stderr,
+"Usage: qrencode [OPTION]... [STRING]\n"
+"Encode input data in a QR Code and save as a PNG or EPS image.\n\n"
+"  -h, --help   display the help message. -h displays only the help of short\n"
+"               options.\n\n"
+"  -o FILENAME, --output=FILENAME\n"
+"               write image to FILENAME. If '-' is specified, the result\n"
+"               will be output to standard output. If -S is given, structured\n"
+"               symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n"
+"               (suffix is removed from FILENAME, if specified)\n"
+"  -s NUMBER, --size=NUMBER\n"
+"               specify module size in dots (pixels). (default=3)\n\n"
+"  -l {LMQH}, --level={LMQH}\n"
+"               specify error correction level from L (lowest) to H (highest).\n"
+"               (default=L)\n\n"
+"  -v NUMBER, --symversion=NUMBER\n"
+"               specify the version of the symbol. (default=auto)\n\n"
+"  -m NUMBER, --margin=NUMBER\n"
+"               specify the width of the margins. (default=4 (2 for Micro)))\n\n"
+"  -d NUMBER, --dpi=NUMBER\n"
+"               specify the DPI of the generated PNG. (default=72)\n\n"
+"  -t {PNG,EPS,SVG,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8}, --type={PNG,EPS,\n"
+"               SVG,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8}\n"
+"               specify the type of the generated image. (default=PNG)\n\n"
+"  -S, --structured\n"
+"               make structured symbols. Version must be specified.\n\n"
+"  -k, --kanji  assume that the input text contains kanji (shift-jis).\n\n"
+"  -c, --casesensitive\n"
+"               encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
+"  -i, --ignorecase\n"
+"               ignore case distinctions and use only upper-case characters.\n\n"
+"  -8, --8bit   encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
+"  -M, --micro  encode in a Micro QR Code. (experimental)\n\n"
+"  --foreground=RRGGBB[AA]\n"
+"  --background=RRGGBB[AA]\n"
+"               specify foreground/background color in hexadecimal notation.\n"
+"               6-digit (RGB) or 8-digit (RGBA) form are supported.\n"
+"               Color output support available only in PNG and SVG.\n"
+"  -V, --version\n"
+"               display the version number and copyrights of the qrencode.\n\n"
+"  [STRING]     input data. If it is not specified, data will be taken from\n"
+"               standard input.\n"
+			);
+		} else {
+			fprintf(stderr,
+"Usage: qrencode [OPTION]... [STRING]\n"
+"Encode input data in a QR Code and save as a PNG or EPS image.\n\n"
+"  -h           display this message.\n"
+"  --help       display the usage of long options.\n"
+"  -o FILENAME  write image to FILENAME. If '-' is specified, the result\n"
+"               will be output to standard output. If -S is given, structured\n"
+"               symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n"
+"               (suffix is removed from FILENAME, if specified)\n"
+"  -s NUMBER    specify module size in dots (pixels). (default=3)\n"
+"  -l {LMQH}    specify error correction level from L (lowest) to H (highest).\n"
+"               (default=L)\n"
+"  -v NUMBER    specify the version of the symbol. (default=auto)\n"
+"  -m NUMBER    specify the width of the margins. (default=4 (2 for Micro))\n"
+"  -d NUMBER    specify the DPI of the generated PNG. (default=72)\n"
+"  -t {PNG,EPS,SVG,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8}\n"
+"               specify the type of the generated image. (default=PNG)\n"
+"  -S           make structured symbols. Version must be specified.\n"
+"  -k           assume that the input text contains kanji (shift-jis).\n"
+"  -c           encode lower-case alphabet characters in 8-bit mode. (default)\n"
+"  -i           ignore case distinctions and use only upper-case characters.\n"
+"  -8           encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
+"  -M           encode in a Micro QR Code.\n"
+"  --foreground=RRGGBB[AA]\n"
+"  --background=RRGGBB[AA]\n"
+"               specify foreground/background color in hexadecimal notation.\n"
+"               6-digit (RGB) or 8-digit (RGBA) form are supported.\n"
+"               Color output support available only in PNG and SVG.\n"
+"  -V           display the version number and copyrights of the qrencode.\n"
+"  [STRING]     input data. If it is not specified, data will be taken from\n"
+"               standard input.\n"
+			);
+		}
+	}
+}
+
+static int color_set(unsigned int color[4], const char *value)
+{
+	int len = strlen(value);
+	int count;
+	if(len == 6) {
+		count = sscanf(value, "%02x%02x%02x%n", &color[0], &color[1], &color[2], &len);
+		if(count < 3 || len != 6) {
+			return -1;
+		}
+		color[3] = 255;
+	} else if(len == 8) {
+		count = sscanf(value, "%02x%02x%02x%02x%n", &color[0], &color[1], &color[2], &color[3], &len);
+		if(count < 4 || len != 8) {
+			return -1;
+		}
+	} else {
+		return -1;
+	}
+	return 0;
+}
+
+#define MAX_DATA_SIZE (7090 * 16) /* from the specification */
+static unsigned char *readStdin(int *length)
+{
+	unsigned char *buffer;
+	int ret;
+
+	buffer = (unsigned char *)malloc(MAX_DATA_SIZE + 1);
+	if(buffer == NULL) {
+		fprintf(stderr, "Memory allocation failed.\n");
+		exit(EXIT_FAILURE);
+	}
+	ret = fread(buffer, 1, MAX_DATA_SIZE, stdin);
+	if(ret == 0) {
+		fprintf(stderr, "No input data.\n");
+		exit(EXIT_FAILURE);
+	}
+	if(feof(stdin) == 0) {
+		fprintf(stderr, "Input data is too large.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	buffer[ret] = '\0';
+	*length = ret;
+
+	return buffer;
+}
+
+static FILE *openFile(const char *outfile)
+{
+	FILE *fp;
+
+	if(outfile == NULL || (outfile[0] == '-' && outfile[1] == '\0')) {
+		fp = stdout;
+	} else {
+		fp = fopen(outfile, "wb");
+		if(fp == NULL) {
+			fprintf(stderr, "Failed to create file: %s\n", outfile);
+			perror(NULL);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	return fp;
+}
+
+static int writePNG(QRcode *qrcode, const char *outfile)
+{
+	static FILE *fp; // avoid clobbering by setjmp.
+	png_structp png_ptr;
+	png_infop info_ptr;
+	png_colorp palette;
+	png_byte alpha_values[2];
+	unsigned char *row, *p, *q;
+	int x, y, xx, yy, bit;
+	int realwidth;
+
+	realwidth = (qrcode->width + margin * 2) * size;
+	row = (unsigned char *)malloc((realwidth + 7) / 8);
+	if(row == NULL) {
+		fprintf(stderr, "Failed to allocate memory.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if(outfile[0] == '-' && outfile[1] == '\0') {
+		fp = stdout;
+	} else {
+		fp = fopen(outfile, "wb");
+		if(fp == NULL) {
+			fprintf(stderr, "Failed to create file: %s\n", outfile);
+			perror(NULL);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if(png_ptr == NULL) {
+		fprintf(stderr, "Failed to initialize PNG writer.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	info_ptr = png_create_info_struct(png_ptr);
+	if(info_ptr == NULL) {
+		fprintf(stderr, "Failed to initialize PNG write.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if(setjmp(png_jmpbuf(png_ptr))) {
+		png_destroy_write_struct(&png_ptr, &info_ptr);
+		fprintf(stderr, "Failed to write PNG image.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	palette = (png_colorp) malloc(sizeof(png_color) * 2);
+	palette[0].red   = fg_color[0];
+	palette[0].green = fg_color[1];
+	palette[0].blue  = fg_color[2];
+	palette[1].red   = bg_color[0];
+	palette[1].green = bg_color[1];
+	palette[1].blue  = bg_color[2];
+	alpha_values[0] = fg_color[3];
+	alpha_values[1] = bg_color[3];
+	png_set_PLTE(png_ptr, info_ptr, palette, 2);
+	png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL);
+
+	png_init_io(png_ptr, fp);
+	png_set_IHDR(png_ptr, info_ptr,
+			realwidth, realwidth,
+			1,
+			PNG_COLOR_TYPE_PALETTE,
+			PNG_INTERLACE_NONE,
+			PNG_COMPRESSION_TYPE_DEFAULT,
+			PNG_FILTER_TYPE_DEFAULT);
+	png_set_pHYs(png_ptr, info_ptr,
+			dpi * INCHES_PER_METER,
+			dpi * INCHES_PER_METER,
+			PNG_RESOLUTION_METER);
+	png_write_info(png_ptr, info_ptr);
+
+	/* top margin */
+	memset(row, 0xff, (realwidth + 7) / 8);
+	for(y=0; y<margin * size; y++) {
+		png_write_row(png_ptr, row);
+	}
+
+	/* data */
+	p = qrcode->data;
+	for(y=0; y<qrcode->width; y++) {
+		bit = 7;
+		memset(row, 0xff, (realwidth + 7) / 8);
+		q = row;
+		q += margin * size / 8;
+		bit = 7 - (margin * size % 8);
+		for(x=0; x<qrcode->width; x++) {
+			for(xx=0; xx<size; xx++) {
+				*q ^= (*p & 1) << bit;
+				bit--;
+				if(bit < 0) {
+					q++;
+					bit = 7;
+				}
+			}
+			p++;
+		}
+		for(yy=0; yy<size; yy++) {
+			png_write_row(png_ptr, row);
+		}
+	}
+	/* bottom margin */
+	memset(row, 0xff, (realwidth + 7) / 8);
+	for(y=0; y<margin * size; y++) {
+		png_write_row(png_ptr, row);
+	}
+
+	png_write_end(png_ptr, info_ptr);
+	png_destroy_write_struct(&png_ptr, &info_ptr);
+
+	fclose(fp);
+	free(row);
+
+	return 0;
+}
+
+static int writeEPS(QRcode *qrcode, const char *outfile)
+{
+	FILE *fp;
+	unsigned char *row, *p;
+	int x, y, yy;
+	int realwidth;
+
+	fp = openFile(outfile);
+   
+	realwidth = (qrcode->width + margin * 2) * size;
+	/* EPS file header */
+	fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n"
+				"%%%%BoundingBox: 0 0 %d %d\n"
+				"%%%%Pages: 1 1\n"
+				"%%%%EndComments\n", realwidth, realwidth);
+	/* draw point */
+	fprintf(fp, "/p { "
+				"moveto "
+				"0 1 rlineto "
+				"1 0 rlineto "
+				"0 -1 rlineto "
+				"fill "
+				"} bind def "
+				"%d %d scale ", size, size);
+	
+	/* data */
+	p = qrcode->data;
+	for(y=0; y<qrcode->width; y++) {
+		row = (p+(y*qrcode->width));
+		yy = (margin + qrcode->width - y - 1);
+		
+		for(x=0; x<qrcode->width; x++) {
+			if(*(row+x)&0x1) {
+				fprintf(fp, "%d %d p ", margin + x,  yy);
+			}
+		}
+	}
+
+	fprintf(fp, "\n%%%%EOF\n");
+	fclose(fp);
+
+	return 0;
+}
+
+static void writeSVG_writeRect(FILE *fp, int x, int y, int width, char* col, float opacity)
+{
+	if(fg_color[3] != 255) {
+		fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\
+				"fill=\"#%s\" fill-opacity=\"%f\" />\n", 
+				x, y, width, col, opacity );
+	} else {
+		fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\
+				"fill=\"#%s\" />\n", 
+				x, y, width, col );
+	}
+}
+
+static int writeSVG( QRcode *qrcode, const char *outfile )
+{
+	FILE *fp;
+	unsigned char *row, *p;
+	int x, y, x0, pen;
+	int symwidth, realwidth;
+	float scale;
+	char fg[7], bg[7];
+	float fg_opacity;
+	float bg_opacity;
+
+	fp = openFile(outfile);
+
+	scale = dpi * INCHES_PER_METER / 100.0;
+
+	symwidth = qrcode->width + margin * 2;
+	realwidth = symwidth * size;
+
+	snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1],  fg_color[2]);
+	snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1],  bg_color[2]);
+	fg_opacity = (float)fg_color[3] / 255;
+	bg_opacity = (float)bg_color[3] / 255;
+
+	/* XML declaration */
+	fputs( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", fp );
+
+	/* DTD 
+	   No document type specified because "while a DTD is provided in [the SVG] 
+	   specification, the use of DTDs for validating XML documents is known to be 
+	   problematic. In particular, DTDs do not handle namespaces gracefully. It 
+	   is *not* recommended that a DOCTYPE declaration be included in SVG 
+	   documents." 
+	   http://www.w3.org/TR/2003/REC-SVG11-20030114/intro.html#Namespace
+	*/
+
+	/* Vanity remark */
+	fprintf( fp, "<!-- Created with qrencode %s (http://fukuchi.org/works/qrencode/index.html.en) -->\n", 
+			QRcode_APIVersionString() );
+
+	/* SVG code start */
+	fprintf( fp, "<svg width=\"%0.2fcm\" height=\"%0.2fcm\" viewBox=\"0 0 %d %d\""\
+			" preserveAspectRatio=\"none\" version=\"1.1\""\
+			" xmlns=\"http://www.w3.org/2000/svg\">\n", 
+			realwidth / scale, realwidth / scale, symwidth, symwidth
+		   );
+
+	/* Make named group */
+	fputs( "\t<g id=\"QRcode\">\n", fp );
+
+	/* Make solid background */
+	if(bg_color[3] != 255) {
+		fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\" fill-opacity=\"%f\" />\n", symwidth, symwidth, bg, bg_opacity);
+	} else {
+		fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\" />\n", symwidth, symwidth, bg);
+	}
+
+	/* Create new viewbox for QR data */
+	fputs( "\t\t<g id=\"Pattern\">\n", fp);
+
+	/* Write data */
+	p = qrcode->data;
+	for(y=0; y<qrcode->width; y++) {
+		row = (p+(y*qrcode->width));
+
+		/* simple RLE */
+		pen = 0;
+		x0  = 0;
+		for(x=0; x<qrcode->width; x++) {
+			if( !pen ) {
+				pen = *(row+x)&0x1;
+				x0 = x;
+			} else {
+				if(!(*(row+x)&0x1)) {
+					writeSVG_writeRect(fp, x0 + margin, y + margin, x-x0, fg, fg_opacity);
+					pen = 0;
+				}
+			}
+		}
+		if( pen ) {
+			writeSVG_writeRect(fp, x0 + margin, y + margin, qrcode->width - x0, fg, fg_opacity);
+		}
+	}
+
+	/* Close QR data viewbox */
+	fputs( "\t\t</g>\n", fp );
+
+	/* Close group */
+	fputs( "\t</g>\n", fp );
+
+	/* Close SVG code */
+	fputs( "</svg>\n", fp );
+	fclose( fp );
+
+	return 0;
+}
+
+static void writeANSI_margin(FILE* fp, int realwidth,
+                             char* buffer, int buffer_s,
+                             char* white, int white_s )
+{
+	int y;
+
+	strncpy(buffer, white, white_s);
+	memset(buffer + white_s, ' ', realwidth * 2);
+	strcpy(buffer + white_s + realwidth * 2, "\033[0m\n"); // reset to default colors
+	for(y=0; y<margin; y++ ){
+		fputs(buffer, fp);
+	}
+}
+
+static int writeANSI(QRcode *qrcode, const char *outfile)
+{
+	FILE *fp;
+	unsigned char *row, *p;
+	int x, y;
+	int realwidth;
+	int last;
+
+	char *white, *black, *buffer;
+	int white_s, black_s, buffer_s;
+
+	if( image_type == ANSI256_TYPE ){
+		/* codes for 256 color compatible terminals */
+		white = "\033[48;5;231m";
+		white_s = 11;
+		black = "\033[48;5;16m";
+		black_s = 10;
+	} else {
+		white = "\033[47m";
+		white_s = 5;
+		black = "\033[40m";
+		black_s = 5;
+	}
+
+	size = 1;
+
+	fp = openFile(outfile);
+
+	realwidth = (qrcode->width + margin * 2) * size;
+	buffer_s = ( realwidth * white_s ) * 2;
+	buffer = (char *)malloc( buffer_s );
+	if(buffer == NULL) {
+		fprintf(stderr, "Failed to allocate memory.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* top margin */
+	writeANSI_margin(fp, realwidth, buffer, buffer_s, white, white_s);
+
+	/* data */
+	p = qrcode->data;
+	for(y=0; y<qrcode->width; y++) {
+		row = (p+(y*qrcode->width));
+
+		bzero( buffer, buffer_s );
+		strncpy( buffer, white, white_s );
+		for(x=0; x<margin; x++ ){
+			strncat( buffer, "  ", 2 );
+		}
+		last = 0;
+
+		for(x=0; x<qrcode->width; x++) {
+			if(*(row+x)&0x1) {
+				if( last != 1 ){
+					strncat( buffer, black, black_s );
+					last = 1;
+				}
+			} else {
+				if( last != 0 ){
+					strncat( buffer, white, white_s );
+					last = 0;
+				}
+			}
+			strncat( buffer, "  ", 2 );
+		}
+
+		if( last != 0 ){
+			strncat( buffer, white, white_s );
+		}
+		for(x=0; x<margin; x++ ){
+			strncat( buffer, "  ", 2 );
+		}
+		strncat( buffer, "\033[0m\n", 5 );
+		fputs( buffer, fp );
+	}
+
+	/* bottom margin */
+	writeANSI_margin(fp, realwidth, buffer, buffer_s, white, white_s);
+
+	fclose(fp);
+	free(buffer);
+
+	return 0;
+}
+
+static void writeUTF8_margin(FILE* fp, int realwidth,
+			     const char* white, const char *reset,
+			     int use_ansi)
+{
+	int x, y;
+
+	for (y = 0; y < margin/2; y++) {
+		fputs(white, fp);
+		for (x = 0; x < realwidth; x++)
+			fputs("\342\226\210", fp);
+		fputs(reset, fp);
+		fputc('\n', fp);
+	}
+}
+
+static int writeUTF8(QRcode *qrcode, const char *outfile, int use_ansi)
+{
+	FILE *fp;
+	int x, y;
+	int realwidth;
+	unsigned char *p;
+	const char *white, *reset;
+
+	if (use_ansi){
+		white = "\033[40;37;1m";
+		reset = "\033[0m";
+	} else {
+		white = "";
+		reset = "";
+	}
+
+	fp = openFile(outfile);
+
+	realwidth = (qrcode->width + margin * 2);
+
+	/* top margin */
+	writeUTF8_margin(fp, realwidth, white, reset, use_ansi);
+
+	/* data */
+	p = qrcode->data;
+	for(y = 0; y < qrcode->width; y += 2) {
+		unsigned char *row1, *row2;
+		row1 = p + y*qrcode->width;
+		row2 = p + y*qrcode->width + qrcode->width;
+
+		fputs(white, fp);
+
+		for (x = 0; x < margin; x++)
+			fputs("\342\226\210", fp);
+
+		for (x = 0; x < qrcode->width; x++) {
+			if ((*(row1 + x) & 1) && (*(row2 + x) & 1))
+				fputc(' ', fp);
+			else if (*(row1 + x) & 1)
+				fputs("\342\226\204", fp);
+			else if (*(row2 + x) & 1)
+				fputs("\342\226\200", fp);
+			else
+				fputs("\342\226\210", fp);
+		}
+
+		for (x = 0; x < margin; x++)
+			fputs("\342\226\210", fp);
+
+		fputs(reset, fp);
+		fputc('\n', fp);
+	}
+
+	/* bottom margin */
+	writeUTF8_margin(fp, realwidth, white, reset, use_ansi);
+
+	fclose(fp);
+
+	return 0;
+}
+
+static void writeASCII_margin(FILE* fp, int realwidth, char* buffer, int buffer_s, int invert)
+{
+	int y, h;
+
+	h = margin;
+
+	memset(buffer, (invert?'#':' '), realwidth);
+	buffer[realwidth] = '\n';
+	buffer[realwidth + 1] = '\0';
+	for(y=0; y<h; y++ ){
+		fputs(buffer, fp);
+	}
+}
+
+static int writeASCII(QRcode *qrcode, const char *outfile, int invert)
+{
+	FILE *fp;
+	unsigned char *row;
+	int x, y;
+	int realwidth;
+	char *buffer, *p;
+	int buffer_s;
+	char black = '#';
+	char white = ' ';
+
+	if(invert) {
+		black = ' ';
+		white = '#';
+	}
+
+	size = 1;
+
+	fp = openFile(outfile);
+
+	realwidth = (qrcode->width + margin * 2) * 2;
+	buffer_s = realwidth + 1;
+	buffer = (char *)malloc( buffer_s );
+	if(buffer == NULL) {
+		fprintf(stderr, "Failed to allocate memory.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* top margin */
+	writeASCII_margin(fp, realwidth, buffer, buffer_s, invert);
+
+	/* data */
+	for(y=0; y<qrcode->width; y++) {
+		row = qrcode->data+(y*qrcode->width);
+		p = buffer;
+
+		memset(p, white, margin * 2);
+		p += margin * 2;
+
+		for(x=0; x<qrcode->width; x++) {
+			if(row[x]&0x1) {
+				*p++ = black;
+				*p++ = black;
+			} else {
+				*p++ = white;
+				*p++ = white;
+			}
+		}
+
+		memset(p, white, margin * 2);
+		p += margin * 2;
+		*p++ = '\n';
+		*p++ = '\0';
+		fputs( buffer, fp );
+	}
+
+	/* bottom margin */
+	writeASCII_margin(fp, realwidth, buffer, buffer_s, invert);
+
+	fclose(fp);
+	free(buffer);
+
+	return 0;
+}
+
+static QRcode *encode(const unsigned char *intext, int length)
+{
+	QRcode *code;
+
+	if(micro) {
+		if(eightbit) {
+			code = QRcode_encodeDataMQR(length, intext, version, level);
+		} else {
+			code = QRcode_encodeStringMQR((char *)intext, version, level, hint, casesensitive);
+		}
+	} else {
+		if(eightbit) {
+			code = QRcode_encodeData(length, intext, version, level);
+		} else {
+			code = QRcode_encodeString((char *)intext, version, level, hint, casesensitive);
+		}
+	}
+
+	return code;
+}
+
+static void qrencode(const unsigned char *intext, int length, const char *outfile)
+{
+	QRcode *qrcode;
+	
+	qrcode = encode(intext, length);
+	if(qrcode == NULL) {
+		perror("Failed to encode the input data");
+		exit(EXIT_FAILURE);
+	}
+	switch(image_type) {
+		case PNG_TYPE:
+			writePNG(qrcode, outfile);
+			break;
+		case EPS_TYPE:
+			writeEPS(qrcode, outfile);
+			break;
+		case SVG_TYPE:
+			writeSVG(qrcode, outfile);
+			break;
+		case ANSI_TYPE:
+		case ANSI256_TYPE:
+			writeANSI(qrcode, outfile);
+			break;
+		case ASCIIi_TYPE:
+			writeASCII(qrcode, outfile,  1);
+			break;
+		case ASCII_TYPE:
+			writeASCII(qrcode, outfile,  0);
+			break;
+		case UTF8_TYPE:
+			writeUTF8(qrcode, outfile, 0);
+			break;
+		case ANSIUTF8_TYPE:
+			writeUTF8(qrcode, outfile, 1);
+			break;
+		default:
+			fprintf(stderr, "Unknown image type.\n");
+			exit(EXIT_FAILURE);
+	}
+	QRcode_free(qrcode);
+}
+
+static QRcode_List *encodeStructured(const unsigned char *intext, int length)
+{
+	QRcode_List *list;
+
+	if(eightbit) {
+		list = QRcode_encodeDataStructured(length, intext, version, level);
+	} else {
+		list = QRcode_encodeStringStructured((char *)intext, version, level, hint, casesensitive);
+	}
+
+	return list;
+}
+
+static void qrencodeStructured(const unsigned char *intext, int length, const char *outfile)
+{
+	QRcode_List *qrlist, *p;
+	char filename[FILENAME_MAX];
+	char *base, *q, *suffix = NULL;
+	const char *type_suffix;
+	int i = 1;
+	size_t suffix_size;
+
+	switch(image_type) {
+		case PNG_TYPE:
+			type_suffix = ".png";
+			break;
+		case EPS_TYPE:
+			type_suffix = ".eps";
+			break;
+		case SVG_TYPE:
+			type_suffix = ".svg";
+			break;
+		case ANSI_TYPE:
+		case ANSI256_TYPE:
+		case ASCII_TYPE:
+		case UTF8_TYPE:
+		case ANSIUTF8_TYPE:
+			type_suffix = ".txt";
+			break;
+		default:
+			fprintf(stderr, "Unknown image type.\n");
+			exit(EXIT_FAILURE);
+	}
+
+	if(outfile == NULL) {
+		fprintf(stderr, "An output filename must be specified to store the structured images.\n");
+		exit(EXIT_FAILURE);
+	}
+	base = strdup(outfile);
+	if(base == NULL) {
+		fprintf(stderr, "Failed to allocate memory.\n");
+		exit(EXIT_FAILURE);
+	}
+	suffix_size = strlen(type_suffix);
+	if(strlen(base) > suffix_size) {
+		q = base + strlen(base) - suffix_size;
+		if(strcasecmp(type_suffix, q) == 0) {
+			suffix = strdup(q);
+			*q = '\0';
+		}
+	}
+	
+	qrlist = encodeStructured(intext, length);
+	if(qrlist == NULL) {
+		perror("Failed to encode the input data");
+		exit(EXIT_FAILURE);
+	}
+
+	for(p = qrlist; p != NULL; p = p->next) {
+		if(p->code == NULL) {
+			fprintf(stderr, "Failed to encode the input data.\n");
+			exit(EXIT_FAILURE);
+		}
+		if(suffix) {
+			snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix);
+		} else {
+			snprintf(filename, FILENAME_MAX, "%s-%02d", base, i);
+		}
+		switch(image_type) {
+			case PNG_TYPE: 
+				writePNG(p->code, filename);
+				break;
+			case EPS_TYPE: 
+				writeEPS(p->code, filename);
+				break;
+			case SVG_TYPE: 
+				writeSVG(p->code, filename);
+				break;
+			case ANSI_TYPE:
+			case ANSI256_TYPE:
+				writeANSI(p->code, filename);
+				break;
+			case ASCIIi_TYPE:
+				writeASCII(p->code, filename, 1);
+				break;
+			case ASCII_TYPE:
+				writeASCII(p->code, filename, 0);
+				break;
+			case UTF8_TYPE:
+				writeUTF8(p->code, filename, 0);
+				break;
+			case ANSIUTF8_TYPE:
+				writeUTF8(p->code, filename, 0);
+				break;
+
+			default:
+				fprintf(stderr, "Unknown image type.\n");
+				exit(EXIT_FAILURE);
+		}
+		i++;
+	}
+
+	free(base);
+	if(suffix) {
+		free(suffix);
+	}
+
+	QRcode_List_free(qrlist);
+}
+
+#ifndef ZOO_SERVICE_PROVIDER
+int main(int argc, char **argv)
+#else
+	extern "C" {
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int QREncode(maps*& conf, maps*& inputs, maps*& outputs)
+#endif
+{
+	int opt, lindex = -1;
+	char *outfile = NULL;
+	unsigned char *intext = NULL;
+	int length = 0;
+
+#ifndef ZOO_SERVICE_PROVIDER
+	while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
+		switch(opt) {
+			case 'h':
+				if(lindex == 0) {
+					usage(1, 1);
+				} else {
+					usage(1, 0);
+				}
+				exit(EXIT_SUCCESS);
+				break;
+			case 'o':
+				outfile = optarg;
+				break;
+			case 's':
+				size = atoi(optarg);
+				if(size <= 0) {
+					fprintf(stderr, "Invalid size: %d\n", size);
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 'v':
+				version = atoi(optarg);
+				if(version < 0) {
+					fprintf(stderr, "Invalid version: %d\n", version);
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 'l':
+				switch(*optarg) {
+					case 'l':
+					case 'L':
+						level = QR_ECLEVEL_L;
+						break;
+					case 'm':
+					case 'M':
+						level = QR_ECLEVEL_M;
+						break;
+					case 'q':
+					case 'Q':
+						level = QR_ECLEVEL_Q;
+						break;
+					case 'h':
+					case 'H':
+						level = QR_ECLEVEL_H;
+						break;
+					default:
+						fprintf(stderr, "Invalid level: %s\n", optarg);
+						exit(EXIT_FAILURE);
+						break;
+				}
+				break;
+			case 'm':
+				margin = atoi(optarg);
+				if(margin < 0) {
+					fprintf(stderr, "Invalid margin: %d\n", margin);
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 'd':
+				dpi = atoi(optarg);
+				if( dpi < 0 ) {
+					fprintf(stderr, "Invalid DPI: %d\n", dpi);
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 't':
+				if(strcasecmp(optarg, "png") == 0) {
+					image_type = PNG_TYPE;
+				} else if(strcasecmp(optarg, "eps") == 0) {
+					image_type = EPS_TYPE;
+				} else if(strcasecmp(optarg, "svg") == 0) {
+					image_type = SVG_TYPE;
+				} else if(strcasecmp(optarg, "ansi") == 0) {
+					image_type = ANSI_TYPE;
+				} else if(strcasecmp(optarg, "ansi256") == 0) {
+					image_type = ANSI256_TYPE;
+				} else if(strcasecmp(optarg, "asciii") == 0) {
+					image_type = ASCIIi_TYPE;
+				} else if(strcasecmp(optarg, "ascii") == 0) {
+					image_type = ASCII_TYPE;
+				} else if(strcasecmp(optarg, "utf8") == 0) {
+					image_type = UTF8_TYPE;
+				} else if(strcasecmp(optarg, "ansiutf8") == 0) {
+					image_type = ANSIUTF8_TYPE;
+				} else {
+					fprintf(stderr, "Invalid image type: %s\n", optarg);
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 'S':
+				structured = 1;
+			case 'k':
+				hint = QR_MODE_KANJI;
+				break;
+			case 'c':
+				casesensitive = 1;
+				break;
+			case 'i':
+				casesensitive = 0;
+				break;
+			case '8':
+				eightbit = 1;
+				break;
+			case 'M':
+				micro = 1;
+				break;
+			case 'f':
+				if(color_set(fg_color, optarg)) {
+					fprintf(stderr, "Invalid foreground color value.\n");
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 'b':
+				if(color_set(bg_color, optarg)) {
+					fprintf(stderr, "Invalid background color value.\n");
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 'V':
+				usage(0, 0);
+				exit(EXIT_SUCCESS);
+				break;
+			default:
+				fprintf(stderr, "Try `qrencode --help' for more information.\n");
+				exit(EXIT_FAILURE);
+				break;
+		}
+	}
+
+	if(argc == 1) {
+		usage(1, 0);
+		exit(EXIT_SUCCESS);
+	}
+
+	if(outfile == NULL && image_type == PNG_TYPE) {
+		fprintf(stderr, "No output filename is given.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if(optind < argc) {
+		intext = (unsigned char *)argv[optind];
+		length = strlen((char *)intext);
+	}
+	if(intext == NULL) {
+		intext = readStdin(&length);
+	}
+#else
+	outfile=(char*)malloc(1024*sizeof(char));
+	map *tmpMap=getMapFromMaps(conf,"main","tmpPath");
+	sprintf(outfile,"%s/qr_%d.png",tmpMap->value,getpid());
+	tmpMap=getMapFromMaps(inputs,"Text","value");
+	intext=(unsigned char*)tmpMap->value;
+	dpi = 92;
+	level = QR_ECLEVEL_H;
+	map* tmp1=getMapFromMaps(inputs,"size","value");
+	if(tmp1!=NULL)
+		size = atoi(tmp1->value);
+	tmp1=getMapFromMaps(inputs,"bgcolor","value");
+	if(tmp1!=NULL && color_set(bg_color, tmp1->value)){
+		setMapInMaps(conf,"lenv","message","Unable to parse bgcolor settings");
+		return SERVICE_FAILED;
+	}
+	tmp1=getMapFromMaps(inputs,"fgcolor","value");
+	if(tmp1!=NULL && color_set(fg_color, tmp1->value)){
+		setMapInMaps(conf,"lenv","message","Unable to parse fgcolor settings");
+		return SERVICE_FAILED;
+	}
+#endif
+	
+	if(micro && version > MQRSPEC_VERSION_MAX) {
+		fprintf(stderr, "Version should be less or equal to %d.\n", MQRSPEC_VERSION_MAX);
+		exit(EXIT_FAILURE);
+	} else if(!micro && version > QRSPEC_VERSION_MAX) {
+		fprintf(stderr, "Version should be less or equal to %d.\n", QRSPEC_VERSION_MAX);
+		exit(EXIT_FAILURE);
+	}
+
+	if(margin < 0) {
+		if(micro) {
+			margin = 2;
+		} else {
+			margin = 4;
+		}
+	}
+
+	if(micro) {
+		if(version == 0) {
+			fprintf(stderr, "Version must be specified to encode a Micro QR Code symbol.\n");
+			exit(EXIT_FAILURE);
+		}
+		if(structured) {
+			fprintf(stderr, "Micro QR Code does not support structured symbols.\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if(structured) {
+		if(version == 0) {
+			fprintf(stderr, "Version must be specified to encode structured symbols.\n");
+			exit(EXIT_FAILURE);
+		}
+		qrencodeStructured(intext, length, outfile);
+	} else {
+		qrencode(intext, length, outfile);
+	}
+
+#ifdef ZOO_SERVICE_PROVIDER
+	FILE * fichier=fopen(outfile,"rb");
+	fseek(fichier, 0, SEEK_END);
+	long count = ftell(fichier);
+	rewind(fichier);
+	
+	struct stat file_status;
+	stat(outfile, &file_status);
+	if(fichier==NULL){
+		fprintf(stderr,"Failed to open file %s for reading purpose.\n",outfile);
+		setMapInMaps(conf,"lenv","message","Unable to read produced file. Please try again later");
+		return SERVICE_FAILED;
+	}
+
+	maps* tmp=getMaps(outputs,"QR");
+	map* tmpMap1=getMapFromMaps(outputs,"QR","value");
+	if(tmpMap1==NULL){
+		addToMap(outputs->content,"value","null");
+		tmpMap1=getMapFromMaps(outputs,"QR","value");
+	}
+	free(tmpMap1->value);
+	tmpMap1->value=(char*) malloc((count+1)*sizeof(char));  
+	fread(tmpMap1->value,1,count*sizeof(char),fichier);
+	fclose(fichier);
+	unlink(outfile);
+
+	char rsize[100];
+	sprintf(rsize,"%d",count*sizeof(char));
+	addToMap(tmpMap1,"size",rsize);  
+	return SERVICE_SUCCEEDED;
+#endif
+
+	return 0;
+}
+#ifdef ZOO_SERVICE_PROVIDER
+	}
+#endif
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/Makefile	(revision 942)
@@ -0,0 +1,14 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+
+cgi-env/wps_hpc.zo: service.c service2.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/wps_hpc.zo service.c service2.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} ${FCGI_LDFLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service ${ZRPATH}/zoo-kernel/sshapi.o ${HPCLDFLAGS}
+
+install:
+	install -d ${CGI_DIR}
+	install cgi-env/*.zcfg ${CGI_DIR}/
+	install cgi-env/*.zo ${CGI_DIR}/
+
+clean:
+	rm -f cgi-env/wps_hpc.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/DeleteData.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/DeleteData.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/DeleteData.zcfg	(revision 942)
@@ -0,0 +1,50 @@
+[DeleteData]
+ Title = Delete the data associated with an input or an output
+ Abstract = Delete the data associated with an input or an output
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_hpc.zo
+ serviceType = C
+ <DataInputs>
+  [jobid]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+  [filename]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+  [ioname]
+   Title = the input / output name
+   Abstract = the input / output name
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The resulting message string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC.zcfg	(revision 942)
@@ -0,0 +1,30 @@
+[FinalizeHPC]
+ Title = Start phase 3 of HPC execution
+ Abstract = Unblock the ZOO-Kernel awaiting for a remote job execution 
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_hpc.zo
+ serviceType = C
+ <DataInputs>
+  [JobId]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The hello string
+   Abstract = The Hello message string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC1.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC1.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/cgi-env/FinalizeHPC1.zcfg	(revision 942)
@@ -0,0 +1,30 @@
+[FinalizeHPC1]
+ Title = Start phase 3 of HPC execution
+ Abstract = Unblock the ZOO-Kernel awaiting for a remote job execution 
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_hpc.zo
+ serviceType = C
+ <DataInputs>
+  [JobId]
+   Title = the image
+   Abstract = The image to process
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = The resulting string
+   Abstract = The message returned by the service execution as a string.
+   <LiteralOutput>
+    DataType = string
+    <Default>
+    </Default>
+   </LiteralOutput>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/service.c	(revision 942)
@@ -0,0 +1,363 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "service.h"
+#include "service_internal.h"
+#include "sshapi.h"
+#include "server_internal.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <dirent.h>
+extern "C" {
+
+  /**
+   * FinalizeHPC ZOO Service :
+   * This service is used to inform a ZOO-Kernel waiting for the end of the
+   * execution of a HPC service
+   */
+  ZOO_DLL_EXPORT int FinalizeHPC(maps*& conf,maps*& inputs,maps*& outputs){
+    // Retrieve the jobid corresponding to the identifier generated by SLURM
+    // by reading the file generated when running the SBATCH file
+    map* jobid=getMapFromMaps(inputs,"jobid","value");
+    struct sockaddr_un addr;
+    char buf[100]="3";
+    int fd,rc=NULL;
+    int i=0;
+    map* usid=getMapFromMaps(conf,"lenv","usid");
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+
+    char *flenv =
+      (char *) malloc ((strlen (tmpPath->value) + 
+			strlen (jobid->value) + 12) * sizeof (char));
+    sprintf (flenv, "%s/%s_lenv.cfg", tmpPath->value, jobid->value);
+    maps* m = (maps *) malloc (MAPS_SIZE);
+    m->child=NULL;
+    m->next=NULL;
+    map* configId=NULL;
+
+    
+    if(conf_read(flenv, m) != 2){
+      configId=getMapFromMaps(m,"lenv","configId");
+      setMapInMaps(conf,"lenv","configId",configId->value);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("Unable to read the lenv section file of the requested jobid"));
+      return SERVICE_FAILED;
+    }
+    
+    SSHCON *test=ssh_connect(conf);
+    /*if(test==NULL){
+      setMapInMaps(conf,"lenv","message",_("Unable to connect using ssh."));
+      return SERVICE_FAILED;
+      }*/
+
+    char *logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+12)*sizeof(char));
+    sprintf(logPath,"%s/exec_out_%s",tmpPath->value,jobid->value);
+    struct stat f_status;
+    int ts=stat(logPath, &f_status);
+    char* fcontent = NULL;
+    if(ts==0) {
+      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(logPath,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("No service with this jobid can be found"));
+      return SERVICE_FAILED;
+    }
+    free(logPath);
+    // Run scontrol to check if the service execution ended.
+    // Store all the informations returned by scontrol command as a cfg file to
+    // be parsed back by the ZOO-Kernel waiting for the execution of the remote
+    // service
+    maps* tmpMaps=createMaps("henv");
+    char* command=(char*)malloc((126)*sizeof(char));
+    sprintf(command,"scontrol show jobid | grep -A24 JobId=%s",fcontent);    
+    if(ssh_exec(conf,command,ssh_get_cnt(conf))==0){
+      free(command);
+      setMapInMaps(conf,"lenv","message",_("Failed to run scontrol remotely"));
+      // TODO: check status in db and if available continue in other case return SERVICE_FAILED
+      return SERVICE_FAILED;
+    }else{
+      free(command);
+      logPath=(char*)malloc((strlen(tmpPath->value)+strlen(usid->value)+11)*sizeof(char));
+      sprintf(logPath,"%s/exec_out_%s",tmpPath->value,usid->value);
+      int ts=stat(logPath, &f_status);
+      if(ts==0) {
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(logPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	int fsize=f_status.st_size;
+	fcontent[fsize]=0;
+	fclose(f);
+	free(logPath);
+	char *token, *saveptr;
+	token = strtok_r (fcontent, " ", &saveptr);
+	while (token != NULL)
+	  {
+	    char *token1, *saveptr1;
+	    char *tmpToken=strdup(token);
+	    token1 = strtok_r (tmpToken, "=", &saveptr1);
+	    int isNext=-1;
+	    int hasTwoElements=0;
+	    char *name=NULL;
+	    while (token1 != NULL)
+	      {
+		if(hasTwoElements==0)
+		  name=strdup(token1);
+		if(hasTwoElements<1)
+		  hasTwoElements+=1;
+		else{
+		  char *value=strdup(token1);
+		  if(value[strlen(value)-1]=='\n')
+		    value[strlen(value)-1]=0;
+		  if(strlen(name)>0 && strlen(value)>0){
+		    if(tmpMaps->content==NULL)
+		      tmpMaps->content=createMap(name,value);
+		    else
+		      addToMap(tmpMaps->content,name,value);
+		    free(value);
+		  }
+		  free(name);
+		  hasTwoElements=0;
+		}
+		token1 = strtok_r (NULL, "=", &saveptr1);
+	      }
+	    free(tmpToken);
+	    token = strtok_r (NULL, " ", &saveptr);
+	  }
+      }else{
+	setMapInMaps(conf,"lenv","message",_("Unable to access the downloaded execution log file"));
+	return SERVICE_FAILED;
+      }
+    }
+    logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+15)*sizeof(char));
+    sprintf(logPath,"%s/exec_status_%s",tmpPath->value,jobid->value);
+    dumpMapsToFile(tmpMaps,logPath,0);
+    char *sname=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+21));
+    sprintf(sname,"%s/.wait_socket_%s.sock",tmpPath->value,jobid->value);
+    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+      perror("socket error");
+      setMapInMaps(conf,"lenv","message",_("Socket error"));
+      return SERVICE_FAILED;
+    }
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, sname, sizeof(addr.sun_path)-1);
+    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+      perror("connect error");
+      setMapInMaps(conf,"lenv","message",_("Unable to connect"));
+      return SERVICE_FAILED;
+    }
+    if (write(fd, "3", 1) != rc) {
+      if (rc < 0) {
+	perror("write error");
+	setMapInMaps(conf,"lenv","message",_("Unable to announce the successful execution of the HPC service"));
+	close(fd);
+	return SERVICE_FAILED;
+      }
+    }
+    close(fd);
+    setOutputValue(outputs,"Result",(char*)"\"FinalizeHPC run successfully\"",32);
+    unlink(flenv);
+    free(flenv);
+
+    return SERVICE_SUCCEEDED;
+  }
+
+
+  /**
+   * FinalizeHPC1 ZOO Service :
+   * This service is used to inform a ZOO-Kernel waiting for the end of the
+   * execution of a HPC service
+   *
+   * format="AllocCPUS"; for i in $(sacct -e) ; do format="$format,$i"; done; format="$(echo $format | sed "s:AllocCPUS,::")" ; echo $format; sacct --format=$format -p | grep "997f-11e8-9f78-0050569320d2" 
+   *
+   * AllocCPUS,AllocGRES,AllocNodes,AllocTRES,Account,AssocID,AveCPU,AveCPUFreq,AveDiskRead,AveDiskWrite,AvePages,AveRSS,AveVMSize,BlockID,Cluster,Comment,ConsumedEnergy,ConsumedEnergyRaw,CPUTime,CPUTimeRAW,DerivedExitCode,Elapsed,Eligible,End,ExitCode,GID,Group,JobID,JobIDRaw,JobName,Layout,MaxDiskRead,MaxDiskReadNode,MaxDiskReadTask,MaxDiskWrite,MaxDiskWriteNode,MaxDiskWriteTask,MaxPages,MaxPagesNode,MaxPagesTask,MaxRSS,MaxRSSNode,MaxRSSTask,MaxVMSize,MaxVMSizeNode,MaxVMSizeTask,MinCPU,MinCPUNode,MinCPUTask,NCPUS,NNodes,NodeList,NTasks,Priority,Partition,QOS,QOSRAW,ReqCPUFreq,ReqCPUFreqMin,ReqCPUFreqMax,ReqCPUFreqGov,ReqCPUS,ReqGRES,ReqMem,ReqNodes,ReqTRES,Reservation,ReservationId,Reserved,ResvCPU,ResvCPURAW,Start,State,Submit,Suspended,SystemCPU,Timelimit,TotalCPU,UID,User,UserCPU,WCKey,WCKeyID
+   * 28||1|cpu=28,node=1|geosud|258|||||||||cluster||||00:00:56|56|0:0|00:00:02|2018-08-06T15:48:13|2018-08-06T15:48:16|0:0|1019|geosud|883299|883299|ZOO-Project_5bd1c32b-997f-11e8-9f78-0050569320d2_GSDBandMath_6_2_005||||||||||||||||||||28|1|muse044||4294360886|defq|qos_geosud|20|Unknown|Unknown|Unknown|Unknown|1||0n|1|cpu=1,node=1|||00:00:01|00:00:01|1|2018-08-06T15:48:14|COMPLETED|2018-08-06T15:48:13|00:00:00||UNLIMITED|00:00:00|1229|geosudwps|||0|
+   * 
+   */
+  ZOO_DLL_EXPORT int FinalizeHPC1(maps*& conf,maps*& inputs,maps*& outputs){
+    // Retrieve the jobid corresponding to the identifier generated by SLURM
+    // by reading the file generated when running the SBATCH file
+    map* jobid=getMapFromMaps(inputs,"jobid","value");
+    struct sockaddr_un addr;
+    char buf[100]="3";
+    int fd,rc=NULL;
+    int i=0;
+    map* usid=getMapFromMaps(conf,"lenv","usid");
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+
+    char *flenv =
+      (char *) malloc ((strlen (tmpPath->value) + 
+			strlen (jobid->value) + 12) * sizeof (char));
+    sprintf (flenv, "%s/%s_lenv.cfg", tmpPath->value, jobid->value);
+    maps* m = (maps *) malloc (MAPS_SIZE);
+    m->child=NULL;
+    m->next=NULL;
+    map* configId=NULL;
+
+    
+    if(conf_read(flenv, m) != 2){
+      configId=getMapFromMaps(m,"lenv","configId");
+      setMapInMaps(conf,"lenv","configId",configId->value);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("Unable to read the lenv section file of the requested jobid"));
+      return SERVICE_FAILED;
+    }
+
+    SSHCON *test=ssh_connect(conf);
+    /*if(test==NULL){
+      setMapInMaps(conf,"lenv","message",_("Unable to connect using ssh."));
+      return SERVICE_FAILED;
+      }*/
+
+    char *logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+12)*sizeof(char));
+    sprintf(logPath,"%s/exec_out_%s",tmpPath->value,jobid->value);
+    struct stat f_status;
+    int ts=stat(logPath, &f_status);
+    char* fcontent = NULL;
+    if(ts==0) {
+      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(logPath,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      int fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+    }else{
+      setMapInMaps(conf,"lenv","message",_("No service with this jobid can be found"));
+      return SERVICE_FAILED;
+    }
+    free(logPath);
+    // Run sacct to check if the service execution ended.
+    // Store all the informations returned by scontrol command as a cfg file to
+    // be parsed back by the ZOO-Kernel waiting for the execution of the remote
+    // service
+    maps* tmpMaps=createMaps("henv");
+    
+    map* tmpMap=getMapFromMaps(conf,configId->value,"remote_command_opt");
+    char* command=(char*)malloc((126+strlen(tmpMap->value))*sizeof(char));
+    sprintf(command,"sacct --format=%s -p | grep \"%s\" | sed \"s:||:|None|:g;s:||:|None|:g\"",tmpMap->value,jobid->value);    
+    if(ssh_exec(conf,command,ssh_get_cnt(conf))==0){
+      free(command);
+      setMapInMaps(conf,"lenv","message",_("Failed to run sacct remotely"));
+      // TODO: check status in db and if available continue in other case return SERVICE_FAILED
+      return SERVICE_FAILED;
+    }else{
+      free(command);
+      logPath=(char*)malloc((strlen(tmpPath->value)+strlen(usid->value)+11)*sizeof(char));
+      sprintf(logPath,"%s/exec_out_%s",tmpPath->value,usid->value);
+      int ts=stat(logPath, &f_status);
+      if(ts==0) {
+	fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+	FILE* f=fopen(logPath,"rb");
+	fread(fcontent,f_status.st_size,1,f);
+	int fsize=f_status.st_size;
+	fcontent[fsize]=0;
+	fclose(f);
+	free(logPath);
+	char *token, *saveptr;
+	char *token1, *saveptr1;
+	token = strtok_r (tmpMap->value, ",", &saveptr);
+	token1 = strtok_r (fcontent, "|", &saveptr1);
+	while (token != NULL) {
+	  fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,token);
+	  fflush(stderr);
+	  fprintf(stderr,"%s %d %s %s \n",__FILE__,__LINE__,token,token1);
+	  fflush(stderr);
+	  if(token1 != NULL){
+	    if(tmpMaps->content==NULL)
+	      tmpMaps->content=createMap(token,token1);
+	    else
+	      addToMap(tmpMaps->content,token,token1);
+	  }
+	  token = strtok_r (NULL, ",", &saveptr);
+	  token1 = strtok_r (NULL, "|", &saveptr1);
+	}
+      }else{
+	free(logPath);
+	setMapInMaps(conf,"lenv","message",_("Unable to access the downloaded execution log file"));
+	return SERVICE_FAILED;
+      }
+    }
+    tmpMap=getMapFromMaps(tmpMaps,"henv","JobId");
+    if(tmpMap!=NULL){
+      char* tmpStr=(char*)malloc((32)*sizeof(char));
+      sprintf(tmpStr,"slurm-%s.out",tmpMap->value);
+      addToMap(tmpMaps->content,"StdErr",tmpStr); 
+      free(tmpStr);
+    }
+    logPath=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+15)*sizeof(char));
+    sprintf(logPath,"%s/exec_status_%s",tmpPath->value,jobid->value);
+    dumpMapsToFile(tmpMaps,logPath,0);
+    char *sname=(char*)malloc((strlen(tmpPath->value)+strlen(jobid->value)+21));
+    sprintf(sname,"%s/.wait_socket_%s.sock",tmpPath->value,jobid->value);
+    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+      perror("socket error");
+      setMapInMaps(conf,"lenv","message",_("Socket error"));
+      return SERVICE_FAILED;
+    }
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, sname, sizeof(addr.sun_path)-1);
+    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+      perror("connect error");
+      setMapInMaps(conf,"lenv","message",_("Unable to connect"));
+      return SERVICE_FAILED;
+    }
+    if (write(fd, "3", 1) != rc) {
+      if (rc < 0) {
+	perror("write error");
+	setMapInMaps(conf,"lenv","message",_("Unable to announce the successful execution of the HPC service"));
+	close(fd);
+	return SERVICE_FAILED;
+      }
+    }
+    close(fd);
+    unlink(flenv);
+    free(flenv);
+    setOutputValue(outputs,"Result",(char*)"\"FinalizeHPC run successfully\"",32);
+
+    return SERVICE_SUCCEEDED;
+  }
+  
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/service2.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/service2.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/hpc/service2.c	(revision 942)
@@ -0,0 +1,270 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2017 GeoLabs SARL. All rights reserved.
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * This work was supported by public funds received in the framework of GEOSUD,
+ * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
+ * by the French National Research Agency
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "service.h"
+#include "service_internal.h"
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <dirent.h>
+#include <string.h>
+#include <cerrno>
+
+extern "C" {
+
+  /** 
+   * Retrieve the error message which occured when trying to remove a file
+   * (return values can be EACCES, EBUSY, EFAULT, EIO, EISDIR, ELOOP, 
+   * ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EPERM, EROFS, UNKNOWN).
+   *
+   * @param errn
+   * @result a string corresponding to the error number 
+   */ 
+  char* fetchErrno(int errn){
+   switch(errn){
+    case EACCES:
+	return "EACCES";
+    case EBUSY:
+	return "EBUSY";
+    case EFAULT:
+	return "EFAULT";
+    case EIO:
+	return "EIO";
+    case EISDIR:
+	return "EISDIR";
+    case ELOOP:
+	return "ELOOP";
+    case ENAMETOOLONG:
+	return "ENAMETOOLONG";
+    case ENOENT:
+	return "ENOENT";
+    case ENOMEM:
+	return "ENOMEM";
+    case ENOTDIR:
+	return "ENOTDIR";
+    case EPERM:
+	return "EPERM";
+    case EROFS:
+	return "EROFS";
+    default:
+	return "UNKNOWN";
+   }
+  }
+
+  /**
+   * Try to delete a cache file.
+   * 
+   * @param storage the full path to store the file
+   * @param filename the filename to store
+   * @param ext the extention of the file
+   * @return 0 in case of success
+   */
+  int tryDeleteCacheFile(const char* storage,const char* filename,const char* ext){
+    char *filename_noext=(char*)malloc((strlen(filename)-3)*sizeof(char));
+    snprintf(filename_noext,strlen(filename)-4,"%s",filename);
+    char* filename_full=(char*)malloc((strlen(filename)+1)*sizeof(char));
+    sprintf(filename_full,"%s.%s",filename_noext,ext);
+    char* fullpath=(char*)malloc((strlen(storage)+strlen(filename_full)+2)*sizeof(char));
+    sprintf(fullpath,"%s/%s",storage,filename_full);
+    if(unlink(fullpath)==0){
+      // TODO store the filename_full in the deletedfiles
+      fprintf(stderr,"#### DeleteData #### %s %d %s has been successfully deleted\n",__FILE__,__LINE__,filename_full);
+    }else{
+      fprintf(stderr,"#### DeleteData #### unable to delete %s \n",fullpath);
+    }
+    free(fullpath);
+    free(filename_full);
+    return 0;
+  }  
+
+  /**
+   * Try to delete a data file.
+   * 
+   * @param storage the full path to store the file
+   * @param filename the filename to store
+   * @return 0 in case of success
+   */
+  int tryDeleteDataFile(const char* storage,const char* filename){
+    char* fullpath=NULL;
+    if(filename!=NULL){
+      fullpath=(char*)malloc((strlen(storage)+strlen(filename)+2)*sizeof(char));
+      sprintf(fullpath,"%s/%s",storage,filename);
+    }
+    else
+      fullpath=zStrdup(storage);
+    if(unlink(fullpath)==0){
+      // TODO store the filename_full in the deletedfiles
+      fprintf(stderr,"#### DeleteData #### %s %d %s has been successfully deleted\n",__FILE__,__LINE__,(filename!=NULL && strlen(filename)>0?filename:fullpath));
+    }else{
+      fprintf(stderr,"#### DeleteData #### unable to delete %s %s \n",fullpath,fetchErrno(errno));
+    }
+    free(fullpath);
+    return 0;
+  }  
+  
+  
+  /**
+   * DeleteData ZOO-Service :
+   * This service is used in the ZOO-Project to delete the data file
+   * associated with input or output.
+   */
+  ZOO_DLL_EXPORT int DeleteData(maps*& conf,maps*& inputs,maps*& outputs){
+    map* dataPath=getMapFromMaps(conf,"main","dataPath");
+    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
+    map* cacheDir=getMapFromMaps(conf,"main","cacheDir");
+    map* jobid=getMapFromMaps(inputs,"jobid","value");
+    map* filename=getMapFromMaps(inputs,"filename","value");
+    map* ioname=getMapFromMaps(inputs,"ioname","value");
+    char tmp0[4];
+    sprintf(tmp0,"%c%c%c",filename->value[strlen(filename->value)-3],filename->value[strlen(filename->value)-2],filename->value[strlen(filename->value)-1]);
+    char *cfilename=NULL;
+    if(strcasecmp(tmp0,"zca")==0){
+      cfilename=(char*) malloc((strlen(filename->value)+strlen(cacheDir->value)+2)*sizeof(char));
+      sprintf(cfilename,"%s/%s",cacheDir->value,filename->value);
+    }
+    else{
+      cfilename=(char*) malloc((strlen(filename->value)+strlen(tmpPath->value)+2)*sizeof(char));
+      sprintf(cfilename,"%s/%s",tmpPath->value,filename->value);
+    }
+    zooLock* lck=lockFile(conf,cfilename,'w');
+    char** deletedfiles;
+    if(lck!=NULL){
+      if(strcasecmp(tmp0,"zca")==0){
+	// Read the zcp file to verify if it comes from a shared source
+	char *filename_noext=(char*)malloc((strlen(filename->value)-3)*sizeof(char));
+	snprintf(filename_noext,strlen(filename->value)-4,"%s",filename->value);
+	char* filename_full=(char*)malloc((strlen(filename->value)+1)*sizeof(char));
+	sprintf(filename_full,"%s.zcp",filename_noext);
+	char* fullpath=(char*)malloc((strlen(cacheDir->value)+strlen(filename_full)+2)*sizeof(char));
+	sprintf(fullpath,"%s/%s",cacheDir->value,filename_full);
+	FILE* f0=fopen(fullpath,"rb");
+	char *fcontent=NULL;
+	if(f0!=NULL){
+	  long flen;
+	  fseek (f0, 0, SEEK_END);
+	  flen = ftell (f0);
+	  fseek (f0, 0, SEEK_SET);
+	  fcontent = (char *) malloc ((flen + 1) * sizeof (char));
+	  fread(fcontent,flen,1,f0);
+	  fcontent[flen]=0;
+	  fclose(f0);
+	}
+	if(fcontent!=NULL && strcasecmp(fcontent,"SHARED")!=0){
+	  // Delete associated zcm, zcp and maps files
+	  tryDeleteCacheFile(cacheDir->value,filename->value,"zca");
+	  tryDeleteCacheFile(cacheDir->value,filename->value,"zcm");
+	  tryDeleteCacheFile(cacheDir->value,filename->value,"zcp");
+	  tryDeleteCacheFile(tmpPath->value,filename->value,"maps");
+	  // Delete <input>_<sid>.map
+	  char* datafile=(char*)malloc((strlen(jobid->value)+strlen(ioname->value)+19)*sizeof(char));
+	  sprintf(datafile,"%s_%s.map",ioname->value,jobid->value);
+	  tryDeleteDataFile(dataPath->value,datafile);
+	  free(datafile);
+	}else{
+	  setMapInMaps(conf,"lenv","message",_ss("The file you try to delete is a shared ressource and cannot be deleted by nature."));
+	  unlockFile(conf,lck);
+	  return SERVICE_FAILED;
+	}
+	setMapInMaps(outputs,"Result","value",_ss("The input data has been correclty removed"));
+      }else{
+	char tmp1[8];
+	snprintf(tmp1,7,"%s",filename->value);
+	if(strcasecmp(tmp1,"output")==0 || strstr(filename->value,".zca")!=NULL || strcasecmp(tmp1,"input_")==0){
+	  tryDeleteDataFile(tmpPath->value,filename->value);
+          char *tmp=zStrdup(filename->value);
+	  tmp[strlen(tmp)-strlen(strrchr(tmp,'.'))]=0;
+	  char *mapsfile=(char*)malloc((strlen(tmp)+6)*sizeof(char));
+	  sprintf(mapsfile,"%s.maps",tmp);
+          char* mapPath=(char*)malloc((strlen(tmpPath->value)+strlen(mapsfile)+2)*sizeof(char));
+          sprintf(mapPath,"%s/%s",tmpPath->value,mapsfile);
+	  FILE* myMapsfile=fopen(mapPath,"r");
+          if(myMapsfile!=NULL){
+	    char *buffer=(char*)malloc(1024*sizeof(char));
+	    while(fgets(buffer, 1024, myMapsfile) != NULL){
+	      buffer[strlen(buffer)-1]=0;
+	      tryDeleteDataFile(buffer,NULL);
+	    }
+	    free(buffer);
+	    fclose(myMapsfile);
+          }
+          tryDeleteDataFile(mapPath,NULL);
+          free(mapPath);
+          free(mapsfile);
+	  // Delete ZOO_DATA_<output>_<sid>.data and <output>_<sid>.map
+	  char* datafile=(char*)malloc((strlen(jobid->value)+strlen(ioname->value)+19)*sizeof(char));
+	  sprintf(datafile,"ZOO_DATA_%s_%s.data",ioname->value,jobid->value);
+	  tryDeleteDataFile(dataPath->value,datafile);
+	  free(datafile);
+	  datafile=(char*)malloc((strlen(jobid->value)+strlen(ioname->value)+19)*sizeof(char));
+	  sprintf(datafile,"%s_%s.map",ioname->value,jobid->value);
+	  tryDeleteDataFile(dataPath->value,datafile);
+	  free(datafile);
+	  char* webServices[3]={"wms","wfs","wcs"};
+	  int i=0;
+	  // Delete ZOO_DATA_<ws>_link_<sid>.data and <ws>_link_<sid>.map
+	  // with <ws> is the corresponding OGC web service (wms,wfs,wcs)
+	  for(i=0;i<3;i++){
+	    datafile=(char*)malloc((strlen(jobid->value)+24)*sizeof(char));
+	    sprintf(datafile,"ZOO_DATA_%s_link_%s.data",webServices[i],jobid->value);
+	    tryDeleteDataFile(dataPath->value,datafile);
+	    free(datafile);
+	    datafile=(char*)malloc((strlen(jobid->value)+14)*sizeof(char));
+	    sprintf(datafile,"%s_link_%s.map",webServices[i],jobid->value);
+	    tryDeleteDataFile(dataPath->value,datafile);
+	    free(datafile);
+	  }
+	  setMapInMaps(outputs,"Result","value",_ss("The output data has been correclty removed"));
+	}else{
+	  setMapInMaps(conf,"lenv","message",_ss("The file you try to delete is nor an input, nor an output."));
+	  unlockFile(conf,lck);
+	  return SERVICE_FAILED;
+	}
+      }
+      unlockFile(conf,lck);
+    }
+    else{
+      setMapInMaps(conf,"lenv","message",_ss("Failed to acquire lock for deletion, please try again later."));
+      return SERVICE_FAILED;
+    }
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/Makefile	(revision 942)
@@ -0,0 +1,24 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+ZCFLAGS=-I${ZRPATH}/zoo-kernel/ ${CFLAGS} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+
+YAML_FILES=""
+ifeq ("${YAML_FILE}","")
+else
+	YAML_FILES="${ZRPATH}/zoo-kernel/${YAML_FILE}"
+endif
+
+MS_FILES=""
+ifeq ("${MS_FILE}","")
+else
+	MS_FILES="${ZRPATH}/zoo-kernel/${MS_FILE}"
+endif
+
+cgi-env/wps_registry.zo: service.c
+	g++ ${ZCFLAGS} -shared -fpic -o cgi-env/wps_registry.zo ./service.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} -lfcgi -L${ZRPATH}/zoo-kernel/ -lzoo_service ${ZRPATH}/zoo-kernel/server_internal.o ${ZRPATH}/zoo-kernel/lex.cr.o ${ZRPATH}/zoo-kernel/lex.sr.o ${ZRPATH}/zoo-kernel/service_conf.tab.o ${ZRPATH}/zoo-kernel/main_conf_read.tab.o ${ZRPATH}/zoo-kernel/response_print.o ${YAML_FILES} ${MS_FILES} ${MS_LDFLAGS} ${YAML_LDFLAGS}
+
+install:
+	install -d ${CGI_DIR}
+	install cgi-env/* ${CGI_DIR}/
+clean:
+	rm -f cgi-env/wps_registry.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/cgi-env/GetFromRegistry.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/cgi-env/GetFromRegistry.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/cgi-env/GetFromRegistry.zcfg	(revision 942)
@@ -0,0 +1,36 @@
+[GetFromRegistry]
+ Title = Provide access to the Profile Registry
+ Abstract = Return a GenericProcess, Process or simple Concept based on the profiles registry
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_registry.zo
+ serviceType = C
+ <DataInputs>
+  [id]
+   Title = The registry path
+   Abstract = The profiles registry path
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = integer
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = the GenericProcess, Process or Concept
+   Abstract = The resulting GenericProcess, Process or Concept
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/wps/2.0/wps.xsd
+    </Default>
+    <Supported>
+     mimeType = text/plain
+     encoding = UTF-8
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/makefile.vc	(revision 942)
@@ -0,0 +1,25 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/libzoo_service.lib $(ZOOK_DIR)/server_internal.obj $(ZOOK_DIR)/response_print.obj $(ZOOK_DIR)/lex.cr.obj $(ZOOK_DIR)/lex.sr.obj $(ZOOK_DIR)/service_conf.tab.obj $(ZOOK_DIR)/service_conf.tab.obj $(ZOOK_DIR)/main_conf_read.tab.obj
+
+!IFDEF JS_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(JS_FILE)
+!ENDIF
+!IFDEF JDK_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(JAVA_FILE)
+!ENDIF
+!IFDEF PY_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(PY_FILE)
+!ENDIF
+!IFDEF MS_DIR
+FILES=$(FILES) $(ZOOK_DIR)$(MS_FILE)
+!ENDIF
+
+cgi-env/wps_registry.zo: service.c
+	$(CPP) /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/wps_registry.zo $(FILES) ./service.obj $(LDFLAGS) /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\*_registry.*
+	erase *.obj
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/registry/service.c	(revision 942)
@@ -0,0 +1,138 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "service.h"
+#include "service_internal.h"
+#include "server_internal.h"
+#include "response_print.h"
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <dirent.h>
+extern "C" {
+
+  /**
+   * GetFromRegistry ZOO Service :
+   * This service is used in the ZOO-Project to browse the profiles registry.
+   */
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int GetFromRegistry(maps*& conf,maps*& inputs,maps*& outputs){
+    const char *params[4 + 1];
+    int xmlLoadExtDtdDefaultValue;
+    map* tmpMap=NULL,*tmpMmap=NULL, *tmpTmap=NULL;
+
+    map* reg = getMapFromMaps (conf, "main", "registry");
+    registry* zooRegistry=NULL;
+    if(reg!=NULL){
+      int saved_stdout = dup (fileno (stdout));
+      dup2 (fileno (stderr), fileno (stdout));
+      createRegistry (conf,&zooRegistry,reg->value);
+      dup2 (saved_stdout, fileno (stdout));
+      close(saved_stdout);
+    }else{
+      setMapInMaps(conf,"lenv","message",_ss("No registry defined"));
+      return SERVICE_FAILED;
+    }
+    tmpMap=getMapFromMaps(inputs,"id","value");
+    if(strstr(tmpMap->value,"/")==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse your registry identifier"));
+      return SERVICE_FAILED;
+    }
+    char* tmp=zStrdup(tmpMap->value);
+    char* tmp1=zStrdup(strstr(tmpMap->value,"/")+1);
+    tmp[strlen(tmp)-strlen(tmp1)-1]=0;
+    service* inherited=getServiceFromRegistry(zooRegistry,tmp,tmp1);
+    if(inherited!=NULL){
+      dumpService(inherited);
+      xmlDocPtr doc = xmlNewDoc (BAD_CAST "1.0");
+      xmlNodePtr n = printWPSHeader(doc,conf,"DescribeProcess",
+				    root_nodes[1][1],"2.0.0",1);
+      setMapInMaps(conf,"main","rversion","2.0.0");
+      printDescribeProcessForProcess(zooRegistry,conf,doc,n,inherited);
+      setMapInMaps(conf,"main","rversion","1.0.0");
+
+
+      xmlNodePtr n1 = xmlFirstElementChild(xmlFirstElementChild(n));
+
+
+      xmlDocPtr doc1 = xmlNewDoc (BAD_CAST "1.0");
+      int vid=1;
+      char *tmp=(char*) malloc((86+strlen("DescribeProcess")+1)*sizeof(char));
+      sprintf(tmp,schemas[vid][4],schemas[vid][2],schemas[vid][3],"DescribeProcess");
+      xmlNewProp(n1,BAD_CAST "xsi:schemaLocation",BAD_CAST tmp);
+      free(tmp);
+
+      n1->ns=xmlCopyNamespaceList(n->ns);
+      n1->nsDef=xmlCopyNamespaceList(n->nsDef);
+      
+      xmlDocSetRootElement(doc1, n1);
+      
+      xmlChar *xmlbuff;
+      int buffersize;
+      xmlDocDumpFormatMemoryEnc(doc1, &xmlbuff, &buffersize, "utf-8", 1);
+      setMapInMaps(outputs,"Result","value",(char*)xmlbuff);
+      xmlFree(xmlbuff);
+      xmlFreeDoc(doc);
+      xmlFreeDoc(doc1);
+      return SERVICE_SUCCEEDED;
+    }else{
+      if(strcasecmp(tmp,"concept")==0){
+	char *file_path=(char*)malloc((strlen(reg->value)+strlen(tmpMap->value)+5)*sizeof(char));
+	sprintf(file_path,"%s/%s.txt",reg->value,tmpMap->value);
+	FILE* f=fopen(file_path,"r");
+	if(f!=NULL){
+	  fseek(f, 0, SEEK_END);
+	  long count = ftell(f);
+	  fseek(f, 0, SEEK_SET);
+	  setMapInMaps(outputs,"Result","value","");
+	  map* tmpMap=getMapFromMaps(outputs,"Result","value");
+	  free(tmpMap->value);
+	  tmpMap->value=(char*) malloc((count+1)*sizeof(char));  
+	  fread(tmpMap->value,1,count,f);
+	  tmpMap->value[count]=0;
+	  fclose(f);
+	  setMapInMaps(outputs,"Result","mimeType","text/plain");
+	  return SERVICE_SUCCEEDED;
+	}else{
+	  setMapInMaps(conf,"lenv","message",_ss("Unable to access this item in the registry."));
+	  return SERVICE_FAILED;
+	}
+      }
+      setMapInMaps(conf,"lenv","message",_ss("Unable to access this item in the registry."));
+      return SERVICE_FAILED;
+    }
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/Makefile
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/Makefile	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/Makefile	(revision 942)
@@ -0,0 +1,15 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS1=${CFLAGS} -I${INST_INCLUDE} ${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+
+cgi-env/wps_status.zo: service.c
+	g++ ${CFLAGS1} -shared -fpic -o cgi-env/wps_status.zo ./service.c ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} ${XSLT_LDFLAGS} ${FCGI_LDFLAGS} -L${ZRPATH}/zoo-kernel/ -lzoo_service
+
+install:
+	install -d ${CGI_DIR}
+	install cgi-env/*.zcfg ${CGI_DIR}/
+	install cgi-env/*.zo ${CGI_DIR}/
+	install cgi-env/updateStatus.xsl ${SHAREDSTATEDIR}/
+
+clean:
+	rm -f cgi-env/wps_status.zo
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/GetStatus.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/GetStatus.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/GetStatus.zcfg	(revision 942)
@@ -0,0 +1,43 @@
+[GetStatus]
+ Title = Produce an updated ExecuteResponse document. 
+ Abstract = Create an ExecuteResponse document from a sid (Service ID), it will use the niternal ZOO Kernel mechanisms to access the current status from a running Service and update the percentCompleted from the original backup file used by the ZOO Kernel when running a Service in background. 
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_status.zo
+ serviceType = C
+ <MetaData>
+   title = Demo GetStatus request
+ </MetaData>
+ <DataInputs>
+  [sid]
+   Title = Service ID
+   Abstract = The ZOO Service ID of the ZOO Service we want to get the current status.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    DataType = integer
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = ExecuteResponse document
+   Abstract = The resulting ExecuteResponse document.
+   <MetaData>
+    title = Demo XSL use case
+   </MetaData>   
+   <ComplexData>
+    <Default>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/wps/1.0.0/wpsExecute_response.xsd
+    </Default>
+    <Supported>
+     mimeType = text/xml
+     encoding = UTF-8
+     schema = http://schemas.opengis.net/wps/1.0.0/wpsExecute_response.xsd
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/demo.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/demo.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/demo.zcfg	(revision 942)
@@ -0,0 +1,32 @@
+[demo]
+ Title = Demo long process. 
+ Abstract = This service doesn't do anything except taking its time to return an error message, it demonstrates how to use the update_status function of the Python ZOO-API from your services code.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = service
+ serviceType = Python
+ <DataInputs>
+  [sid]
+   Title = Service ID
+   Abstract = A ZOO Service ID (unused).
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = integer
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = ExecuteResponse document
+   Abstract = The resulting ExecuteResponse document.
+   <MetaData>
+    title = Demo XSL use case
+   </MetaData>   
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/longProcess.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/longProcess.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/longProcess.zcfg	(revision 942)
@@ -0,0 +1,36 @@
+[longProcess]
+ Title = Demo long process. 
+ Abstract = This service doesn't do anything except taking its time, it demonstrates how to use the updateStatus function from your ZOO Service. 
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = wps_status.zo
+ serviceType = C
+ <MetaData>
+   title = Demo GetStatus request
+ </MetaData>
+ <DataInputs>
+  [sid]
+   Title = Service ID
+   Abstract = A ZOO Service ID (unused).
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = integer
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Result]
+   Title = ExecuteResponse document
+   Abstract = The resulting ExecuteResponse document.
+   <MetaData>
+    title = Demo XSL use case
+   </MetaData>   
+   <LiteralData>
+    dataType = string
+    <Default>
+    </Default>
+   </LiteralData>
+ </DataOutputs>  
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/service.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/service.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/service.py	(revision 942)
@@ -0,0 +1,14 @@
+def demo(conf,inputs,outputs):
+    import zoo,time
+    i=0
+    while i < 100:
+        conf["lenv"]["message"]="Step "+str(i)
+        zoo.update_status(conf,i)
+        time.sleep(0.5)
+        i+=1
+    conf["lenv"]["message"]=zoo._("Error executing the service")
+    return zoo.SERVICE_FAILED
+
+def demo1(conf,inputs,outputs):
+    conf["lenv"]["message"]=zoo._("Error executing the service")
+    return zoo.SERVICE_FAILED
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/updateStatus.xsl
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/updateStatus.xsl	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/cgi-env/updateStatus.xsl	(revision 942)
@@ -0,0 +1,26 @@
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:ows="http://www.opengis.net/ows/1.1"
+                xmlns:wps="http://www.opengis.net/wps/1.0.0"
+                xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <xsl:output method="xml"/>
+  <xsl:param name="value" select="string('-1')"/>
+  <xsl:param name="message" select="string('-1')"/>
+
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+
+  <xsl:template match="/wps:ExecuteResponse/wps:Status/wps:ProcessStarted">
+    <xsl:copy>
+      <xsl:attribute name="percentCompleted">
+	<xsl:value-of select="$value"/>
+      </xsl:attribute>
+      <xsl:value-of select="$message" />
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/locale/po/fr_FR.utf8.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/locale/po/fr_FR.utf8.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/locale/po/fr_FR.utf8.po	(revision 942)
@@ -0,0 +1,91 @@
+# French translations for PACKAGE package.
+# Copyright (C) 2010 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# root <gerald.fenoy@geolabs.fr>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: zoo-services\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-30 03:46+0200\n"
+"PO-Revision-Date: 2010-09-30 03:50+0200\n"
+"Last-Translator: root <gerald.fenoy@geolabs.fr>\n"
+"Language-Team: French\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: ../.cache/my_service_string_to_translate.c:1
+msgid "Produce an updated ExecuteResponse document. "
+msgstr ""
+"Produit un document ExecuteResponse à jour par rapport à l'exécution d'un service en "
+"tâche de fond."
+
+#: ../.cache/my_service_string_to_translate.c:2
+#: ../.cache/my_service_string_to_translate.c:8
+msgid "Service ID"
+msgstr "identifiant de service"
+
+#: ../.cache/my_service_string_to_translate.c:3
+#: ../.cache/my_service_string_to_translate.c:9
+msgid "ExecuteResponse document"
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:4
+msgid ""
+"Create an ExecuteResponse document from a sid (Service ID), it will use the "
+"niternal ZOO Kernel mechanisms to access the current status from a running "
+"Service and update the percentCompleted from the original backup file used "
+"by the ZOO Kernel when running a Service in background. "
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:5
+msgid ""
+"The ZOO Service ID of the ZOO Service we want to get the current status."
+msgstr ""
+"L'identifiant de Service ZOO dont ont veut obetnir le status."
+
+#: ../.cache/my_service_string_to_translate.c:6
+#: ../.cache/my_service_string_to_translate.c:12
+msgid "The resulting ExecuteResponse document."
+msgstr "Le document ExecuteResponse resultant."
+
+#: ../.cache/my_service_string_to_translate.c:7
+msgid "Demo long process. "
+msgstr "Service de démonstration."
+
+#: ../.cache/my_service_string_to_translate.c:10
+msgid ""
+"This service doesn't do anything except taking its time, it demonstrates how "
+"to use the updateStatus function from your ZOO Service. "
+msgstr ""
+"Ce service se contente de prendre son temps, il permet de montrer comment utiliser "
+"la fonction updateStatus depuis vos services ZOO."
+
+#: ../.cache/my_service_string_to_translate.c:11
+msgid "A ZOO Service ID (unused)."
+msgstr "Un identifiant de Service ZOO."
+
+#: ../.cache/my_service_string_to_translate.c:94
+#, c-format
+msgid ""
+"GetStatus was unable to use the tmpPath value set in main.cfg file as "
+"directory %s."
+msgstr ""
+"Le service GetStatus n'a pas été en mesure d'accéder au répertoire correspondant à la "
+"variable tmpPath définie dans le fichier main.cfg comme : %s."
+
+#: ../.cache/my_service_string_to_translate.c:100
+#, c-format
+msgid "GetStatus was unable to find any cache file for Service ID %s."
+msgstr "Le service GetStatus n'a pas été en mesure de trouver un fichier pour l'identifiant de Servicer ZOO %s."
+
+#: ../.cache/my_service_string_to_translate.c:126
+#, c-format
+msgid ""
+"ZOO GetStatus Service was unable to parse the cache xml file available for "
+"the Service ID %s."
+msgstr ""
+"Le Service ZOO GetStatus n'a pas été en mesure de charger le fichier xml pour "
+"l'identifiant %s."
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/locale/po/messages.po
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/locale/po/messages.po	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/locale/po/messages.po	(revision 942)
@@ -0,0 +1,82 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: zoo-services\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-30 03:46+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../.cache/my_service_string_to_translate.c:1
+msgid "Produce an updated ExecuteResponse document. "
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:2
+#: ../.cache/my_service_string_to_translate.c:8
+msgid "Service ID"
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:3
+#: ../.cache/my_service_string_to_translate.c:9
+msgid "ExecuteResponse document"
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:4
+msgid ""
+"Create an ExecuteResponse document from a sid (Service ID), it will use the "
+"niternal ZOO Kernel mechanisms to access the current status from a running "
+"Service and update the percentCompleted from the original backup file used "
+"by the ZOO Kernel when running a Service in background. "
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:5
+msgid ""
+"The ZOO Service ID of the ZOO Service we want to get the current status."
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:6
+#: ../.cache/my_service_string_to_translate.c:12
+msgid "The resulting ExecuteResponse document."
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:7
+msgid "Demo long process. "
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:10
+msgid ""
+"This service doesn't do anything except taking its time, it demonstrates how "
+"to use the updateStatus function from your ZOO Service. "
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:11
+msgid "A ZOO Service ID (unused)."
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:94
+#, c-format
+msgid ""
+"GetStatus was unable to use the tmpPath value set in main.cfg file as "
+"directory %s."
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:100
+#, c-format
+msgid "GetStatus was unable to find any cache file for Service ID %s."
+msgstr ""
+
+#: ../.cache/my_service_string_to_translate.c:126
+#, c-format
+msgid ""
+"ZOO GetStatus Service was unable to parse the cache xml file available for "
+"the Service ID %s."
+msgstr ""
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/makefile.vc
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/makefile.vc	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/makefile.vc	(revision 942)
@@ -0,0 +1,10 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+cgi-env/wps_status.zo: service.c
+	$(CPP) /D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DZOO_SERVICE $(CFLAGS) /c service.c
+	link /dll /out:cgi-env/wps_status.zo $(FILES) ./service.obj $(LDFLAGS) $(XSLT_DIR)\win32\bin.msvc\libxslt.lib $(ZOOK_DIR)\libzoo_service.lib /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\*_status.*
+	erase *.obj
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/service.c
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/service.c	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/service.c	(revision 942)
@@ -0,0 +1,159 @@
+/**
+ * Author : Gérald FENOY
+ *
+ * Copyright 2008-2009 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "service.h"
+#include "service_internal.h"
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <dirent.h>
+extern "C" {
+
+  /**
+   * GetStatus ZOO Service :
+   * This service is used in the ZOO-Project to get information about Services
+   * running as background tasks. The service will first get the XML document 
+   * cached by the ZOO-Kernel before calling effectively the Service, then 
+   * will access the shared memory space created by the Kernel to extract the 
+   * current status of the running Service. Using a simple XSL file it will 
+   * finally produce the final ExecuteResponse including the updated 
+   * percentCompleted attribute of the ProcessStarted node of the cached
+   * document if any (so if the Service is currently running) else it will 
+   * return the final ExecuteResponse stored on the Server file system.
+   */
+  ZOO_DLL_EXPORT int GetStatus(maps*& conf,maps*& inputs,maps*& outputs){	  
+    const char *params[4 + 1];
+    int xmlLoadExtDtdDefaultValue;
+    map* tmpMap=NULL,*tmpMmap=NULL, *tmpTmap=NULL;
+
+    tmpMap=getMapFromMaps(inputs,"sid","value");
+    tmpTmap=getMapFromMaps(conf,"main","tmpPath");
+    tmpMmap=getMapFromMaps(conf,"main","dataPath");
+    if(tmpMmap==NULL)
+      tmpMmap=tmpTmap;
+    xmlInitParser();
+    int hasFile=-1;
+    char xslFileName[1024];
+    char* mem=_getStatusFile(conf,tmpMap->value);
+    if(mem==NULL){
+      char tmp[1024];
+      snprintf(tmp,1024,_ss("GetStatus was unable to find any cache file for Service ID %s."),tmpMap->value);
+      setMapInMaps(conf,"lenv","message",tmp);
+      return SERVICE_FAILED;
+    }
+    map* tmpMap1=getMapFromMaps(conf,"lenv","semaphore");
+    if(tmpMap1!=NULL && strcasecmp(tmpMap1->value,"Created")==0)
+      removeShmLock(conf,1);
+    sprintf(xslFileName,"%s/updateStatus.xsl",tmpMmap->value);
+    xmlSubstituteEntitiesDefault(1);
+    xmlLoadExtDtdDefaultValue = 0;
+    xsltStylesheetPtr cur = NULL;
+    xmlDocPtr doc, res;
+    cur = xsltParseStylesheetFile(BAD_CAST xslFileName);
+    doc = xmlParseMemory(mem,strlen(mem));
+    //doc = xmlParseFile(fileName);
+    if(cur!=NULL && doc!=NULL){
+      /**
+       * Parse Status to extract Status / Message
+       */
+      char *tmpStr=_getStatus(conf,tmpMap->value);
+      //#ifdef DEBUG
+      fprintf(stderr,"DEBUG: %s \n",tmpStr);
+      //#endif
+      if(tmpStr!=NULL && strncmp(tmpStr,"-1",2)!=0){
+	char *tmpStr1=strdup(tmpStr);
+	char *tmpStr0=strdup(strstr(tmpStr,"|")+1);
+	free(tmpStr);
+	tmpStr1[strlen(tmpStr1)-strlen(tmpStr0)-1]='\0';
+	char *tmpStrFinal=(char*)malloc((strlen(tmpStr0)+11)*sizeof(char));
+	sprintf(tmpStrFinal,"string(\"%s\")",tmpStr0);
+	params[0]="value";
+	params[1]=tmpStr1;
+	params[2]="message";
+	params[3]=tmpStrFinal;
+	params[4]=NULL;
+	res = xsltApplyStylesheet(cur, doc, params);
+	xmlChar *xmlbuff;
+	int buffersize;
+	xmlDocDumpFormatMemory(res, &xmlbuff, &buffersize, 1);
+	setMapInMaps(outputs,"Result","value",(char*)xmlbuff);
+	xmlFree(xmlbuff);
+	free(tmpStr1);
+	free(tmpStr0);
+	free(tmpStrFinal);
+      }else{
+	xmlChar *xmlbuff;
+	int buffersize;
+	xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
+	setMapInMaps(outputs,"Result","value",(char*)xmlbuff);
+	xmlFree(xmlbuff);
+      }
+    }
+    else{
+      char tmp[1024];
+      sprintf(tmp,_ss("ZOO GetStatus Service was unable to parse the cache xml file available for the Service ID %s."),tmpMap->value);
+      setMapInMaps(conf,"lenv","message",tmp);
+      return SERVICE_FAILED;
+    }
+    return SERVICE_SUCCEEDED;
+  }
+
+
+  /**
+   * longProcess ZOO Service :
+   * Simple Service which just loop over 100 times then return a welcome message
+   * string, at each step the service will sleep for one second.
+   */
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int longProcess(maps*& conf,maps*& inputs,maps*& outputs){
+    int i=0;
+    while(i<100){
+      char message[10];
+      sprintf(message,"Step %d",i);
+      fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
+      fflush(stderr);
+      updateStatus(conf,i,message);
+#ifndef WIN32
+      sleep(1);
+#else
+      Sleep(1000);
+#endif
+      i+=5;
+    }
+    setOutputValue(outputs,"Result",(char*)"\"Long process run successfully\"",-1);
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/test.sh
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/test.sh	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/utils/status/test.sh	(revision 942)
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+rm -f log log1
+
+./zoo_loader.cgi "request=Execute&service=WPS&version=1.0.0&Identifier=longProcess&DataInputs=&storeExecuteResponse=true&status=true" > log
+
+if [ -z "$(grep "ows:ExceptionReport" log)" ]; then
+    while [ -z "$(grep "wps:ProcessSucceeded" log1)" ]; 
+    do 
+	./zoo_loader.cgi $(grep statusLocation= ./log | cut -d'?' -f2 | cut -d'"' -f1 | sed "s:amp;::g") > log1 ;
+	cat log1 ; 
+    done
+    cat log1
+else
+    echo "Service failed, please make sure that your main.cfg file contains"
+    echo "in the [main] section valid values for both tmpPath and dataPath."
+    echo 
+    cat log
+fi
Index: /tags/rel-1.7.0/zoo-project/zoo-services/wcps-proxy/cgi-env/WCPS.py
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/wcps-proxy/cgi-env/WCPS.py	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/wcps-proxy/cgi-env/WCPS.py	(revision 942)
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+#
+# Author : Vlad Merticariu <merticariu@rasdaman.com>
+#
+# Copyright 2015 rasdaman GmbH. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including with
+# out limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+import zoo
+import requests
+
+WCPS_REQUEST_TEMPLATE = "%endPoint%?service=WCS&version=2.0.1&request=ProcessCoverages&query=%query%"
+
+def WCPS(conf,inputs,outputs):
+	end_point = validate_end_point(inputs["endPoint"]["value"])
+        query = get_correct_query(inputs["query"]["value"],outputs["Response"]["mimeType"])
+        response_data_type = get_data_type(query)
+        status, response = execute_wcps_request(end_point, query)
+	import sys    
+	print >> sys.stderr,query
+	#handle errors
+	if status:
+		conf["lenv"]["message"] = zoo._("The end point at " + end_point + " could not be reached.")
+		return zoo.SERVICE_FAILED
+ 	if "ows:ExceptionReport" in response:
+		conf["lenv"]["message"] = parse_error_message(response)
+		return zoo.SERVICE_FAILED
+		
+	#no errors, everything ok 	
+        outputs["Response"]["value"] = remove_trailing_characters(response, response_data_type)
+        #outputs["Response"]["mimeType"] = response_data_type
+        #outputs["Response"]["encoding"] = get_encoding(outputs["Response"]["mimeType"])
+	return zoo.SERVICE_SUCCEEDED
+
+def parse_error_message(response):
+	return response.split("<ows:ExceptionText>")[1].split("</ows:ExceptionText>")[0]
+
+def validate_end_point(end_point):
+	ret = end_point
+	if not end_point.startswith("http"):
+        	ret = "http://" + end_point
+	return ret
+
+def get_data_type(query):
+	ret = "text/plain"
+	if "\"png\"" in query:
+		ret = "image/png"
+	if "\"csv\"" in query:
+		ret = "text/csv"
+	if "\"tiff\"" in query:
+		ret = "image/tiff"
+	if "\"jpeg\"" in query or "\"jpg\"" in query:
+		ret = "image/jpeg"
+	return ret
+
+def get_correct_query(query,mimeType):
+    return query.replace("[format]",get_data_ext(mimeType))
+
+def get_data_ext(mimeType):
+	ret = "csv"
+	for i in ["png","csv","tiff","jpeg"]:
+		if i in mimeType:
+			ret = i
+			break
+	return ret
+
+def get_encoding(data_type):
+	ret = "utf-8"
+	if data_type.startswith("image"):
+		ret = "base64"
+	return ret
+
+def remove_trailing_characters(response, data_type):
+        response_start = 27
+        if data_type.startswith("image"):
+		response_start += len(data_type)
+	else:
+		response_start += 10
+        ret = response[response_start:-17]
+	return ret
+
+def execute_wcps_request(end_point, query):
+        composed_url = WCPS_REQUEST_TEMPLATE.replace("%endPoint%", end_point).replace("%query%", query) 
+	try:
+		response = requests.get(composed_url)
+	except:
+		#can not open url
+		return 1, ""
+	#all ok
+	return 0, response.content
+
+    
Index: /tags/rel-1.7.0/zoo-project/zoo-services/wcps-proxy/cgi-env/WCPS.zcfg
===================================================================
--- /tags/rel-1.7.0/zoo-project/zoo-services/wcps-proxy/cgi-env/WCPS.zcfg	(revision 942)
+++ /tags/rel-1.7.0/zoo-project/zoo-services/wcps-proxy/cgi-env/WCPS.zcfg	(revision 942)
@@ -0,0 +1,54 @@
+[WCPS]
+ Title = Execute WCPS queries
+ Abstract = Execute a Web Coverage Processing Service request, through a WPS process.
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = WCPS
+ serviceType = Python
+ <MetaData>
+   title = WCPS
+ </MetaData>
+ <DataInputs>
+  [endPoint]
+   Title = WCPS End Point
+   Abstract = The WCPS End Point against which the WCPS query is executed.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+  [query]
+   Title = WCPS Query
+   Abstract = The query to be executed at the provided end point.
+   minOccurs = 1
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+ </DataInputs>
+ <DataOutputs>
+  [Response]
+   Title = WCPS Response
+   Abstract = The response to the WCPS query.
+   <ComplexData>
+    <Default>
+    mimeType = text/csv
+    encoding = utf-8
+    </Default>
+    <Supported>
+    mimeType = image/png
+    encoding = base64
+    </Supported>
+    <Supported>
+    mimeType = image/tiff
+    encoding = base64
+    </Supported>
+    <Supported>
+    mimeType = image/jpeg
+    encoding = base64
+    </Supported>
+   </ComplexData>
+ </DataOutputs>
