Index: tags/rel-1.3.0-rc1/docs/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/docs/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/Makefile	(revision 417)
@@ -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.3.0-rc1/docs/_static/basic.css
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/basic.css	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/basic.css	(revision 417)
@@ -0,0 +1,545 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+    clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+    width: 100%;
+    font-size: 90%;
+}
+
+div.related h3 {
+    display: none;
+}
+
+div.related ul {
+    margin: 0;
+    padding: 0 0 0 10px;
+    list-style: none;
+}
+
+div.related li {
+    display: inline;
+}
+
+div.related li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+    padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+    float: left;
+    width: 25%;
+    margin-left: -100%;
+    font-size: 90%;
+}
+
+div.sphinxsidebar ul {
+    list-style: none;
+    padding:10px;
+   	background: #FFCD0B;
+    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#FFCD0B'); /* for IE */
+    background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#FFCD0B)); /* for webkit browsers */
+    background: -moz-linear-gradient(center top , #FFFFFF, #FFCD0B) repeat scroll 0 0 transparent;
+     -moz-border-radius-bottomright: 5px;
+border-bottom-right-radius:5px;
+-webkit-border-bottom-right-radius:5px;
+-moz-border-radius-bottomleft: 5px;
+border-bottom-left-radius:5px;
+-webkit-border-bottom-left-radius:5px;
+background:#FFFFFF;
+    }
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+    margin-left: 20px;
+    list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+    margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: Verdana;
+    font-size: 1em;
+}
+
+img {
+    border: 0;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+    margin: 10px 0 0 20px;
+    padding: 0;
+}
+
+ul.search li {
+    padding: 5px 0 5px 20px;
+    background-image: url(file.png);
+    background-repeat: no-repeat;
+    background-position: 0 7px;
+}
+
+ul.search li a {
+    font-weight: bold;
+}
+
+ul.search li div.context {
+    color: #888;
+    margin: 2px 0 0 30px;
+    text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+    font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.3em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+    font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+    width: 100%;
+}
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+div.modindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+a.headerlink {
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+div.body p.caption {
+    text-align: inherit;
+}
+
+div  td {
+    text-align: left;
+}
+
+.field-list ul {
+    padding-left: 1em;
+}
+
+.first {
+    margin-top: 0 !important;
+}
+
+p.rubric {
+    margin-top: 30px;
+    font-weight: bold;
+}
+
+img.align-left, .figure.align-left, object.align-left {
+    clear: left;
+    float: left;
+    margin-right: 1em;
+}
+
+img.align-right, .figure.align-right, object.align-right {
+    clear: right;
+    float: right;
+    margin-left: 1em;
+}
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.align-left {
+    text-align: left;
+}
+
+.align-center {
+    clear: both;
+    text-align: center;
+}
+
+.align-right {
+    text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+    margin: 0 0 0.5em 1em;
+    border: 1px solid #ddb;
+    padding: 7px 7px 0 7px;
+    background-color: #ffe;
+    width: 40%;
+    float: right;
+}
+
+p.sidebar-title {
+    font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+    border: 1px solid #ccc;
+    padding: 7px 7px 0 7px;
+    margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+    font-size: 1.1em;
+    font-weight: bold;
+    margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    padding: 7px;
+}
+
+div.admonition dt {
+    font-weight: bold;
+}
+
+div.admonition dl {
+    margin-bottom: 0;
+}
+
+p.admonition-title {
+    margin: 0px 10px 5px 0px;
+    font-weight: bold;
+}
+
+div.body p.centered {
+    text-align: center;
+    margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+    border: 0;
+    border-collapse: collapse;
+}
+
+table.docutils td, table.docutils th {
+    padding: 1px 8px 1px 5px;
+    border-top: 0;
+    border-left: 0;
+    border-right: 0;
+    border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+    border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+    border: 0 !important;
+}
+
+th {
+    text-align: left;
+    padding-right: 5px;
+}
+
+table.citation {
+    border-left: solid 1px gray;
+    margin-left: 1px;
+}
+
+table.citation td {
+    border-bottom: none;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+    list-style: decimal;
+}
+
+ol.loweralpha {
+    list-style: lower-alpha;
+}
+
+ol.upperalpha {
+    list-style: upper-alpha;
+}
+
+ol.lowerroman {
+    list-style: lower-roman;
+}
+
+ol.upperroman {
+    list-style: upper-roman;
+}
+
+dl {
+    margin-bottom: 15px;
+}
+
+dd p {
+    margin-top: 0px;
+}
+
+dd ul, dd table {
+    margin-bottom: 10px;
+}
+
+dd {
+    margin-top: 3px;
+    margin-bottom: 10px;
+    margin-left: 30px;
+}
+
+dt:target, .highlighted {
+    background-color: #fbe54e;
+}
+
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.field-list ul {
+    margin: 0;
+    padding-left: 1em;
+}
+
+.field-list p {
+    margin: 0;
+}
+
+.refcount {
+    color: #060;
+}
+
+.optional {
+    font-size: 1.3em;
+}
+
+.versionmodified {
+    font-style: italic;
+}
+
+.system-message {
+    background-color: #fda;
+    padding: 5px;
+    border: 3px solid red;
+}
+
+.footnote:target  {
+    background-color: #ffa;
+}
+
+.line-block {
+    display: block;
+    margin-top: 1em;
+    margin-bottom: 1em;
+}
+
+.line-block .line-block {
+    margin-top: 0;
+    margin-bottom: 0;
+    margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+    font-family: verdana;
+}
+
+.accelerator {
+    text-decoration: underline;
+}
+
+.classifier {
+    font-style: oblique;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+    overflow: auto;
+    overflow-y: hidden;  /* fixes display issues on Chrome browsers */
+}
+
+td.linenos pre {
+    padding: 5px 0px;
+    border: 0;
+    background-color: transparent;
+    color: #aaa;
+}
+
+table.highlighttable {
+    margin-left: 0.5em;
+}
+
+table.highlighttable td {
+    padding: 0 0.5em 0 0.5em;
+}
+
+tt.descname {
+    background-color: transparent;
+    font-weight: bold;
+    font-size: 1.2em;
+}
+
+tt.descclassname {
+    background-color: transparent;
+}
+
+tt.xref, a tt {
+    background-color: transparent;
+    font-weight: bold;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+    background-color: transparent;
+}
+
+.viewcode-link {
+    float: right;
+}
+
+.viewcode-back {
+    float: right;
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    margin: -1px -10px;
+    padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+    vertical-align: middle;
+}
+
+div.body div.math p {
+    text-align: center;
+}
+
+span.eqno {
+    float: right;
+}
+
+  div.footer {
+        padding:0;
+        margin:0;
+    }
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+    div.document,
+    div.documentwrapper,
+    div.bodywrapper {
+        margin: 0 !important;
+        width: 100%;
+    }
+
+    div.sphinxsidebar,
+    div.related,
+    div.footer,
+    #top-link {
+        display: none;
+    }
+}
Index: tags/rel-1.3.0-rc1/docs/_static/default.css
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/default.css	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/default.css	(revision 417)
@@ -0,0 +1,528 @@
+/*
+ * default.css_t
+ * ~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- default theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: Verdana, Arial, Helvetica, sans-serif;
+    font-size: 14px;
+    background-color: #ffffff;
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+div.document {
+    background-color: white;
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+     background:#bababa;
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#bababa', endColorstr='#707070'); /* for IE */
+background:-webkit-gradient(linear, left top, left bottom, from(#bababa), to(#707070)); /* for webkit browsers */
+background:-moz-linear-gradient(top,  #bababa,  #707070); /* for firefox 3.6+ */
+ }
+
+div.bodywrapper {
+    margin: 0 0 0 230px;
+
+}
+
+div.body {
+background:#FFFFFF;
+    color: #333333;
+    padding: 10px 20px 20px 20px;
+}
+div.bodywrapper {
+    margin: 1em 25% 1em 1em;
+}
+
+
+div.footer {
+    color: #333333;
+    width: 100%;
+    padding:0;
+    text-align: center;
+    font-size:12px;
+}
+
+#footer p{padding:10px 0 5px 0;}
+
+
+div.footer a {
+    color: #646464;
+    text-decoration: underline;
+}
+
+div.related {
+    background-color: #ed910d;
+    line-height: 30px;
+    color: #ffffff;
+}
+
+div.related a {
+	margin: 0 0 10px 10px;
+    color: #ffffff;
+}
+
+div.sphinxsidebar {
+    float: right;
+    
+}
+
+/* -- Custom Sidebar styles ----------------------------------------------------------- */
+
+.categories{
+	background: #ee920c;
+        filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee920c', endColorstr='#ffcd0b'); /* for IE */
+        background:-webkit-gradient(linear, left top, left bottom, from(#ee920c), to(#ffcd0b)); /* for webkit browsers */
+        background:-moz-linear-gradient(top,  #ee920c,  #ffcd0b); /* for firefox 3.6+ */
+	font-size: 1.3em;
+	width: 98%;
+	margin-bottom: 10px;
+	border:0;
+	padding:1%;
+	text-shadow: 1px 1px 1px #E0E0E0;
+	-moz-border-radius: 5px;
+	-webkit-border-radius: 5px;
+        border-radius: 5px;
+}
+
+.twitts, .donate, #searchbox {
+    -moz-border-radius: 5px;
+    -webkit-border-radius:5px;
+    border-radius:5px;
+    background: #FFCD0B;
+    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#FFCD0B'); /* for IE */
+    background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#FFCD0B)); /* for webkit browsers */
+    background: -moz-linear-gradient(center top , #FFFFFF, #FFCD0B) repeat scroll 0 0 transparent;
+    border: 0 none;
+    height: auto;
+    margin-bottom: 10px;
+    padding: 1%;
+    width: 98%;
+}
+
+.twitts img{width:180px;height:40px;}
+
+
+
+/* -- End Custom Sidebar styles ----------------------------------------------------------- */
+
+div.sphinxsidebar h1, .donate h1, .twitts h1 {
+    font-family: Verdana, Arial, Helvetica, sans-serif;
+    color: #663e05;
+    font-size: 1.4em;
+    font-weight: normal;
+    margin: 0;
+    padding: 0;
+    margin:10px 0 10px 10px;
+}
+
+div.sphinxsidebar h3 {
+    font-family: Verdana, Arial, Helvetica, sans-serif;
+    color: #663e05;
+    font-size: 1.4em;
+    font-weight: normal;
+    margin: 0;
+    padding: 0;
+
+}
+
+div.sphinxsidebar h3 a {
+    color: #5D3805;
+         -moz-border-radius-topright: 5px;
+border-top-right-radius:5px;
+-webkit-border-top-right-radius:5px;
+-moz-border-radius-topleft: 5px;
+border-top-left-radius:5px;
+-webkit-border-top-left-radius:5px;
+background:#FFFFFF;
+display:block;
+padding:5px;
+}
+
+div.sphinxsidebar h4 {
+    font-family: 'Verdana, Arial, Helvetica, sans-serif';
+    color: #663e05;
+    font-size: 1.3em;
+    font-weight: normal;
+    margin: 5px 0 0 0;
+    padding: 0;
+}
+
+div.sphinxsidebar p {
+    color: #333333;
+}
+
+div.sphinxsidebar p.topless {
+    margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+    margin: 0 0 1em 0;
+
+
+    
+}
+
+div.sphinxsidebar a {
+    color: #ED910D;
+    text-decoration:none;
+}
+
+
+div.sphinxsidebar a p.version{
+color:#FFFFFF;
+text-shadow: none;
+margin:0 0 10px 10px ;
+padding:0;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #5F3A05;
+    font-family: Verdana;
+    font-size: 1em;
+    -moz-border-radius:5px;
+    -webkit-border-radius:5px;
+    border-radius:5px;
+}
+
+
+
+/* -- hyperlink styles ------------------------------------------------------ */
+
+a {
+    color: #ffac59;
+    text-decoration: none;
+}
+
+a:visited {
+    color: #ffac59;
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}
+
+
+
+/* -- body styles ----------------------------------------------------------- */
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: 'Verdana';
+    background-color: #ffffff;
+    font-weight: normal;
+    color: #663e05;
+    margin: 20px -20px 10px -20px;
+    padding: 3px 0 3px 10px;
+}
+
+div.body h1 {
+	font-size: 1.4em;
+	font-family:Verdana;
+	margin: 10px 0 0 0;
+	padding:0;
+	 }
+div.body h2 { font-size: 120%; }
+div.body h3 { font-size: 100%; }
+div.body h4 { font-size: 90%; }
+div.body h5 { font-size: 80%; }
+div.body h6 { font-size: 70%; }
+
+a.headerlink {
+    color: #c60f0f;
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+}
+
+a.headerlink:hover {
+    background-color: #c60f0f;
+    color: white;
+}
+
+div.body p, div.body dd, div.body li {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+    display: inline;
+}
+
+div.admonition p {
+    margin-bottom: 5px;
+}
+
+div.admonition pre {
+    margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+    margin-bottom: 5px;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+
+div.topic {
+    background-color: #eee;
+}
+
+div.warning {
+    background-color: #ffe4e4;
+    border: 1px solid #f66;
+}
+
+p.admonition-title {
+    display: inline;
+}
+
+p.admonition-title:after {
+    content: ":";
+}
+
+pre {
+    padding: 5px;
+    background-color: #fff6ce;
+    color: #333333;
+    line-height: 120%;
+    border: 1px solid #beb899;
+    border-left: none;
+    border-right: none;
+}
+
+tt {
+    background-color: #ecf0f3;
+    padding: 0 1px 0 1px;
+    font-size: 0.95em;
+}
+
+th {
+    background-color: #fff6ce;
+}
+
+.warning tt {
+    background: #efc2c2;
+}
+
+.note tt {
+    background: #d6d6d6;
+}
+
+.viewcode-back {
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
+
+/*  Custom Menu Bar ---------------------------------------- */
+
+ul.topnav {
+	position:relative;
+	top:0;
+	left:0;
+	list-style: none;
+	padding: 0 ;	
+	margin: 0;
+	float: left;
+	width: 100%;
+	height:40px;
+	background: #563404;
+filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#563404', endColorstr='#663e05'); /* for IE */
+background:-webkit-gradient(linear, left top, left bottom, from(#563404), to(#663e05)); /* for webkit browsers */
+background:-moz-linear-gradient(top,  #563404,  #663e05); /* for firefox 3.6+ */
+	font-size: 1.2em;
+}
+ul.topnav li {
+	float: left;
+	margin: 0;	
+	padding: 0 15px 0 0;
+	position: relative; /*--Declare X and Y axis base--*/
+}
+ul.topnav li a{
+	padding: 9px 10px 10px 20px;
+	color: #fff;
+	display: block;
+	text-decoration: none;
+	float: left;
+	
+}
+ul.topnav li a:hover{
+	background: transparent;
+	color:#ffcd0b;
+}
+ul.topnav li span { /*--Drop down trigger styles--*/
+	width: 17px;
+	height: 35px;
+	float: left;
+}
+ul.topnav li span.subhover {background-position: center bottom; cursor: pointer;} /*--Hover effect for trigger--*/
+ul.topnav li ul.subnav {
+	list-style: none;
+	position: absolute; /*--Important - Keeps subnav from affecting main navigation flow--*/
+	left: 20px; top: 35px;
+	margin: 0; padding: 0;
+	display: none;
+	float: left;
+	width: 170px;
+	-moz-border-radius-bottomleft: 5px;
+	-moz-border-radius-bottomright: 5px;
+	-webkit-border-bottom-left-radius: 5px;
+	-webkit-border-bottom-right-radius: 5px;
+	border: 1px solid #663e05;
+	z-index:1000000;
+	
+
+}
+ul.topnav li ul.subnav li{
+	margin: 0; padding: 0;
+
+	clear: both;
+	width: 125px;
+}
+html ul.topnav li ul.subnav li a {
+		font-size:.8em;
+	float: left;
+	width: 155px;
+	background: #663e05;
+	padding:5px 5px 7px 10px ;
+
+}
+html ul.topnav li ul.subnav li a:hover { /*--Hover effect for subnav links--*/
+ 
+}
+
+/*  Custom Header ---------------------------------------- */
+
+#wrapper { 
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+#myheader {
+ color: #333;
+ width: 100%;
+ height: 180px;
+ margin: 0;
+ background: #FFFFFF ;
+filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#fff196'); /* for IE */
+background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#fff196)); /* for webkit browsers */
+background:-moz-linear-gradient(top,  #FFFFFF, #fff196  ); /* for firefox 3.6+ */
+}
+
+.hleft{
+float:left;
+margin:0;
+width:380px;
+height:180px;
+background:url(images/zoo-title.png) no-repeat;}
+
+h1.title{width:290px;position:relative;top:102px;left:15px;font-size:1.4em;letter-spacing:2px;color:#727272;text-transform:uppercase;padding:5px;
+ background:#999999;font-weight:normal;
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e0e0e0', endColorstr='#bbbbbb'); /* for IE */
+background:-webkit-gradient(linear, left top, left bottom, from(#e0e0e0), to(#bbbbbb)); /* for webkit browsers */
+background:-moz-linear-gradient(top,  #e0e0e0,  #bbbbbb); /* for firefox 3.6+ */
+	-moz-border-radius: 5px;
+	-webkit-border-radius: 5px;
+	-webkit-border-radius: 5px;
+		border: 1px solid #d4d4d4;
+		text-align:center;
+		text-shadow: 1px 1px 1px #E0E0E0;
+}
+
+.orange{color:#ffaa17;display:block;padding:5px;}
+
+.hright{
+float:right;
+margin:0;
+width:533px;
+background:url(images/zoo-banner.png) no-repeat;
+height:180px;
+}
+
+/*  Custom Footer ---------------------------------------- */
+
+#footer { 
+	clear:both;
+ width:99.99%;
+ color: #333;
+ background: #ffcd0b;
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffcd0b', endColorstr='#ee920c'); /* for IE */
+background:-webkit-gradient(linear, left top, left bottom, from(#ffcd0b), to(#ee920c)); /* for webkit browsers */
+background:-moz-linear-gradient(top,  #ffcd0b, #ee920c  ); /* for firefox 3.6+ */
+ margin: 0;
+ padding: 0;
+}
+
+#footer p{
+	padding: 0;
+	text-align: center;
+	margin: 0;
+	padding:10px 0 10px 0;
+	color: #676561;
+	font-size: 12px;
+}
+
+#footer a{
+	color: #663e05;
+	font-weight: bold;
+	text-decoration: none;
+	font-size: 14px;
+}
+
+#footer .icon{
+	display: none;
+}
+
+#footer div{
+	text-align: center;
+}
+
+
+#footer .menuContainer{
+width: 750px; margin-left: auto; margin-right: auto;
+}
+
+#footer .menuItemList{
+	margin-top: 1em;
+	float: left;
+	padding-left: 1em;
+	padding-right: 1em;
+	border-left: 1px dashed #563404;;
+}
+
+#footer .menuItemList a{
+	font-weight: normal;
+}
Index: tags/rel-1.3.0-rc1/docs/_static/doctools.js
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/doctools.js	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/doctools.js	(revision 417)
@@ -0,0 +1,247 @@
+/*
+ * doctools.js
+ * ~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilties for all documentation.
+ *
+ * :copyright: Copyright 2007-2011 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;
+};
+
+/**
+ * small function to check if an array contains
+ * a given item.
+ */
+jQuery.contains = function(arr, item) {
+  for (var i = 0; i < arr.length; i++) {
+    if (arr[i] == item)
+      return true;
+  }
+  return false;
+};
+
+/**
+ * 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);
+  });
+};
+
+/**
+ * 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
+   */
+  fixFirefoxAnchorBug : function() {
+    if (document.location.hash && $.browser.mozilla)
+      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');
+      window.setTimeout(function() {
+        $.each(terms, function() {
+          body.highlightText(this.toLowerCase(), 'highlighted');
+        });
+      }, 10);
+      $('<li class="highlight-link"><a href="javascript:Documentation.' +
+        'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
+          .appendTo($('.sidebar .this-page-menu'));
+    }
+  },
+
+  /**
+   * 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() {
+    $('.sidebar .this-page-menu li.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.3.0-rc1/docs/_static/jquery.js
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/jquery.js	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/jquery.js	(revision 417)
@@ -0,0 +1,154 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.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".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
Index: tags/rel-1.3.0-rc1/docs/_static/pygments.css
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/pygments.css	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/pygments.css	(revision 417)
@@ -0,0 +1,62 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight  { background: #eeffcc; }
+.highlight .c { color: #408090; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #007020; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #007020 } /* Comment.Preproc */
+.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #303030 } /* Generic.Output */
+.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #007020 } /* Keyword.Pseudo */
+.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #902000 } /* Keyword.Type */
+.highlight .m { color: #208050 } /* Literal.Number */
+.highlight .s { color: #4070a0 } /* Literal.String */
+.highlight .na { color: #4070a0 } /* Name.Attribute */
+.highlight .nb { color: #007020 } /* Name.Builtin */
+.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.highlight .no { color: #60add5 } /* Name.Constant */
+.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #007020 } /* Name.Exception */
+.highlight .nf { color: #06287e } /* Name.Function */
+.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #bb60d5 } /* Name.Variable */
+.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #208050 } /* Literal.Number.Float */
+.highlight .mh { color: #208050 } /* Literal.Number.Hex */
+.highlight .mi { color: #208050 } /* Literal.Number.Integer */
+.highlight .mo { color: #208050 } /* Literal.Number.Oct */
+.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
+.highlight .sc { color: #4070a0 } /* Literal.String.Char */
+.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
+.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
+.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.highlight .sx { color: #c65d09 } /* Literal.String.Other */
+.highlight .sr { color: #235388 } /* Literal.String.Regex */
+.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
+.highlight .ss { color: #517918 } /* Literal.String.Symbol */
+.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
+.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
+.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
+.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
Index: tags/rel-1.3.0-rc1/docs/_static/searchtools.js
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/searchtools.js	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/searchtools.js	(revision 417)
@@ -0,0 +1,518 @@
+/*
+ * searchtools.js
+ * ~~~~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilties for the full-text search.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/**
+ * helper function to return a node containing the
+ * search summary for a given text. keywords is a list
+ * of stemmed words, hlwords is the list of normal, unstemmed
+ * words. the first one is used to find the occurance, the
+ * latter for highlighting it.
+ */
+
+jQuery.makeSearchSummary = function(text, keywords, hlwords) {
+  var textLower = text.toLowerCase();
+  var start = 0;
+  $.each(keywords, function() {
+    var i = textLower.indexOf(this.toLowerCase());
+    if (i > -1)
+      start = i;
+  });
+  start = Math.max(start - 120, 0);
+  var excerpt = ((start > 0) ? '...' : '') +
+  $.trim(text.substr(start, 240)) +
+  ((start + 240 - text.length) ? '...' : '');
+  var rv = $('<div class="context"></div>').text(excerpt);
+  $.each(hlwords, function() {
+    rv = rv.highlightText(this, 'highlighted');
+  });
+  return rv;
+}
+
+/**
+ * Porter Stemmer
+ */
+var PorterStemmer = function() {
+
+  var step2list = {
+    ational: 'ate',
+    tional: 'tion',
+    enci: 'ence',
+    anci: 'ance',
+    izer: 'ize',
+    bli: 'ble',
+    alli: 'al',
+    entli: 'ent',
+    eli: 'e',
+    ousli: 'ous',
+    ization: 'ize',
+    ation: 'ate',
+    ator: 'ate',
+    alism: 'al',
+    iveness: 'ive',
+    fulness: 'ful',
+    ousness: 'ous',
+    aliti: 'al',
+    iviti: 'ive',
+    biliti: 'ble',
+    logi: 'log'
+  };
+
+  var step3list = {
+    icate: 'ic',
+    ative: '',
+    alize: 'al',
+    iciti: 'ic',
+    ical: 'ic',
+    ful: '',
+    ness: ''
+  };
+
+  var c = "[^aeiou]";          // consonant
+  var v = "[aeiouy]";          // vowel
+  var C = c + "[^aeiouy]*";    // consonant sequence
+  var V = v + "[aeiou]*";      // vowel sequence
+
+  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
+  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
+  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
+  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem
+
+  this.stemWord = function (w) {
+    var stem;
+    var suffix;
+    var firstch;
+    var origword = w;
+
+    if (w.length < 3)
+      return w;
+
+    var re;
+    var re2;
+    var re3;
+    var re4;
+
+    firstch = w.substr(0,1);
+    if (firstch == "y")
+      w = firstch.toUpperCase() + w.substr(1);
+
+    // Step 1a
+    re = /^(.+?)(ss|i)es$/;
+    re2 = /^(.+?)([^s])s$/;
+
+    if (re.test(w))
+      w = w.replace(re,"$1$2");
+    else if (re2.test(w))
+      w = w.replace(re2,"$1$2");
+
+    // Step 1b
+    re = /^(.+?)eed$/;
+    re2 = /^(.+?)(ed|ing)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      re = new RegExp(mgr0);
+      if (re.test(fp[1])) {
+        re = /.$/;
+        w = w.replace(re,"");
+      }
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1];
+      re2 = new RegExp(s_v);
+      if (re2.test(stem)) {
+        w = stem;
+        re2 = /(at|bl|iz)$/;
+        re3 = new RegExp("([^aeiouylsz])\\1$");
+        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+        if (re2.test(w))
+          w = w + "e";
+        else if (re3.test(w)) {
+          re = /.$/;
+          w = w.replace(re,"");
+        }
+        else if (re4.test(w))
+          w = w + "e";
+      }
+    }
+
+    // Step 1c
+    re = /^(.+?)y$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(s_v);
+      if (re.test(stem))
+        w = stem + "i";
+    }
+
+    // Step 2
+    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step2list[suffix];
+    }
+
+    // Step 3
+    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step3list[suffix];
+    }
+
+    // Step 4
+    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
+    re2 = /^(.+?)(s|t)(ion)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      if (re.test(stem))
+        w = stem;
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1] + fp[2];
+      re2 = new RegExp(mgr1);
+      if (re2.test(stem))
+        w = stem;
+    }
+
+    // Step 5
+    re = /^(.+?)e$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      re2 = new RegExp(meq1);
+      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
+        w = stem;
+    }
+    re = /ll$/;
+    re2 = new RegExp(mgr1);
+    if (re.test(w) && re2.test(w)) {
+      re = /.$/;
+      w = w.replace(re,"");
+    }
+
+    // and turn initial Y back to y
+    if (firstch == "y")
+      w = firstch.toLowerCase() + w.substr(1);
+    return w;
+  }
+}
+
+
+/**
+ * Search Module
+ */
+var Search = {
+
+  _index : null,
+  _queued_query : null,
+  _pulse_status : -1,
+
+  init : function() {
+      var params = $.getQueryParameters();
+      if (params.q) {
+          var query = params.q[0];
+          $('input[name="q"]')[0].value = query;
+          this.performSearch(query);
+      }
+  },
+
+  loadIndex : function(url) {
+    $.ajax({type: "GET", url: url, data: null, success: null,
+            dataType: "script", cache: true});
+  },
+
+  setIndex : function(index) {
+    var q;
+    this._index = index;
+    if ((q = this._queued_query) !== null) {
+      this._queued_query = null;
+      Search.query(q);
+    }
+  },
+
+  hasIndex : function() {
+      return this._index !== null;
+  },
+
+  deferQuery : function(query) {
+      this._queued_query = query;
+  },
+
+  stopPulse : function() {
+      this._pulse_status = 0;
+  },
+
+  startPulse : function() {
+    if (this._pulse_status >= 0)
+        return;
+    function pulse() {
+      Search._pulse_status = (Search._pulse_status + 1) % 4;
+      var dotString = '';
+      for (var i = 0; i < Search._pulse_status; i++)
+        dotString += '.';
+      Search.dots.text(dotString);
+      if (Search._pulse_status > -1)
+        window.setTimeout(pulse, 500);
+    };
+    pulse();
+  },
+
+  /**
+   * perform a search for something
+   */
+  performSearch : function(query) {
+    // create the required interface elements
+    this.out = $('#search-results');
+    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
+    this.dots = $('<span></span>').appendTo(this.title);
+    this.status = $('<p style="display: none"></p>').appendTo(this.out);
+    this.output = $('<ul class="search"/>').appendTo(this.out);
+
+    $('#search-progress').text(_('Preparing search...'));
+    this.startPulse();
+
+    // index already loaded, the browser was quick!
+    if (this.hasIndex())
+      this.query(query);
+    else
+      this.deferQuery(query);
+  },
+
+  query : function(query) {
+    var stopwords = ['and', 'then', 'into', 'it', 'as', 'are', 'in',
+                     'if', 'for', 'no', 'there', 'their', 'was', 'is',
+                     'be', 'to', 'that', 'but', 'they', 'not', 'such',
+                     'with', 'by', 'a', 'on', 'these', 'of', 'will',
+                     'this', 'near', 'the', 'or', 'at'];
+
+    // stem the searchterms and add them to the correct list
+    var stemmer = new PorterStemmer();
+    var searchterms = [];
+    var excluded = [];
+    var hlterms = [];
+    var tmp = query.split(/\s+/);
+    var object = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
+    for (var i = 0; i < tmp.length; i++) {
+      if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
+          tmp[i] == "") {
+        // skip this "word"
+        continue;
+      }
+      // stem the word
+      var word = stemmer.stemWord(tmp[i]).toLowerCase();
+      // select the correct list
+      if (word[0] == '-') {
+        var toAppend = excluded;
+        word = word.substr(1);
+      }
+      else {
+        var toAppend = searchterms;
+        hlterms.push(tmp[i].toLowerCase());
+      }
+      // only add if not already in the list
+      if (!$.contains(toAppend, word))
+        toAppend.push(word);
+    };
+    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
+
+    // console.debug('SEARCH: searching for:');
+    // console.info('required: ', searchterms);
+    // console.info('excluded: ', excluded);
+
+    // prepare search
+    var filenames = this._index.filenames;
+    var titles = this._index.titles;
+    var terms = this._index.terms;
+    var objects = this._index.objects;
+    var objtypes = this._index.objtypes;
+    var objnames = this._index.objnames;
+    var fileMap = {};
+    var files = null;
+    // different result priorities
+    var importantResults = [];
+    var objectResults = [];
+    var regularResults = [];
+    var unimportantResults = [];
+    $('#search-progress').empty();
+
+    // lookup as object
+    if (object != null) {
+      for (var prefix in objects) {
+        for (var name in objects[prefix]) {
+          var fullname = (prefix ? prefix + '.' : '') + name;
+          if (fullname.toLowerCase().indexOf(object) > -1) {
+            match = objects[prefix][name];
+            descr = objnames[match[1]] + _(', in ') + titles[match[0]];
+            // XXX the generated anchors are not generally correct
+            // XXX there may be custom prefixes
+            result = [filenames[match[0]], fullname, '#'+fullname, descr];
+            switch (match[2]) {
+            case 1: objectResults.push(result); break;
+            case 0: importantResults.push(result); break;
+            case 2: unimportantResults.push(result); break;
+            }
+          }
+        }
+      }
+    }
+
+    // sort results descending
+    objectResults.sort(function(a, b) {
+      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
+    });
+
+    importantResults.sort(function(a, b) {
+      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
+    });
+
+    unimportantResults.sort(function(a, b) {
+      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
+    });
+
+
+    // perform the search on the required terms
+    for (var i = 0; i < searchterms.length; i++) {
+      var word = searchterms[i];
+      // no match but word was a required one
+      if ((files = terms[word]) == null)
+        break;
+      if (files.length == undefined) {
+        files = [files];
+      }
+      // create the mapping
+      for (var j = 0; j < files.length; j++) {
+        var file = files[j];
+        if (file in fileMap)
+          fileMap[file].push(word);
+        else
+          fileMap[file] = [word];
+      }
+    }
+
+    // now check if the files don't contain excluded terms
+    for (var file in fileMap) {
+      var valid = true;
+
+      // check if all requirements are matched
+      if (fileMap[file].length != searchterms.length)
+        continue;
+
+      // ensure that none of the excluded terms is in the
+      // search result.
+      for (var i = 0; i < excluded.length; i++) {
+        if (terms[excluded[i]] == file ||
+            $.contains(terms[excluded[i]] || [], file)) {
+          valid = false;
+          break;
+        }
+      }
+
+      // if we have still a valid result we can add it
+      // to the result list
+      if (valid)
+        regularResults.push([filenames[file], titles[file], '', null]);
+    }
+
+    // delete unused variables in order to not waste
+    // memory until list is retrieved completely
+    delete filenames, titles, terms;
+
+    // now sort the regular results descending by title
+    regularResults.sort(function(a, b) {
+      var left = a[1].toLowerCase();
+      var right = b[1].toLowerCase();
+      return (left > right) ? -1 : ((left < right) ? 1 : 0);
+    });
+
+    // combine all results
+    var results = unimportantResults.concat(regularResults)
+      .concat(objectResults).concat(importantResults);
+
+    // print the results
+    var resultCount = results.length;
+    function displayNextItem() {
+      // results left, load the summary and display it
+      if (results.length) {
+        var item = results.pop();
+        var listItem = $('<li style="display:none"></li>');
+        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
+          // dirhtml builder
+          var dirname = item[0] + '/';
+          if (dirname.match(/\/index\/$/)) {
+            dirname = dirname.substring(0, dirname.length-6);
+          } else if (dirname == 'index/') {
+            dirname = '';
+          }
+          listItem.append($('<a/>').attr('href',
+            DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
+            highlightstring + item[2]).html(item[1]));
+        } else {
+          // normal html builders
+          listItem.append($('<a/>').attr('href',
+            item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
+            highlightstring + item[2]).html(item[1]));
+        }
+        if (item[3]) {
+          listItem.append($('<span> (' + item[3] + ')</span>'));
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
+          $.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
+                item[0] + '.txt', function(data) {
+            if (data != '') {
+              listItem.append($.makeSearchSummary(data, searchterms, hlterms));
+              Search.output.append(listItem);
+            }
+            listItem.slideDown(5, function() {
+              displayNextItem();
+            });
+          });
+        } else {
+          // no source available, just display title
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        }
+      }
+      // search finished, update title and status message
+      else {
+        Search.stopPulse();
+        Search.title.text(_('Search Results'));
+        if (!resultCount)
+          Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
+        else
+            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
+        Search.status.fadeIn(500);
+      }
+    }
+    displayNextItem();
+  }
+}
+
+$(document).ready(function() {
+  Search.init();
+});
Index: tags/rel-1.3.0-rc1/docs/_static/sidebar.js
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/sidebar.js	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/sidebar.js	(revision 417)
@@ -0,0 +1,148 @@
+/*
+ * sidebar.js
+ * ~~~~~~~~~~
+ *
+ * This script makes the Sphinx sidebar collapsible.
+ *
+ * .sphinxsidebar contains .sphinxsidebarwrapper.  This script adds
+ * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
+ * used to collapse and expand the sidebar.
+ *
+ * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
+ * and the width of the sidebar and the margin-left of the document
+ * are decreased. When the sidebar is expanded the opposite happens.
+ * This script saves a per-browser/per-session cookie used to
+ * remember the position of the sidebar among the pages.
+ * Once the browser is closed the cookie is deleted and the position
+ * reset to the default (expanded).
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+$(function() {
+  // global elements used by the functions.
+  // the 'sidebarbutton' element is defined as global after its
+  // creation, in the add_sidebar_button function
+  var bodywrapper = $('.bodywrapper');
+  var sidebar = $('.sphinxsidebar');
+  var sidebarwrapper = $('.sphinxsidebarwrapper');
+
+  // original margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar expanded
+  var bw_margin_expanded = bodywrapper.css('margin-left');
+  var ssb_width_expanded = sidebar.width();
+
+  // margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar collapsed
+  var bw_margin_collapsed = '.8em';
+  var ssb_width_collapsed = '.8em';
+
+  // colors used by the current theme
+  var dark_color = $('.related').css('background-color');
+  var light_color = $('.document').css('background-color');
+
+  function sidebar_is_collapsed() {
+    return sidebarwrapper.is(':not(:visible)');
+  }
+
+  function toggle_sidebar() {
+    if (sidebar_is_collapsed())
+      expand_sidebar();
+    else
+      collapse_sidebar();
+  }
+
+  function collapse_sidebar() {
+    sidebarwrapper.hide();
+    sidebar.css('width', ssb_width_collapsed);
+    bodywrapper.css('margin-left', bw_margin_collapsed);
+    sidebarbutton.css({
+        'margin-left': '0',
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('»');
+    sidebarbutton.attr('title', _('Expand sidebar'));
+    document.cookie = 'sidebar=collapsed';
+  }
+
+  function expand_sidebar() {
+    bodywrapper.css('margin-left', bw_margin_expanded);
+    sidebar.css('width', ssb_width_expanded);
+    sidebarwrapper.show();
+    sidebarbutton.css({
+        'margin-left': ssb_width_expanded-12,
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('«');
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    document.cookie = 'sidebar=expanded';
+  }
+
+  function add_sidebar_button() {
+    sidebarwrapper.css({
+        'float': 'left',
+        'margin-right': '0',
+        'width': ssb_width_expanded - 28
+    });
+    // create the button
+    sidebar.append(
+        '<div id="sidebarbutton"><span>&laquo;</span></div>'
+    );
+    var sidebarbutton = $('#sidebarbutton');
+    light_color = sidebarbutton.css('background-color');
+    // find the height of the viewport to center the '<<' in the page
+    var viewport_height;
+    if (window.innerHeight)
+ 	  viewport_height = window.innerHeight;
+    else
+	  viewport_height = $(window).height();
+    sidebarbutton.find('span').css({
+        'display': 'block',
+        'margin-top': (viewport_height - sidebar.position().top - 20) / 2
+    });
+
+    sidebarbutton.click(toggle_sidebar);
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    sidebarbutton.css({
+        'color': '#FFFFFF',
+        'border-left': '1px solid ' + dark_color,
+        'font-size': '1.2em',
+        'cursor': 'pointer',
+        'height': bodywrapper.height(),
+        'padding-top': '1px',
+        'margin-left': ssb_width_expanded - 12
+    });
+
+    sidebarbutton.hover(
+      function () {
+          $(this).css('background-color', dark_color);
+      },
+      function () {
+          $(this).css('background-color', light_color);
+      }
+    );
+  }
+
+  function set_position_from_cookie() {
+    if (!document.cookie)
+      return;
+    var items = document.cookie.split(';');
+    for(var k=0; k<items.length; k++) {
+      var key_val = items[k].split('=');
+      var key = key_val[0];
+      if (key == 'sidebar') {
+        var value = key_val[1];
+        if ((value == 'collapsed') && (!sidebar_is_collapsed()))
+          collapse_sidebar();
+        else if ((value == 'expanded') && (sidebar_is_collapsed()))
+          expand_sidebar();
+      }
+    }
+  }
+
+  add_sidebar_button();
+  var sidebarbutton = $('#sidebarbutton');
+  set_position_from_cookie();
+});
Index: tags/rel-1.3.0-rc1/docs/_static/underscore.js
===================================================================
--- tags/rel-1.3.0-rc1/docs/_static/underscore.js	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_static/underscore.js	(revision 417)
@@ -0,0 +1,16 @@
+(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
+a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
+var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
+d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=
+function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,
+function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};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){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a,
+0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d,
+e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d=
+a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;1;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)});
+return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);
+var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;
+if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
+0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&
+a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g,
+" ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);
+o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
Index: tags/rel-1.3.0-rc1/docs/_templates/index.html
===================================================================
--- tags/rel-1.3.0-rc1/docs/_templates/index.html	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_templates/index.html	(revision 417)
@@ -0,0 +1,3 @@
+{% extends "layout.html" %}
+{% set title = 'Overview' %}
+
Index: tags/rel-1.3.0-rc1/docs/_templates/indexsidebar.html
===================================================================
--- tags/rel-1.3.0-rc1/docs/_templates/indexsidebar.html	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_templates/indexsidebar.html	(revision 417)
@@ -0,0 +1,20 @@
+<div class="categories">
+  <a href="{{ pathto('dl/index') }}"><h1>Download now !</h1>
+        <p class="version">ZOO Version 1.0</p></a>
+</div>
+<div class="donate">
+  <h1 id="SupportZOO-Project">Support ZOO-Project</h1>
+    <form action="https://www.paypal.com/cgi-bin/webscr" method="post" style="text-align: center;">
+      <input type="hidden" name="cmd" value="_s-xclick"></input>
+      <input type="hidden" name="hosted_button_id" value="WTHKTUQBHBHSQ"></input>
+      <input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" style="border:0"></input>
+      <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"></img>
+    </form>
+</div>
+<div class="twitts">
+  <h1 id="FollowtheZOO">Follow the ZOO</h1>
+    <p>
+      <a style="padding:0; border:none" href="http://twitter.com/ZOO_Project"><img src="http://a0.twimg.com/a/1291253242/images/fronts/logo_withbird_home.png" alt="http://a0.twimg.com/a/1291253242/images/fronts/logo_withbird_home.png" title="http://a0.twimg.com/a/1291253242/images/fronts/logo_withbird_home.png"></img></a>
+    </p>
+</div>
+
Index: tags/rel-1.3.0-rc1/docs/_templates/layout.html
===================================================================
--- tags/rel-1.3.0-rc1/docs/_templates/layout.html	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/_templates/layout.html	(revision 417)
@@ -0,0 +1,165 @@
+{% extends "!layout.html" %}
+
+{% block extrahead %}
+
+<script type="text/javascript">
+$(document).ready(function(){
+
+	$("ul.topnav li a").hover(function() {
+
+		//Following events are applied to the subnav itself (moving subnav up and down)
+		$(this).parent().find("ul.subnav").slideDown('fast').show(); //Drop down the subnav on click
+
+		$(this).parent().hover(function() {
+		}, function(){
+			$(this).parent().find("ul.subnav").slideUp('slow'); //When the mouse hovers out of the subnav, move it back up
+		});
+
+		//Following events are applied to the trigger (Hover events for the trigger)
+		}).hover(function() {
+			$(this).addClass("subhover"); //On hover over, add class "subhover"
+		}, function(){	//On Hover Out
+			$(this).removeClass("subhover"); //On hover out, remove class "subhover"
+	});
+
+});
+</script>
+
+    {{ super() }}
+{% endblock %}
+
+{% block header %}
+<!-- Begin Header -->
+<div id="wrapper">
+  	<div id="myheader">
+    	<div class="hleft">
+    	  <h1 class="title">Open WPS Platform</h1>
+    	</div>
+    	<div class="hright">
+    	</div>
+  	</div>
+</div>
+<ul class="topnav">
+  <li><a href="http://www.zoo-project.org/">Home</a></li>
+  <li><a href="#">ZOO Project</a>
+       <ul class="subnav">
+
+         <li><a href="/site/ZooWebSite/ZooProject/About">About</a></li>
+         <li><a href="/site/ZooWebSite/ZooProject/Tribe">ZOO Tribe</a></li>
+         <li><a href="/site/ZooWebSite/ZooProject/Events">Events</a></li>
+         <li><a href="/site/ZooWebSite/ZooProject/Photos">Photos</a></li>
+         <li><a href="/site/ZooWebSite/ZooProject/Contact">Contacts</a></li>
+       </ul>
+
+  </li>
+  <li>
+    <a href="#">Components</a>
+    <ul class="subnav">
+      <li><a href="/site/ZooWebSite/ZooKernel">ZOO Kernel</a></li>
+      <li><a href="/site/ZooWebSite/ZooServices">ZOO Services</a></li>
+      <li><a href="/site/ZooWebsite/ZooApi">ZOO API</a></li>
+
+    </ul>
+  </li>
+  <li><a href="/site/Downloads">Download</a></li>
+  <li><a href="{{ pathto('index') }}">Docs</a></li>
+  <li><a href="#">Demos</a>
+    <ul class="subnav">
+      <li><a href="/site/ZooWebSite/Demo/SpatialTools">ZOO Spatial Tools</a></li>
+
+      <li><a href="/site/ZooWebSite/Demo/CGAL">ZOO CGAL Vor</a></li>
+      <li><a href="/site/ZooWebSite/Demo/WFS-T">ZOO Mapserver WFS-T</a></li>
+      <li><a href="/site/ZooWebSite/Demo/GdalProfile">ZOO Elevation Profile</a></li>
+      <li><a href="/site/ZooWebSite/Demo/FormTools">ZOO Form tools</a></li>
+    </ul>
+  </li>
+  <li><a href="/trac">Trac</a></li>
+</ul>
+<!-- End Header -->
+    {{ super() }}
+{% endblock %}
+
+{% block footer %}
+<!-- Begin Footer -->
+<div id="footer">
+<div>
+
+<div>
+  <div class="menuContainer">
+    <div class="menuItemList">
+      <a href="{{ pathto('index') }}" shape="rect">Home</a>
+      <br/>
+    </div>
+    <div class="menuItemList">
+      <a href="#" shape="rect">ZOO Project</a>
+
+      <br/>
+      <a href="/site/ZooWebSite/ZooProject/About" shape="rect">About</a>
+      <br/>
+      <a href="/site/ZooWebSite/ZooProject/Tribe" shape="rect">ZOO Tribe</a>
+      <br/>
+      <a href="/site/ZooWebSite/ZooProject/Events" shape="rect">Events</a>
+      <br/>
+
+      <a href="/site/ZooWebSite/ZooProject/Photos" shape="rect">Photos</a>
+      <br/>
+      <a href="/site/ZooWebSite/ZooProject/Contact" shape="rect">Contacts</a>
+      <br/>
+    </div>
+    <div class="menuItemList">
+      <a href="#" shape="rect">Components</a>
+
+      <br/>
+      <a href="/site/ZooWebSite/ZooKernel" shape="rect">ZOO Kernel</a>
+      <br/>
+      <a href="/site/ZooWebSite/ZooServices" shape="rect">ZOO Services</a>
+      <br/>
+      <a href="/site/ZooWebsite/ZooApi" shape="rect">ZOO API</a>
+      <br/>
+
+    </div>
+    <div class="menuItemList">
+      <a href="{{ pathto('dl/index') }}" shape="rect">Download</a>
+      <br/>
+    </div>
+    <div class="menuItemList">
+      <a href="{{ pathto('doc/index') }}" shape="rect">Docs</a>
+      <br/>
+
+    </div>
+    <div class="menuItemList">
+      <a href="#" shape="rect">Demos</a>
+      <br/>
+      <a href="/site/ZooWebSite/Demo/SpatialTools" shape="rect">ZOO Spatial Tools</a>
+      <br/>
+      <a href="/site/ZooWebSite/Demo/WFS-T" shape="rect">ZOO Mapserver WFS-T</a>
+
+      <br/>
+      <a href="/site/ZooWebSite/Demo/GdalProfile" shape="rect">ZOO Elevation Profile</a>
+      <br/>
+      <a href="/site/ZooWebSite/Demo/FormTools" shape="rect">ZOO Form tools</a>
+      <br/>
+    </div>
+    <div class="menuItemList">
+      <a href="/trac" shape="rect">Trac</a>
+
+      <br/>
+    </div>
+  </div>
+  <br style="clear:both"/>
+</div>
+</div>
+<p>
+&copy; Copyright 2011 - <a class="ext-link" href="http://www.zoo-project.org" shape="rect"><span class="icon"> </span>ZOO Project</a> - All Rights Reserved. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{sphinx_version}}.
+</p>
+</div>
+<!-- End Footer -->
+    {{ super() }}
+{% endblock %}
+
+{# put the sidebar before the body #}
+{% block sidebar1 %}{% endblock %}
+{% block sidebar2 %}{{ sidebar() }}{% endblock %}
+
+{# remove second relbar, at the bottom of the page #}
+{% block relbar2 %}{% endblock %}
Index: tags/rel-1.3.0-rc1/docs/api/classes.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/classes.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/classes.txt	(revision 417)
@@ -0,0 +1,38 @@
+.. _api-classes:
+
+Classes
+=======
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+The following classes are available in the ZOO API:
+
+.. toctree::
+   :maxdepth: 2
+   
+   zoo
+   zoo-bounds  
+   zoo-feature   
+   zoo-format
+   zoo-format-geojson 
+   zoo-format-gml   
+   zoo-format-json 
+   zoo-format-kml
+   zoo-format-wkt  
+   zoo-format-wps  
+   zoo-geometry  
+   zoo-geometry-collection  
+   zoo-geometry-curve
+   zoo-geometry-linearring   
+   zoo-geometry-linestring   
+   zoo-geometry-multilinestring   
+   zoo-geometry-multipoint 
+   zoo-geometry-multipolygon   
+   zoo-geometry-point 
+   zoo-geometry-polygon   
+   zoo-geometry-surface 
+   zoo-process   
+   zoo-projection   
+   zoo-request
+   zoo-string   
Index: tags/rel-1.3.0-rc1/docs/api/description.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/description.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/description.txt	(revision 417)
@@ -0,0 +1,43 @@
+.. _api-description:
+
+Description
+===========
+
+ZOO API is a 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.
+
+Download ZOO API
+----------------
+
+    * `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>`__
+
+ZOO API MIT/X-11 License
+------------------------
+
+::
+
+  Copyright (c) 2011 3LIZ
+
+  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.3.0-rc1/docs/api/examples.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/examples.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/examples.txt	(revision 417)
@@ -0,0 +1,54 @@
+.. _api-examples:
+
+Examples
+========
+
+In this page you can find some small examples on how to use the JavaScript ZOO-API 
+on the server side.
+
+ZOO-API contains many classes and functions. You can find the description list :ref:`here <api-classes>`.
+
+ZOO.Process example of use
+--------------------------
+
+::
+
+  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
+----------------
+
+::
+
+  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.3.0-rc1/docs/api/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/index.txt	(revision 417)
@@ -0,0 +1,14 @@
+.. _api:
+
+ZOO API Documentation
+=====================
+
+The following sections will assist you with the ZOO API:
+
+.. toctree::
+   :maxdepth: 2
+   
+   description
+   classes
+   examples
+
Index: tags/rel-1.3.0-rc1/docs/api/zoo-bounds.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-bounds.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-bounds.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-feature.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-feature.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-feature.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-format-geojson.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-format-geojson.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-format-geojson.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-format-gml.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-format-gml.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-format-gml.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-format-json.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-format-json.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-format-json.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-format-kml.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-format-kml.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-format-kml.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-format-wkt.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-format-wkt.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-format-wkt.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-format-wps.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-format-wps.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-format-wps.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-format.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-format.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-format.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-collection.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-collection.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-collection.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-curve.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-curve.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-curve.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-linearring.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-linearring.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-linearring.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-linestring.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-linestring.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-linestring.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-multilinestring.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-multilinestring.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-multilinestring.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-multipoint.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-multipoint.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-multipoint.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-multipolygon.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-multipolygon.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-multipolygon.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-point.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-point.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-point.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-polygon.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-polygon.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-polygon.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry-surface.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry-surface.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry-surface.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-geometry.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-geometry.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-geometry.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-process.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-process.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-process.txt	(revision 417)
@@ -0,0 +1,149 @@
+.. _api-zoo-process:
+
+ZOO.Process
+===========
+
+Used to query OGC WPS process defined by its URL and its identifier.  Usefull 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.3.0-rc1/docs/api/zoo-projection.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-projection.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-projection.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-request.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-request.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-request.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo-string.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo-string.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo-string.txt	(revision 417)
@@ -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.3.0-rc1/docs/api/zoo.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/api/zoo.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/api/zoo.txt	(revision 417)
@@ -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.3.0-rc1/docs/community/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/community/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/community/index.txt	(revision 417)
@@ -0,0 +1,13 @@
+.. _community:
+
+ZOO Community
+=============
+
+The following sections will help you interact with the ZOO community.
+
+.. toctree::
+   :maxdepth: 2
+   
+   mailinglist
+   irc
+
Index: tags/rel-1.3.0-rc1/docs/community/irc.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/community/irc.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/community/irc.txt	(revision 417)
@@ -0,0 +1,59 @@
+.. _community-irc:
+
+IRC Chat
+========
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna, Luca Delucchi
+:Last Updated: $Date$
+
+Some of the development of the ZOO-Project is coordinated through IRC. This page
+describes how you log on to chat, ask questions, and hack around with the
+developers.
+
+Server and Channel Information
+------------------------------
+
+::
+
+  Server: irc.freenode.net
+  Channel: #zoo-project
+
+Why IRC?
+--------
+
+IRC is a primary medium where Open Source GIS hackers congregate, collaborate,
+and hack. It makes it easy to communicate things like compilation issues,
+where immediate, iterative feedback allows folks to make a lot of progress.
+Something that might take days of heavily-quoted emails through a mailinglist
+might only take fifteen minutes on IRC.
+
+IRC is a great way to coordinate on-line meetings. The ZOO PSC conducts their
+monthly meetings through IRC.
+
+How do I join?
+--------------
+
+- `Chatzilla <http://chatzilla.hacksrus.com/>`__ is
+  probably the easiest way to get going. Chatzilla works with Mozilla or
+  Firefox, and once you have it installed, you can log on to the channel by
+  pointing your browser at::
+
+    irc://irc.freenode.net/#zoo-project
+
+- There are many other IRC clients available. `This page
+  <http://tikiwiki.org/ConnectingToIrc>`__ provides a good listing for many
+  different platforms.
+  
+- You can also connect to IRC directly in your Web browser without a client:
+
+  - goto http://webchat.freenode.net/
+  - enter a nickname (usually your first initial plus your last name)
+  - in "Channels" enter: zoo-project
+  - Connect!
+
+IRC logs
+-----------
+
+It is possible to see the logs (history) of ZOO-Project IRC channel
+`here <http://svn.zoo-project.org/irc/>`_
+
Index: tags/rel-1.3.0-rc1/docs/community/mailinglist.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/community/mailinglist.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/community/mailinglist.txt	(revision 417)
@@ -0,0 +1,28 @@
+.. _community-mailinglist:
+
+Mailing Lists
+=============
+
+ZOO-Discuss
+-----------
+
+The ``zoo-discuss`` list is your main source of support for the ZOO-Project.
+
+- **Subscribing to zoo-discuss**
+
+  To subscribe to the zoo-discuss listserv visit
+  http://lists.osgeo.org/cgi-bin/mailman/listinfo/zoo-discuss. You can later change
+  your subscription information or leave the list at this website.
+
+- **Submitting Questions to zoo-discuss**
+
+  To submit questions to the zoo-discuss listserv, first join the list by
+  following the subscription procedure above. Then post questions to the list by
+  sending an email message to zoo-discuss@lists.osgeo.org.
+
+- **Searching the Archives**
+
+  All zoo-discuss archives are located in
+  http://lists.osgeo.org/pipermail/zoo-discuss/.
+
+.. Searching the archives is best done with `Nabble <http://zoo-discuss.1049523.n5.nabble.com/>`_.:
Index: tags/rel-1.3.0-rc1/docs/conf.py
===================================================================
--- tags/rel-1.3.0-rc1/docs/conf.py	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/conf.py	(revision 417)
@@ -0,0 +1,267 @@
+# -*- coding: utf-8 -*-
+#
+# ZOO Project documentation build configuration file, created by
+# sphinx-quickstart on Tue Mar 08 12:11:20 2011.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.txt'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'ZOO Project'
+copyright = u'2011, Nicolas Bozon, Gérald Fenoy, Jeff McKenna'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.0'
+# The full version, including alpha/beta/rc tags.
+release = '1.3'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {
+    "rightsidebar": "true",
+    "headbgcolor": "#ffffff",
+    "bgcolor": "#ffffff",
+    "textcolor": "#333333",
+    "linkcolor": "#fc9326",
+    "visitedlinkcolor": "#fc9326",    
+    "sidebarbgcolor": "white",
+    "relbarbgcolor": "#ffa500"    
+}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "ZOO Project " + release + " documentation"
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+html_short_title = "ZOO Docs"
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = 
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = "favicon.ico"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {
+'**': ['globaltoc.html', 'sourcelink.html', 'searchbox.html'],
+"index":["indexsidebar.html",'searchbox.html']}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = False
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+html_show_sphinx = False
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+html_show_copyright = False
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ZOOProjectdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'ZOOProject.tex', u'ZOO Project Documentation',
+   u'Nicolas Bozon, Gérald Fenoy, Jeff McKenna', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+latex_logo = './_static/images/zoo-banner-large.png'
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+latex_preamble = '\setcounter{tocdepth}{3}'
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'zooproject', u'ZOO Project Documentation',
+     [u'Nicolas Bozon, Gérald Fenoy, Jeff McKenna'], 1)
+]
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'ZOO Project'
+epub_author = u'Nicolas Bozon, Gérald Fenoy, Jeff McKenna'
+epub_publisher = u'Nicolas Bozon, Gérald Fenoy, Jeff McKenna'
+epub_copyright = u'2011, Nicolas Bozon, Gérald Fenoy, Jeff McKenna'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+epub_scheme = 'URL'
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+epub_identifier = 'http://zoo-project.org'
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
Index: tags/rel-1.3.0-rc1/docs/development/documentation.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/development/documentation.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/development/documentation.txt	(revision 417)
@@ -0,0 +1,167 @@
+.. _documentation_development:
+
+Documentation Development Guide
+===============================
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+Background
+----------
+
+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.
+
+reStructuredText Reference Guides
+---------------------------------
+
+- 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>`__
+
+reStructuredText Formatting
+---------------------------
+
+- All text should be hard breaks at or around the 80 column mark, just as
+  the source code.
+
+Installing and Using Sphinx for rst-html Generation
+---------------------------------------------------
+
+.. note::
+   
+    You can browse the versions of the Sphinx packages `here <http://pypi.python.org/pypi?%3Aaction=index>`__,
+    and then install the exact version such as:
+        
+    ::
+        
+        easy_install Sphinx==1.0.7
+
+
+**On Windows:**
+
+#. 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
+
+   ...you should see message: "Finished processing dependencies for Sphinx"
+
+   .. note::
+   
+      Make sure you install Sphinx 1.0 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.
+
+**On Linux:**
+
+#. make sure you have the Python dev and setuptools packages installed.
+   On Ubuntu:
+
+   ::
+
+       sudo apt-get install python-dev
+       sudo apt-get install python-setuptools
+
+#. install sphinx using easy_install:
+
+   ::
+
+       sudo easy_install Sphinx
+       
+   .. note::
+    
+      Make sure you install Sphinx 1.0 or more recent.  See note above.  
+      
+#. 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:**
+
+#. install sphinx using easy_install:
+
+   ::
+
+       sudo easy_install Sphinx
+       
+   .. note::
+   
+      Make sure you install Sphinx 1.0 or more recent.  See note above.        
+
+#. 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.
Index: tags/rel-1.3.0-rc1/docs/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/index.txt	(revision 417)
@@ -0,0 +1,73 @@
+.. _home:
+
+ZOO 1.3 Documentation
+=====================
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+Quick Links
+===========
+
+..   csv-table:: Quick Links
+
+    :ref:`kernel`,:ref:`services`,:ref:`api`
+    :ref:`kernel-installation`,:ref:`community`,`Search mailing list <http://zoo-discuss.1049523.n5.nabble.com/>`__
+    :ref:`documentation_development`,:ref:`workshop-foss4g-japan-2010`,:ref:`workshop-foss4g-cee-2012`
+
+.. note::
+    The entire documentation is also available as a single
+    `PDF document <./ZOOProject.pdf>`__ |image|  and `ePub document <./ZOOProject.epub>`__
+
+About ZOO Documentation
+=======================
+
+ZOO Documentation is a collaborative process; once users contribute documentation
+through the ZOO Wiki, the Documentation Committee will then review the contributions
+to add them into the official docs.  The committee is currently composed of:
+
+::
+
+  Nicolas Bozon (nicolas.bozon at gmail.com)
+  Gérald Fenoy (gerald.fenoy at geolabs.fr)
+  Jeff McKenna (jmckenna at gatewaygeomatics.com)
+  
+A special thank to the ZOO-Project sponsors and knwoledge partners for their support.
+  
+The committee would like to thank ``Venkatesh Raghavan`` for his help on promoting ZOO Workshop in many places.
+
+The committee would like to thank ``Hirofumi Hayashi`` and ``Daisuke Yoshida`` for their help and japanese translation effort for the ZOO-Project Worshop 2010.
+  
+The committee would also like to thank the early contributors to the documentation: ``Luca Delucchi``, ``René-Luc D'Hont``,  ``Angelos Tzotsos`` and ``Guillaume Sueur``.
+
+  
+ZOO Wiki
+========
+
+Users wishing to contribute steps and documents should use the
+`ZOO Wiki <http://www.zoo-project.org/trac>`__.  
+
+Official Documentation
+======================
+
+This section contains the official ZOO Project documentation.
+    
+.. |image| image:: _static/images/pdf.png
+   :height: 15
+   :width: 15
+   :alt: PDF icon
+   :target: /ZOOProject.pdf
+
+.. toctree::
+   :maxdepth: 3
+   
+   kernel/index
+   services/index
+   api/index
+   workshop/2010/index
+   workshop/2012/index
+   community/index
+   development/documentation
+
+
+
Index: tags/rel-1.3.0-rc1/docs/kernel/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/index.txt	(revision 417)
@@ -0,0 +1,14 @@
+.. _kernel:
+
+ZOO Kernel Documentation
+========================
+
+The following sections will assist you with the ZOO Kernel:
+
+.. toctree::
+   :maxdepth: 2
+   
+   introduction
+   installation
+   mapserver
+
Index: tags/rel-1.3.0-rc1/docs/kernel/install-centos.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/install-centos.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/install-centos.txt	(revision 417)
@@ -0,0 +1,168 @@
+.. _kernel-installation-centos:
+
+CentOS
+======
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+.. note::
+   This documentation was created thanks to Guillaume Sueur from Neogeo Technologies which took time to test 
+   installing the ZOO-Kernel on a CentOS 5.5 environment.
+
+Requirements
+------------
+
+Install some standard tools to be able to run ZOO-Kernel on your platform :
+
+::
+
+  yum install apache2
+  yum install build-essentials
+  yum install gcc-c++
+  yum install zlib-devel
+  yum install libxml2-devel
+  yum install bison
+  yum install openssl 
+  yum install python-devel
+  yum install subversion
+
+Compile then install FastCGI library from source
+
+::
+
+  wget http://www.fastcgi.com/dist/fcgi.tar.gz
+  tar xzf fcgi-2.4.0.tar.gz 
+  ./configure
+  make
+  make install
+  echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf
+  ldconfig
+
+Compile then install the autoconf tools :
+
+::
+
+  wget http://ftp.gnu.org/gnu/autoconf/autoconf-latest.tar.gz
+  tar xzf autoconf-latest.tar.gz
+  ./configure --prefix=/usr
+  make 
+  make install
+
+Compile then install the flex tool :
+
+::
+
+  wget http://downloads.sourceforge.net/project/flex/flex/flex-2.5.35/flex-2.5.35.tar.gz?r=http%3A%2F%2Fflex.sourceforge.net%2F&ts=1292529005&use_mirror=switch
+  tar xzf flex-2.5.35.tar.gz
+  cd flex-2.5.35
+  ./configure --prefix=/usr
+  make
+  make install
+
+Using the curl provided in the CentOS distribution will produce a ZOO-Kernel unable to run any 
+Service. Indeed, some segmentation faults occur when trying to run ``Execute`` requests on the ZOO-Kernel, 
+compiling the ZOO-Kernel setting ``USE_GDB`` flag in the ``CFLAGS`` of your ``Makefile`` will let you run 
+ZOO-Kernel from gdb and be able to get more information on what is going wrong with your ZOO-Kernel. 
+Doing this we can figure out that code on `line 173 <http://zoo-project.org/trac/browser/trunk/zoo-kernel/ulinet.c#L173>`__ 
+and `line 175 <http://zoo-project.org/trac/browser/trunk/zoo-kernel/ulinet.c#L175>`__ have to be commented in the 
+``ulinet.c`` file to get a ZOO-Kernel working using the curl available in CentOS (curl version 7.15.5). 
+If you don't apply the modification, you will get an error from a gdb session pointing 
+segfault in ``Curl_cookie_clearall``.
+
+You can optionally compile then install curl from source :
+
+::
+
+  wget http://curl.haxx.se/download/curl-7.21.3.tar.bz2
+  tar xjf curl-7.21.3.tar.bz2
+  cd curl-7.21.3
+  ./configure --prefix=/usr
+  make
+  make install
+
+Compile then install Python :
+
+::
+ 
+  wget http://www.python.org/ftp/python/2.6.6/Python-2.6.6.tar.bz2
+  tar xjf Python-2.6.6.tar.bz2
+  cd Python-2.6.6
+  ./configure
+  make
+  make install
+
+Compile then install your own GDAL library :
+
+::
+
+  wget http://download.osgeo.org/gdal/gdal-1.7.3.tar.gz
+  tar xzf gdal-1.7.3.tar.gz
+  cd gdal-1.7.3
+  ./configure  # add your options here
+  make
+  make install
+
+Install the Sun JAVA SDK into ``/usr/share`` then use the following command to ensure that the ``libjvm.so`` 
+will be found at runtime from any context.
+
+::
+
+  echo /usr/share/java-1.6.0-openjdk-1.6.0.0/jre/lib/i386/client/ >> /etc/ld.so.conf.d/jvm.conf
+  ldconfig
+
+Compile ZOO-Kernel and ZOO-Services
+-----------------------------------
+
+Compile then install ZOO-Kernel and your first ZOO-Services.
+
+First of all, compile the cgic library providen in the SVN source tree:
+
+::
+
+  svn co http://svn.zoo-project.org/svn/trunk zoo-project
+  cd zoo-project/thirds/cgic206
+  make
+
+Compile then install ZOO-Kernel.
+
+::
+
+  cd ../../zoo-kernel
+  ./configure --with-java=/usr/share/jdk1.6.0_23/ --with-python
+  make zoo_loader.cgi
+  cp main.cfg /var/www/cgi-bin/
+  cp  zoo_loader.cgi /var/www/cgi-bin/
+
+Compile then deploy your first ZOO-ServicesProviders (simple HelloPy, line 1 and 2, and the OGR base-vect-ops 
+ServiceProvider, line 3 to 6):
+
+::
+
+  cp ../zoo-services/hello-py/cgi-env/*.zcfg /var/www/cgi-bin/
+  cp ../zoo-services/hello-py/test_service.py /var/www/cgi-bin/
+  cd ../ogr/base-vect-ops/
+  make
+  cp ./cgi-env/* /var/www/cgi-bin/
+  vi /var/www/cgi-bin/main.cfg --> set your own informations here
+
+To ensure that the ``libjvm.so`` will be found from apache, please restart it :
+
+::
+
+  /etc/init.d/httpd restart
+
+Testing your ZOO-Kernel
+-----------------------
+
+Test your ZOO-Kernel from command line:
+
+::
+
+  cd /var/www/cgi-bin
+  ./zoo_loader.cgi "request=Execute&service=WPS&version=1.0.0&Identifier=HelloPy&DataInputs=a=Djay"
+  ./zoo_loader.cgi "request=Execute&service=WPS&version=1.0.0&Identifier=Buffer&DataInputs=BufferDistance=1@datat
Index: tags/rel-1.3.0-rc1/docs/kernel/install-debian.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/install-debian.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/install-debian.txt	(revision 417)
@@ -0,0 +1,253 @@
+.. _kernel-installation-debian:
+
+Debian / Ubuntu
+===============
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna, Luca Delucchi
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+.. note::
+   An Ubuntu 10.4 with ZOO virtual image is available at http://www.zoo-project.org/Ubuntu10.4_ZOO.zip
+   (root: ZOO.test)
+
+Ubuntu 12.04 dependencies
+--------------------------------------
+
+- install default dependencies
+
+::
+
+  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
+
+- add ubuntugis repository to obtain the newer GIS libraries
+
+::
+
+  sudo add-apt-repository ppa:ubuntugis/ppa
+  sudo apt-get update
+
+
+- install geographic library
+
+::
+
+  sudo apt-get install libgdal1-dev
+
+- download ZOO  source
+
+Debian 7.0 dependencies
+--------------------------------------
+
+- install dependencies
+
+::
+
+  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
+
+
+Installation Workflow
+--------------------------------------
+
+.. note :: In the following lines you will find ``as administrator user`` note,
+	   on Ubuntu you have to add ``sudo`` at the beginning of line, on Debian
+	   you can use ``su -c COMMAND``)
+
+::
+
+  svn checkout http://svn.zoo-project.org/svn/trunk zoo-project
+
+- install cgic from packages
+
+::
+
+  cd zoo-project/thirds/cgic206/
+
+- compile
+
+::
+
+  make
+
+- if you want use Mapserver (optional) for WMS, WFS and WCS output read :ref:`mapserver`
+
+- go to kernel path
+
+::
+
+  cd ../../zoo-project/zoo-kernel/
+
+- create configure file
+
+::
+
+  autoconf
+
+- run configure
+
+::
+
+  ./configure --with-js --with-python
+
+.. note:: For PHP, you must make sure to compile PHP with `--enable-embed <http://www.zoo-project.org/trac/wiki/ZooKernel/Embed/PHP#ConfigureandInstallPHPEmbedlibrary>`__.
+
+.. note:: To use MapServer add the option ``--with-mapserver=/path/to/mapserver/source`` 
+
+- compile
+
+::
+
+  make
+
+- copy necessary files into your cgi-bin (as administrator user)
+
+
+::
+
+  cp main.cfg /usr/lib/cgi-bin
+  cp zoo_loader.cgi /usr/lib/cgi-bin
+
+- install ZOO ServiceProvider, in this case we try Python service (as administrator user)
+
+::
+
+  cp ../zoo-services/hello-py/cgi-env/*.zcfg /usr/lib/cgi-bin
+  cp ../zoo-services/hello-py/*.py /usr/lib/cgi-bin/
+
+- change some information in the main.cfg (as administrator user)
+
+::
+
+  nano /usr/lib/cgi-bin/main.cfg
+  - serverAddress = http://127.0.0.1
+
+
+- try the installation
+
+  - http://127.0.0.1/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=GetCapabilities&Version=1.0.0
+  - http://127.0.0.1/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=DescribeProcess&Version=1.0.0&Identifier=HelloPy
+  - 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::
+   If you have some problem in the execute request using Python service, add the following to ``main.cfg``: 
+
+   ::
+   
+     [env]
+     PYTHONPATH=<YOUR_PYTHONPATH>
+
+
+Rewrite rule configuration
+-----------------------------
+
+- for better readability and fully functional ZOO Kernel, you have to modify the default
+  Apache configuration in order to be able to use the http://localhost/zoo/ url directly.
+  Run (as administrator user)
+
+::
+
+    nano /usr/lib/cgi-bin/main.cfg
+    - serverAddress = http://localhost/zoo
+
+- first, please create a ``zoo`` directory in ``/var/www/`` which is used by Apache as the
+  DocumentRoot (as administrator user)
+
+::
+
+  mkdir /var/www/zoo
+
+- Then, please edit the ``/etc/apache2/sites-available/default`` configuration file and add the following
+  lines after the Directory block related to /var/www directory (as administrator user)
+
+::
+
+  <Directory /var/www/zoo/>
+      Options Indexes FollowSymLinks MultiViews
+      AllowOverride All
+      Order allow,deny
+      allow from all
+  </Directory>
+
+- now create a small .htaccess file in the ``/var/www/zoo`` containing the following lines (as administrator user)
+
+::
+
+  RewriteEngine on
+  RewriteRule call/(.*)/(.*) /cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=$1&DataInputs=sid=$2&RawDataOutput=Result [L,QSA]
+  RewriteRule (.*)/(.*) /cgi-bin/zoo_loader.cgi?metapath=$1 [L,QSA]
+  RewriteRule (.*) /cgi-bin/zoo_loader.cgi [L,QSA]
+
+
+- for this last file to be taken into account by Apache, you must activate the
+  rewrite Apache module by copying a load file as bellow (as administrator user)
+
+::
+
+  cp /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/
+
+- or using the a2enmod tool this way (as administrator user)
+
+::
+
+  a2enmod rewrite
+
+- now you should be able to access the ZOO Kernel using a simplified by restarting
+  your Apache Web server (as administrator user)
+
+::
+  /etc/init.d/apache2 restart
+
+- now you can try:
+
+  - http://localhost/zoo/?Service=WPS&Request=GetCapabilities&Version=1.0.0
+  - http://localhost/zoo/?Service=WPS&Request=DescribeProcess&Version=1.0.0&Identifier=HelloPy
+  - http://localhost/zoo/?Service=WPS&Request=Execute&Version=1.0.0&Identifier=HelloPy&DataInputs=a=myname
+
+.. _mapserver:
+
+Compile MapServer
+------------------
+
+- install MapServer dependencies (as administrator user)
+
+::
+
+  apt-get install git libfreetype6-dev libproj-dev libkml-dev libcairo-dev libxml2-dev libgd2-xpm-dev libxslt1-dev
+
+- extract MapServer from git repository
+
+::
+
+  git clone https://github.com/mapserver/mapserver.git
+  cd mapserver
+  git checkout branch-6-2
+  git pull
+
+- now compile MapServer
+
+::
+
+  ./configure --with-ogr --with-gdal --with-wfsclient --with-wmsclient --with-tiff --with-jpeg --with-gd --with-wcs --with-sos --with-xml2-config --with-wfs --with-fastcgi --with-proj --with-cairo --with-kml=yes --with-xslt --with-threads --with-geos
+  make
+
+- now install MapServer (as administrator user)
+
+::
+
+  make install
+
+- now add path to libraries path (as administrator user)
+
+::
+
+  nano /etc/ld.so.conf.d/mapserver.conf
+  - /usr/local/lib/
+
+- run as administrator
+
+::
+
+  ldconfig
Index: tags/rel-1.3.0-rc1/docs/kernel/install-mac.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/install-mac.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/install-mac.txt	(revision 417)
@@ -0,0 +1,191 @@
+.. _kernel-installation-mac:
+
+Mac OS X
+========
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+Using the Installer
+-------------------
+
+1. To install a default build of the ZOO-Project on your Mac OS X computer use the `installer <http://www.zoo-project.org/trac/raw-attachment/wiki/ZooDocumentation/ZOOKernel/MacOSX_installation/ZOO-Project-Installer.pkg>`__.
+
+   .. note::
+      The installer assumes that you are using the distributed Apache2 version that comes with your Mac.  The installer will
+      place ZOO-Kernel and ZOO-Services into your cgi-bin at ``/Library/WebServer/CGI-Executables``, and the zoo-demo folder
+      will be placed within your document root at ``/Library/WebServer/Documents``
+
+2. Make sure that your Apache server is running, and then access the ZOO Project Demo at:
+
+      http://localhost/zoo-demo/spatialtools.html
+      
+3. To add additional services, please follow the following intructions to compile your own ZOO Project instance.
+
+Compiling from Source
+---------------------
+
+1. Install `Xcode <http://developer.apple.com/technologies/tools/>`__.
+
+2. Before you start downloading the ZOO-Project source code, you'll need to install some tools required to 
+   compile ZOO-Kernel properly.
+
+   First of all install PROJ, GEOS and GDAL frameworks from `here <http://www.kyngchaos.com/software/frameworks>`__.
+
+   At this step, you should get the following directories on your local hard drive :
+
+   ::
+   
+     /Library/Frameworks/PROJ.framework
+     /Library/Frameworks/GEOS.framework
+     /Library/Frameworks/GDAL.framework
+
+3. Then, create a ``src`` directory and inside that directory download the `gettext source code <http://www.gnu.org/software/gettext/#TOCdownloading>`__ and uncompress it.
+
+   now, compile gettext with the following commands to produce a universal binary :
+
+   ::
+   
+     cd gettext-0.18.1.1
+     CFLAGS="-O -g -arch i386 -arch ppc -arch x86_64"  \
+       LDFLAGS="-arch i386 -arch ppc -arch x86_64"   ./configure
+     make
+     sudo make install
+
+4. Compile and install your ZOO-Kernel
+
+   - Download source from SVN, and use the following command to compile libcgic :
+
+     ::
+     
+       svn co http://svn.zoo-project.org/svn/trunk zoo
+       cd zoo/thirds/cgic206
+       make
+
+   - If you produced the ``libcgic.a`` file, you can run ``autoconf`` and then ``configure`` from zoo-kernel directory.
+
+     ::
+     
+       cd zoo/zoo-kernel
+       autoconf
+       ./configure --with-python --with-java=macos \
+          --with-gdal-config=/Library/Frameworks/GDAL.framework/Versions/1.8/Programs/gdal-config
+
+     Obviously, if you don't need Python or Java support then you should remove the corresponding configure option.
+
+     .. note:: 
+        Note that we used the --with-java=macos configure option. Due to the generic location of the JDK on all 
+        Mac OS X platforms, you don't have to provide its full path.
+
+   - Now, run the following commands to compile and deploy your ZOO-Kernel on your Apache server :
+
+     ::
+     
+       make
+       cp zoo_loader.cgi main.cfg /Library/WebServer/CGI-Executables
+
+     You should be ready to request your ZOO-Kernel installation using the following link :  http://localhost/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS .
+
+     If everything is ok, you can follow the next steps to deploy new Services Providers.
+     
+     .. note::
+        If you are using your own libs (not the default libs on your system) then you must take care to create
+        universal versions of those libs, as the ZOO-Kernel will try to create a universal binary.  If you are
+        not following this advice, you might receive compile errors of ``symbol(s) not found for architecture ppc`` or ``file was built for 
+        unsupported file format which is not the architecture being linked (ppc)``.
+     
+Deploy the OGR Services Provider
+--------------------------------
+
+Requirements
+************
+
+Before your try to use any service, please set the correct path in the ``main.cfg`` for tmpPath and tmpUrl.
+
+You can use the following setup :
+
+::
+
+  tmpPath = /Library/WebServer/Documents/tmp
+  tmpUrl = ../../tmp
+
+Obviously you'll then need to create this directory, using the following command :
+
+::
+
+  mkdir /Library/WebServer/Documents/tmp
+
+C Version
+*********
+
+To compile the base-vect-ops ServicesProvider you'll need to edit the Makefile in *zoo/zoo-services/ogr/base-vect-ops/* 
+directory. Add "-I/Library//Frameworks/GEOS.framework/Versions/3/Headers/" to the CFLAGS value on the first line. 
+To compile, add GDAL framework to the PATH environmenet variable, to ensure that gdal-config tool will be found, 
+run make and then copy cgi-env files in the /Library/WebServer/CGI-Executables directory.
+
+::
+
+  cd zoo/zoo-services/ogr/base-vect-ops/
+  export PATH=$PATH:/Library/Frameworks/GDAL.framework/Versions/1.7/Programs/
+  make
+  cp cgi-env/* /Library/WebServer/CGI-Executables
+
+You can test using this `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>`__ 
+if everything is ok with your setup.
+
+Python Version
+**************
+
+**Requirements**
+
+First of all run python from a Terminal.app and try the following import from the python interpreter :
+
+::
+
+  import osgeo.ogr
+  import libxml2
+
+If you get an issue when importing the libxml2 module from your python interpreter then that means you 
+need to install the Python support for the libxml2 library which is already installed on your Mac OS X environment. 
+To accomplish this, you have first to determine what version of libxml2 is installed on your platform, using the following command:
+
+xml2-config --version
+
+Download the source corresponding to your version (i.e. on 10.6.6 you get 2.7.3) from the libxml2  
+`download page <ftp://xmlsoft.org/libxml2/>`__ into your ``src`` directory then uncompress it.
+
+Use the following command to install the python support :
+
+::
+
+  cd src/libxml2-2.7.3/python/
+  python setup.py install
+
+**Deploy OGR Python Services Provider**
+
+- Now copy the ``zoo-services/ogt/base-vect-ops/cgi-env`` files into ``/Library/WebServer/CGI-Executables``.
+
+You can test using this `url <http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=BufferPy&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>`__ 
+if everything is ok with your setup.
+
+Test using Local Demo Page
+--------------------------
+
+- Download the `OpenLayers <http://openlayers.org>`__ library and uncompress it in your personal Sites directory 
+  (located in your home directory). 
+  
+- Rename the OpenLayers directory as openlayers. 
+
+- Download this `zip archive <http://www.zoo-project.org/trac/raw-attachment/wiki/ZooDocumentation/ZOOKernel/MacOSX_installation/zoo-demo.zip>`__ 
+  and then uncompress it in your personal Sites directory. 
+  
+- Load your local demo pages using urls similar to the following (replacing MyUserName by your MacOS user name) :
+
+    *  http://localhost/~MyUserName/zoo-demo/spatialtools.html
+    *  http://localhost/~MyUserName/zoo-demo/spatialtools-py.html 
+
+
Index: tags/rel-1.3.0-rc1/docs/kernel/install-opensuse.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/install-opensuse.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/install-opensuse.txt	(revision 417)
@@ -0,0 +1,67 @@
+.. _kernel-installation-opensuse:
+
+OpenSUSE
+========
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+Zoo-Kernel is maintained as a package in `OpenSUSE Build Service (OBS) <https://build.opensuse.org/package/show?package=zoo-kernel&project=Application%3AGeo>`__. 
+This way, rpm's are provided for all versions of openSUSE Linux (11.2, 11.3, 11.4, Factory).
+
+Stable Releases
+---------------
+
+For installing Zoo-Kernel in openSUSE there are 3 ways available:
+
+One Click Installer
+*******************
+
+One-click installer that can be found  `here <http://software.opensuse.org/search?q=zoo-kernel&baseproject=openSUSE%3A11.4&lang=en&exclude_debug=true>`__. 
+For openSUSE 11.4 this is the 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 using a GUI
+*********************************
+
+The `Application:Geo <http://download.opensuse.org/repositories/Application:/Geo/>`__ repository has to be added 
+to the Software Repositories and then Zoo-kernel can be found in Software Management through search.
+
+Command line (as root for openSUSE 11.4)
+****************************************
+
+::
+
+  zypper ar http://download.opensuse.org/repositories/Application:/Geo/openSUSE_11.4/
+  zypper refresh
+  zypper install zoo-kernel
+
+Unstable 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 the stable version. Make sure to use `this <http://download.opensuse.org/repositories/home:/tzotsos/>`__ repository instead.
+
+Command line installation (as root for openSUSE 11.4)
+*****************************************************
+
+::
+
+  zypper ar http://download.opensuse.org/repositories/home:/tzotsos/openSUSE_11.4/
+  zypper refresh
+  zypper install zoo-kernel
+  zypper install zoo-kernel-grass-bridge
+
+Additionally, there is the option of adding the zoo-wps-grass-bridge package. This option will automatically install grass7 (svn trunk).
+
+Try the Installation
+--------------------
+
+- http://localhost/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=GetCapabilities&Version=1.0.0
+- http://localhost/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=DescribeProcess&Version=1.0.0&Identifier=HelloPy
+- http://localhost/cgi-bin/zoo_loader.cgi?ServiceProvider=&metapath=&Service=WPS&Request=Execute&Version=1.0.0&Identifier=HelloPy&DataInputs=a=myname
Index: tags/rel-1.3.0-rc1/docs/kernel/install-prerequisites.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/install-prerequisites.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/install-prerequisites.txt	(revision 417)
@@ -0,0 +1,76 @@
+.. _kernel-installation-prereq:
+
+Prerequisites
+=============
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna, Luca Delucchi
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+Obtaining the ZOO Kernel Source
+-------------------------------
+
+.. _svn:
+
+Use the following command to get the ZOO Kernel source code through Subversion:
+
+::
+
+  svn checkout http://svn.zoo-project.org/svn/trunk zoo-project
+
+For users which get a developer account, use 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-project
+
+The first line of the instruction above defines a specific tunnel to access the svn server through 
+the SSH protocol. Indeed, the ZOO SVN server listens on the 1046 (1024+22) port rather than the default one (22).
+
+Prerequisites
+-------------
+
+The following libraries are required on your system before you can install the ZOO Kernel:
+
+- autoconf (  http://www.gnu.org/software/autoconf/ ) 
+- cgic (  http://www.boutell.com/cgic )
+- cURL (  http://curl.haxx.se )
+- FastCGI (  http://www.fastcgi.com )
+- Flex & Bison (  http://flex.sourceforge.net/  http://www.gnu.org/software/bison/ )
+- libxml2 (  http://xmlsoft.org )
+- OpenSSL (  http://www.openssl.org )
+- Python (  http://www.python.org )
+
+Optional libraries include:
+
+- MapServer (optional for WMS, WFS and WCS output) ( http://mapserver.org )
+- PHP Embedded (optional) (  http://www.php.net )
+- Java SDK (optional) (  http://java.sun.com )
+- SpiderMonkey (optional) (  http://www.mozilla.org/js/spidermonkey/ ) 
+
+Compile libcgic
+---------------
+
+The first step is to compile libcgic from the ``zoo-project/thirds`` directory. For such a task, please use 
+the following command:
+
+::
+
+  cd thirds/cgic206
+  make
+
+Make sure that a ``libcgic.a`` is created in your ``zoo-project/thirds/cgic206`` directory. If yes, then 
+you can go to the next step.
+
+On Windows, rather than using the make command, please use:
+
+::
+
+  nmake /f makefile.vc. 
+  
+.. warning::
+   If you don't compile libcgic first, and try to compile the ZOO Kernel, you will get an error such as *cannot find -lcgic*
Index: tags/rel-1.3.0-rc1/docs/kernel/install-unix.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/install-unix.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/install-unix.txt	(revision 417)
@@ -0,0 +1,233 @@
+.. _kernel-installation-unix:
+
+Unix
+====
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna, Luca Delucchi
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+.. note::
+   You must be sure to perform the :ref:`prerequisite steps <kernel-installation-prereq>` before following this page.
+
+For the impatient
+-----------------
+
+To build the ``zoo_loader.cgi`` CGI program with the default options, cd to the directory 
+where you extracted the ZOO Kernel source code package and use the following commands:
+
+::
+
+  $ cd zoo-kernel
+  $ autoconf  
+  $ ./configure
+  $ make
+
+Unless something went wrong, you should have executables in the current directory for the ``zoo_loader.cgi`` 
+CGI program. You can copy the ``zoo_loader.cgi`` program and the ``main.cfg`` file to your HTTP server's CGI 
+directory and start using it.
+
+At this step your ZOO-Kernel should work. Nevertheless, don't forget to correct the main.cfg settings 
+to set ``tmpPath`` and ``tmpUrl`` to fit your web server configuration.
+
+Configure Options
+-----------------
+
+Here is the list of available options as returned by *./configure --help*:
+
+::
+
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gdal-config=FILE specify an alternative gdal-config file
+  --with-xml2config=FILE  specify an alternative xml2-config file
+  --with-mapserver=PATH   specify the path for MapServer compiled source tree
+  --with-python=PATH      To enable python support or specify an alternative
+                          directory for python installation, disabled by
+                          default
+  --with-pyvers=NUM       To use a specific python version
+  --with-php=PATH         To enable php support or specify an alternative
+                          directory for php installation, disabled by default
+  --with-perl=PATH        To enable perl support or specify an alternative
+                          directory for perl installation, disabled by default
+  --with-java=PATH        To enable java support, specify a JDK_HOME,
+                          disabled by default
+  --with-js=PATH          specify --with-js=path-to-js to enable js support,
+                          specify --with-js on linux debian like, js support
+                          is disabled by default
+
+All the options are described in more details below.
+
+(Required) GDAL Support
+***********************
+
+If your gdal-config program is not found in your PATH then you can use the 
+``--with-gdal-config`` option to specify its location. For instance, let's suppose that your gdal-config 
+was installed in /usr/local/bin and this directory is not in your PATH, then you can use 
+the following command:
+
+::
+
+  $ ./configure --with-gdal-config=/usr/local/bin/gdal-config
+
+(Required) XML2 Support
+***********************
+
+If your xml2-config program is not found in your PATH then you can use the 
+``--with-xml2config`` option to specify its location. For instance, let's suppose that 
+your xml2-config was installed in /usr/local/bin and this directory is not in your PATH, 
+then you can use the following command:
+
+::
+
+  $ ./configure --with-xml2config=/usr/local/bin/xml2-config
+
+(Optional) MapServer Support
+*****************************
+
+If you want to activate the WMS, WFS and WCS outputs using MapServer then you will have
+to use the ``--with-mapserver`` option. You have to set the path to your ``mapserver-config``
+locate in the source code of MapServer as following command:
+
+::
+
+  $ ./configure --with-mapserver=/path/to/your/mapserver_config/
+
+(Optional) Python Support
+*************************
+
+If you want to activate Python support for the ZOO Kernel then you will have to use the 
+``--with-python`` option. If your python-config program is found in your PATH then you 
+don't have to specify the path where Python was installed, such as:
+
+::
+
+  $ ./configure --with-python
+
+This assumes that python-config is found in your PATH.
+
+In the case that your python-config is not found in your PATH, then you can specify the Python 
+installation directory you are using. For instance, let's suppose that you installed 
+Python in /usr/local, then you can use the following command:
+
+::
+
+  $ ./configure --with-python=/usr/local
+
+This assumes that /usr/local/bin/python-config exists.
+
+(Optional) Python Version
+*************************
+
+If you want use a specific version of Python you will have to use the ``--with-pyvers``
+option. You can specify a Python version as:
+
+::
+
+  $ ./configure --with-pyvers=2.6
+
+
+(Optional) PHP Support
+**********************
+
+To be able to activate PHP support for the ZOO Kernel you'll need to get a local PHP Embedded 
+installation; for more information about the required configure options when compiling PHP you 
+can refer to this page :
+
+     http://zoo-project.org/trac/wiki/ZooKernel/Embed/PHP
+
+If you want to activate the PHP support for the ZOO Kernel then you will have to use the 
+``--with-php`` option. If your php-config program is found in your PATH then you don't have 
+to specify the path where PHP was installed, then you can use the following commnd:
+
+::
+
+  $ ./configure --with-php
+
+This assumes that php-config is found in your PATH.
+
+In the case that your php-config is not found in your PATH, then you can specify the PHP installation 
+directory you are using. For instance, let's suppose that you installed PHP in /usr/local, 
+then you can use the following command:
+
+::
+
+  $ ./configure --with-php=/usr/local
+
+This assumes that /usr/local/bin/php-config exists.
+
+(Optional) Perl Support
+***********************
+
+If you want to activate Perl support for the ZOO Kernel then you will have to use the 
+``--with-perl`` option. If you do not set any value to this option, then the perl program will 
+be searched in your PATH. So in such a case, you can use the following command:
+
+::
+
+  $ ./configure --with-perl 
+
+This assumes that perl is found in your PATH.
+
+In the other case, for custom Perl installations, you can set the installation directory. For instance, 
+let's suppose that you installed Perl in /usr/local and /usr/local/bin is not in your PATH, 
+then you can use the following command:
+
+::
+
+  $ ./configure --with-perl=/usr/local
+
+This assumes that /usr/local/bin/perl exists.
+
+(Optional) Java Support
+***********************
+
+If you want to activate Java support for the ZOO Kernel then you will have to use the 
+``--with-java`` option and set the installation path of your Java SDK. For instance, 
+let's suppose that your Java SDK was installed in the /usr/lib/jvm/java-6-sun-1.6.0.22/ directory, 
+then you can use the following command:
+
+::
+
+  $ ./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/, include/linux contains the jni.h headers file and 
+jre/lib/i386/client/ contains the libjvm.so file.
+
+.. 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
+
+(Optional) JavaScript Support
+*****************************
+
+If you want to activate JavaScript support for the ZOO Kernel then you will have to use 
+the ``--with-js`` option. 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, so you can use the following command:
+
+::
+
+  $ ./configure --with-js 
+
+This assumes that js_api.h and libmozjs.so are found in default directories.
+
+If you have a custom installation of SpiderMonkey or you are not using a Debian packaging 
+system, then you'll have to specify the directory where you installed it. For 
+instance, let's suppose that you installed your SpiderMonkey in /usr, then you'll 
+have to use the following command:
+
+::
+
+  $ ./configure --with-js=/usr
+
+This assumes that the /usr/include/js exists and contains the js_api.h headers file and 
+/usr/lib contains libmozjs.so file.
Index: tags/rel-1.3.0-rc1/docs/kernel/install-windows.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/install-windows.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/install-windows.txt	(revision 417)
@@ -0,0 +1,175 @@
+.. _kernel-installation-windows:
+
+Windows
+=======
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+.. contents:: Table of Contents
+    :depth: 2
+    :backlinks: top
+
+Using OSGeo4W
+-------------
+
+Install OSGeo4W
+***************
+
+Download the OSGeo4W installer from  http://trac.osgeo.org/osgeo4w/, and install it with all the dependencies needed by your 
+services (GDAL/OGR for example). The following libs are required: FastCGI, libxml, Python, cURL.
+
+Install other tools and libraries
+*********************************
+
+After installing OSGeo4W on your platform you'll need more GNU tools and libraries. `This package <http://www.zoo-project.org/dl/tool-win32.zip>`__ 
+contains full dependencies required to compile on WIN32 platform and this one contains `full runtime dependencies to place <http://www.zoo-project.org/dl/zoo-runtime.zip>`__ 
+in your c:\OSGeo4W\bin.
+
+Download and Install ZOO Kernel
+*******************************
+
+Download the `binary version <http://www.zoo-project.org/dl/zoo_loader.cgi>`__  of the ZOO Kernel for WIN32 then place it in the 
+``C:\OSGeo4W\bin`` directory. Don't forget to place a ``main.cfg`` file in the same directory, you can use a modified copy of 
+`this file <http://www.zoo-project.org/trac/browser/trunk/zoo-kernel/main.cfg>`__.
+
+Deploy ZOO Services Providers
+*****************************
+
+Your can use the binary version of the OGR Services Provider available from `here <http://www.zoo-project.org/dl/zoo-services-win32.zip>`__. 
+Then place the two libraries with their respective .zcfg files in your local ``C:\OSGeo4W\bin`` directory.
+
+Testing
+*******
+
+Now you should be able to query your local ZOO Kernel. 
+
+Compiling Using Your Own Libraries
+----------------------------------
+
+.. note::
+   You must be sure to perform the :ref:`prerequisite steps <kernel-installation-prereq>` before compiling the ZOO Kernel.
+
+The following steps are for use with the Microsoft Visual Studio compiler (and tested with MSVC 2008).
+
+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 file ``zoo-project\zoo-kernel\nmake.opt`` to point to your local libraries.  You can find a modified nmake.opt that points to local libs `here <http://www.zoo-project.org/trac/attachment/ticket/27/nmake.opt>`__. 
+   You can also find a modified ``zoo-project\zoo-kernel\makefile.vc`` file `here <http://www.zoo-project.org/trac/attachment/ticket/27/makefile.vc>`__.
+   
+3. Execute:
+
+   ::
+   
+     nmake /f makefile.vc
+     
+4. A file ``zoo_loader.cgi`` 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`` 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 file ``cgi-bin/main.cfg`` 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>
+       ...
+       
+Optionally Compile Individual Services
+**************************************
+
+An example could be the ``OGR base-vect-ops`` provider in the ``zoo-project\zoo-services\ogr\base-vect-ops`` directory.  
+
+1. Edit the makefile.vc located in that directory, and execute:
+
+   ::
+   
+     nmake /f makefile.vc
+     
+   Inside that same directory, the file ``cgi-env\ogr_service.zo`` should be created.
+   
+2. Copy all of 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.3.0-rc1/docs/kernel/installation.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/installation.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/installation.txt	(revision 417)
@@ -0,0 +1,22 @@
+.. _kernel-installation:
+
+Installation
+============
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+This page provides documentation on how to compile then install the ZOO Kernel on Unix, Windows, and Mac OS X platforms.
+
+.. toctree::
+   :maxdepth: 2
+   
+   install-prerequisites
+   install-unix
+   install-opensuse
+   install-centos
+   install-debian
+   install-windows
+   install-mac
+
+
Index: tags/rel-1.3.0-rc1/docs/kernel/introduction.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/introduction.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/introduction.txt	(revision 417)
@@ -0,0 +1,52 @@
+.. _kernel-introduction:
+
+Introduction
+============
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+ZOO Kernel is the heart of the ZOO. It is a powerful server-side C Kernel which makes 
+it possible to manage and chain Web services, by loading dynamic libraries and handling 
+them as on-demand Web services. The ZOO Kernel is written in the C language, but supports 
+several common programming languages in order to connect to numerous libraries and models.
+
+Using ZOO Kernel as a Web Processing Platform
+---------------------------------------------
+
+ZOO Kernel works with Apache and can communicate with cartographic engines and Web mapping 
+clients. It simply adds the WPS support to your spatial data infrastructure and your 
+Web mapping application!
+
+.. note::
+   If you'd like some background on the WPS standard, head to: http://www.opengeospatial.org/standards/wps
+
+Supported Languages
+-------------------
+
+ZOO Kernel supports the following programming languages, and let's you use them to create 
+new ZOO Services from new or existing code:
+
+============ =================== ========================= ============
+**Language** **ServiceProvider** **DataStructure**         **Return**
+------------ ------------------- ------------------------- ------------
+C / C++      Shared Library      maps* M 	           integer
+Fortran      Shared Library      CHARACTER*(1024) M(10,30) integer
+Java 	     Class File 	 `HashMap`_ 	           integer
+Python 	     Module File 	 `dictionary`_ 	           integer
+PHP 	     Script File 	 `Array`_ 	           integer
+Perl 	     Script File 		                   integer
+JavaScript   Script file 	 `Object`_ or Array	   Array/Object 
+============ =================== ========================= ============
+
+.. _`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/
+
+ZOO Kernel is a WPS Espresso Machine
+------------------------------------
+
+.. image:: ../_static/images/zoo_kernel_scheme.png
+
+
Index: tags/rel-1.3.0-rc1/docs/kernel/mapserver.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/kernel/mapserver.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/kernel/mapserver.txt	(revision 417)
@@ -0,0 +1,264 @@
+.. _kernel-mapserver:
+    
+How To Use the Internal MapServer W*S support
+=============================================
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$ 
+
+The key idea of the MapServer W*S support implementation is that it
+doesn't require to change a single line of the service source code to
+activate the automatic publication of your result as WMS/WFS or WCS
+ressource. You simply need to modify the ``zcfg`` file corresponding
+to your service to make it working.
+
+Here is an overview of the way to install the MapServer W*S support, the
+configuration required and the internal mechanisms. 
+
+.. contents:: Table of Contents
+    :depth: 3
+    :backlinks: top
+
+How to make it working ?
+------------------------
+
+Requirement
+**************
+
+   * last ZOO-Kernel trunk version
+   * MapServer version >= 6.0.1
+
+Installation steps
+********************
+
+First download lastest zoo-kernel directory available on the svn, do that from the directory of your previous checkout (so where zoo-api, zoo-services and zoo-kernel directories are available), we will use ``<PREV_SVN_CO>`` here for this directory:
+
+.. code-block:: guess
+
+    cd <PREV_SVN_CO>
+    svn checkout http://svn.zoo-project.org/svn/trunk/zoo-kernel zoo-kernel-ms
+
+Uncompress the MapServer archive (ie. ``mapserver-6.0.1.tar.bz2``) into ``/tmp/zoo-ms-src``, then compile MapServer 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
+
+Autotools was updated to add the ``--with-mapserver`` configure option. From your ZOO-Project SVN trunk directory, compile the ZOO-Kernel using the following command:
+
+.. code-block:: guess
+
+     cd zoo-kernel-ms
+     autoconf
+     ./configure --with-python --with-mapserver=/tmp/zoo-ms-src/mapserver-6.0.1
+     make
+     cp zoo_loader.cgi /usr/lib/cgi-bin
+
+Configuration steps
+*************************
+
+Main configuration file
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Add the following content to your ``/usr/lib/cgi-bin/main.cfg`` file
+ in the ``[main]`` section:
+
+.. code-block:: guess
+
+      dataPath = /var/www/temp/
+      mapserverAddress=http://localhost/cgi-bin/mapserv
+
+The ``dataPath`` directory should exists and be writable by apache user. In this directory, a ``symbols.sym`` file have to be present, containing the following:
+
+.. code-block:: guess
+
+      SYMBOLSET
+      SYMBOL
+        NAME "circle"
+        TYPE ellipse
+        FILLED true
+        POINTS
+          1 1
+        END
+      END
+      END
+
+Only one symbol definition is required with any name, used for WMS service output.
+
+Now, your ZOO-Kernel get the MapServer support ready to be used. Note that if you don't add the ``mapserverAddress`` then it imply the ZOO-Kernel will segfault (checking ``NULL`` value should correct this behavior).
+
+Here you can optionally add a ``msOgcVersion`` parameter to specify which version of the OGC WebService you want to use for each services. For example, if you want to force to version 1.0.0, you can set the following in the ``[main]`` section of your ``main.cfg`` file:
+
+.. code-block:: guess
+
+     msOgcVersion=1.0.0
+
+Service configuration file
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To activate MapServer WebServices output for a service, you have to add a specific parameter in the ``<Default>`` or ``<Supported>`` block: ``useMapserver``. This can take the value true or should not appear. If true, it means that the output result is an OGR / GDAL compatible datasource and you want it to be outputted as an OGC web server instance (WMS/WFS/WCS).
+
+You get an optional parameter, to use a custom MapServer style block (used for vector datasource only): msStyle. For example:
+
+.. code-block:: guess
+
+     msStyle = STYLE COLOR 125 0 105 OUTLINECOLOR 0 0 0 WIDTH 3 END
+
+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).
+
+When you add useMapserver option to an output ``<Default>`` or ``<Supported>`` block, then you have to know what are the sensible mimeType:
+
+   * text/xml: will imply that the output data will be accessible through a WFS GetFeature request (default protocol version 1.1.0)
+   * image/tiff: will imply 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: will imply that the output data will be accessible trhough a WMS GetMap request (you have to limit yourself to what your MapServer installation support, GetCapabilities? request give information of supported output mimeType) (default protocol version 1.3.0) 
+
+How does it work ?
+---------------------
+
+Whatever your service return as default output ``mimeType``, this one will be used when one output including the ``useMapserver`` option was found.
+
+So if you get the following ``<Default>`` and ``<Supported>`` blocks in the ZOO Configuration File of your service:
+
+.. 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>
+
+It means that per default, your service return GML 3.1 Feature. When the client request for ``mimeType=image/png``, then the ZOO-Kernel will detect that this ``mimeType`` get the ``useMapServer`` option set to true so it will:
+
+    1) execute the service using the ``<Default>`` block definition (this should be understandable by GDAL/OGR)
+
+    2) store the result of the service on disk (in the ``[main]`` > ``dataPath`` directory)
+
+    3) write a Mapfile (in the ``[main]`` > ``dataPath`` directory) using the MapServer C-API to setup both WMS and WFS services.
+
+.. Note:: even if you don't ask for this, the resulting Mapfile includes both configuration for WMS and WFS in case of Vector datasource.
+
+If your service output a raster file, then the behavior is quite the same except that the ZOO-Kernel will setup both WMS and WCS services for the result of the service. Here you cannot define your own style. Nevertheless, when one band raster is returned then the ZOO-Kernel can use its own default style definitions to classify the raster using equivalent intervals (you can easily see that in the outputed Mapfile), this classification is specific to WMS protocol. You should add a ``msClassify`` parameter and set it to ``true`` in your output ComplexData ``<Default>`` or ``<Supported>`` node to activate this classification.
+Special note for client implementers
+
+Note that depending on the request, the ZOO-Kernel can return a location header.
+
+Differente request types:
+
+    * ResponseDocument=XXXX@asReference=true - in this case, the Kernel will return the GetMap/GetFeature/GetCoverage request in KVP in the href of the result.
+    * ResponseDocument=XXXX@asReference=false - in this case, the Kernel will return the result he get using the GetMap/GetFeature/GetCoverage request in KVP used for the href in previous case.
+    * RawDataOutput=XXXX@asReference=true/false - in this case, the Kernel will return the GetMap/GetFeature/GetCoverage request in KVP in the specific location header, which imply that the browser should follow and request MapServer directly. 
+
+Simple sample use cases
+-----------------------
+
+Consider the existing BufferPy service from zoo-services/ogr-base-vect-ops-py. Set the following content to your local BufferPy.zcfg file in the Result output definition, then copy it to /usr/lib/cgi-bin/:
+
+.. 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 = image/tif
+     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>
+
+This modifications make your service ready to return result as WMS GetMap or WFS GetFeature requests. Note that some bug occurs locally using the application/vnd.google-earth.kmz output.
+Raster
+
+Using the following simple service code we get a service capable to output any kind of internet files (useful for testing this functionality):
+
+.. code-block:: guess
+
+    import zoo
+    def HelloPy(conf,inputs,outputs):
+            outputs["Result"]["value"]=inputs["a"]["value"]
+            return zoo.SERVICE_SUCCEEDED
+
+Define the ``[Result]`` output in your ``HelloPy.zcfg`` file with the following ComplexData block content:
+
+.. code-block:: guess
+
+    <Default>
+     mimeType = image/png
+     useMapServer = true
+    </Default>
+    <Supported>
+     mimeType = image/tiff
+     useMapServer = true
+    </Supported>
+    <Supported>
+     mimeType = text/xml
+     useMapServer = true
+    </Supported>
+
+It means that 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.
+
+With this simple service you can test the new capabilities to output result as WebServices for each mimeTypes. Note, that you'll probably get wrong ``mimeType``, as the default was set to ``image/png``.
+
+There is a support for Zipped ShapeFile but I doubt it is really
+useful. Anyway, as it is present you can test it easily by passing a
+zip file in ``xlink:href`` for the ``a`` value of the ``HelloPy``
+service.
+
+Testings
+***********
+
+Using the simple ``HelloPy`` service code, you can use the following urls, note it supposes that you get an available http://localhost/data/data.zip file containing a ShapeFile and a http://localhost/data/demo.tif:
+
+Test 1: 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
+
+Test 2: 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
+
+Test 3: 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
+
+Test 4: 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.3.0-rc1/docs/make.bat
===================================================================
--- tags/rel-1.3.0-rc1/docs/make.bat	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/make.bat	(revision 417)
@@ -0,0 +1,170 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	: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.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  changes    to make an overview over 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
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	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.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end
Index: tags/rel-1.3.0-rc1/docs/services/debug.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/services/debug.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/services/debug.txt	(revision 417)
@@ -0,0 +1,97 @@
+.. _services-debug:
+
+How To Debug ZOO Services
+=========================
+
+:Authors: Luca Delucchi
+:Last Updated: $Date: 2013-03-27 00:06:12 +0100 (Wed, 27 Mar 2013) $
+
+There are different ways to debug your services, the most used solutions are via web
+or via command line.
+
+Web
+----
+
+Using the web request you can see any problem with the log file of Apache.
+
+On Unix system usually to log file is in ``/var/log/apache2`` and the useful file
+is ``error_log``. A simple way to look inside the file is to use ``tail`` command,
+it permits to see the update of the file for each request ::
+
+  tail -f /var/log/apache2/error_log
+
+If the log is not so clear you can add some information inside your code. You have to write
+in the standard error.
+
+Python
+********
+Using Python for example you can do this
+
+.. code-block:: python
+
+  import sys
+  
+  #add this line when you want see your message
+  sys.stderr.write("My message")
+
+.. _web_javascript:
+
+Javascript
+************
+
+You can user ``alert`` to print a string to the standard error.
+
+.. code-block:: javascript
+
+  // add this line when you want see your 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 return only ``[object Object]``
+
+Command line
+--------------
+
+It is possible to use the ZOO kernel ``zoo_loader.cgi`` also from command line.
+This is really useful to debug in a deeper way your service.
+
+.. code-block:: bash
+
+  # 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"
+
+Using this way you can use standard debug system of the programming language used
+in your service.
+
+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"
+
+At this point you can ask help to 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 more in the code
+  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.3.0-rc1/docs/services/examples.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/services/examples.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/services/examples.txt	(revision 417)
@@ -0,0 +1,45 @@
+.. _services-examples:
+
+Service Examples
+================
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$
+
+ZOO Services 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 with links to their corresponding ``.zcfg`` files.
+
+.. contents:: Table of Contents
+    :depth: 3
+    :backlinks: top
+
+GDAL ZOO Service
+----------------
+
+The GDAL ZOO Service is based on  GDAL source code and copyright. This ZOO Service 
+aims to provide some basic raster processing operations to your ZOO Kernel installation. 
+Learn more and read documentation on the official `GDAL website <http://www.gdal.org/>`__.
+
+Implemented functions
+*********************
+
+Gdal_Grid
+    creates regular grid from the scattered data
+
+
+Gdal_Translate
+    converts raster data between different formats
+
+
+OGR ZOO Service
+---------------
+
+The OGR ZOO Service is based on  OGR source code and copyright. This ZOO Service aims 
+to provide some basic vector spatial operations to your ZOO Kernel installation. 
+Learn more and read documentation on the official `OGR website <http://www.gdal.org/ogr/index.html>`__.
+
+Implemented functions
+*********************
+
+Base_Vect_Ops
Index: tags/rel-1.3.0-rc1/docs/services/howtos.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/services/howtos.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/services/howtos.txt	(revision 417)
@@ -0,0 +1,227 @@
+.. _services-howtos:
+
+How To Setup ZOO Services
+=========================
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna, Luca Delucchi
+:Last Updated: $Date$
+
+ZOO Services 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  and JavaScript with links to their corresponding 
+``.zcfg`` files.
+
+.. contents:: Table of Contents
+    :depth: 3
+    :backlinks: top
+
+Common informations
+----------------------
+
+The function of the process for each programming language take three arguments: the main
+configuration, inputs and outputs.
+
+.. Note:: The service has to **return 3 if the process run successfully instead it 
+	  return 4** if the process end 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 sys
+  def HelloPy(conf,inputs,outputs):
+     outputs["Result"]["value"]="Hello "+inputs["a"]["value"]+" from Python World !"
+     return 3
+
+PHP
+---
+
+.. code-block:: php
+
+  <?
+  function HelloPHP(&$main_conf,&$inputs,&$outputs){
+     $outputs["Result"]["value"]="Hello ".$inputs[S][value]." from PHP world !";
+     return 3;
+  }
+  ?>
+
+Java
+----
+
+.. 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 3;
+    }
+  }
+
+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);
+  }
+
Index: tags/rel-1.3.0-rc1/docs/services/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/services/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/services/index.txt	(revision 417)
@@ -0,0 +1,15 @@
+.. _services:
+
+ZOO Services Documentation
+==========================
+
+The following sections will assist you with ZOO Services:
+
+.. toctree::
+   :maxdepth: 2
+   
+   introduction
+   zcfg-reference
+   howtos
+   debug
+   examples
Index: tags/rel-1.3.0-rc1/docs/services/introduction.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/services/introduction.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/services/introduction.txt	(revision 417)
@@ -0,0 +1,30 @@
+.. _services-intro:
+
+Introduction
+============
+
+ZOO Services are example Web services which work with the ZOO :ref:`Kernel <kernel-introduction>`. 
+They are based on various existing Open Source libraries and tend to provide simple Web processing 
+functions such as GIS format conversion, GIS file reprojection, basic spatial operations, 
+basic raster operations...
+
+The available ZOO Services are under development and come without any warranty. They are based 
+on existing code and prove that the :ref:`ZOO Kernel <kernel-introduction>` works with many different 
+codes and languages (please have a look to the ZOO demos!). The ZOO Project team wants to encourage 
+people to use the ZOO Services as a functional basis for Web processing, but above all to provide a 
+source of inspiration to the community for creating new ZOO Services.
+
+What is a ZOO Service?
+----------------------
+
+A ZOO Service is a couple composed of:
+
+- The code you want to turn into a standardized Web service
+- A configuration file (.zcfg) which describes this Web service 
+
+Learn more on configuring ZOO services by reading the :ref:`.zcfg Reference <services-zcfg>`.
+
+Example ZOO Services
+--------------------
+
+See the ZOO Services :ref:`examples page <services-examples>`.
Index: tags/rel-1.3.0-rc1/docs/services/zcfg-reference.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/services/zcfg-reference.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/services/zcfg-reference.txt	(revision 417)
@@ -0,0 +1,233 @@
+.. _services-zcfg:
+    
+ZCFG : the ZOO Service Configuration File
+=========================================  
+
+:Authors: Nicolas Bozon, Gérald Fenoy, Jeff McKenna
+:Last Updated: $Date$ 
+
+.. contents:: Table of Contents
+    :depth: 3
+    :backlinks: top
+
+The ZOO Service configuration file (.zcfg) describes the service and will be parsed by 
+the ZOO Kernel. We will describe here what such a file contains. 
+You can also take a look at the existing examples of ZCFG files in the ``cgi-env`` directory 
+of each services available in the `ZOO-Project SVN source tree <http://zoo-project.org/trac/browser/trunk/zoo-services>`__.
+
+A ZOO Configuration file is divided into three distinct sections :
+
+1. Main Metadata information
+2. List of Inputs metadata information
+3. List of Outputs metadata information
+
+.. Note:: The ZOO Service Configuration File is case sensitive.
+
+Main Metadata Information
+-------------------------
+
+The fist part in a ZOO Configuration file contains the metadata information relative to the 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.
+
+You can see below a description of the main metadata information:
+
+.. code-block:: none
+   :linenos:
+
+   [Name of your service]
+   Title = Title of your service
+   Abstract = Description of your service
+   processVersion = Version number of your service
+   storeSupported = true/false
+   statusSupported = true/false
+   serviceType = the programming language used to implement the service (C/Fortran/Python/Java/PHP/Javascript)
+   serviceProvider = name of your services provider (shared library/Python Module/Java Class/PHP Script/JavaScript script)
+   <MetaData>
+     title = Metadata title of your service
+   </MetaData>
+
+List of Inputs
+--------------
+
+The list of inputs contains metadata information of each supported input, and they are grouped using a ``<DataInputs>`` node.
+
+Each input is defined as :
+
+-  a name (between brackets as for the name of the service before)
+- various medata properties (``Title``, ``Abstract``, ``minOccurs`` and ``maxOccurs``)
+- a Type Of Data node (:ref:`description <typeDataNodes>`)
+
+A typical list of inputs (``<DataInputs>``) look 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:: you can add ``<MetaData>`` node as in the main metadata information.
+
+List of Outputs
+---------------
+
+The list of outputs is very similar to a list of inputs except it is specified as a ``<DataOutputs>`` node.
+
+A typical ``<DataOutputs>`` node 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
+------------------
+
+In the beginning of this ZCFG introduction, we spoke about "Type Of Data Nodes" to describe the data type of inputs and outputs.
+
+You can define your data as:
+
+- :ref:`LiteralData <LiteralData>`
+- :ref:`BoundingBoxData <BoundingBoxData>`
+- :ref:`ComplexData <ComplexData>`
+
+Except for ``LiteralData``, each *Type Of Data* node must have at least one ``<Default>`` and one ``<Supported>`` node. Even 
+if one of those are empty, it **has to be present** with an opening and closing tag on two different lines. So, something 
+like the following:
+
+.. code-block:: guess
+   :linenos:
+
+   <Default>
+   </Default>
+
+Otherwise, ZOO-Kernel won't be able to parse your ZCFG and will fail to process requests.
+
+.. _LiteralData:
+
+LiteralData node
+****************
+
+A ``<LiteralData>`` node contains:
+
+- 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>
+
+.. _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.3.0-rc1/docs/tutorial/environment.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/tutorial/environment.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/tutorial/environment.txt	(revision 417)
@@ -0,0 +1,115 @@
+.. _environment:
+
+Using ZOO from an OSGeoLive virtual machine
+===========================================
+
+Development Environment Description
+-----------------------------------
+
+`OSGeoLive <http://live.osgeo.org/>`__ is a live DVD and virtual machine based on 
+`Xubuntu <http://www.xubuntu.org/>`__  that allows you to try a 
+wide variety of open source geospatial software without installing anything. It is 
+composed entirely of free software and include ZOO 1.0 this year, for testing purpose.
+
+As already said in introduction, an OSGeoLive virtual machine image disk has been 
+installed on your computer, allowing you to use ZOO Kernel in a development environment 
+directly. Using a virtual machine image disk seems to be the simplest way to use 
+ZOO Kernel and to develop ZOO Services locally, as we can ensure that everything 
+requested for compile C Services and run Python Services is available and ready to use. 
+Every ZOO related material and source code have been placed in */home/user/zoows* directory. 
+We will work inside it during this workshop. As the binary version of ZOO Kernel is 
+already compiled and stored in */home/user/zoows/sources/zoo-kernel*, you only have to 
+copy two important files inside the */usr/lib/cgi-bin directory*: *zoo_loader.cgi*
+and the *main.cfg* in order to make ZOO Kernel available, using the following commands:
+
+::
+
+  sudo cp ~/zoows/sources/zoo-kernel/zoo_loader.cgi /usr/lib/cgi-bin
+  sudo cp ~/zoows/sources/zoo-kernel/main.cfg /usr/lib/cgi-bin
+  
+Please note that we will talk about ZOO Kernel or zoo_loader.cgi script without any 
+distinction during this workshop.
+
+The *main.cfg* file contains metadata informations about the identification and provider 
+but also some important settings. The file is composed of various sections, namely *main*,  
+*identification* and *provider* per default. Obviously, you are free to add new sections 
+to the files if you need them for a specific Service. Nevertheless, you have to know 
+that the env section name is used in a specific way. It lets you define environment 
+variables that your Service requires during its runtime. For instance, if your Service 
+requires to access to a X server running on framebuffer, you can add *DISPLAY=:1* line in 
+your env section to take this specificity into account.
+
+Please have a look to this file. Three important parameters are commented below:
+
+serverAddress
+  The url to access to the ZOO Kernel
+
+tmpPath
+  The full path to store temporary files
+
+tmpUrl
+  The url path relative to serverAddress to access temporary directory.
+
+The values of the *main.cfg* file used from the running virtual machine are the following:
+
+::
+
+  serverAddress=http://localhost/zoo
+  tmpPath=/var/www/temp
+  tmpUrl=../temp/
+
+You could have noticed that the *tmpUrl* is a relative url from *serverAddress*, so it must 
+be a directory. Even if ZOO Kernel can be used with the full url of the zoo_loader.cgi 
+script, for  better readability and fully functional ZOO Kernel, you have to modify the 
+default Apache configuration in order to be able to use the http://localhost/zoo/ url 
+directly.
+
+First, please create a zoo directory in the existing */var/www* which is used by Apache as 
+the DirectoryIndex. Then, please edit the */etc/apache2/sites-available/default* configuration 
+file and add the following lines after the Directory block related to */var/www* directory :
+
+::
+
+  <Directory /var/www/zoo/>
+          Options Indexes FollowSymLinks MultiViews
+          AllowOverride All
+          Order allow,deny
+          allow from all
+  </Directory>
+  
+Now create a small *.htaccess* file in the */var/www/zoo* containing the following lines:
+
+::
+
+  RewriteEngine on
+  RewriteRule (.*)/(.*) /cgi-bin/zoo_loader.cgi?metapath=$1 [L,QSA]
+  RewriteRule (.*) /cgi-bin/zoo_loader.cgi [L,QSA]
+
+For this last file to be taken into account by Apache, you must activate the rewrite 
+Apache module by copying a load file as bellow :
+
+::
+
+  sudo cp /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/
+
+Now you should be able to access the ZOO Kernel using a simplified by restarting 
+your Apache Web server :
+
+::
+
+  sudo /etc/init.d/apache2 restart
+  
+Two other softwares form the OSGeoLive environment will be used during this workshop. 
+Geoserver will first be used to provide WFS input data for the ZOO Services we are going 
+to develop. The Geoserver sample dataset (United States polygons) will be passed to our 
+service during section 3. So please start the Geoserver using the corresponding launcher 
+in the Servers folder, as illustrated in the following screenshot :
+
+OpenLayers library is also available on the OSGeoLive virtual machine image disk, and it 
+will be used during section 4, for building a simple WPS client application able to query 
+the newly developed ZOO Services. 
+
+As we planned to use OGR C-API and Python module of the GDAL library, we will need the 
+corresponding header files, libraries and associated files. Hopefully everything was 
+already available per default and so ready to use on the OSGeoLive packaging.
+
Index: tags/rel-1.3.0-rc1/docs/tutorial/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/tutorial/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/tutorial/index.txt	(revision 417)
@@ -0,0 +1,10 @@
+.. _tutorial:
+
+ZOO Tutorial
+============
+
+.. toctree::
+   :maxdepth: 2
+   
+   introduction
+   environment
Index: tags/rel-1.3.0-rc1/docs/tutorial/introduction.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/tutorial/introduction.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/tutorial/introduction.txt	(revision 417)
@@ -0,0 +1,97 @@
+.. _tutorialintro:
+
+Introduction
+============
+
+What is ZOO?
+------------
+
+ZOO is a WPS (Web Processing Service) open source project recently released under a MIT/X-11 
+style license. It provides an OGC WPS compliant developer-friendly framework to create and 
+chain WPS Web services. ZOO is made of three parts:
+
+ZOO Kernel
+  A powerful server-side C Kernel which makes it possible to manage and chain Web services 
+  coded in different programming languages. 
+  
+ZOO Services
+  A growing suite of example Web Services based on various open source libraries. 
+  
+ZOO API
+  A server-side JavaScript API able to call and chain the ZOO Services, which makes the 
+  development and chaining processes easier. 
+
+ZOO is designed to make the WPS server-side development easier by providing a powerful system 
+able to understand and execute WPS compliant queries. It supports several programming languages, 
+thus allowing you to create Web Services in your favorite language and from existing code. 
+Further information on the project is available on the 
+`ZOO Project official website <http://www.zoo-project.org/>`__.
+
+How does ZOO work?
+------------------
+
+ZOO is based on a 'WPS Service Kernel' which constitutes the ZOO's core system (aka ZOO Kernel). 
+The latter is able to load dynamic libraries and to handle them as on-demand Web services. 
+The ZOO Kernel is written in C language, but supports several common programming languages 
+for creating ZOO Services.
+
+A :ref:`ZOO Service <services>` is a link composed of a ZOO metadata file (.zcfg) and the code 
+for the corresponding implementation. The metadata file describes all the available functions 
+which can be called using a WPS Exec Request, as well as the desired input/output. Services 
+contain the algorithms and functions, and can now be implemented in C/C++, Fortran, Java, 
+Python, PHP and JavaScript.
+
+:ref:`ZOO Kernel <kernel>` works with Apache and can communicate with cartographic engines 
+and Web mapping clients. It simply adds the WPS support to your spatial data infrastructure 
+and your Web mapping application. It can use every GDAL/OGR supported formats as input data 
+and create suitable vector or raster output for your cartographic engine and/or your 
+web-mapping client application.
+
+What are we going to do in this workshop?
+-----------------------------------------
+
+This workshop aims to present the ZOO Project and its features, and to explain its capabilities 
+regarding the WPS 1.0.0 specification. The participants will learn in 3 hours how to use ZOO 
+Kernel, how to create ZOO Services  and their configuration files and finally how to link 
+the created Service with a client-side webmapping application.
+
+A pre-compiled ZOO 1.0 version is provided inside OSGeoLive, the OSGeo official Live DVD. 
+For the sack of simplicity, an OSGeoLive Virtual Machine image disk is already installed 
+on your computers. This will be used during this workshop, so the participants won't have 
+to compile and install ZOO Kernel manually. Running and testing ZOO Kernel from this 
+OSGeoLive image disk is thus the first step of the workshop, and every participants should 
+get a working ZOO Kernel in less than 30 minutes.
+
+Once ZOO Kernel will be tested from a Web browser using GetCapabilities requests, 
+participants will be invited to create an OGR based ZOO Service Provider aiming to enable 
+simple spatial operations on vector data. Participants will first have to choose whether 
+they will create the service using C or Python language. Every programming step of the ZOO 
+Service Provider and the related Services will be each time detailed in C and Python.
+
+Once the ZOO Services will be ready and callable by ZOO Kernel, participants will finally 
+learn how to use its different functions from an OpenLayers simple application. A sample 
+dataset from Geoserver will be displayed on a simple map using WMS/WFS standards and used as 
+input data by the ZOO Services. Then, some specific selection and execution controls will be 
+added in the JavaScript code in order to execute single and multiple geometries on the displayed 
+polygons.
+
+Once again, the whole procedure will be organized step-by-step and detailed with numerous code 
+snippets and their respective explanations. The instructors will check the ZOO Kernel functioning 
+on each machine and will assist you while coding. Technical questions are of course welcome 
+during the workshop.
+
+Usefull tips for reading
+------------------------
+
+Codes snipets are included in yellow blocks
+
+Code changes are included in grey blocks
+
+Code snipets included in sentences are displayed this way
+
+HTTP and XML Requests are included in blue blocks
+
+
+
+*Let's go !*
+
Index: tags/rel-1.3.0-rc1/docs/workshop/2010/building_wps_client_using_ol.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2010/building_wps_client_using_ol.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2010/building_wps_client_using_ol.txt	(revision 417)
@@ -0,0 +1,329 @@
+.. _building_wps_client_using_ol:
+
+Building a WPS client using OpenLayers
+######################################
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+The next step of our workshop is to connect to the OGR Services we have created 
+from an OpenLayers map. This will allow to apply single or multiple geometries 
+processes on user-selected polygons and to display the new generated geometries. 
+
+Creating a simple map showing the dataset as WMS
+************************************************
+
+OpenLayers is also included in OSGeoLive default distribution, so it is convenient 
+to use it for our needs. Please open ``/var/www/zoo-ogr.html`` using your favorite 
+text editor and paste the following HTML snippet: 
+
+.. code-block:: guess
+
+    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="EN" lang="EN">
+     <head>
+      <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
+      <title>ZOO WPS Client example</title>
+      <style>
+      #map{width:700px;height:600px;}
+      </style>
+      <link rel="stylesheet" href="/openlayers/theme/default/style.css" type="text/css" />
+      <script type="text/javascript" src="/openlayers/lib/OpenLayers.js"></script>
+     </head>
+     <body onload="init()">
+      <div id="map"></div>
+     </body>
+    </html>
+
+The following JavaScript code must then be added in a ``<script></script>`` section within the 
+``<head>`` one. This will setup a map showing the japanese regions data as WMS. 
+
+.. code-block:: guess
+
+    var map, layer, select, hover, multi, control;
+    
+    var typename="regions";
+    var main_url="http://localhost/cgi-bin/mapserv?map=/var/www/wfs.map";
+    
+    function init(){
+      map = new OpenLayers.Map('map', {
+        controls: [
+          new OpenLayers.Control.PanZoom(),
+          new OpenLayers.Control.Permalink(),
+          new OpenLayers.Control.Navigation()
+        ]
+      });
+      layer = new OpenLayers.Layer.WMS(typename,main_url, {
+            layers: 'regions',
+            transparent: 'true',
+            format: 'image/png'
+          }, 
+          {
+            isBaseLayer: true,
+            visibility: true,
+            buffer: 0,
+            singleTile: true
+          }
+    );
+      map.addLayers([layer]);
+      map.setCenter(new OpenLayers.LonLat(138,33.5),5);
+    }
+
+Once done, please save your HTML file as ``zoo-ogr.html`` in your workshop directory, 
+then copy it in ``/var/www`` and visualize it with your favorite Web browser using this link :  
+``http://localhost/zoo-ogr.html``. You should obtain a map centered on the Japan with the WMS layer activated. 
+
+.. image:: ./images/OL-JP-1.png
+   :width: 356px
+   :height: 280px
+   :align: center
+
+Fetching the data layer as WFS and adding selection controls
+************************************************************
+
+Before accessing the displayed data via WFS, you first have to create new vector layers 
+dedicated to host the several interactions we are going to create. Please add the following 
+lines within the ``init()`` function, and do not forget to add the newly created layer in 
+the map.addLayers method: 
+
+.. code-block:: guess
+
+    select = new OpenLayers.Layer.Vector("Selection", {
+      styleMap: new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"])
+    });
+          
+    hover = new OpenLayers.Layer.Vector("Hover");
+    multi = new OpenLayers.Layer.Vector("Multi", { styleMap: 
+      new OpenLayers.Style({
+        fillColor:"red",
+        fillOpacity:0.4,
+        strokeColor:"red",
+        strokeOpacity:1,
+        strokeWidth:2
+      })
+    });
+    
+    map.addLayers([layer, select, hover, multi]);
+
+Then, you can now access the data by creating new controls to select polygons, as the 
+following. Please note that ``OpenLayers.Protocol.WFS.fromWMSLayer`` is used to access 
+geometries and that several state of selection are declared and append to the control variable. 
+
+.. code-block:: guess
+
+    var protocol = OpenLayers.Protocol.WFS.fromWMSLayer(layer, {
+            featurePrefix: 'ms',
+            geometryName: 'msGeometry',
+            featureType: typename
+    });
+    
+    control = new OpenLayers.Control.GetFeature({
+            protocol: protocol,
+            box: false,
+            hover: false,
+            multipleKey: "shiftKey",
+            toggleKey: "ctrlKey"
+    });
+    control.events.register("featureselected", this, function(e) {
+                    select.addFeatures([e.feature]);
+    });
+    control.events.register("featureunselected", this, function(e) {
+                    select.removeFeatures([e.feature]);
+    });
+    map.addControl(control);
+    control.activate();
+
+Please save your HTML file again. You should now be able to select a polygon only by 
+clicking on it. The selected polygon should appear in blue color. 
+
+.. image:: ./images/OL-JP-2.png
+   :width: 356px
+   :height: 280px
+   :align: center
+
+Calling the single geometry services from JavaScript
+****************************************************
+
+Now that everything is setup, we can go on and call our OGR ZOO services with JavaScript. 
+Please add the following lines after the ``init()`` function, which will call the single 
+geometry processes. You can notice that we use a specific ``parseMapServerId`` function 
+which let us remove the unecessary white space returned as fid value. 
+
+.. code-block:: guess
+
+    function parseMapServerId(){
+      var sf=arguments[0].split(".");
+      return sf[0]+"."+sf[1].replace(/ /g,'');
+    }
+    
+    function simpleProcessing(aProcess) {
+      if (select.features.length == 0)
+        return alert("No feature selected!");
+      if(multi.features.length>=1)
+      	multi.removeFeatures(multi.features);
+      var url = '/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&';
+      if (aProcess == 'Buffer') {
+        var dist = document.getElementById('bufferDist')?document.getElementById('bufferDist').value:'1';
+        if (isNaN(dist)) return alert("Distance is not a Number!");
+        url+='Identifier=Buffer&DataInputs=BufferDistance='+dist+'@datatype=interger;InputPolygon=Reference@xlink:href=';
+      } else
+        url += 'Identifier='+aProcess+'&DataInputs=InputPolygon=Reference@xlink:href=';
+      var xlink = control.protocol.url +"&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0";
+      xlink += '&typename='+control.protocol.featurePrefix;
+      xlink += ':'+control.protocol.featureType;
+      xlink += '&SRS='+control.protocol.srsName;
+      xlink += '&FeatureID='+parseMapServerId(select.features[0].fid);
+      url += encodeURIComponent(xlink);
+      url += '&RawDataOutput=Result@mimeType=application/json';
+      
+      var request = new OpenLayers.Request.XMLHttpRequest();
+      request.open('GET',url,true);
+      request.onreadystatechange = function() {
+        if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
+          var GeoJSON = new OpenLayers.Format.GeoJSON();
+          var features = GeoJSON.read(request.responseText);
+          hover.removeFeatures(hover.features);
+          hover.addFeatures(features);
+        }
+      }
+      request.send();
+    }
+
+
+Then, some specific buttons must be added in the HTML, in order to be able to call 
+the different processes we just declared. You can add them on top of the map by writing 
+the following lines before the ``<div id="map"></div>``. 
+
+.. code-block:: guess
+
+    <div style="float: right;padding-left: 5px;">
+     <h3>Single geometry processing</h3>
+     <ul>
+       <li>
+        <input type="button" onclick="simpleProcessing(this.value);" value="Buffer" />
+        <input id="bufferDist" value="1" />
+       </li>
+       <li>
+        <input type="button" onclick="simpleProcessing(this.value);" value="ConvexHull" />
+       </li>
+       <li>
+        <input type="button" onclick="simpleProcessing(this.value);" value="Boundary" />
+       </li>
+       <li>
+        <input type="button" onclick="simpleProcessing(this.value);" value="Centroid" />
+       </li>
+     </ul>
+    </div>
+
+Save your HTML file again. You should now be able to select a polygon and to launch a Buffer, 
+ConvexHull, Boundary or Centroid on it by clicking one of the button. The result of the 
+process should appear as GeoJSON layer on the map, in orange color. 
+
+.. image:: ./images/OL-JP-3.png
+   :width: 536px
+   :height: 270px
+   :align: center
+
+Calling the multiples geometries processes from JavaScript
+**********************************************************
+
+Using the same technique, you can now write a function dedicated to the multiple geometries 
+processes. Please add the following lines after the ``simpleProcessing()`` function, we will 
+guide you during the exercise in section 5 on how to create such a function. 
+
+.. code-block:: guess
+
+    function multiProcessing(aProcess) {
+      if (select.features.length == 0 || hover.features.length == 0)
+        return alert("No feature created!");
+      var url = '/cgi-bin/zoo_loader.cgi';
+      var xlink = control.protocol.url +"&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0";
+      xlink += '&typename='+control.protocol.featurePrefix;
+      xlink += ':'+control.protocol.featureType;
+      xlink += '&SRS='+control.protocol.srsName;
+      xlink += '&FeatureID='+parseMapServerId(select.features[0].fid);
+      var GeoJSON = new OpenLayers.Format.GeoJSON();
+      try {
+        var params = '<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">';
+        params += '<ows:Identifier>'+aProcess+'</ows:Identifier>';
+        params += '<wps:DataInputs>';
+        params += '<wps:Input>';
+        params += '<ows:Identifier>InputEntity1</ows:Identifier>';
+        params += '<wps:Reference xlink:href="'+xlink.replace(/&/gi,'&amp;')+'"/>';
+        params += '</wps:Input>';
+        params += '<wps:Input>';
+        params += '<ows:Identifier>InputEntity2</ows:Identifier>';
+        params += '<wps:Data>';
+        params += '<wps:ComplexData mimeType="application/json"> '+GeoJSON.write(hover.features[0].geometry)+' </wps:ComplexData>';
+        params += '</wps:Data>';
+        params += '</wps:Input>';
+        params += '</wps:DataInputs>';
+        params += '<wps:ResponseForm>';
+        params += '<wps:RawDataOutput>';
+        params += '<ows:Identifier>Result</ows:Identifier>';
+        params += '</wps:RawDataOutput>';
+        params += '</wps:ResponseForm>';
+        params += '</wps:Execute>';
+      } catch(e) {
+        alert(e);
+        return false;
+      }
+      var request = new OpenLayers.Request.XMLHttpRequest();
+      request.open('POST',url,true);
+      request.setRequestHeader('Content-Type','text/xml');
+      request.onreadystatechange = function() {
+        if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
+          var GeoJSON = new OpenLayers.Format.GeoJSON();
+          var features = GeoJSON.read(request.responseText);
+          multi.removeFeatures(multi.features);
+          multi.addFeatures(features);
+        }
+      }
+      request.send(params);
+    }
+
+Note that this time we didn't use the GET method to request the ZOO Kernel but a XML POST. 
+We did that because if you use the GET method you will get error due to the HTTP GET method 
+limitation based on the length of your request. Using JSON string representing the geometry 
+will make your request longer.
+
+Once you get the functions to call your multiple geometries processes, you' must add some 
+buttons to fire the request call. Here is the HTML code to add to your current ``zoo-ogr.html`` file : 
+
+.. code-block:: guess
+
+    <h3>Multiple geometries processing</h3>
+    <ul>
+      <li>
+        <input type="button" onclick="multiProcessing(this.value);" value="Union"/>
+      </li>
+      <li>
+        <input type="button" onclick="multiProcessing(this.value);" value="Difference"/>
+      </li>
+      <li>
+        <input type="button" onclick="multiProcessing(this.value);" value="SymDifference"/>
+      </li>
+      <li>
+        <input type="button" onclick="multiProcessing(this.value);" value="Intersection"/>
+      </li>
+    </ul>
+
+Please reload the page. You should then be able to run your multiple geometries services and 
+you should get results displayed in red as shown by the following screenshots : 
+
+
+.. image:: ./images/OL-JP-4.png
+   :width: 406px
+   :height: 140px
+.. image:: ./images/OL-JP-5.png
+   :width: 406px
+   :height: 140px
+.. image:: ./images/OL-JP-6.png
+   :width: 406px
+   :height: 140px
+.. image:: ./images/OL-JP-7.png
+   :width: 406px
+   :height: 140px
+   
+It seems that something is missing in your Services Provider to get the same results … 
+The multiple geometries Services ! This is what we are going to do together in the next section. 
Index: tags/rel-1.3.0-rc1/docs/workshop/2010/exercise.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2010/exercise.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2010/exercise.txt	(revision 417)
@@ -0,0 +1,56 @@
+.. _exercise:
+
+Exercise
+########
+
+You know everything now about writting zcfg matadata files and get short pieces 
+of code in ``service.c`` or ``ogr_service_provider.py`` depending if you choosen 
+C or Python programming language respectively.
+
+The goal of this exercise is to implement the following multiple geometries services :
+
+  - Intersection
+  - Union
+  - Difference
+  - SymDifference
+
+C version
+*********
+
+Your are now invited to edit the source.c file you have created during this workshop 
+to add the multiple geometries, using the following OGR C-API functions :
+
+  - `OGR_G_Intersection <http://www.gdal.org/ogr/ogr__api_8h.html#5a271b5c7b72994120e7a6bbc7e7e5cb>`__ (OGRGeometryH, OGRGeometryH)
+  - `OGR_G_Union <http://www.gdal.org/ogr/ogr__api_8h.html#5a271b5c7b72994120e7a6bbc7e7e5cb>`__ (OGRGeometryH, OGRGeometryH)
+  - `OGR_G_Difference <http://www.gdal.org/ogr/ogr__api_8h.html#497977bec6ecd9dade7a9694f776be64>`__ (OGRGeometryH, OGRGeometryH)
+  - `OGR_G_SymmetricDifference <http://www.gdal.org/ogr/ogr__api_8h.html#d6dacf495617a230c6f19950bc415f17>`__ (OGRGeometryH, OGRGeometryH)
+
+You can use the ``Boundary.zcfg`` file as example, rename the InputPolygon input 
+to ``InputEntity1`` and add a similar input named ``IntputEntity2``. You are 
+invited to update other values in the ZOO Metadata File to set the proper 
+metadata informations.
+
+Python Version
+**************
+
+Your are invited to edit the ``ogr_ws_service_provider.py`` file you created 
+during this workshop to add the multiple geometries using the following 
+``osgeo.ogr`` Geometry methods applied on the first Geometry instance :
+
+  - Intersection(Geometry)
+  - Union(Geometry)
+  - Difference(Geometry)
+  - SymmetricDifference(Geometry)
+
+You can once again use the ``Boundary.zcfg`` file as example, rename the ``InputPolygon`` 
+input to ``InputEntity1`` and add a similar input named ``IntputEntity2``. You are 
+invited to update other values in the ZOO metadata file to set the proper metadata 
+informations.
+
+Testing your services
+*********************
+
+Once the multiple geometries Services are deployed on your local environment, 
+please reload the ``zoo-ogr.html`` file created during the previous section 
+from your browser and test your brand new ZOO Services. 
+
Index: tags/rel-1.3.0-rc1/docs/workshop/2010/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2010/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2010/index.txt	(revision 417)
@@ -0,0 +1,107 @@
+.. _workshop-foss4g-japan-2010:
+
+##############################################################
+Workshop: Practical Introduction to ZOO: The Open WPS Platform
+##############################################################
+
+:Author:  Nicolas Bozon, Gérald Fenoy
+:Last Updated: $Date$
+
+****************************************
+FOSS4G 2010 Osaka / Tokyo / Beijing
+****************************************
+
+.. image:: ./images/foss4g2010tokyo.png
+   :width: 193px
+   :height: 100px
+
+.. image:: ./images/molamola_gps1.png
+   :width: 100px
+   :height: 100px
+
+**************
+Sponsored By
+**************
+
+.. image:: ../../_static/images/geolabs-logo.png
+   :width: 156px
+   :height: 60px 
+   :target: http://www.geolabs.fr/  
+
+.. image:: ../../_static/images/apptech-logo.png
+   :width: 200px
+   :height: 60px
+   :target: http://www.apptec.co.jp/   
+
+.. image:: ../../_static/images/neogeo-logo.png
+   :width: 156px
+   :height: 60px 
+   :target: http://www-neogeo-online.net/  
+   
+.. raw:: latex
+
+   \\
+
+.. image:: ../../_static/images/3liz-logo.png
+   :width: 156px
+   :height: 60px
+   :target: http://www.3liz.com/   
+
+.. image:: ../../_static/images/gateway-logo.png
+   :width: 200px
+   :height: 60px
+   :target: http://www.gatewaygeomatics.com/   
+
+*******************************************
+Special Thanks To Our Knowledge Partners
+*******************************************
+
+.. image:: ../../_static/images/ocu-logo.png
+   :width: 200px
+   :height: 50px
+   :target: http://www.osaka-cu.ac.jp/english/
+
+.. image:: ../../_static/images/logo-fem.png
+   :width: 260px
+   :height: 50px
+   :target: http://www.fondazioneedmundmach.it/
+   
+.. raw:: latex
+
+   \\
+
+.. image:: ../../_static/images/polimi-logo.png
+   :width: 200px
+   :height: 50px
+   :target: http://geomatica.como.polimi.it/
+
+.. image:: ../../_static/images/gucas-logo.png
+   :width: 200px
+   :height: 50px
+   :target: http://www.gucas.ac.cn/gscasenglish/index.aspx
+   
+.. raw:: latex
+
+   \\
+
+.. image:: ../../_static/images/cumtb-logo.png
+   :width: 200px
+   :height: 50px
+   :target: http://www.cumtb.edu.cn/
+
+.. image:: ../../_static/images/logo-supsi.png
+   :width: 260px
+   :height: 50px
+   :target: http://www.supsi.ch/home.html
+
+****************************
+Workshop Table of Contents
+****************************
+.. toctree::
+   :maxdepth: 5
+   
+   introduction
+   using_zoo_from_osgeolivevm
+   ogr_base_vect_ops
+   building_wps_client_using_ol
+   exercise
Index: tags/rel-1.3.0-rc1/docs/workshop/2010/introduction.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2010/introduction.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2010/introduction.txt	(revision 417)
@@ -0,0 +1,92 @@
+.. _introduction:
+
+Introduction
+############
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+What is ZOO ?
+*************
+
+ZOO is a WPS (Web Processing Service) open source project recently released under a `MIT/X-11 <http://zoo-project.org/trac/wiki/Licence>`__ style license. It provides an OGC WPS compliant developer-friendly framework to create and chain WPS Web services. ZOO is made of three parts:
+
+  - `ZOO Kernel <http://zoo-project.org/trac/wiki/ZooWebSite/ZooKernel/Introduction>`__ : A powerful server-side C Kernel which makes it possible to manage and chain Web services coded in different programming languages.
+  - `ZOO Services <http://zoo-project.org/trac/wiki/ZooWebSite/ZooServices/Introduction>`__ : A growing suite of example Web Services based on various open source libraries.
+  - `ZOO API <http://zoo-project.org/trac/wiki/ZooWebSite/ZOOAPI/Introduction>`__ : A server-side JavaScript API able to call and chain the ZOO Services, which makes the development and chaining processes easier.
+
+ZOO is designed to make the service development easier by providing a powerful system 
+able to understand and execute WPS compliant queries. It supports several programming 
+languages, thus allowing you to create Web Services in your favorite one and from an 
+already existing code. Further information on the project is available on the  
+`ZOO Project official website <http://www.zoo-project.org/>`__ .
+
+How does ZOO works ?
+********************
+
+ZOO is based on a 'WPS Service Kernel' which constitutes the ZOO's core system 
+(aka ZOO Kernel). The latter is able to load dynamic libraries and to handle them 
+as on-demand Web services. The ZOO Kernel is written in C language, but supports 
+several common programming languages for creating ZOO Services.
+
+A ZOO Service is a link composed of a ZOO metadata file (.zcfg) and the code for 
+the corresponding implementation. The metadata file describes all the available 
+functions which can be called using a WPS Exec Request, as well as the desired 
+input/output. Services contain the algorithms and functions, and can now be 
+implemented in C/C++, Fortran, Java, Python, Perl, PHP and JavaScript.
+
+ZOO Kernel works with Apache and can communicate with cartographic engines and 
+Web mapping clients. It simply adds the WPS support to your spatial data infrastructure 
+and your Web mapping application. It can use every GDAL/OGR supported formats as input 
+data and create suitable vector or raster output for your cartographic engine and/or 
+your web-mapping client application.
+
+What are we going to do in this workshop?
+*****************************************
+
+This workshop aims to present the ZOO Project and its features, and to explain its 
+capabilities regarding the  `OGC WPS 1.0.0 specification <http://www.opengeospatial.org/standards/wps>`__. 
+The participants will learn in 3 hours how to use ZOO Kernel, how to create 
+ZOO Services and their configuration files and finally how to link the created 
+Service with a client-side webmapping application. A pre-compiled ZOO 1.0 version 
+is provided inside OSGeoLive, the OSGeo official Live DVD. For the sack of simplicity, 
+an OSGeoLive Virtual Machine image disk is already installed on your computers. 
+This will be used during this workshop, so the participants won't have to compile 
+and install ZOO Kernel manually. Running and testing ZOO Kernel from this OSGeoLive 
+image disk is thus the first step of the workshop, and every participants should 
+get a working ZOO Kernel in less than 30 minutes.
+
+Once ZOO Kernel will be tested from a Web browser using GetCapabilities requests, 
+participants will be invited to create an OGR based ZOO Service Provider aiming to 
+enable simple spatial operations on vector data. Participants will first have to 
+choose whether they will create the service using C or Python language. Every programming 
+step of the ZOO Service Provider and the related Services will be each time detailed in 
+C and Python. Once the ZOO Services will be ready and callable by ZOO Kernel, participants 
+will finally learn how to use its different functions from an  OpenLayers simple application. 
+A sample dataset was providen by Orkney and included in the OSGeoLiveDVD, data are 
+available trough OGC WMS/WFS WebServices using  MapServer and will be displayed on a 
+simple map and used as input data by the ZOO Services. Then, some specific selection 
+and execution controls will be added in the JavaScript code in order to execute single 
+and multiple geometries on the displayed polygons.
+
+Once again, the whole procedure will be organized step-by-step and detailed with 
+numerous code snippets and their respective explanations. The instructors will check 
+the ZOO Kernel functioning on each machine and will assist you while coding. Technical 
+questions are of course welcome during the workshop.
+
+Usefull tips for reading :
+**************************
+
+.. code-block:: guess
+
+    this is a code block
+
+.. warning:: This is a warning message.
+
+.. note:: This is an important note.
+
+
+
+
+**Let's go !**
Index: tags/rel-1.3.0-rc1/docs/workshop/2010/ogr_base_vect_ops.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2010/ogr_base_vect_ops.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2010/ogr_base_vect_ops.txt	(revision 417)
@@ -0,0 +1,1282 @@
+.. _ogr_base_vect_ops:
+
+Creating OGR based Web Services
+===============================
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+Introduction
+------------
+
+In this part, we are going to create a ZOO ServicesProvider containing several Services 
+based on the OGR C API or on the OGR Python module, which have also been placed in the 
+ZOO installation on OSGeoLive. The intended goal is to use OGR and its GEOS based simple 
+spatial functions as WPS Services.
+
+We will first start with the Boundary spatial function, which will be explained, codded 
+and tested gradually as a ZOO Service. The same procedure will then be used to enable 
+the Buffer, Centroid and Convex Hull functions. Once done, some multiple geometries processes 
+such as Intersection, Union, Difference and Symetric Difference will be implemented through 
+an `exercise <./exercise.html>`__ at the end of the workshop.
+
+As already said in the introduction, you have the choice to code your service in C or 
+Python (or both!) during this workshop. Explanations will be based on the C part, but 
+will be very helpful for those who will choose Python. Please decide according to your 
+habits and preferences and tell your choice to the instructors. The results will be the 
+same in both case. 
+
+Preparing ZOO metadata file
+---------------------------
+
+A ZOO Service is a combination of a ZOO metadata file (``.zcfg``) and the runtime module 
+for the corresponding implementation, which is commonly called ZOO Service Provider. We 
+will first prepare a ``.zcfg`` file step-by-step. Please open your preferred text editor 
+and edit a file named ``Boundary.zcfg`` in your ``/home/user/zoows/sources/zoo-services/ws_sp`` 
+directory. First, you need to name the service between brackets at the top of the file, as the 
+following
+
+::
+
+[Boundary]
+
+This name is very important, it is the name of the Service and so the name of the function 
+defined in the Services Provider. A title and a brief abstract must then be added to inform 
+clients on what the service can do: 
+
+.. code-block:: guess
+
+    Title = Compute boundary.
+    Abstract = Returns the boundary of the geometry on which the method is invoked.
+
+Such metadata informations will be returned by a GetCapabilities request.
+
+You can also add other specific informations like the ``processVersion``. You can set if 
+your ZOO Service can store its results, by setting the ``storeSupported`` parameter to 
+true or false. You can also decide if the function can be run as a background task and 
+inform on its current status, according to the ``statusSupported`` value : 
+
+.. code-block:: guess
+
+    processVersion = 1
+    storeSupported = true
+    statusSupported = true
+
+In the main section of the ZOO Service metadata file, you must also specify two important things:
+
+  - ``serviceProvider``, which is the name of the C shared library containing the Service function or the Python module name.
+  - ``serviceType``, which defines the programming language to be used for the Service. (value can be C or Python depending on what language you have decided to use) 
+
+C ServicesProvider Example : 
+
+.. code-block:: guess
+
+    serviceProvider=ogr_ws_service_provider.zo
+    serviceType=C
+
+In this case you will get an ``ogr_ws_service_provider.zo`` shared library containing 
+the Boundary function, placed in the same directory than ZOO Kernel.
+
+Python ServicesProvider Example : 
+
+.. code-block:: guess
+
+    serviceProvider=ogr_ws_service_provider
+    serviceType=Python
+
+In this case, you will get an ``ogr_ws_service_provider.py`` file containing the Python code of your Boundary function.
+
+In the main section you can also add any other metadata information, as the following: 
+
+.. code-block:: guess
+
+    <MetaData>
+        Title = Demo
+    </MetaData>
+
+The main metadata informations have been declared, so you can now define data input 
+which will be used by the ZOO Service. You can define any input needed by the Service. 
+Please note that you can request ZOO Kernel using more data input than defined in 
+the ``.zcfg`` file without any problem, those values will be passed to your service 
+without filtering. In the Boundary Service example, a single polygon will be used as 
+input, the one on which to apply the Boundary function.
+
+The data input declarations are included in a DataInputs block. They use the same 
+syntax as the Service itself and the input name is between brackets. You can also 
+fill a title, an abstract and a MetaData section for the input. You must set values 
+for the ``minOccurs`` and ``maxOccurs`` parameters, as they will inform ZOO Kernel 
+which parameters are required to be able to run the Service function. 
+
+.. code-block:: none
+
+    [InputPolygon]
+      Title = Polygon to compute boundary
+      Abstract = URI to a set of GML that describes the polygon.
+      minOccurs = 1
+      maxOccurs = 1
+      <MetaData>
+          Test = My test
+      </MetaData>
+
+
+The metadata defines what type of data the Service supports. In the Boundary example, 
+the input polygon can be provided as a GML file or as a JSON string. Next step is 
+thus to define the default and supported input formats. Both formats should be declared 
+in a LitteralData or ComplexData block depending on their types. For this first example 
+we will use ComplexData blocks only. 
+
+.. code-block:: guess
+
+    <ComplexData>
+     <Default>
+       mimeType = text/xml
+       encoding = UTF-8
+     </Default>
+     <Supported>
+       mimeType = application/json
+       encoding = UTF-8
+     </Supported>
+    </ComplexData>
+
+
+Then, the same metadata information must be defined for the output of the Service, inside a DataOutputs block, as the following: 
+
+.. code-block:: none
+
+    [Result]
+     Title = The created geometry
+     Abstract = The geometry containing the boundary of the geometry on which the method  was invoked.
+     <MetaData>
+       Title = Result
+     </MetaData>
+     <ComplexData>
+      <Default>
+       mimeType = application/json
+       encoding = UTF-8
+      </Default>
+      <Supported>
+       mimeType = text/xml
+       encoding = UTF-8
+      </Supported>
+     </ComplexData>
+
+A complete copy of this ``.zcfg`` file can be found at the following URL: http://zoo-project.org/trac/browser/trunk/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg.
+
+
+Once the ZOO metadata file is modified, you have to copy it in the same directory 
+than your ZOO Kernel (so in your case ``/usr/lib/cgi-bin``). Then you should be 
+able to run the following request : 
+
+http://localhost/zoo/?Request=DescribeProcess&Service=WPS&Identifier=Boundary&version=1.0.0
+
+The returned ProcessDescriptions XML document should look like the following : 
+
+.. image:: ./images/Practical-introduction-to-ZOO-5.png
+   :width: 456px
+   :height: 157px
+   :align: center
+
+Please note that the GetCapabilities and DescribeProcess only need a ``.zcfg`` 
+file to be completed. Simple, isn't it ? At this step, if you request ZOO Kernel 
+for an Execute, you will get an ExceptionReport document as response, looking as the following : 
+
+.. image:: ./images/Practical-introduction-to-ZOO-6.png
+   :width: 546px
+   :height: 80px
+   :align: center
+
+A similar error message will be returned if you try to run your Python Service : 
+
+.. image:: ./images/Practical-introduction-to-ZOO-7.png
+   :width: 489px
+   :height: 87px
+   :align: center
+
+
+Implementing single geometry services
+-------------------------------------
+
+In order to learn the Services Provider creation and deployement step-by-step, 
+we will first focus on creating a very simple one dedicated to the Boundary function. 
+Similar procedure will then be used for the Buffer, Centroid and ConvexHull implementation. 
+
+Your metadata is now ok, so you now must create the code of your Service. The most 
+important thing you must be aware of when coding ZOO Services is that the function 
+corresponding to your Service takes three parameters (internal maps datatype or  
+`Python dictionaries  <http://docs.python.org/tutorial/datastructures.html#dictionaries>`__) 
+and returns an integer value representing the status of execution (SERVICE_FAILED or SERVICE_SUCCEEDED): 
+
+  -  ``conf`` : The main environment configuration (corresponding to the ``main.cfg`` content) 
+  - ``inputs`` : The requested / default inputs 
+  - ``outputs`` : The requested / default outputs 
+
+Boundary
+********
+
+C Version
+^^^^^^^^^
+
+As explained before, ZOO Kernel will pass the parameters to your Service function 
+in a specific datatype called maps. In order to code your Service in C language, 
+you also need to learn how to access this datatype in read/write mode.
+
+The maps are simple map named linked list containing a name, a content map and a 
+pointer to the next map in the list (or NULL if there is no more map in the list). 
+Here is the datatype definition as you can find in the zoo-kernel/service.h file: 
+
+.. code-block:: c
+
+    typedef struct maps{
+        char* name;
+        struct map* content;
+        struct maps* next;
+    } maps;
+
+The map included in the maps is also a simple linked list and is used to store Key 
+Value Pair values. A map is thus a couple of name and value and a pointer to the 
+next map in the list. Here is the datatype definition you can find in the zoo-kernel/service.h file:
+
+.. code-block:: guess
+
+    typedef struct map{
+        char* name;       /* The key */
+        char* value;      /* The value */
+        struct map* next; /* Next couple */
+    } map; 
+
+
+As partially or fully filled datastructures will be passed by the ZOO Kernel to 
+your Services, this means that you do not need to deal with maps creation but 
+directly with existing map, in other words the content of each maps. The first 
+function you need to know is getMapFromMaps (defined in the zoo-kernel/service.h file) 
+which let you access to a specific map of a maps.
+
+This function takes three parameters listed bellow:
+
+  - ``m`` : a maps pointer representing the maps used to search the specific map
+  - ``name`` : a char* representing the name of the map you are searching for
+  - ``key`` : a specific key in the map named name 
+
+For example, the following syntax will be used to access the InputPolygon value 
+map of a maps named inputs, your C code should be: 
+
+.. code-block:: guess
+
+    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+
+Once you get the map, you can access the name or the value fields, using the following syntax : 
+
+.. code-block:: guess
+
+    tmp->name
+    tmp->value
+
+As you know how to read and access the map fields from a maps, you can now learn 
+how to write in such a datastructure. This is done by using the simple setMapInMaps 
+function once again defined in zoo-kernel/service.h. The setMapInMaps function takes four parameters :
+
+  - ``m`` : a maps pointer you want to update,
+  - ``ns`` : the name of the maps you want you want to update,
+  - ``n`` : the name of the map you want to add or update the value,
+  - ``v`` : the value you want to set for this map. 
+
+Here is an example of how to add or edit the values of some map in the Result maps from outputs : 
+
+.. code-block:: guess
+
+    setMapInMaps(outputs,"Result","value","Hello from the C World !");
+    setMapInMaps(outputs,"Result","mimeType","text/plain");
+    setMapInMaps(outputs,"Result","encoding","UTF-8");
+
+
+Please note that the setMapInMaps function is able to create or update an existing map. 
+Indeed, if a map called « value » allready exists, then its value will be updated automatically.
+
+Even if you will mainly use map from maps during this workshop, you can also add or 
+update values in a map directly using the addToMap function defined in zoo-kernel/service.h. 
+The addToMap function take three paramters :
+
+  - ``m`` : a map pointer you want to update,
+  - ``n`` : the name of the map you want to add or update the value,
+  - ``v`` : the value you want to set in this map. 
+
+This datatype is really important cause it is used in every C based ZOO Services. It is 
+also the same representation used in other languages but using their respectives datatypes. 
+For Example in Python, the dictionaries datatype is used, so manipulation is much easier.
+
+Here is an example of the correspoding maps datatype used in Python language (this is a 
+summarized version of the main configaration maps): 
+
+.. code-block:: guess
+
+    main={
+      "main": {
+        "encoding": "utf-8",
+        "version": "1.0.0",
+        "serverAddress": "http://www.zoo-project.org/zoo/",
+        "lang": "fr-FR,en-CA"
+      },
+      "identification": {"title": "The Zoo WPS Development Server",
+        "abstract": "Development version of ZooWPS.",
+        "fees": "None",
+        "accessConstraints": "none",
+        "keywords": "WPS,GIS,buffer"
+      }
+    }
+
+As you know how to deal with maps and map, you are ready to code the first ZOO Service by using the OGR Boundary function.
+
+As already said in introduction we will use the MapServer WFS server available on 
+OSGeoLive, so full WFS Response will be used as inputs values. As we will use the 
+simple OGR Geometry functions like  `OGR_G_GetBoundary <http://www.gdal.org/ogr/ogr__api_8h.html#a797af4266c02846d52b9cf3207ef958>`__, 
+only the Geometry object will be used rather than a full WFS Response. The first 
+thing to do is to write a function which will extract the geometry definition 
+from the full WFS Response. We will call it createGeometryFromWFS.
+
+Here is the code of such a function: 
+
+.. code-block:: guess
+
+    OGRGeometryH createGeometryFromWFS(maps* conf,char* inputStr){
+      xmlInitParser();
+      xmlDocPtr doc = xmlParseMemory(inputStr,strlen(inputStr));
+      xmlChar *xmlbuff;
+      int buffersize;
+      xmlXPathContextPtr xpathCtx;
+      xmlXPathObjectPtr xpathObj;
+      char * xpathExpr="/*/*/*/*/*[local-name()='Polygon' or local-name()='MultiPolygon']";
+      xpathCtx = xmlXPathNewContext(doc);
+      xpathObj = xmlXPathEvalExpression(BAD_CAST xpathExpr,xpathCtx);
+      if(!xpathObj->nodesetval){
+        errorException(conf, "Unable to parse Input Polygon","InvalidParameterValue");
+        exit(0);
+      }
+      int size = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0;
+      xmlDocPtr ndoc = xmlNewDoc(BAD_CAST "1.0");
+      for(int k=size-1;k>=0;k--){
+        xmlDocSetRootElement(ndoc, xpathObj->nodesetval->nodeTab[k]);
+      }
+      xmlDocDumpFormatMemory(ndoc, &xmlbuff, &buffersize, 1);
+      char *tmp=strdup(strstr((char*)xmlbuff,"?>")+2);
+      xmlXPathFreeObject(xpathObj);
+      xmlXPathFreeContext(xpathCtx);
+      xmlFree(xmlbuff);
+      xmlFreeDoc(doc);
+      xmlCleanupParser();
+      OGRGeometryH res=OGR_G_CreateFromGML(tmp);
+      if(res==NULL){
+        errorException(conf, "Unable to call OGR_G_CreatFromGML","NoApplicableCode");
+        exit(0);
+      }
+      else
+        return res;
+    }
+
+
+The only thing we will focus on is the call to the errorException function used 
+in the function body. This function is declared in the zoo-kernel/service_internal.h 
+and defined in zoo-kernel/service_internal.c file. It takes three parameters as follow:
+
+  - the main environment maps,
+  - a char* representing the error message to display,
+  - a char* representing the error code (as defined in the WPS specification – Table 62). 
+
+In other words, if the WFS response cannot be parsed properly, then you will return 
+an ExceptionReport document informing the client that a problem occured.
+
+The function to extract the geometry object from a WFS Response is written, so you 
+can now start defining the Boundary Service. Here is the full code for the Boundary Service: 
+
+.. code-block:: guess
+
+    int Boundary(maps*& conf,maps*& inputs,maps*& outputs){
+      OGRGeometryH geometry,res;
+      map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+      if(tmp==NULL){
+        setMapInMaps(m,"lenv","message","Unable to parse InputPolygon");
+        return SERVICE_FAILED;
+      }
+      map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0)
+        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+      else
+        geometry=createGeometryFromWFS(conf,tmp->value);
+      if(geometry==NULL){
+        setMapInMaps(m,"lenv","message","Unable to parse InputPolygon");
+        return SERVICE_FAILED;
+      }
+      res=OGR_G_GetBoundary(geometry);
+      tmp1=getMapFromMaps(outputs,"Result","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0){
+        char *tmp=OGR_G_ExportToJson(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        setMapInMaps(outputs,"Result","mimeType","text/plain");
+        free(tmp);
+      }
+      else{
+        char *tmp=OGR_G_ExportToGML(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        free(tmp);
+      }
+      outputs->next=NULL;
+      OGR_G_DestroyGeometry(geometry);
+      OGR_G_DestroyGeometry(res);
+      return SERVICE_SUCCEEDED;
+    }
+
+As you can see in the code above, the mimeType of the data inputs passed to our Service is first checked:
+
+.. code-block:: guess
+
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+    if(strncmp(tmp1->value,"application/json",16)==0)
+      geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+    else
+      geometry=createGeometryFromWFS(conf,tmp->value);
+
+Basically, if we get an input with a mimeType set to application/json, then we will 
+use our ``OGR_G_CreateGeometryFromJson`` in other case, our ``createGeometryFromWFS`` local function.
+
+Please note that in some sense the data inputs are not really of the same kind. 
+Indeed as we used directly ``OGR_G_CreateGeometryFromJson`` it means that the JSON 
+string include only the geometry object and not the full GeoJSON string. Nevertheless, 
+you can easily change this code to be able to use a full GeoJSON string, simply by 
+creating a function which will extract the geometry object from the GeoJSON string 
+(using the json-c library for instance, which is also used by the OGR GeoJSON Driver).
+
+Once you can access the input geometry object, you can use the  ``OGR_G_GetBoundary`` 
+function and store the result in the res geometry variable. Then, you only have to 
+store the value in the right format : GeoJSON per default or GML as we declared it as a supported output format.
+
+Please note that ZOO Kernel will give you pre-filled outputs values, so you will 
+only have to fill the value for the key named value, even if in our example we 
+override the mimeType using the text/plain value rather than the application/json 
+(to show that we can also edit other fields of a map). Indeed, depending on the 
+format requested by the client (or the default one) we will provide JSON or GML representation of the geometry. 
+
+.. code-block:: guess
+
+      tmp1=getMapFromMaps(outputs,"Result","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0){
+        char *tmp=OGR_G_ExportToJson(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        setMapInMaps(outputs,"Result","mimeType","text/plain");
+        free(tmp);
+      }
+      else{
+        char *tmp=OGR_G_ExportToGML(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        free(tmp);
+      }
+
+The Boundary ZOO Service is now implemented and you need to compile it to produce 
+a Shared Library. As you just used functions defined in service.h (``getMapFromMaps``, 
+``setMapInMaps`` and ``addToMap``), you must include this file in your C code. The 
+same requirement is needed to be able to use the ``errorException`` function declared 
+in ``zoo-kernel/service_internal.h``, you also must link your service object file to 
+the ``zoo-kernel/service_internal.o`` in order to use ``errorException`` on runtime. 
+You must then include the required files to access the libxml2 and OGR C-API.
+
+For the need of the Shared Library, you have to put your code in a block declared as 
+extern "C". The final Service code should be stored in a service.c file located in 
+the root of the Services Provider directory (so in ``/home/zoows/sources/zoo-services/ws_sp``). 
+It should look like this: 
+
+.. code-block:: guess
+
+    #include "ogr_api.h"
+    #include "service.h"
+    extern "C" {
+    #include <libxml/tree.h>
+    #include <libxml/parser.h>
+    #include <libxml/xpath.h>
+    #include <libxml/xpathInternals.h>
+    <YOUR SERVICE CODE AND OTHER UTILITIES FUNCTIONS>
+    }
+
+The full source code of your Service is now ready and you must produce the corresponding 
+Service Shared Object by compiling the code as a Shared Library. This can be done using the following command: 
+
+.. code-block:: guess
+
+    g++ $CFLAGS -shared -fpic -o cgi-env/!ServicesProvider.zo ./service.c $LDFLAGS
+
+Please note that the ``CFLAGS`` and ``LDFLAGS`` environment variables values must be set before.
+
+The ``CFLAGS`` must contain all the requested paths to find included headers, so the 
+path to the directories where the ``ogr_api.h``, ``libxml2`` directory, ``service.h`` 
+and ``service_internal.h`` files are located. Thanks to the OSGeoLive environment, 
+some of the provided tools can be used to retrieve those values : ``xml2-config`` and 
+``gdal-config``, both used with the ``--cflags`` argument. They will produce the desired paths for you.
+
+If you follow the instructions to create your ZOO Services Provider main directory in 
+``zoo-services``, then you should find the ZOO Kernel headers and source tree which is 
+located in the ``../../zoo-kernel`` directory relatively to your current path (``/home/user/zoows/sources/zoo-services/ws_sp``). 
+Note that you can also use a full path to the ``zoo-kernel`` directory but using relative 
+path will let you move your sources tree somewhere else and keep your code compiling 
+using exactly the same command line. So you must add a ``-I../../zoo-kernel`` to your 
+``CFLAGS`` to make the compiler able to find the ``service.h`` and ``service_internal.h`` files.
+
+The full ``CFLAGS`` definition should look like this:
+
+.. code-block:: guess
+
+    CFLAGS=`gdal-config --cflags` `xml2-config --clfags` -I../../zoo-kernel/ 
+
+Once you get the included paths correctly set in your ``CFLAGS`` , it is time to concentrate 
+on the library we have to link against (defined in the ``LDFLAGS`` environment variable). 
+In order to link against the gdal and libxml2 libraries, you can use the same tools than 
+above using the ``--libs`` argument rather than ``--cflags``. The full ``LDFLAGS`` 
+definition must look like this : 
+
+.. code-block:: guess
+
+    LDFLAGS=`gdal-config --libs` `xml2-config --libs` ../../zoo-kernel/service_internal.o
+
+Let's now create a ``Makefile`` which will help you compiling your code over the time. 
+Please write a short ``Makefile`` in the root of your ZOO Services Provider directory, containing the following lines:
+
+.. code-block:: guess
+
+    ZOO_SRC_ROOT=../../zoo-kernel/
+    CFLAGS=-I${ZOO_SRC_ROOT} `xml2-config --cflags` `gdal-config --cflags`
+    LDFLAGS=`xml2-config --libs` `gdal-config --libs`${ZOO_SRC_ROOT}/service_internal.o
+
+    cgi-env/ogr_ws_service_provider.zo: service.c
+        g++ ${CFLAGS} -shared -fpic -o cgi-env/ogr_ws_service_provider.zo ./service.c $ {LDFLAGS}
+    clean:
+        rm -f cgi-env/ogr_ws_service_provider.zo
+
+
+Using this ``Makefile``, you should be able to run ``make`` from your ZOO Service Provider 
+main directory and to get the resulting ``ogr_ws_service_provider.zo`` file located in the ``cgi-env`` directory.
+
+The metadata file and the ZOO Service Shared Object are now both located in the ``cgi-env`` 
+directory. In order to deploy your new ServicesProvider, you only have to copy the ZOO 
+Service Shared Object and its corresponding metadata file in the directory where ZOO 
+Kernel is located, so in ``/usr/lib/cgi-bin``. You must use a ``sudo`` command to achieve this task: 
+
+.. code-block:: guess
+
+    sudo cp ./cgi-env/* /usr/lib/cgi-bin
+
+You should now understand more clearly the meannings of the ZOO Service Provider source tree ! 
+The ``cgi-env`` directory will let you deploy your new Services or Services Provider in 
+an easy way , simply by copying the whole cgi-env content in your ``cgi-bin`` directory.
+
+Please note that you can add the following lines to your ``Makefile`` to be able to type 
+``make install`` directly and to get your new Services Provider available for use from ZOO Kernel:
+
+.. code-block:: none
+
+    install:
+        sudo cp ./cgi-env/* /usr/lib/cgi-bin
+
+Your ZOO Services Provider is now ready to use from an Execute request passed to ZOO Kernel. 
+
+Python Version
+^^^^^^^^^^^^^^
+
+For those using Python to implement their ZOO Services Provider, the full code to copy in 
+``ogr_ws_service_provider.py`` in ``cgi-env`` directory is shown bellow. Indeed, as 
+Python is an interpreted language, you do not have to compile anything before deploying 
+your service which makes the deployement step much easier:
+
+.. code-block:: guess
+
+    import osgeo.ogr
+    import libxml2
+
+    def createGeometryFromWFS(my_wfs_response):
+        doc=libxml2.parseMemory(my_wfs_response,len(my_wfs_response))
+        ctxt = doc.xpathNewContext()
+        res=ctxt.xpathEval("/*/*/*/*/*[local-name()='Polygon' or local- name()='MultiPolygon']")
+        for node in res:
+            geometry_as_string=node.serialize()
+            geometry=osgeo.ogr.CreateGeometryFromGML(geometry_as_string)
+            return geometry
+        return geometry
+
+    def Boundary(conf,inputs,outputs):
+        if inputs["InputPolygon"]["mimeType"]=="application/json":
+            geometry=osgeo.ogr.CreateGeometryFromJson(inputs["InputPolygon"]["value"])
+        else:
+            geometry=createGeometryFromWFS(inputs["InputPolygon"]["value"])
+        rgeom=geometry.GetBoundary()
+        if outputs["Result"]["mimeType"]=="application/json":
+            outputs["Result"]["value"]=rgeom.ExportToJson()
+            outputs["Result"]["mimeType"]="text/plain"
+        else:
+            outputs["Result"]["value"]=rgeom.ExportToGML()
+        geometry.Destroy()
+        rgeom.Destroy()
+        return 3 
+
+We do not dicuss the functions body here as we already gave all the details before and 
+the code was volontary made in a similar way.
+
+As done before, you only have to copy the ``cgi-env`` files into your ``cgi-bin`` directory: 
+
+.. code-block:: guess
+
+    sudo cp ./cgi-env/* /usr/lib/cgi-bin
+
+A simple ``Makefile`` containing the install section can be written as the following : 
+
+.. code-block:: none
+
+    install:
+    	sudo cp ./cgi-env/* /usr/lib/cgi-bin/
+
+Finally, simply run make install from the ZOO Services Provider main directory, in order to deploy your ZOO Service Provider. 
+
+
+Testing the Service using Execute Request
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+**The simple and unreadable way**
+
+Everybody should now get his own copy of the OGR Boundary Service stored as a ZOO 
+Services Provider called ``ogr_ws_service_provider`` and deployed in the ZOO Kernel 
+tree, so the following Execute request can be used to test the Service:
+
+`link <http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192>`__
+
+.. code-block:: guess
+
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192
+
+As you can see in the url above, we use an URLEncoded WFS request to the MapServer 
+WFS server available on OSGeoLive as a ``xlink:href`` key in the DataInputs KVP value, 
+and set the ``InputPolygon`` value to Reference. The corresponding non encoded WFS request is as follow:
+
+::
+
+    http://localhost/cgi-bin/mapserv?map=/var/www/wfs.map&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&typename=regions&SRS=EPSG:4326&featureid=regions.3192
+
+Please note that you can add ``lineage=true`` to the previous request if you need 
+to get information about the input values used to run your Service. Furthermore, 
+you may need to store the ExecuteResponse document of your ZOO Service to re-use 
+it later. In this case you must add ``storeExecuteResponse=true`` to the previous 
+request. Note that is an important thing as the behavior of ZOO Kernel is not 
+exactly the same than when running without this parameter settled to true. Indeed, 
+in such a request, ZOO Kernel will give you an ExecuteResponse document which will 
+contain the attribute statusLocation, which inform the client where the ongoing 
+status or the final ExecuteResponse will be located.
+
+Here is an example of what the ExecuteResponse would look like in case ``storeExecuteResponse`` was set to true in the request:
+
+.. image:: ./images/Practical-introduction-to-ZOO-7.png
+   :width: 610px
+   :height: 146px
+   :align: center
+
+Then, according to the statusLocation, you should get the ExecuteResponse as you get 
+before using the previous request. Note that can be really useful to provide some 
+caching system for a client application.
+
+You didn't specify any ResponseForm in the previous request, it is not requested 
+and should return a ResponseDocument per default using the application/json mimeType 
+as you defined in you zcfg file. Nevertheless, you can tell ZOO Kernel what kind of 
+data you want to get in result of your query adding the attribute ``mimeType=text/xml`` 
+to your ``ResponseDocument`` parameter. Adding this parameter to the previous request 
+will give us the result as its GML representation : 
+
+`link <http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192&ResponseDocument=Result@mimeType=text/xml>`__ 
+
+.. code-block:: guess
+
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192&ResponseDocument=Result@mimeType=text/xml 
+
+As defined by the WPS specifications, you can also ask for a ``RawDataOutput`` to 
+get only the data without the full ``ResponseDocument``. To do that, you only have 
+to replace the ``ResponseDocument`` of your request by ``RawDataOutput``, like in 
+the following request : 
+
+`link <http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192&RawDataOutput=Result@mimeType=application/json>`__
+
+.. code-block:: guess
+
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192&RawDataOutput=Result@mimeType=application/json
+
+Please note that we go back to the default mimeType to directly obtain the JSON 
+string as we will use this kind of request to develop our client application in 
+the next section of this workshop.
+
+Now, you know how to ask ZOO Kernel to run service in background, ask for ``RawDataOutput`` 
+specifying ``mimeType`` or any specific format to be returned by the Kernel. When you 
+ask for ``ResponseDocument``, you can also specify to the ZOO Kernel that you want the 
+result to be stored on the server side.
+
+To do such a thing, you have to set the attribute ``asReference`` as true and then the 
+resulting ExecuteResponse will contain a Reference node including the href attribute 
+to let you access the produced file. To be able to handle this, you have to add the 
+extension parameter in your ``DataOutputs`` node in the corresponding ZCFG file.
+
+Here is a sample url which provide such a result:
+
+`link <http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192&ResponseDocument=Result@mimeType=application/json@asReference=true>`__ 
+
+.. code-block:: guess
+
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fvar%2Fwww%2Fwfs.map%26SERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192&ResponseDocument=Result@mimeType=application/json@asReference=true
+
+You can see bellow what kind of result can be expected : 
+
+.. image:: ./images/screenshot-ZOO-asReference-attribute.png
+   :width: 620px
+   :height: 217px
+   :align: center
+
+**Simplification and readability of request**
+
+As you can see in the simple example we used since the begining of this workshop, 
+it is sometimes hard to write the Execute requests using the GET method as it 
+makes really long and complexe URLs. In the next requests examples, we will 
+thus use the POST XML requests. First , here is the XML request corresponding 
+to the previous Execute we used:
+
+.. code-block:: guess
+
+    <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>Boundary</ows:Identifier>
+     <wps:DataInputs>
+      <wps:Input>
+       <ows:Identifier>InputPolygon</ows:Identifier>
+       <ows:Title>Playground area</ows:Title>
+       <wps:Reference xlink:href="http://localhost/cgi-bin/mapserv?map=/var/www/wfs.map&amp;SERVICE=WFS&amp;REQUEST=GetFeature&amp;VERSION=1.0.0&amp;typename=regions&amp;SRS=EPSG:4326&amp;featureid=regions.3192"/>
+      </wps:Input>
+     </wps:DataInputs>
+     <wps:ResponseForm>
+      <wps:ResponseDocument>
+       <wps:Output>
+        <ows:Identifier>Result</ows:Identifier>
+        <ows:Title>Area serviced by playground.</ows:Title>
+        <ows:Abstract>Area within which most users of this playground will live.</ows:Abstract>
+       </wps:Output>
+      </wps:ResponseDocument>
+     </wps:ResponseForm>
+    </wps:Execute> 
+
+In order to let you easily run the XML requests, a simple HTML form called 
+``test_services.html`` is available in your ``/var/www`` directory. You can 
+access it using the following link :  http://localhost/test_services.html.
+
+Please open this page in your browser, simply fill the XML request content into 
+the textarea field and click the « run using XML Request » submit button. You will 
+get exactly the same result as when running your Service using the GET request. The 
+screenshot above show the HTML form including the request and the ExecuteResponse 
+document displayed in the iframe at the bottom of the page:
+
+.. image:: ./images/Practical-introduction-to-ZOO-8.png
+   :width: 573px
+   :height: 308px
+   :align: center
+
+The xlink:href value is used in the simplest way to deal with such data input. Obviously, 
+you can also use a full JSON string of the geometry, as shown in the following XML Request example : 
+
+.. code-block:: guess
+
+    <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.xsda">
+     <ows:Identifier>Boundary</ows:Identifier>
+     <wps:DataInputs>
+      <wps:Input>
+       <ows:Identifier>InputPolygon</ows:Identifier>
+       <wps:Data>
+        <wps:ComplexData mimeType="application/json">
+    { "type": "MultiPolygon", "coordinates": [ [ [ [ -105.998360, 31.393818 ], [ -106.212753, 31.478128 ], [ -106.383041, 31.733763 ], [ -106.538971, 31.786198 ], [ -106.614441, 31.817728 ], [ -105.769730, 31.170780 ], [ -105.998360, 31.393818 ] ] ], [ [ [ -94.913429, 29.257572 ], [ -94.767380, 29.342451 ], [ -94.748405, 29.319490 ], [ -95.105415, 29.096958 ], [ -94.913429, 29.257572 ] ] ] ] }
+        </wps:ComplexData>
+       </wps:Data>
+      </wps:Input>
+     </wps:DataInputs>
+     <wps:ResponseForm>
+      <wps:ResponseDocument>
+       <wps:Output>
+        <ows:Identifier>Result</ows:Identifier>
+        <ows:Title>Area serviced by playground.</ows:Title>
+        <ows:Abstract>Area within which most users of this playground will live.</ows:Abstract>
+       </wps:Output>
+      </wps:ResponseDocument>
+     </wps:ResponseForm>
+    </wps:Execute>
+ 
+If everything went well, you should get the Boundary of the JSON geometry passed as 
+argument, and so be sure that your Service support both GML and JSON as input data. 
+Note that in the previous request, we added a ``mimeType`` attribute to the 
+``ComplexData`` node to specify that the input data is not in the default ``text/xml`` 
+mimeType but passed as an ``application/json`` string directly. It is similar to add 
+``@mimeType=application/json`` as we discussed before. 
+
+**storeExecuteResponse parameter and GetStatus Service**
+
+If you go in your local ``/home/user/zoows/sources/zoo-services/utils/status``, you'll 
+find the code for a ServiceProvider which will provide the GetStatus service and the 
+longProcess one. The last is a simple example to learn how to use the status variable 
+from lenv section of the main configuration maps and the updateStatus function you 
+have to call to take your status value into account. The main service provider is 
+the GetStatus one, it is able to give you information about the current status value 
+from a service running in background mode.
+
+You have to know that the ZOO Kernel will detect the presence of the GetStatus service 
+and if it is available it will then return the link the corresponding Execute request.
+
+So now you will deploy the GetStatus and longProcess service on your local environment. 
+As for each services, you shall be able to deploy the services simply by copying the 
+cgi-env directory into your Apache ``cgi-bin`` directory. You can use the following command : 
+
+.. code-block:: guess
+
+    sudo cp ~user/zoows/sources/zoo-services/utils/status/cgi-env/*{zcfg,zo} /usr/lib/cgi-bin
+
+For simple Services it is the right way to deploy Service Providers. But in this specific 
+case you'll have also to add some special parameter in the main section of you main 
+configuration file and to copy an xsl file used to replace on the fly in the ResponseDocument 
+the percentCompleted attribute of the ProcessStarted node returned by the GetStatus service.
+
+So first edit you ``main.cfg`` file to add the following lines in your main section : 
+
+.. code-block:: guess
+
+    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 we 
+defined in the previous section.
+
+To finish your deployment, you'll have now to copy the xsl file in the defined dataPath 
+directory. You can use the following command : 
+
+.. code-block:: guess
+
+    cp ~/zoows/sources/zoo-services/utils/status/cgi-env/*xsl /var/www/data
+
+Now, if you run the following request to run the service longProcess : 
+
+http://localhost/zoo/?request=Execute&service=WPS&version=1.0.0&Identifier=longProcess&DataInputs=&storeExecuteResponse=true
+
+You shall get the a XML document looking like the following:
+
+.. image:: ./images/Practical-introduction-to-ZOO-9.png
+   :width: 590px
+   :height: 155px
+   :align: center
+
+If you poll the statusLocation url provider in the answer you'll then be able to view 
+the evolution of the percentCompleted attribute value growing, like you can see in the following screenshot. 
+
+.. image:: ./images/Practical-introduction-to-ZOO-10.png
+   :width: 589px
+   :height: 146px
+   :align: center
+
+This won't be used during this workshop but can be useful for really time consuming services. 
+
+
+Creating Services for other functions (ConvexHull and Centroid)
+***************************************************************
+
+As the Boundary sample service code is available, you can now easily add ConvexHull and 
+Centroid functions as they take exactly the same number of arguments : Only one geometry. 
+The details for implementing and deploying the ConvexHull Service are provided bellow, 
+and we will let you do the same thing for the Centroid one. 
+
+C Version
+^^^^^^^^^
+
+Please add first the following code to the service.c source code : 
+
+.. code-block:: guess
+
+    int ConvexHull(maps*& conf,maps*& inputs,maps*& outputs){
+      OGRGeometryH geometry,res;
+      map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+      if(tmp==NULL){
+        setMapInMaps(conf,"lenv","message","Unable to fetch InputPolygon value.");
+        return SERVICE_FAILED;
+      }
+      map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0)
+        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+      else
+        geometry=createGeometryFromWFS(conf,tmp->value);
+      if(geometry==NULL){
+        setMapInMaps(conf,"lenv","message","Unable to parse InputPolygon value.");
+        return SERVICE_FAILED;
+      }
+      res=OGR_G_ConvexHull(geometry);
+      tmp1=getMapFromMaps(outputs,"Result","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0){
+        char* tmp=OGR_G_ExportToJson(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        setMapInMaps(outputs,"Result","mimeType","text/plain");
+        free(tmp);
+      }
+      else{
+        char* tmp=OGR_G_ExportToGML(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        free(tmp);
+      }
+      OGR_G_DestroyGeometry(geometry);
+      OGR_G_DestroyGeometry(res);
+      return SERVICE_SUCCEEDED;
+    }
+
+
+This new code is exactly the same as for the Boundary Service. The only thing we modified 
+is the line where the  `OGR_G_ConvexHull <http://www.gdal.org/ogr/ogr__api_8h.html#7a93026cfae8ee6ce25546dba1b2df7d>`__ 
+function is called (rather than the OGR_G_GetBoundary you used before). It is better to not copy 
+and paste the whole function and find a more generic way to define your new Services as the 
+function body will be the same in every case. The following generic function is proposed to make things simpler:
+
+.. code-block:: guess
+
+    int applyOne(maps*& conf,maps*& inputs,maps*& outputs,OGRGeometryH (*myFunc) (OGRGeometryH)){
+      OGRGeometryH geometry,res;
+      map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+      if(tmp==NULL){
+        setMapInMaps(conf,"lenv","message","Unable to fetch InputPolygon value.");
+        return SERVICE_FAILED;
+      }
+      map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0)
+        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+      else
+        geometry=createGeometryFromWFS(conf,tmp->value);
+      if(geometry==NULL){
+        setMapInMaps(conf,"lenv","message","Unable to parse InputPolygon value.");
+        return SERVICE_FAILED;
+      }
+      res=(*myFunc)(geometry);
+      tmp1=getMapFromMaps(outputs,"Result","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0){
+        char *tmp=OGR_G_ExportToJson(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        setMapInMaps(outputs,"Result","mimeType","text/plain");
+        free(tmp);
+      }
+      else{
+        char *tmp=OGR_G_ExportToGML(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        free(tmp);
+      }
+      outputs->next=NULL;
+      OGR_G_DestroyGeometry(geometry);
+      OGR_G_DestroyGeometry(res);
+      return SERVICE_SUCCEEDED;
+    } 
+
+Then, a function pointer called myFunc rather than the full function name can be used. 
+This way we can re-implement our Boundary Service this way:
+
+.. code-block:: guess
+
+    int Boundary(maps*& conf,maps*& inputs,maps*& outputs){
+      return applyOne(conf,inputs,outputs,&OGR_G_GetBoundary);
+    }
+
+Using this applyOne local function defined in the service.c source code, we can define 
+other Services this way:
+
+.. code-block:: guess
+
+    int ConvexHull(maps*& conf,maps*& inputs,maps*& outputs){
+      return applyOne(conf,inputs,outputs,&OGR_G_ConvexHull);
+    }
+    int Centroid(maps*& conf,maps*& inputs,maps*& outputs){
+      return applyOne(conf,inputs,outputs,&MY_OGR_G_Centroid);
+    }
+
+The genericity of the applyOne function let you add two new Services in your ZOO Services Provider : ConvexHull and Centroid.
+
+Note that you should define MY_OGR_Centroid function before the Centroid one as  `OGR_G_Centroid <http://www.gdal.org/ogr/ogr__api_8h.html#23f5a19a81628af7f9cc59a37378cb2b>`__ don't return a geometry object but set the value to an already existing one and support only Polygon as input, so to ensure we use the ConvexHull for MultiPolygon. So please use the code bellow:
+
+.. code-block:: guess
+
+    OGRGeometryH MY_OGR_G_Centroid(OGRGeometryH hTarget){
+      OGRGeometryH res;
+      res=OGR_G_CreateGeometryFromJson("{\"type\": \"Point\", \"coordinates\": [0,0] }");
+      OGRwkbGeometryType gtype=OGR_G_GetGeometryType(hTarget);
+      if(gtype!=wkbPolygon){
+        hTarget=OGR_G_ConvexHull(hTarget);
+      }
+      OGR_G_Centroid(hTarget,res);
+      return res;
+    } 
+
+To deploy your Services, you only have to copy the ``Boundary.zcfg`` metadata file from 
+your cgi-env directory as ``ConvexHull.zcfg`` and ``Centroid.zcfg``. Then, you must 
+rename the Service name on the first line to be able to run and test the Execute request 
+in the same way you did before. You only have to set the Identifier value to ConvexHull 
+or Centroid in your request depending on the Service you want to run.
+
+Note here that the GetCapabilities and DescribeProcess requests will return odd results 
+as we didn't modified any metadata informations, you can edit the ``.zcfg`` files to set 
+correct values. By the way it can be used for testing purpose, as the input and output 
+get the same name and default/supported formats. 
+
+Python Version
+^^^^^^^^^^^^^^
+
+.. code-block:: guess
+
+    def ConvexHull(conf,inputs,outputs):
+        if inputs["InputPolygon"]["mimeType"]=="application/json":
+            geometry=osgeo.ogr.CreateGeometryFromJson(inputs["InputPolygon"]["value"])
+        else:
+            geometry=createGeometryFromWFS(inputs["InputPolygon"]["value"])
+        rgeom=geometry.ConvexHull()
+        if outputs["Result"]["mimeType"]=="application/json":
+            outputs["Result"]["value"]=rgeom.ExportToJson()
+            outputs["Result"]["mimeType"]="text/plain"
+        else:
+            outputs["Result"]["value"]=rgeom.ExportToGML()
+        geometry.Destroy()
+        rgeom.Destroy()
+        return 3
+
+
+Once again, you can easily copy and paste the function for Boundary and simply modify 
+the line where the Geometry method was called. Nevertheless, as we did for the C language 
+we will give you a simple way to get things more generic.
+
+First of all, the first step which consists in extracting the InputPolygon Geometry as 
+it will be used in the same way in each Service functions, so we will first create a 
+function which will do that for us. The same thing can also be done for filling the 
+output value, so we will define another function to do that automaticaly. Here is the 
+code of this two functions (extractInputs and outputResult) : 
+
+.. code-block:: guess
+
+    def extractInputs(obj):
+        if obj["mimeType"]=="application/json":
+            return osgeo.ogr.CreateGeometryFromJson(obj["value"])
+        else:
+            return createGeometryFromWFS(obj["value"])
+        return null
+
+    def outputResult(obj,geom):
+        if obj["mimeType"]=="application/json":
+            obj["value"]=geom.ExportToJson()
+            obj["mimeType"]="text/plain"
+        else:
+            obj["value"]=geom.ExportToGML()
+
+We can so minimize the code of the Boundary function to make it simplier using the following function definition : 
+
+.. code-block:: guess
+
+    def Boundary(conf,inputs,outputs):
+        geometry=extractInputs(inputs["InputPolygon"])
+        rgeom=geometry.GetBoundary()
+        outputResult(outputs["Result"],rgeom)
+        geometry.Destroy()
+        rgeom.Destroy()
+        return 3
+
+Then definition of the ConvexHull and Centroid Services can be achieved using the following code:
+
+.. code-block:: guess
+
+    def ConvexHull(conf,inputs,outputs):
+        geometry=extractInputs(inputs["InputPolygon"])
+        rgeom=geometry.ConvexHull()
+        outputResult(outputs["Result"],rgeom)
+        geometry.Destroy()
+        rgeom.Destroy()
+        return 3
+
+    def Centroid(conf,inputs,outputs):
+        geometry=extractInputs(inputs["InputPolygon"])
+        if geometry.GetGeometryType()!=3:
+            geometry=geometry.ConvexHull()
+        rgeom=geometry.Centroid()
+        outputResult(outputs["Result"],rgeom)
+        geometry.Destroy()
+        rgeom.Destroy()
+        return 3
+ 
+Note, that in Python you also need to use ConvexHull to deal with MultiPolygons.
+
+You must now copy the ``Boundary.zcfg`` file as we explained for the C version in ``ConvexHull.zcfg`` and ``Centroid.zcfg`` respectively and then, use make install command to re-deploy and test your Services Provider. 
+
+Create the Buffer Service
+*************************
+
+We can now work on the Buffer Service, which takes more arguments than the other ones. 
+Indeed, the code is a bit different from the one used to implement the Boundary, ConvexHull and Centroid Services.
+
+The Buffer service also takes an input geometry, but uses a BufferDistance parameter. 
+It will also allow you to define LitteralData block as the BufferDistance will be 
+simple integer value. The read access to such kind of input value is made using the 
+same function as used before. 
+
+C Version
+^^^^^^^^^
+
+If you go back to the first Boundary Service source code, you should not find the 
+following very complicated. Indeed, you simply have to add the access of the 
+BufferDistance argument and modify the line whenthe  `OGR_G_Buffer <http://www.gdal.org/ogr/ogr__api_8h.html#1ca0bd5c0fcb4b1af3c3973e467b0ec0>`__ 
+must be called (instead of OGR_G_GetBoundary). Here is the ful lcode : 
+
+.. code-block:: guess
+
+    int Buffer(maps*& conf,maps*& inputs,maps*& outputs){
+      OGRGeometryH geometry,res;
+      map* tmp1=getMapFromMaps(inputs,"InputPolygon","value");
+      if(tmp==NULL){
+        setMapInMaps(conf,"lenv","message","Unable to fetch InputPolygon value.");
+        return SERVICE_FAILED;
+      }
+      map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+      if(strncmp(tmp->value,"application/json",16)==0)
+        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+      else
+        geometry=createGeometryFromWFS(conf,tmp->value);
+      double bufferDistance=1;
+      tmp=getMapFromMaps(inputs,"BufferDistance","value");
+      if(tmp!=NULL)
+        bufferDistance=atof(tmp->value);
+      res=OGR_G_Buffer(geometry,bufferDistance,30);
+      tmp1=getMapFromMaps(outputs,"Result","mimeType");
+      if(strncmp(tmp1->value,"application/json",16)==0){
+        char *tmp=OGR_G_ExportToJson(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        setMapInMaps(outputs,"Result","mimeType","text/plain");
+        free(tmp);    
+      }
+      else{
+        char *tmp=OGR_G_ExportToGML(res);
+        setMapInMaps(outputs,"Result","value",tmp);
+        free(tmp);    
+      }
+      outputs->next=NULL;
+      OGR_G_DestroyGeometry(geometry);
+      OGR_G_DestroyGeometry(res);
+      return SERVICE_SUCCEEDED;
+    }
+
+The new code must be inserted in your service.c file and need to be recompiled and 
+replace the older version of your ZOO Service Provider in the /usr/lib/cgi-bin/ directory. 
+You must of course place the corresponding ZOO Metadata File in the same directory.
+
+As we explained before, ZOO Kernel is permissive in the sense that you can pass more 
+arguments than defined in you zcfg file, so let's try using a copy of the ``Boundary.zcfg`` 
+file renamed as ``Buffer.zcfg`` and containing the Buffer identifier. Then, please 
+test your service using an Execute request as you did before. You will obtain the 
+buffer result in a ResponseDocument.
+
+You may have noted that the above code check if a BufferDistance input was passed 
+to the service. If not, we will use 1 as the default value, which explains why 
+you do not have to use one more input to your previous queries.
+
+You can change the BufferDistance value used by your Service to compute Buffer 
+of your geometry by adding it to the DataInputs value in your request. Note that 
+using KVP syntaxe, each DataInputs are separated by a semicolon.
+
+So, the previous request:
+
+.. code-block:: guess
+
+    DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3FSERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192 
+
+Can now be rewritten this way : 
+
+.. code-block:: guess
+
+    DataInputs=InputPolygon=Reference@xlink:href=http%3A%2F%2Flocalhost%2Fcgi-bin%2Fmapserv%3FSERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dregions%26SRS%3DEPSG%3A4326%26FeatureID%3Dregions.3192;BufferDistance=2
+
+Setting BufferDistance value to 2 would give you a different result, then don't 
+pass any other parameter as we defined 1 as the default value in the source code.
+
+Here you can find the same query in XML format to use from the  http://localhost/test_services.html HTML form : 
+
+.. code-block:: guess
+
+    <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.xsda">
+     <ows:Identifier>Buffer</ows:Identifier>
+     <wps:DataInputs>
+      <wps:Input>
+       <ows:Identifier>InputPolygon</ows:Identifier>
+       <ows:Title>Playground area</ows:Title>
+       <wps:Reference xlink:href="http://localhost/cgi-bin/mapserv?map=/var/www/wfs.map&amp;SERVICE=WFS&amp;REQUEST=GetFeature&amp;VERSION=1.0.0&amp;typename=regions&amp;SRS=EPSG:4326&amp;featureid=regions.3192"/>
+      </wps:Input>
+      <wps:Input>
+       <ows:Identifier>BufferDistance</ows:Identifier>
+       <wps:Data>
+        <wps:LiteralData uom="degree">2</wps:LiteralData>
+       </wps:Data>
+      </wps:Input>
+     </wps:DataInputs>
+     <wps:ResponseForm>
+      <wps:ResponseDocument>
+       <wps:Output>
+        <ows:Identifier>Buffer</ows:Identifier>
+        <ows:Title>Area serviced by playground.</ows:Title>
+        <ows:Abstract>Area within which most users of this playground will live.</ows:Abstract>
+       </wps:Output>
+      </wps:ResponseDocument>
+     </wps:ResponseForm>
+    </wps:Execute>
+
+Python Version
+^^^^^^^^^^^^^^
+
+As we already defined the utility functions createGeometryFromWFS and outputResult, 
+the code is as simple as this:
+ 
+.. code-block:: guess
+
+    def Buffer(conf,inputs,outputs):
+        geometry=extractInputs(inputs["InputPolygon"])
+        try:
+            bdist=int(inputs["BufferDistance"]["value"])
+        except:
+            bdist=10
+        rgeom=geometry.Buffer(bdist)
+        outputResult(outputs["Result"],rgeom)
+        geometry.Destroy()
+        rgeom.Destroy()
+        return 3
+
+We simply added the use of inputs["BufferDistance"]["value"] as arguments of the 
+Geometry instance Buffer method. Once you get this code added to your ogr_ws_service_provider.py 
+file, simply copy it in the ZOO Kernel directory (or type make install from your ZOO Service 
+Provider root directory). Note that you also need the ``Buffer.zcfg`` file detailled in the next section. 
+
+The Buffer MetadataFile file
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You must add BufferDistance to the Service Metadata File to let clients know that 
+this Service supports this parameter. To do this, please copy your orginal ``Boundary.zcfg`` 
+file as ``Buffer.zcfg`` and add the following lines to the DataInputs block : 
+
+.. code-block:: none
+
+    [BufferDistance]
+     Title = Buffer Distance
+     Abstract = Distance to be used to calculate buffer.
+     minOccurs = 0
+     maxOccurs = 1
+     <LiteralData>
+      DataType = float
+      <Default>
+       uom = degree
+       value = 10
+      </Default>
+      <Supported>
+       uom = meter
+      </Supported>
+     </LiteralData>
+
+Note that as minOccurs is set to 0 which means that the input parameter is optional 
+and don't have to be passed. You must know that ZOO Kernel will pass the default 
+value to the Service function for an optional parameter with a default value set.
+
+You can get a full copy of the ``Buffer.zcfg`` file here : 
+
+http://zoo-project.org/trac/browser/trunk/zoo-services/ogr/base-vect-ops/cgi-env/Buffer.zcfg
+
+You can now ask ZOO Kernel for GetCapabilities, DescribeProcess and Execute for the Buffer Service. 
Index: tags/rel-1.3.0-rc1/docs/workshop/2010/using_zoo_from_osgeolivevm.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2010/using_zoo_from_osgeolivevm.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2010/using_zoo_from_osgeolivevm.txt	(revision 417)
@@ -0,0 +1,181 @@
+.. _using_zoo_from_osgeolivevm:
+
+Using ZOO from an OSGeoLive virtual machine
+###########################################
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+`OSGeoLive <http://live.osgeo.org/>`__ is a live DVD and virtual machine based on  `Xubuntu <http://www.xubuntu.org/>`__ that allows you to try a wide variety of open source geospatial software without installing anything. It is composed entirely of free software and include ZOO 1.0 this year, for testing purpose. 
+
+ZOO Kernel Installation
+***********************
+
+As already said in introduction, an OSGeoLive virtual machine image disk has 
+been installed on your computer, allowing you to use ZOO Kernel in a development 
+environment directly. Using a virtual machine image disk seems to be the simplest 
+way to use ZOO Kernel and to develop ZOO Services locally, as we can ensure that 
+everything requested for compiling C Services and running Python ones is available 
+and ready to use. Every ZOO related material and source code have been placed in 
+``/home/user/zoows`` directory. We will work inside it during this workshop. As 
+the binary version of ZOO Kernel is already compiled and stored in ``/home/user/zoows/sources/zoo-kernel``, 
+you only have to copy two important files inside the ``/usr/lib/cgi-bin`` 
+directory : ``zoo_loader.cgi`` and the ``main.cfg`` in order to make ZOO Kernel 
+available, using the following commands : 
+
+.. code-block:: guess
+
+    sudo cp ~/zoows/sources/zoo-kernel/zoo_loader.cgi /usr/lib/cgi-bin
+    sudo cp ~/zoows/sources/zoo-kernel/main.cfg /usr/lib/cgi-bin
+
+
+Please note that we will talk about ZOO Kernel or ``zoo_loader.cgi`` script without 
+any distinction during this workshop.
+
+The ``main.cfg`` file contains metadata informations about the identification and 
+provider but also some important settings. The file is composed of various sections, 
+namely main, identification and provider per default. Obviously, you are free to add 
+new sections to the file if you need them for a specific Service. Nevertheless, you 
+have to know that the env and lenv sections name are used in a specific way.
+
+The env section lets you define environment variables that your Service requires 
+during its runtime. For instance, if your Service requires to access to a X server 
+running on framebuffer, then you will have to set the ``DISPLAY`` environnement 
+variably, in this case you would add ``DISPLAY=:1`` line in your env section.
+
+As for the env section, there is the section lenv where specific informations about 
+status informations of a running Service will be written by the ZOO Kernel or the 
+ZOO Services. For instance, when your service failed, you can set the value for 
+message in lenv to see it displayed in the Status node of the ExecuteResponse 
+returned back to the client. If your service will take long time and can get 
+informations about processing status, you can then set a value between 0 and 100 
+to status in lenv to represent the percentage completed of the running Service task, 
+we will talk deeper about this later in this workshop.
+
+Please take a look to your local file ``main.cfg`` file. Three important parameters are commented bellow:
+
+  - serverAddress : The url to access to the ZOO Kernel
+  - tmpPath : The full path to store temporary files
+  - tmpUrl : The url path relative to serverAddress to access temporary directory. 
+
+The values of the main.cfg file used from the running virtual machine are the following : 
+
+.. code-block:: guess
+
+    serverAddress=http://localhost/zoo
+    tmpPath=/var/www/temp
+    tmpUrl=../temp/
+
+You could have noticed that the tmpUrl is a relative url from ``serverAddress``, 
+so it must be a directory. Even if ZOO Kernel can be used with the full url of 
+the ``zoo_loader.cgi`` script, for better readability and fully functional ZOO Kernel, 
+you have to modify the default Apache configuration in order to be able to use the  
+http://localhost/zoo/ url directly. 
+
+First, please create a ``zoo`` directory in the existing ``/var/www`` which is 
+used by Apache as the ``DocumentRoot``. Then, please edit the ``/etc/apache2/sites-available/default`` 
+configuration file and add the following lines after the ``Directory`` block related to ``/var/www`` directory : 
+
+.. code-block:: none
+
+    <Directory /var/www/zoo/>
+        Options Indexes FollowSymLinks MultiViews
+        AllowOverride All
+        Order allow,deny
+        allow from all
+    </Directory>
+
+Now create a small ``.htaccess`` file in the ``/var/www/zoo`` containing the following lines: 
+
+.. code-block:: guess
+
+    RewriteEngine on
+    RewriteRule call/(.*)/(.*) /cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=$1&DataInputs=sid=$2&RawDataOutput=Result [L,QSA]
+    RewriteRule (.*)/(.*) /cgi-bin/zoo_loader.cgi?metapath=$1 [L,QSA]
+    RewriteRule (.*) /cgi-bin/zoo_loader.cgi [L,QSA]
+
+For this last file to be taken into account by Apache, you must activate the 
+rewrite Apache module by copying a load file as bellow : 
+
+.. code-block:: guess
+
+    sudo cp /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/
+
+Or using the ``a2enmod`` tool this way : 
+
+.. code-block:: guess
+
+    a2enmod rewrite
+
+Now you should be able to access the ZOO Kernel using a simplified by restarting your Apache Web server : 
+
+.. code-block:: guess
+
+    sudo /etc/init.d/apache2 restart
+
+
+Two other softwares form the OSGeoLive environment will be used during this workshop. 
+MapServer will first be used to provide WFS input data for the ZOO Services we are 
+going to develop. The MapServer dataset providen by Orkney (japanese regions polygons) 
+will be passed to our service during `section 4 <http://zoo-project.org/trac/wiki/ZooWorkshop/FOSS4GJapan/CreatingOGRBasedWebServices#CallingthesinglegeometryservicesfromJavaScript>`__.
+
+OpenLayers library is also available on the OSGeoLive virtual machine image disk, 
+and it will be used during `section 4 <http://zoo-project.org/trac/wiki/ZooWorkshop/FOSS4GJapan/CreatingOGRBasedWebServices#CallingthesinglegeometryservicesfromJavaScript>`__, for building a simple WPS client application able to query the newly developed ZOO Services.
+
+As we planned to use OGR C-API and Python module of the GDAL library, we will need 
+the corresponding header files, libraries and associated files. Hopefully everything 
+was already available per default and so ready to use on the OSGeoLive packaging. 
+
+Testing the ZOO installation with GetCapabilities
+*************************************************
+
+
+You can now simply query ZOO Kernel using the following request from your Internet browser: 
+
+http://localhost/cgi-bin/zoo_loader.cgi?Request=GetCapabilities&Service=WPS
+
+You should then get a valid Capabilities XML document, as the following : 
+
+.. image:: ./images/Practical-introduction-to-ZOO-2.png
+   :width: 458px
+   :height: 159px
+   :align: center
+
+Please note that no Process node is returned in the ProcessOfferings section, as no 
+ZOO Service is available yet. You can also proceed to a GetCapabilities request from 
+the command line, using the following command: 
+
+.. code-block:: none
+
+    cd /usr/lib/cgi-bin
+    ./zoo_loader.cgi “request=GetCapabilities&service=WPS”
+
+The same result as in your browser will be returned, as shown in the following screenshot: 
+
+.. image:: ./images/Practical-introduction-to-ZOO-3.png
+   :width: 395px
+   :height: 251px
+   :align: center
+
+Invoking ZOO Kernel from command line can be helpful during development process of new Services. 
+
+Preparing your ZOO Services Provider directory
+**********************************************
+
+In order to simplify the task, we will first comment the directory structure which 
+should be used when creating a new Services Provider : 
+
+  - The main Services Provider directory including : 
+
+    - A ``cgi-env`` directory which will contain all the zcfg metadata files and the service shared object (C Shared Library or Python module) 
+    - The ``Makefile`` and the ``*c`` files needed to compile your Services Provider. 
+
+Please create a ws_sp main Services Provider directory in the existing zoo-services one located in ``/home/user/zoows/sources/``, respecting the tree above . 
+
+.. code-block:: guess
+
+    mkdir -p /home/user/zoows/sources/zoo-services/ws_sp/cgi-env
+
+The Makefile and the code of the C and Python Service Shared Object will be detailed in the next sections. 
+
Index: tags/rel-1.3.0-rc1/docs/workshop/2012/building_blocks_presentation.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2012/building_blocks_presentation.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2012/building_blocks_presentation.txt	(revision 417)
@@ -0,0 +1,88 @@
+.. _ogr_base_vect_ops:
+
+*********************************************************
+Presenting building blocks - Using OGR based Web Services 
+*********************************************************
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+Introduction
+============
+
+In this section, you will use basic ZOO-Services : ``BufferPy``, 
+``IntersectionPy`` and ``DifferencePy`` which use OGR Python module.
+The intended goal of this section is to present and interact with your new building blocks before chaining them in the next section.
+
+First of all, you should use the following link to access a user interface to interact with your service :
+`http://localhost/zoows-demo/spatialtools-py.html <http://localhost/zoows-demo/spatialtools-py.html>`__
+
+Services Provider and configuration files
+=========================================
+
+First you may verify if the ZOO-Services are available from your current setup.
+You can take a look at the ``Buffer.zcfg``, ``Intersection.zcfg`` and 
+``DifferencePy.zcfg`` to get details about parameters.
+As you can see from the ZCFG files, you will use ZOO-Services provided by the 
+``foss4g_ws`` Python service provider. So if you want to modify the Python code
+you will have to edit this file. 
+You are invited to use similar requests as you seen in previous sections to learn about each service.
+
+The Buffer Service
+=========================
+
+First click on a street then once the street is displayed in blue, click the 
+'Buffer' button on top, you should get similar result as displayed in the following.
+
+.. image:: ./images/Buffer_Level_15.png
+   :width: 650px
+   :align: center
+
+Since version ZOO-Project 1.2.0, you can run automatically some basic tests to 
+make sure that you wrote a correct ZCFG file and your service is validating.
+
+.. note:: the current testing is really simple and should be adapted to each Services 
+    Provider, mainly to define input names.
+
+You can use the following command:
+
+.. code-block:: bash
+    
+    cd /home/user/zoo/testing
+    ./run.sh http://localhost/cgi-bin/zoo_loader.cgi Buffer
+
+
+.. note:: During or after the test run, you can take a look inside the ``tmp`` directory 
+    which contains both the XML requests send to the ZOO Kernel (``*1.xml``) and the 
+    responses it gave (``output*.xml``).
+
+The Intersection Service
+=========================
+
+Using the same client interface as before, once you get a Buffer, you can then 
+select a street intersecting the Buffer geometry to compute intersection by clicking on the Intersection button.
+
+    
+.. image:: ./images/Intersection_Level_15.png
+   :width: 650px
+   :align: center
+
+
+The Difference Service
+=========================
+
+Using the same instructions as for Intersetion, you can get the following result.
+
+.. image:: ./images/Difference_Level_15.png
+   :width: 650px
+   :align: center
+
+
+Conclusion
+========
+
+Now you know this three services, and you get a simple interface to interact 
+with your MapServer WFS and your ZOO-Project WPS Servers, you are ready to use 
+the Services in a different way by chaining them using the ZOO-API to build 
+more complexe and powerfull services.
Index: tags/rel-1.3.0-rc1/docs/workshop/2012/first_service.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2012/first_service.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2012/first_service.txt	(revision 417)
@@ -0,0 +1,353 @@
+.. _first_service:
+
+*******************************
+Creating your first ZOO Service
+*******************************
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+Introduction
+============
+
+In this part, you will create and publish from a simple ZOO Service named 
+``Hello`` which will simply return a hello message containing the input value 
+provided. It will be usefull to present in deeper details general concept on how ZOO-Kernel works and handles request.
+
+Service and publication process overview
+========================================
+
+Before starting developing a ZOO Service, you should remember that in 
+ZOO-Project, a Service is a couple made of:
+
+ * a metadata file: a ZOO Service Configuration File (ZCFG) containing metadata 
+   informations about a Service (providing informations about default / supported 
+   inputs and outputs for a Service)
+ * a Services Provider: it depends on the programming language used, but for Python it
+   is a module and for JavaScript a script file.
+
+To publish your Service, which means make your ZOO Kernel aware of its presence,
+you should copy a ZCFG file in the directory where ``zoo_loader.cgi`` is located (in this workshop, ``/usr/lib/cgi-bin``). 
+
+.. warning:: only the ZCFG file is required  for the Service to be considerate as 
+    available. So if you don't get the Service Provider, obviously your Execute 
+    request will fail as we will discuss later.
+
+Before publication, you should store your ongoing work, so you'll start by 
+creating a directory to store the files of your Services Provider:
+
+.. code-block:: none
+    
+    mkdir -p /home/user/zoo-ws-2012/src/zoo-project/zoo-services/ws_sp/cgi-env
+
+Once both the ZCFG and the Python module are both ready, you can publish simply
+by copying the corresponding files in the same directory as the ZOO-Kernel.
+
+Creating your first ZCFG file
+=============================
+
+You will start by creating the ZCFG file for the ``Hello`` Service. Edit the 
+``/home/user/zoo-ws-2012/src/zoo-project/zoo-services/ws_sp/Hello.zcfg`` file 
+and add the following content:
+
+.. code-block:: none
+    :linenos:
+    
+    [Hello]
+     Title = Return a hello message.
+     Abstract = Create a welcome string.
+     processVersion = 2
+     storeSupported = true
+     statusSupported = true
+     serviceProvider = test_service
+     serviceType = Python
+     <DataInputs>
+      [name]
+       Title = Input string
+       Abstract = The string to insert in the hello message.
+       minOccurs = 1
+       maxOccurs = 1
+       <LiteralData>
+           dataType = string
+           <Default />
+       </LiteralData>
+     </DataInputs>
+     <DataOutputs>
+      [Result]
+       Title = The resulting string
+       Abstract = The hello message containing the input string
+       <ComplexData>
+       <LiteralData>
+           dataType = string
+           <Default />
+       </LiteralData>
+       </ComplexData>
+     </DataOutputs>
+
+.. note:: the name of the ZCFG file and the name between braket (here ``[Hello]``) 
+    should be the same and correspond to the function name you will define in your 
+    Services provider.
+
+As you can see in the ZOO Service Configuration File presented above it is divided into
+three distinct sections:
+  #. Main Metadata information (from line 2 to 8)
+  #. List of Inputs metadata information (from 9 line to 20)
+  #. List of Outputs metadata information (from line 21 to 36)
+
+You can get more informations about ZCFG from `the reference documentation 
+<http://zoo-project.org/docs/services/zcfg-reference.html>`__.
+
+If you copy the ``Hello.zcfg`` file in the same directory as your ZOO Kernel 
+then you will be able to request for DescribeProcess using the ``Hello`` 
+``Identifier``. The ``Hello`` service should also be listed from Capabilities 
+document.
+
+.. code-block:: none
+   cp /home/user/zoo-ws-2012/src/zoo-project/zoo-services/ws_sp/cgi-env/Hello.zcfg /usr/lib/cgi-bin
+
+Test requests
+=================
+
+In this section you will tests each WPS requests : GetCapabilities, 
+DescribeProcess and Execute. Note that only GetCapabilities and DescribeProcess
+should work at this step.
+
+Test the GetCapabilities request
+--------------------------------
+
+If you run the ``GetCapabilities`` request:
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS
+
+Now, you should find your Hello Service in a ``Process`` node in 
+``ProcessOfferings``:
+
+.. code-block:: xml
+    
+    <wps:Process wps:processVersion="2">
+     <ows:Identifier>Hello</ows:Identifier>
+     <ows:Title>Return a hello message.</ows:Title>
+     <ows:Abstract>Create a welcome string.</ows:Abstract>
+    </wps:Process>
+
+Test the DescribeProcess request
+--------------------------------
+
+You can access the ``ProcessDescription`` of the ``Hello`` service using the 
+following ``DescribeProcess`` request:
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=DescribeProcess&service=WPS&version=1.0.0&Identifier=Hello
+
+You should get the following response:
+
+.. code-block:: xml
+    
+    <wps:ProcessDescriptions 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 http://schemas.opengis.net/wps/1.0.0/wpsDescribeProcess_response.xsd" service="WPS" version="1.0.0" xml:lang="en-US">
+      <ProcessDescription wps:processVersion="2" storeSupported="true" statusSupported="true">
+        <ows:Identifier>Hello</ows:Identifier>
+        <ows:Title>Return a hello message.</ows:Title>
+        <ows:Abstract>Create a welcome string.</ows:Abstract>
+        <DataInputs>
+          <Input minOccurs="1" maxOccurs="1">
+            <ows:Identifier>name</ows:Identifier>
+            <ows:Title>Input string</ows:Title>
+            <ows:Abstract>The string to insert in the hello message.</ows:Abstract>
+            <LiteralData>
+              <ows:DataType ows:reference="http://www.w3.org/TR/xmlschema-2/#string">string</ows:DataType>
+              <ows:AnyValue/>
+            </LiteralData>
+          </Input>
+        </DataInputs>
+        <ProcessOutputs>
+          <Output>
+            <ows:Identifier>Result</ows:Identifier>
+            <ows:Title>The resulting string</ows:Title>
+            <ows:Abstract>The hello message containing the input string</ows:Abstract>
+            <LiteralOutput>
+              <ows:DataType ows:reference="http://www.w3.org/TR/xmlschema-2/#string">string</ows:DataType>
+            </LiteralOutput>
+          </Output>
+        </ProcessOutputs>
+      </ProcessDescription>
+    </wps:ProcessDescriptions>
+
+Test the Execute request
+------------------------
+
+Obviously, you cannot run your Service because the Python file was not published
+yet. If you try the following ``Execute`` request:
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto
+
+You should get an ExceptionReport similar to the one provided in the following, 
+which is normal behavior:
+
+.. code-block:: xml
+
+    <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="NoApplicableCode">
+        <ows:ExceptionText>Python module test_service cannot be loaded.</ows:ExceptionText>
+      </ows:Exception>
+    </ows:ExceptionReport>
+
+Implementing the Python Service
+================================
+
+General Principles
+------------------
+
+The most important thing you must know when implementing a new ZOO-Services 
+using the Python language is that the function corresponding to your Service 
+returns an integer value representing the status of execution 
+(``SERVICE_FAILED`` [#f1]_ or ``SERVICE_SUCCEEDED`` [#f2]_) and takes three 
+arguments (`Python dictionaries
+<http://docs.python.org/tutorial/datastructures.html#dictionaries>`__): 
+
+  -  ``conf`` : the main environment configuration (corresponding to the main.cfg content) 
+  - ``inputs`` : the requested / default inputs (used to access input values)
+  - ``outputs`` : the requested / default outputs (used to store computation result)
+
+.. note:: when your service return ``SERVICE_FAILED`` you can set 
+    ``conf["lenv"]["message"]`` to add a personalized message in the ExceptionReport 
+    returned by the ZOO Kernel in such case.
+
+You get in the following a sample ``conf`` value based on the ``main.cfg`` file you 
+saw `before <using_zoo_from_osgeolivevm.html#zoo-kernel-configuration>`__.
+
+.. code-block:: javascript
+    :linenos:    
+
+    {
+      "main": {
+        language: "en-US",
+        lang: "fr-FR,ja-JP",
+        version: "1.0.0",
+        encoding: "utf-8",
+        serverAddress: "http://localhost/cgi-bin/zoo_loader.cgi",
+        dataPath: "/var/www/zoows-demo/map/data",
+        tmpPath: "/var/www/temp",
+        tmpUrl: "../temp",
+        cacheDir: "/var/www/temp/"
+      },
+      "identification": {
+        title: "The ZOO-Project OSGeoLiveDVD Server 2012",
+        keywords: "WPS,GIS,buffer",
+        abstract: "Demo version of Zoo-Project for OSGeoLiveDVD 2012. See http://www.zoo-project.org",
+        accessConstraints: "none",
+        fees: "None"
+      },
+      "provider": {
+        positionName: "Developer",
+    	providerName: "ZOO-Project",
+    	addressAdministrativeArea: "Lattes",
+    	addressCountry: "fr",
+    	phoneVoice: "False",
+    	addressPostalCode: "34970",
+    	role: "Dev",
+    	providerSite: "http://www.zoo-project.org",
+    	phoneFacsimile: "False",
+    	addressElectronicMailAddress: "gerald.fenoy@geolabs.fr",
+    	addressCity: "Denver",
+    	individualName: "Gérald FENOY"
+      }
+
+In the following you get a sample outputs value passed to a Python or a JavaScript Service:
+
+.. code-block:: javascript
+    :linenos:    
+
+    {
+      'Result': {
+        'mimeType': 'application/json', 
+	'inRequest': 'true', 
+	'encoding': 'UTF-8'
+      }
+    }
+
+.. note:: the ``inRequest`` value is set internally by the ZOO-Kernel and can be    used to determine from the Service if the key was provided in the request.
+
+The Hello Service
+------------------------
+
+You can copy and paste the following into the 
+``/home/user/zoo-ws-2012/src/zoo-project/zoo-services/ws_sp/cgi-env/test_service.py`` file.
+
+.. code-block:: python
+    
+    def Hello(conf,inputs,outputs):
+        outputs["Result"]["value"]=\
+		"Hello "+inputs["name"]["value"]+" from the ZOO-Project Python world !"
+        return 3
+
+Once you finish editing the file, you should copy it in the ``/usr/lib/cgi-bin`` directory: 
+
+.. code-block:: none
+    
+    sudo cp /home/user/zoo-ws-2012/src/zoo-project/zoo-services/ws_sp/cgi-env/* /usr/lib/cgi-bin
+
+
+Interracting with your service using Execute requests
+=====================================================
+
+Now, you can request for Execute using the following basic url:
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto
+
+You can request the WPS Server to return a XML WPS Response containing the result of 
+your computation, requesting for ResponseDocument or you can access the data directly
+requesting for RawDataOutput. 
+
+* Sample request using the RawDataOutput parameter:
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&RawDataOutput=Result
+
+* Sample request using the default ResponseDocument parameter:
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&ResponseDocument=Result
+
+When you are using ResponseDocument there is specific attribut you can use to ask 
+the ZOO Kernel to store the result: ``asReference``. You can use the following example:
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&ResponseDocument=Result@asReference=true
+
+When computation take long time, the client should request setting both
+``storeExecuteResponse`` and ``status`` parameter to true. This will make the ZOO 
+Kernel directly return a response containing a ``statusLocation`` attribut which can be
+used to access the status of an ongoing service or the result when the process ended.
+
+.. code-block:: none
+    
+    http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&ResponseDocument=Result&storeExecuteResponse=true&status=true
+
+Conclusion
+==========
+
+Even if this first service was really simple it was useful to illustrate how the 
+ZOO-Kernel fill ``conf``, ``inputs`` and ``outputs`` parameter prior to load 
+and run your function service, how to write a ZCFG file, how to publish a Services 
+Provider by placing the ZCFG and Python files in the same directory as the 
+ZOO-Kernel, then how to interract with your service using both 
+``GetCapabilities``, ``DescribeProcess`` and ``Execute`` requesr. We will see 
+in the `next section <ogr_base_vect_ops.html>`__ how to write similar requests 
+using the XML syntax.
+
+.. rubric:: Footnotes
+
+.. [#f1] ``SERVICE_FAILED=4``
+.. [#f2] ``SERVICE_SUCCEEDED=3``
+
Index: tags/rel-1.3.0-rc1/docs/workshop/2012/index.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2012/index.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2012/index.txt	(revision 417)
@@ -0,0 +1,68 @@
+.. _workshop-foss4g-cee-2012:
+
+##########################################
+Practical Introduction to ZOO-Project by playing with building blocks
+##########################################
+
+:Author:  Gérald Fenoy, Nicolas Bozon
+:Contact: gerald.fenoy at geolabs.fr, nicolas.bozon at gmail.com
+:Last Updated: $Date$
+
+****************************************
+FOSS4G 2012 Prague
+****************************************
+
+.. image:: ./images/foss4gcee2012.png
+
+**************
+Sponsored By
+**************
+
+.. image:: ../../_static/images/geolabs-logo.png
+   :target: http://www.geolabs.fr/
+
+.. image:: ../../_static/images/apptech-logo.png
+   :target: http://www.apptec.co.jp/
+
+.. image:: ../../_static/images/neogeo-logo.png
+   :target: http://www-neogeo-online.net/
+
+.. image:: ../../_static/images/3liz-logo.png
+   :target: http://www.3liz.com/
+
+.. image:: ../../_static/images/gateway-logo.png
+   :target: http://www.gatewaygeomatics.com/
+
+*******************************************
+Special thanks to our Knowledge Partners
+*******************************************
+
+.. image:: ../../_static/images/ocu-logo.png
+   :target: http://www.osaka-cu.ac.jp/english/
+
+.. image:: ../../_static/images/logo-fem.png
+    :target: http://www.fondazioneedmundmach.it/
+
+.. image:: ../../_static/images/polimi-logo.png
+    :target: http://geomatica.como.polimi.it/
+
+.. image:: ../../_static/images/gucas-logo.png
+    :target: http://www.gucas.ac.cn/gscasenglish/index.aspx
+
+.. image:: ../../_static/images/cumtb-logo.png
+    :target: http://www.cumtb.edu.cn/
+
+.. image:: ../../_static/images/logo-supsi.png
+    :target: http://www.supsi.ch/home.html
+
+****************************
+WorkShop table of content
+****************************
+.. toctree::
+   :maxdepth: 5
+   
+   introduction
+   using_zoo_from_osgeolivevm
+   first_service
+   building_blocks_presentation
+   js_services_chaining
Index: tags/rel-1.3.0-rc1/docs/workshop/2012/introduction.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2012/introduction.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2012/introduction.txt	(revision 417)
@@ -0,0 +1,60 @@
+.. _introduction:
+
+**************
+Introduction
+**************
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+What is ZOO ?
+=============
+
+ZOO-Project is a WPS (Web Processing Service) open source project released under a `MIT/X-11 <http://zoo-project.org/trac/wiki/Licence>`__ style license. It provides an OGC WPS compliant developer-friendly framework to create and chain WPS Web services. ZOO is made of three parts:
+
+* `ZOO Kernel <http://zoo-project.org/docs/kernel/index.html#kernel>`__ : A powerful server-side C Kernel which makes it possible to manage and chain Web services coded in different programming languages.
+* `ZOO Services <http://zoo-project.org/docs/services/index.html#services>`__ : A growing suite of example Web Services based on various open source libraries.
+* `ZOO API <http://zoo-project.org/docs/api/index.html#api>`__ : A server-side JavaScript API able to call and chain the ZOO Services, which makes the development and chaining processes easier and faster.
+
+ZOO was designed to make the service creation and deployment easy, by providing a powerful system able to understand and execute WPS compliant queries. It supports seven programming languages, thus allowing you to create Web Services using the one you prefer. It also lets you use an existing code and to turn it as a WPS Service.
+The current supported programming languages are the following:
+
+* C/C++
+* Python
+* Perl
+* Java
+* Fortran
+* PHP
+* JavaScript
+
+More information on the project is available on the  `ZOO Project official website <http://www.zoo-project.org/>`__ .
+
+How does ZOO works ?
+====================
+
+ZOO is based on a C Kernel which is the ZOO-Project core system (aka ZOO-Kernel). The latter is able to dynamically load libraries and to handle them as on-demand Web services. 
+
+A ZOO-Service is a link composed of a ZOO metadata file (.zcfg) and the code for the corresponding implementation. The metadata file describes all the available functions that can be called using a WPS Execute Request, as well as the desired input/output. Services contain the algorithms and functions, and can be implemented using any of the supported languages.
+
+ZOO-Kernel works as CGI through Apache and can communicate with cartographic engines and Web mapping clients. It simply adds the WPS support to your spatial data infrastructure and your webmapping applications. It can use every GDAL/OGR supported formats as input data and create suitable vector or raster output for your cartographic engine and/or your web-mapping client application. 
+
+What are we going to do in this workshop?
+===============================
+
+Participants will then learn how to use ZOO Kernel and how to create ZOO Services using the OSGeo Live 5.5 A pre-compiled ZOO 1.3-dev package is provided inside OSGeoLive, so participants won't have to compile and install it manually. Configuration file and basic ways to run ZOO Kernel and ZOO Service will be presented. Participants will be then invited to start programming their own service using Python language. Some ZOO Services will be presented and individually tested inside a ready-to-use OpenLayers application. Finally, this services will be chained using the server-side Javascript ZOO API.
+
+The whole workshop is organized step-by-step and numerous code snippets are available along with their respective explanations. The instructors will check the ZOO Kernel functioning on each machine and will assist you while coding. Technical questions are of course welcome during the workshop.
+
+Usefull tips for reading
+========================
+
+.. code-block:: guess
+
+    this is a code block
+
+.. warning:: This is a warning message.
+
+.. note:: This is an important note.
+
+**Let's go !**
Index: tags/rel-1.3.0-rc1/docs/workshop/2012/js_services_chaining.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2012/js_services_chaining.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2012/js_services_chaining.txt	(revision 417)
@@ -0,0 +1,536 @@
+.. _ogr_base_vect_ops:
+
+***************************************************************
+Playing with buildign blocks - Creating JavaScript Web Services
+***************************************************************
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+Introduction
+============
+
+
+This section illustrate how you can use JavaScript on the server-side to chain 
+services together to build new ones. You will create a ZOO Services Provider 
+using the services you seen before and the WFS server using the ZOO-API. The 
+final goal is to query all POIs included in a buffer around a feature and
+to highlight them using a mask around this buffer. The following screenshot show
+you the expected result:
+
+.. image:: ./images/BufferMaskAndRequest_Level_15.png
+   :width: 650px
+   :align: center
+
+You can decompose the result above in two different ones: the mask around the 
+buffer and the points included in the buffer. So you will create two different 
+Services: one called ``BufferMask`` and another one called ``BufferRequest``.
+
+But before implementing any JavaScript Service, you will get an overview of how
+to use ZOO-API from your ZOO-Project installation in the next section.
+
+As before, you first create a new directory to store files for your new Services 
+Provider named ``ws2012js``:
+
+.. code-block:: guess
+    
+    mkdir -p ~/zoo-ws-2012/zoo-project/zoo-services/ws2012js/cgi-env/
+
+
+ZOO-API Overview
+================
+
+ZOO-API and ZOO-Kernel JavaScript support make you able to run services 
+implemented in JavaScript on the server side. JavaScript is a popular programing
+language but mostly used on the client side. Let say from a browser, but here it
+is a bit different.
+
+To support JavaScript language ZOO-Kernel use the 
+`SpiderMonkey <https://developer.mozilla.org/en/SpiderMonkey>`__ API to create a
+javascript runtime environment from which it will load your JS file then extract
+the function corresponding to the service to run it using the prefilled
+parameters. The JavaScript runtime environment created by the ZOO-Kernel 
+depend on your setup. If you placed the ``ZOO-api.js`` and ``ZOO-proj4js.js`` in
+the same directory as your ZOO-Kernel it means that your environment will 
+contains ZOO-API and Proj4js will be loaded before your service. In such case you can access to the Classes defined in the JavaScript ZOO-API 
+to manipulate geographic data, for more informations please refer to the 
+`ZOO-API Documentation <http://zoo-project.org/docs/api/index.html>`__. 
+
+Even if it can be useful to run JavaScript on the server side, you should 
+remember that some basic JavaScript functions you are familiar with does not 
+exist or get a different behavior. For instance the simple ``alert`` 
+function will display messages in apache error logs rather than in a window when
+used from a browser. The ``alert`` function can be used as follow:
+
+.. code-block:: guess
+
+    alert("My alert message");
+
+There is no XMLHttpRequest available in the JavaScript evironement your service 
+will run into. Hopefully, the ZOO-Kernel expose a C function to the JavaScript 
+world named: ``JSRequest``. This function make you able from your JavaScript 
+services to call other WPS services (locally or remotelly) or other kind OGC 
+services such as WFS. When you are using the ZOO-API it is possible to call 
+Services using a ``ZOO.Process`` instance [#f3]_, to parse WPS Responses using 
+``ZOO.Format.WPS`` 
+(cf. `ref <http://zoo-project.org/docs/api/zoo-process.html>`__).
+
+As for Python services you already seen in previous sections, the functions 
+corresponding to a Service should take three arguments: ``conf``, ``inputs`` and
+``outputs`` [#f4]_. Nevertheless, as the ZOO-Kernel is not able to access the 
+values modified [#f5]_ by the Service code, rather than returning an integer as 
+in Python, here you'll need to return both the integer value representing the 
+Status of your Service in a JavaScript Object and the resulting ``outputs`` 
+values as an Object. You can see in the following an example of a JavaScript 
+Service code:
+
+.. code-block:: none
+    
+    function SampleService(conf,inputs,outputs){
+      var resultValue=someComputation(inputs);
+      return
+        {
+            result: ZOO.SERVICE_SUCCEEDED, 
+            outputs: { "Result": { "mimeType": "application/json", "value": resultValue } }
+        };
+    }
+
+Before starting to implement the Services we will need to get our final 
+BufferRequest service, let start with a simplier one.
+
+The Mask Service
+================
+
+In this section you will learn how to create your first JavaScript service which
+will simply return a rectangular mask around a selected feature. To build this 
+mask you will use the Buffer service to create a buffer big enough around a 
+selected geometry to cover a significant part of your map. You can see the 
+expected result in the following screenshot:
+
+.. image:: ./images/Mask_Level_12.png
+   :width: 650px
+   :align: center
+
+As before, you will first start by writting the ZCFG, then you will write the 
+JavaScript source code and finish by publishing your Services Provider.
+
+The ZCFG
+--------
+
+Open the file named 
+``~/zoo-ws-2012/src/zoo-project/zoo-services/ws2012js/cgi-env/Mask.zcfg`` 
+with your favorite text editor and add the following content:
+
+.. code-block:: none
+    :linenos:
+    
+    [Mask]
+     Title = Compute mask
+     Abstract = Compute mask around a geometry
+     processVersion = 1
+     storeSupported = true
+     statusSupported = true
+     serviceProvider = foss4gws.js
+     serviceType = JS
+     <DataInputs>
+      [InputData]
+       Title = The feature
+       Abstract = The feature to run the service with
+       minOccurs = 1
+       maxOccurs = 1
+       <ComplexData>
+        <Default>
+        mimeType = text/xml
+        encoding = utf-8
+        </Default>
+       </ComplexData>
+     </DataInputs>
+     <DataOutputs>
+      [Result]
+       Title = The resulting feature
+       Abstract = The feature created by the service.
+       <ComplexOutput>
+         <Default>
+         mimeType = application/json
+         </Default>
+       </ComplexOutput>
+     </DataOutputs>  
+
+Here you simply define one default ``ComplexData`` for both ``inputData`` and
+``Result``: a GML and a GeoJSON respectively [#f6]_.
+ 
+The JavaScript service
+----------------------
+
+As you will have to request the Buffer service many times from your service, you
+will first define a ``Buffer`` function as follow. It uses the ``ZOO.Process`` 
+to request the Buffer service you seen in the previous section.
+
+Open a file named 
+``~/zoo-ws-2012/src/zoo-project/zoo-services/ws2012js/cgi-env/foss4gws.js`` and 
+add the following content:
+
+.. code-block:: javascript
+    :linenos:
+    
+    var zoo_url='http://localhost/cgi-bin/zoo_loader.cgi';
+    var mapserv_url='http://localhost/cgi-bin/mapserv?'+
+    	'map=/var/www/zoows-demo/map/w2011.map&amp;SERVICE=WFS';
+    
+    function Buffer(inputData,bDist){
+    
+      // Create all required ZOO.formats
+      var fJ=new ZOO.Format.JSON();
+      var fGJ=new ZOO.Format.GeoJSON();
+      var fWPS=new ZOO.Format.WPS();
+    
+      // Pass the value as json
+      var myInputs = {
+      	  InputPolygon: { type: 'complex', value: fGJ.write(inputData), mimeType: "application/json"}, 
+	  BufferDistance: {type: 'float', "value": bDist }
+      };  
+      var myOutputs= { Result: { type: 'ResponseDocument', "mimeType": "application/json" } };
+      var myProcess = new ZOO.Process(zoo_url,'BufferPy');
+      var myExecuteResult=myProcess.Execute(myInputs,myOutputs);
+    
+      // Parse the result and extract JSON geometry
+      var bufferResult=fWPS.read(myExecuteResult);
+      var bufferResultAsGeoJSON=fJ.read(bufferResult.value);
+      return fGJ.read(bufferResultAsGeoJSON);
+    
+    }
+
+From line 12 to 15, you give a GeoJSON string (created from ``inputData``) for 
+InputPolygon and, on line 14, you set the BufferDistance value to ``bDist``. 
+On line 16, you define Result as a ResponseDocument, so you'll have to parse the
+WPS response using the ZOO.Format.WPS, on line 21. 
+
+On line 17, you create a 
+`ZOO.Process <http://zoo-project.org/docs/api/zoo-process.html#zoo-process>`__ 
+instance providing the ZOO-Kernel url and the Service name. Then, on line 18, you
+run the request passing inputs and outputs previously defined (from line 12 to 15).
+
+Now, you get your ``Buffer`` function, it is time to create your first JavaScript 
+service. So, edit your ``foss4gws.js`` file you created before and add the following content:
+
+.. code-block:: javascript
+    :linenos:
+    
+    function Mask(conf,inputs,outputs){
+      
+      // Create all required ZOO.formats
+      var fGML=new ZOO.Format.GML();
+      var fGJ=new ZOO.Format.GeoJSON();
+    
+      // Read the input GML
+      var inputData=fGML.read(inputs["InputData"]["value"]);
+      
+      // Compute Buffer
+      var bufferResultAsJSON=Buffer(inputData,0.015);
+    
+      // Create the Buffer result BBOX and store its geometry in a ZOO.Feature
+      var bbox = new ZOO.Bounds();
+      var bounds=bufferResultAsJSON[0].geometry.getVertices();
+      for(var t in bounds){
+        bbox.extend(bounds[t]);
+      }
+      var finalG=bbox.toGeometry();
+      var result=new ZOO.Feature(finalG,{"name": "Result1000"});
+      
+      // Return the created feature
+      return {
+          result: ZOO.SERVICE_SUCCEEDED, 
+          outputs: { "Result": { mimeType: "application/json", value: fGJ.write(result) } } 
+      };
+     
+    }
+
+Publish and use your Service
+----------------------------
+
+Now you get both your ZCFG and your service code ready, you need to deploy your 
+new Services Provider using the following command:
+
+.. code-block:: bash
+    
+    cp ~/zoo-ws-2012/src/zoo-project/zoo-services/ws2012js/cgi-env/* /usr/lib/cgi-bin
+
+Now you are ready to use your JavaScript service by loading the the following `url 
+<http://localhost/zoows-demo/spatialtools.html>`__, click on a street then click on
+the "Mask" button.
+
+BufferMask Service
+==================
+
+In this section you will implement a simple JavaScript service which will be able create
+a hole in the mask you created in `previous section <#mask-service>`__. This service
+will be used to highlight the buffer zone around a selected fature. You get a preview of 
+the expected result in the following screenshot:
+
+.. image:: ./images/BufferMask_Level_15.png
+   :width: 650px
+   :align: center
+
+
+The ZCFG
+--------
+
+Open the file named 
+``~/zoo-ws-2012/src/zoo-project/zoo-services/ws2012js/cgi-env/BufferMask.zcfg`` 
+with your favorite text editor and copy / paste the following content:
+
+.. code-block:: none
+    :linenos:
+    
+    [BufferMask]
+     Title = Compute buffer mask
+     Abstract = Compute buffer mask around a geometry
+     processVersion = 1
+     storeSupported = true
+     statusSupported = true
+     serviceProvider = foss4gws.js
+     serviceType = JS
+     <DataInputs>
+      [InputData]
+       Title = The feature
+       Abstract = The feature to run the service with
+       minOccurs = 1
+       maxOccurs = 1
+       <ComplexData>
+        <Default>
+        mimeType = text/xml
+        encoding = utf-8
+        </Default>
+       </ComplexData>
+     </DataInputs>
+     <DataOutputs>
+      [Result]
+       Title = The resulting feature
+       Abstract = The feature created by the service.
+       <ComplexOutput>
+         <Default>
+         mimeType = application/json
+         </Default>
+       </ComplexOutput>
+     </DataOutputs>  
+
+This ZCFG is similar to the previous one. Please, refer to comments in the 
+`previous section <#the-zcfg>`__ for more informations.
+
+The JavaScript service
+----------------------
+
+In this Service you will use same source code (until line 19) you used in the 
+`previous section <#the-javascript-service>`__. Indeed, you should compute the Mask
+as you did before then compute Buffer for creating a hole in the mask (on line 22) to run 
+the Difference service (from line 25 to 40). 
+
+.. code-block:: guess
+    :linenos:
+    
+     function BufferMask(conf,inputs,outputs){
+       
+       // Create all required ZOO.formats
+       var fGML=new ZOO.Format.GML();
+       var fGJ=new ZOO.Format.GeoJSON();
+     
+       // Read the input GML
+       var inputData=fGML.read(inputs["InputData"]["value"]);
+       
+       // Compute Buffer
+       var bufferResultAsJSON=Buffer(inputData,0.015);
+     
+       // Create the Buffer result BBOX 
+       var bbox = new ZOO.Bounds();
+       var bounds=bufferResultAsJSON[0].geometry.getVertices();
+       for(var t in bounds){
+         bbox.extend(bounds[t]);
+       }
+       var finalG=bbox.toGeometry();
+
+      // Compute Buffer standard buffer
+      var bufferResultAsJSON=Buffer(inputData,0.0015);
+    
+      // Request Difference service using Buffer result and features in the BBOX
+      var result=new ZOO.Feature(finalG,{"name": "Result1000"});  
+      var myProcess2 = new ZOO.Process(zoo_url,'DifferencePy');
+      var myInputs2 = {
+          InputEntity1: {
+              type: 'complex', 
+              value: fGJ.write(finalG), 
+              mimeType: "application/json" 
+          }, 
+          InputEntity2: { 
+              type: 'complex', 
+              value: fGJ.write(bufferResultAsJSON), 
+              mimeType: "application/json"
+          }
+      };
+      var myOutputs2= {Result: {type: 'RawDataOutput',  mimeType: "application/json" } };
+      var myExecuteResult4=myProcess2.Execute(myInputs2,myOutputs2);
+
+       // Return the bbox
+       var result=new ZOO.Feature(finalG,{"name": "Result1000"});
+       return {
+           result: ZOO.SERVICE_SUCCEEDED, 
+           outputs: { "Result": {mimeType: "application/json", value: myExecuteResult4 } } 
+       };
+     
+     }
+
+Publish and use your Service
+----------------------------
+
+Now, you can publish your service as you did `before <#publish-your-service>`__. To 
+use your service, please use the following `url 
+<http://localhost/zoows-demo/spatialtools.html>`__.
+
+BufferRequest service
+======================
+
+In this section, you will create a new Service: ``BufferRequest`` which will request 
+POIs included in the Buffer around a selected feature [#f7]_. You will use the ``poi`` 
+layer served as WFS through your local mapserver installation. You can see in the 
+following screenshot the expected result: 
+
+.. image:: ./images/BufferRequest_Level_15.png
+   :width: 650px
+   :align: center
+
+The ZCFG
+--------
+
+Open the file named 
+``~/zoo-ws-2012/zoo-project/zoo-services/ws2011js/cgi-env/BufferRequest.zcfg`` 
+with your favorite text editor and copy / paste the following content:
+
+.. code-block:: none
+    :linenos:
+    
+    [BufferRequest]
+     Title = Compute buffer request
+     Abstract = Compute buffer request around a geometry
+     processVersion = 1
+     storeSupported = true
+     statusSupported = true
+     serviceProvider = foss4gws.js
+     serviceType = JS
+     <DataInputs>
+      [InputData]
+       Title = The feature
+       Abstract = The feature to run the service with
+       minOccurs = 1
+       maxOccurs = 1
+       <ComplexData>
+        <Default>
+        mimeType = text/xml
+        encoding = utf-8
+        </Default>
+       </ComplexData>
+     </DataInputs>
+     <DataOutputs>
+      [Result]
+       Title = The resulting feature
+       Abstract = The feature created by the service.
+       <ComplexOutput>
+         <Default>
+         mimeType = application/json
+         </Default>
+       </ComplexOutput>
+     </DataOutputs>  
+
+
+The JavaScript code
+-------------------
+
+As in the previous Service, you will compute a buffer around the input feature. But then
+you will request POIs available in the Buffer extent using a WFS request to use them to 
+run ``Intersection`` service using the initial Buffer. The WFS request is useful to limit 
+the number of points to use when requesting the ``Intersection`` Service.
+
+.. code-block:: javascript
+    :linenos:
+    
+    function BufferRequest(conf,inputs,outputs){
+    
+      // Create all required ZOO.formats
+      var fGJ=new ZOO.Format.GeoJSON();
+      var fGML=new ZOO.Format.GML();
+    
+      // Read the input GML
+      var inputData=fGML.read(inputs["InputData"]["value"]);
+    
+      // Compute Buffer
+      var bufferResultAsJSON=Buffer(inputData,0.0015);
+    
+      // Create the Buffer result BBOX 
+      var bbox = new ZOO.Bounds();
+      var bounds=bufferResultAsJSON[0].geometry.getVertices();
+      for(var t in bounds){
+        bbox.extend(bounds[t]);
+      }
+    
+      // Request Intersection service using Buffer result and WFS request using the
+      // BBOX
+      var myProcess2 = new ZOO.Process(zoo_url,'IntersectionPy');
+      var req="&amp;version=1.0.0&amp;request=GetFeature&amp;typename=poi1";
+      req+="&amp;SRS=EPSG:4326&amp;BBOX=";
+      var myInputs2 = {
+        InputEntity1: { 
+          type: 'complex',  
+          value: fGJ.write(bufferResultAsJSON), 
+          mimeType: "application/json"
+        }, 
+        InputEntity2: { 
+          type: 'complex',  
+          xlink: mapserv_url+req+bbox.left+","+bbox.bottom+","+bbox.right+","+bbox.top, 
+          mimeType: "text/xml" 
+        } 
+      };
+      var myOutputs2= {Result: { type: 'RawDataOutput', "mimeType": "application/json" } };
+      var myExecuteResult4=myProcess2.Execute(myInputs2,myOutputs2);
+    
+      return {
+        result: ZOO.SERVICE_SUCCEEDED, 
+        outputs: {name:"Result", mimeType: "application/json", value: myExecuteResult4} 
+      };
+    
+    }
+
+.. warning:: to take advantage of the ZOO-Kernel cache system, you directly use the WFS
+    request  as ``xlink:href`` rather than value for ``InputEntity2`` (from line 31 to 34) and use ``text/xml`` ``mimeType`` 
+    (on line 40). Indeed, the ZOO-API doesn't use the internal cache mechanisms.
+
+
+Publish and use your Service
+----------------------------
+
+Now, you can publish your service as you did `before <#publish-your-service>`__. To 
+use your service, please use the following `url 
+<http://localhost/zoows-demo/spatialtools.html>`__.
+
+.. note:: You can click on "Buffer Request and Mask"  to get the same result as presented 
+    in  `the initial screenshot <#introduction>`__.
+
+Conclusion
+==========
+
+After understanding how basic Geometric Operation Services works, here you built step by
+step new JavaScript services which reuse the previous ones and combine them in 
+different ways. This was achieved using the ZOO-API, composed by C functions 
+exposed by the ZOO-Kernel to the JavaScript services runtime environement and 
+the JS files which can be optionally installed. 
+
+.. rubric:: Footnotes
+
+.. [#f3] The ``ZOO.Process`` class uses ``JSRequest`` (cf. `ref 
+    <http://zoo-project.org/docs/api/zoo-format-wps.html>`__). You will get example
+    of use `later  <#the-javascript-service>`__.
+.. [#f4] So ``conf``, ``inputs`` and ``outputs`` are simple JavaScript objects, similar 
+    to the Python dictionaries used in the `previous section <ogr_base_vect_ops.html>`__.    
+.. [#f5] Such as ``conf``, ``inputs`` and ``outputs``.
+.. [#f6] Using one of the available ``ZOO.formats`` you are also able to support various
+    ``ComplexData`` for both input and output of the service. To simplify the 
+    presentation here, you will use only this default ones.
+.. [#f7] So in the hole you created in the previous section.
Index: tags/rel-1.3.0-rc1/docs/workshop/2012/using_zoo_from_osgeolivevm.txt
===================================================================
--- tags/rel-1.3.0-rc1/docs/workshop/2012/using_zoo_from_osgeolivevm.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/docs/workshop/2012/using_zoo_from_osgeolivevm.txt	(revision 417)
@@ -0,0 +1,170 @@
+.. _using_zoo_from_osgeolivevm:
+
+********************************************************************
+Configuration and ZOO-Kernel use
+********************************************************************
+
+.. contents:: Table of Contents
+    :depth: 5
+    :backlinks: top
+
+ZOO-Kernel Configuration
+========================
+
+As already said in introduction, an OSGeoLive virtual machine image disk has been installed on your computer, allowing you to use ZOO-Kernel in a development environment directly. Every ZOO-Project related material and source code have been placed in ``/home/user/zoo-ws-2012`` directory. We will work with file included in this directory during this workshop. 
+
+.. note:: we will use ZOO-Kernel or ``zoo_loader.cgi`` script without any distinction 
+    in this document.
+
+As explained later, the ZOO-Kernel may require to store temporary files in ``/var/www/temp``. Depending on 
+parameters set in the ``main.cfg``,  cache files would be located in the same directory.
+
+.. code-block:: guess
+
+    sudo mkdir /var/www/tmp
+    sudo chown www-data /var/www/tmp
+
+General ZOO-Kernel settings are made in the ``main.cfg`` file located in the same
+directory as the ZOO-Kernel, so in ``/usr/lib/cgi-bin/``. You can see a typical 
+``main.cfg`` content in the following:
+
+.. code-block:: guess
+    :linenos:
+    
+    [main]
+    lang=en-US,fr-FR,ja-JP
+    version=1.0.0
+    encoding=utf-8
+    serverAddress=http://localhost/zoo/
+    dataPath=/var/www/data
+    tmpPath=/var/www/tmp
+    tmpUrl=../tmp
+    cacheDir=/var/www/cache/
+    mapserverAddress=http://localhost/cgi-bin/mapserv
+    msOgcVersion=1.0.0
+    
+    [identification]
+    title=The ZOO-Project FOSS4G 2012 Prague Workshop
+    keywords=WPS,GIS,buffer
+    abstract=ZOO-Project platform 2012 .See http://www.zoo-project.org for more informations
+    accessConstraints=none
+    fees=None
+    
+    [provider]
+    positionName=Developer
+    providerName=ZOO-Project
+    addressAdministrativeArea=Lattes
+    addressDeliveryPoint=1280 Av. des Platanes
+    addressCountry=fr
+    phoneVoice=False
+    addressPostalCode=34970
+    role=Dev
+    providerSite=http://www.zoo-project.org
+    phoneFacsimile=False
+    addressElectronicMailAddress=gerald.fenoy@geolabs.fr
+    addressCity=Lattes
+    individualName=Gérald FENOY
+ 
+The ``main.cfg`` file contains metadata informations about the identification and provider but also some important settings. The file is composed of various sections, namely ``[main]``, ``[identification]`` and ``[provider]`` per default. 
+
+From the ``[main]`` section settings are as follow:
+ * ``lang``: the supported languages separated by a coma (the first is the default one),
+ * ``version``: the supported WPS version,
+ * ``encoding``: the default encoding of WPS Responses,
+ * ``serverAddress``: the url to access your ZOO-Kernel instance,
+ * ``dataPath``: the path to store data files (when MapServer support was activated, 
+   this directory is used to store mapfiles and data).
+ * ``tmpPath``: the path to store temporary files (such as ExecuteResponse when 
+   storeExecuteResponse was set to true),
+ * ``tmpUrl``: a url relative to ``serverAddress`` to access the temporary file,
+ * ``cacheDir``: the path to store cached request files [#f1]_ (optional),
+ * ``mapservAddress``: your local MapServer address (optional),
+ * ``msOgcVersion``: the version for all supported OGC Web Services output [#f2]_
+   (optional).
+
+The ``[identification]`` and ``[provider]`` section are specific to OGC metadata and
+should be set [#f3]_.
+
+Obviously, you are free to add new sections to this file if you need more. Nevertheless, you have to know 
+that there is some specific names you should use only for specific needs: ``[env]``, ``[lenv]`` and
+``[senv]``.
+
+.. warning:: ``[senv]`` and ``[lenv]`` are used / produced on runtime internaly by the ZOO-Kernel and should be defined only from the Service code.
+
+The ``env`` section is used to store specific environment variables you want to be set 
+prior to load your Services Provider and run your Service. A typical example, is when your
+Service requires to access to a X server running on framebuffer, then you will have to 
+set the ``DISPLAY`` environnement variable, in this case you would add 
+``DISPLAY=:1`` line in your ``[env]`` section.
+
+The ``lenv`` is used to store runtime informations automatically set by the 
+ZOO-Kernel before running your service and can be accesses / updated from it:
+ * ``sid``: the service unique identifier, 
+ * ``status``: the current progress value (value between 0 and 100, percent),
+ * ``cwd``: the current working directory of the ZOO-Kernel,
+ * ``message``: an error message when returning ``SERVICE_FAILED`` (optional),
+ * ``cookie``: the cookie your service want to return to the client (for authentication
+   purpose or tracking).
+
+The ``senv`` is used to store session informations on the server side. You can then access them automatically from service if the server is requested using a valid cookie. The ZOO-Kernel will store on disk the values set in the ``senv`` maps, then load an dynamically added to the env stored in ``main.cfg``:
+ * ``XXX``: the session unique identifier where ``XXX`` is the name included in the 
+    returned cookie.
+
+.. _cookie_example:
+
+For instance, if you get the following in your Service source code [#f4]_ :
+
+.. code-block:: python
+    
+    conf["lenv"]["cookie"]="XXX=XXX1000000; path=/" 
+    conf["senv"]={"XXX": "XXX1000000","login": "demoUser"}
+
+That means that the ZOO-Kernel will create a file ``sess_XXX1000000.cfg`` in the 
+``cacheDir`` and return the specified cookie to the client. Each time the client will 
+request the ZOO-Kernel using the Cookie, it will automatically load the value stored 
+before running your service. You can then easilly access this informations from your 
+service source code. This functionality won't be used in the following presentation.
+
+Testing the ZOO installation with GetCapabilities
+=================================================
+
+
+You can request ZOO-Kernel using the following link from your Internet browser: 
+
+http://localhost/cgi-bin/zoo_loader.cgi?Request=GetCapabilities&Service=WPS
+
+You should get a valid Capabilities XML document, looking like the following :
+
+.. image:: ./images/GC.png
+   :width: 650px
+   :align: center
+
+Please note that some Process node are returned in the ProcessOfferings section, as somes are available already on OSGeoLive DVD. You can also run a GetCapabilities request from the command line, using the following command: 
+
+.. code-block:: bash
+
+    cd /usr/lib/cgi-bin
+    ./zoo_loader.cgi “request=GetCapabilities&service=WPS”
+
+The same result as in your browser will be returned, as shown in the following screenshot: 
+
+.. image:: ./images/GC_CL.png
+   :width: 450px
+   :align: center
+
+Invoking ZOO Kernel from command line can be helpful during development process of new Services. 
+
+.. rubric:: Footnotes
+
+.. [#f1] when you use GET requests passed through ``xlink:href`` the ZOO-Kernel will
+    execute the request only once, the first time you will ask for this ressource and it will
+    store on disk the result. The next time you will need the same feature, the cached file
+    will be used which make your process running faster. If ``cachedir`` was not 
+    specified in the ``main.cfg`` then ``tmpPath`` value will be used.
+.. [#f2] since version 1.3dev, when MapServer is activated, your service can automatically 
+    return a WMS, WFS or WCS request to expose your data. Your can set here the specific
+    version number you want to use to request your local MapServer setup. It depends 
+    mostly on the client capability to deal with specific OGC Web Services version.
+.. [#f3] since version 1.3dev, when MapServer is activated, the same metadata will be used
+    for setting metadata for OGC Web Services.
+.. [#f4] If you're not familiar with ZOO-Project, you can `pass <using_zoo_from_osgeolivevm#testing-the-zoo-installation-with-getcapabilities>`__  this part and come to it after the next section.
Index: tags/rel-1.3.0-rc1/testing/README
===================================================================
--- tags/rel-1.3.0-rc1/testing/README	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/README	(revision 417)
@@ -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.3.0-rc1/testing/extractStatusLocation.xsl
===================================================================
--- tags/rel-1.3.0-rc1/testing/extractStatusLocation.xsl	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/extractStatusLocation.xsl	(revision 417)
@@ -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.3.0-rc1/testing/requests/dp.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/dp.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/dp.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/igml_o.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/igml_o.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/igml_o.xml	(revision 417)
@@ -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="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.3.0-rc1/testing/requests/ijson_o.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/ijson_o.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/ijson_o.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/ir_o.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/ir_o.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/ir_o.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/ir_o_async.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/ir_o_async.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/ir_o_async.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/ir_or.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/ir_or.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/ir_or.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/ir_or_async.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/ir_or_async.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/ir_or_async.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/irb_o.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/irb_o.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/irb_o.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/irb_o_async.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/irb_o_async.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/irb_o_async.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/irb_or.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/irb_or.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/irb_or.xml	(revision 417)
@@ -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.3.0-rc1/testing/requests/irb_or_async.xml
===================================================================
--- tags/rel-1.3.0-rc1/testing/requests/irb_or_async.xml	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/requests/irb_or_async.xml	(revision 417)
@@ -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.3.0-rc1/testing/run.sh
===================================================================
--- tags/rel-1.3.0-rc1/testing/run.sh	(revision 417)
+++ tags/rel-1.3.0-rc1/testing/run.sh	(revision 417)
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+Usage=$(cat <<EOF
+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
+
+EOF
+)
+
+if [ -z "$1" ] || [ -z "$2" ]; then
+    echo "$Usage"
+    exit
+fi
+
+WPSInstance=$1
+ServiceName=$2
+
+function kvpRequest {
+    echo "Simple KVP request "
+    echo "$1"
+    curl -o "$2" "$1"
+    echo "Checking for ${3} response XML validity..."
+    xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd "$2"
+}
+
+function postRequest {
+    echo "Simple POST request "
+    echo "Checking for ${3} request XML validity..."
+    xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_request.xsd "$4" 
+    curl -H "Content-type: text/xml" -d@"$4" -o "$2" "$1"
+    echo "Checking for ${3} response XML validity..."
+    xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd "$2"
+    if [ -z "$5" ]; then
+	echo ""
+    else
+	xmllint --noout --schema http://schemas.opengis.net/wps/1.0.0/wps${3}_response.xsd "$(xsltproc ./extractStatusLocation.xsl $2)"
+    fi
+}
+
+
+#
+# Tests for GetCapabilities using KVP and POST requests
+#
+kvpRequest "${WPSInstance}?request=GetCapabilities&service=WPS" "tmp/outputGC1.xml" "GetCapabilities"
+
+kvpRequest "${WPSInstance}?REQUEST=GetCapabilities&SERVICE=WPS" "tmp/outputGC2.xml" "GetCapabilities"
+
+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 ""
+
+#
+# Tests for DescribeProcess using KVP and POST requests
+#
+kvpRequest "${WPSInstance}?request=DescribeProcess&service=WPS&version=1.0.0&Identifier=ALL" "tmp/outputDPall.xml" "DescribeProcess"
+
+kvpRequest "${WPSInstance}?request=DescribeProcess&service=WPS&version=1.0.0&Identifier=${ServiceName}" "tmp/outputDPb1.xml" "DescribeProcess"
+
+echo ""
+
+cat requests/dp.xml | sed "s:ServiceName:${ServiceName}:g" > tmp/dp1.xml
+postRequest "${WPSInstance}" "tmp/outputDPp.xml" "DescribeProcess" "tmp/dp1.xml"
+echo "" 
+
+#
+# Tests for Execute using KVP and POST requests
+#
+for i in ijson_o igml_o ir_o ir_o_async ir_or ir_or_async irb_o irb_o_async irb_or irb_or_async; 
+do
+    cat requests/${i}.xml | sed "s:ServiceName:${ServiceName}: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
+
+echo ""
Index: tags/rel-1.3.0-rc1/thirds/cgic206/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/Makefile	(revision 417)
@@ -0,0 +1,41 @@
+OS:=$(shell uname -s)
+CPU:=$(shell uname -m)
+ifeq ($(OS),Darwin)
+	MACOS_CFLAGS=-arch x86_64
+	LIBS= -L./ -lcgic /usr/lib/libfcgi.dylib
+else
+ifeq ($(CPU),x86_64)
+	LIBS= -L./ -lcgic /usr/lib64/libfcgi.so
+else
+	LIBS= -L./ -lcgic /usr/lib/libfcgi.a
+endif
+endif
+CFLAGS=-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.3.0-rc1/thirds/cgic206/capture.c
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/capture.c	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/capture.c	(revision 417)
@@ -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.3.0-rc1/thirds/cgic206/cgic.c
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/cgic.c	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/cgic.c	(revision 417)
@@ -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.3.0-rc1/thirds/cgic206/cgic.h
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/cgic.h	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/cgic.h	(revision 417)
@@ -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.3.0-rc1/thirds/cgic206/cgic.html
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/cgic.html	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/cgic.html	(revision 417)
@@ -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 futher 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.3.0-rc1/thirds/cgic206/cgictest.c
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/cgictest.c	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/cgictest.c	(revision 417)
@@ -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.3.0-rc1/thirds/cgic206/license.txt
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/license.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/license.txt	(revision 417)
@@ -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.3.0-rc1/thirds/cgic206/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/makefile.vc	(revision 417)
@@ -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.3.0-rc1/thirds/cgic206/readme.txt
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/readme.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/readme.txt	(revision 417)
@@ -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.3.0-rc1/thirds/cgic206/support.txt
===================================================================
--- tags/rel-1.3.0-rc1/thirds/cgic206/support.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/cgic206/support.txt	(revision 417)
@@ -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.3.0-rc1/thirds/dirent-win32/dirent.c
===================================================================
--- tags/rel-1.3.0-rc1/thirds/dirent-win32/dirent.c	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/dirent-win32/dirent.c	(revision 417)
@@ -0,0 +1,146 @@
+/*
+
+    Implementation of POSIX directory browsing functions and types for Win32.
+
+    Author:  Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
+    History: Created March 1997. Updated June 2003.
+    Rights:  See end of file.
+
+*/
+
+#include <dirent.h>
+#include <errno.h>
+#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct DIR
+{
+    long                handle; /* -1 for failed rewind */
+    struct _finddata_t  info;
+    struct dirent       result; /* d_name null iff first time */
+    char                *name;  /* null-terminated char string */
+};
+
+DIR *opendir(const char *name)
+{
+    DIR *dir = 0;
+
+    if(name && name[0])
+    {
+        size_t base_length = strlen(name);
+        const char *all = /* search pattern must end with suitable wildcard */
+            strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+        if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
+           (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
+        {
+            strcat(strcpy(dir->name, name), all);
+
+            if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1)
+            {
+                dir->result.d_name = 0;
+            }
+            else /* rollback */
+            {
+                free(dir->name);
+                free(dir);
+                dir = 0;
+            }
+        }
+        else /* rollback */
+        {
+            free(dir);
+            dir   = 0;
+            errno = ENOMEM;
+        }
+    }
+    else
+    {
+        errno = EINVAL;
+    }
+
+    return dir;
+}
+
+int closedir(DIR *dir)
+{
+    int result = -1;
+
+    if(dir)
+    {
+        if(dir->handle != -1)
+        {
+            result = _findclose(dir->handle);
+        }
+
+        free(dir->name);
+        free(dir);
+    }
+
+    if(result == -1) /* map all errors to EBADF */
+    {
+        errno = EBADF;
+    }
+
+    return result;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+    struct dirent *result = 0;
+
+    if(dir && dir->handle != -1)
+    {
+        if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
+        {
+            result         = &dir->result;
+            result->d_name = dir->info.name;
+        }
+    }
+    else
+    {
+        errno = EBADF;
+    }
+
+    return result;
+}
+
+void rewinddir(DIR *dir)
+{
+    if(dir && dir->handle != -1)
+    {
+        _findclose(dir->handle);
+        dir->handle = (long) _findfirst(dir->name, &dir->info);
+        dir->result.d_name = 0;
+    }
+    else
+    {
+        errno = EBADF;
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+
+    Copyright Kevlin Henney, 1997, 2003. All rights reserved.
+
+    Permission to use, copy, modify, and distribute this software and its
+    documentation for any purpose is hereby granted without fee, provided
+    that this copyright and permissions notice appear in all copies and
+    derivatives.
+    
+    This software is supplied "as is" without express or implied warranty.
+
+    But that said, if there are any problems please get in touch.
+
+*/
+
Index: tags/rel-1.3.0-rc1/thirds/dirent-win32/dirent.h
===================================================================
--- tags/rel-1.3.0-rc1/thirds/dirent-win32/dirent.h	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/dirent-win32/dirent.h	(revision 417)
@@ -0,0 +1,50 @@
+#ifndef DIRENT_INCLUDED
+#define DIRENT_INCLUDED 1
+
+/*
+
+    Declaration of POSIX directory browsing functions and types for Win32.
+
+    Author:  Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
+    History: Created March 1997. Updated June 2003.
+    Rights:  See end of file.
+    
+*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct DIR DIR;
+
+struct dirent
+{
+    char *d_name;
+};
+
+DIR           *opendir(const char *);
+int           closedir(DIR *);
+struct dirent *readdir(DIR *);
+void          rewinddir(DIR *);
+
+/*
+
+    Copyright Kevlin Henney, 1997, 2003. All rights reserved.
+
+    Permission to use, copy, modify, and distribute this software and its
+    documentation for any purpose is hereby granted without fee, provided
+    that this copyright and permissions notice appear in all copies and
+    derivatives.
+    
+    This software is supplied "as is" without express or implied warranty.
+
+    But that said, if there are any problems please get in touch.
+
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: tags/rel-1.3.0-rc1/thirds/include/unistd.h
===================================================================
--- tags/rel-1.3.0-rc1/thirds/include/unistd.h	(revision 417)
+++ tags/rel-1.3.0-rc1/thirds/include/unistd.h	(revision 417)
@@ -0,0 +1,18 @@
+#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.3.0-rc1/zoo-project/HISTORY.txt
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/HISTORY.txt	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/HISTORY.txt	(revision 417)
@@ -0,0 +1,56 @@
+Version 1.3.0-dev
+
+  * 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
+
+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 informations runtime specific 
+  * add COOKIE support and {{{senv}}} section to store informations 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.3.0-rc1/zoo-project/zoo-api/js/ZOO-api.js
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-api/js/ZOO-api.js	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-api/js/ZOO-api.js	(revision 417)
@@ -0,0 +1,6315 @@
+/**
+ * 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
+   * 
+   * Returns:
+   * {String} Request result.
+   */
+  Get: function(url,params) {
+    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;
+    }
+    return ZOORequest('GET',url);
+  },
+  /**
+   * 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 data = outputs[0].*::Data.*::*[0];
+      var builder = this.parseData[data.localName().toLowerCase()];
+      if (builder)
+        return builder.apply(this,[data]);
+      else
+        return null;
+    } 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(node) {
+      var result = {type:'reference',value:node.*::href};
+      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,
+  /**
+   * 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;
+  },
+  /**
+   * 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:ResponseForm xmlns:wps="'+this.namespaces['wps']+'"><wps:ResponseDocument><wps:Output'+(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></wps:ResponseDocument></wps:ResponseForm>');
+      if (obj.encoding)
+        output.*::Data.*::ComplexData.@encoding = obj.encoding;
+      if (obj.schema)
+        output.*::Data.*::ComplexData.@schema = obj.schema;
+      output = output.toXMLString();
+      return output;
+    },
+    'RawDataOutput': function(identifier,obj) {
+      var output = new XML('<wps:ResponseForm xmlns:wps="'+this.namespaces['wps']+'"><wps:RawDataOutput><wps:Output '+(obj["mimeType"]?' mimeType="'+obj["mimeType"]+'" ':'')+(obj["encoding"]?' encoding="'+obj["encoding"]+'" ':'')+'><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier></wps:Output></wps:RawDataOutput></wps:ResponseForm>');
+      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><![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();
+      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];
+      outputsArray.push(builder.apply(this,[attr,data]));
+    }
+    return outputsArray.join('\n');
+  },
+
+  CLASS_NAME: "ZOO.Process"
+});
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-api/js/ZOO-proj4js.js
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-api/js/ZOO-proj4js.js	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-api/js/ZOO-proj4js.js	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-kernel/Doxyfile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/Doxyfile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/Doxyfile	(revision 417)
@@ -0,0 +1,1417 @@
+# Doxyfile 1.5.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a 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.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = ZOO Kernel
+
+# 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         = 0.1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# 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       = doc
+
+# 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 cause performance problems for the file system.
+
+CREATE_SUBDIRS         = YES
+
+# 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. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, 
+# and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) 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.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) 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.
+
+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" "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.
+
+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.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then 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.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then 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.
+
+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 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.
+
+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 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# 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 comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+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 behaviour. 
+# 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 behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+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.
+
+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.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts 
+# 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                = 
+
+# 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.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+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.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# 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); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip 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.
+
+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 (the default) 
+# 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.
+
+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.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) 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.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT 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.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+#---------------------------------------------------------------------------
+# 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 and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+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.
+
+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 (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = YES
+
+# 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.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) 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.
+
+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 (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+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 (the default) these declarations will be included in the 
+# documentation.
+
+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 (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+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 (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+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.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) 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.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = 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 default) 
+# the group names will appear in their defined order.
+
+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 default), 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.
+
+SORT_BY_SCOPE_NAME     = 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.
+
+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.
+
+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.
+
+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.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of 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 initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+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.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# 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 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 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. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED 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.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR 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.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+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)
+
+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 stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be 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.
+
+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, which is 
+# also the default input encoding. 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.
+
+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 pattern (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 *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# 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.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+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
+
+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. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are 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.
+
+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 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# 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 also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+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.
+
+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.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# 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 documentstion.
+
+REFERENCES_LINK_SOURCE = 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.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) 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.
+
+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.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+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 one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+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. If left blank `html' will be used as the default path.
+
+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). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+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 the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = YES
+
+# 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, 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.
+
+GENERATE_DOCSET        = YES
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# 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.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, 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.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# 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. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, 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).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = YES
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# 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 FRAME, 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 (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature. Other possible values 
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hiererachy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW      = NONE
+
+# 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.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# 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.
+
+FORMULA_FONTSIZE       = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# 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. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+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.
+
+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, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+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. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). 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.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+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.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# 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 very pretty with 
+# other RTF readers or editors.
+
+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. If left blank `rtf' will be used as the default path.
+
+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.
+
+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 other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+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.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+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. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+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 is NO.
+
+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.
+
+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. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+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.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see 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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+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 (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF 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.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+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.
+
+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.
+
+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 
+# 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.
+
+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.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all 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.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a 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.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+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.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+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            = 
+
+# 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.
+
+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, 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)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output 
+# directory and reference it in all dot files that doxygen generates. This 
+# font does not include all possible unicode characters however, so when you need 
+# these (or just want a differently looking font) you can specify the font name 
+# using DOT_FONTNAME. You need 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.
+
+DOT_FONTNAME           = FreeSans
+
+# By default doxygen will tell dot to use the output directory to look for the 
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
+# different font using DOT_FONTNAME you can set the path where dot 
+# can find it using this tag.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are 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 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are 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.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+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.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# 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.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are 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.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are 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.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are 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.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH 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.
+
+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).
+
+DOTFILE_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.
+
+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.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is enabled by default, which results in a transparent 
+# background. 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).
+
+DOT_TRANSPARENT        = YES
+
+# 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.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/Makefile.in
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/Makefile.in	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/Makefile.in	(revision 417)
@@ -0,0 +1,118 @@
+OS:=$(shell uname -s)
+ifeq ($(OS),Darwin)
+	MACOS_LD_FLAGS=-lintl -framework SystemConfiguration -framework CoreFoundation
+	MACOS_CFLAGS=-arch $(shell uname -m)
+endif
+
+JAVACFLAGS=@JAVA_CPPFLAGS@
+JAVALDFLAGS=@JAVA_LDFLAGS@
+JAVA_ENABLED=@JAVA_ENABLED@
+JAVA_FILE=@JAVA_FILE@
+
+MS_CFLAGS=@MS_CFLAGS@
+MS_LDFLAGS=@MS_LIBS@
+MS_FILE=@MS_FILE@
+
+CFLAGS=${MACOS_CFLAGS} ${MS_CFLAGS} -I../../thirds/cgic206 -I. -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
+LDFLAGS=-lcurl -L../../thirds/cgic206 -lcgic ${GDAL_LIBS} ${XML2LDFLAGS} ${PYTHONLDFLAGS} ${PERLLDFLAGS}  ${PHPLDFLAGS} ${JAVALDFLAGS} ${JSLDFLAGS} -lfcgi -lcrypto ${MS_LDFLAGS} ${MACOS_LD_FLAGS}
+
+PHPCFLAGS=@PHP_CPPFLAGS@
+PHPLDFLAGS=@PHP_LDFLAGS@
+PHP_ENABLED=@PHP_ENABLED@
+PHP_FILE=@PHP_FILE@
+
+
+PYTHONCFLAGS=@PYTHON_CPPFLAGS@
+PYTHONLDFLAGS=@PYTHON_LDFLAGS@
+PYTHON_ENABLED=@PYTHON_ENABLED@
+PYTHON_FILE=@PYTHON_FILE@
+
+JSCFLAGS=@JS_CPPFLAGS@
+JSLDFLAGS=@JS_LDFLAGS@
+JS_ENABLED=@JS_ENABLED@
+JS_FILE=@JS_FILE@
+
+XML2CFLAGS=@XML2_CPPFLAGS@
+XML2LDFLAGS=@XML2_LDFLAGS@
+
+GDAL_CFLAGS=@GDAL_CFLAGS@
+GDAL_LIBS=@GDAL_LIBS@
+
+PERLCFLAGS=@PERL_CPPFLAGS@
+PERLLDFLAGS=@PERL_LDFLAGS@
+PERL_ENABLED=@PERL_ENABLED@
+PERL_FILE=@PERL_FILE@
+
+
+all: zoo_loader.cgi
+
+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
+
+service_internal.o: service_internal.c service.h
+	gcc ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_internal.c
+
+service_internal_ms.o: service_internal_ms.c
+	gcc ${JS_ENABLED} ${JSCFLAGS} ${XML2CFLAGS} ${CFLAGS} -fPIC -c service_internal_ms.c
+
+service_internal_python.o: service_internal_python.c service.h
+	g++ ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} -c service_internal_python.c
+
+service_internal_php.o: service_internal_php.c service.h
+	g++ -c ${XML2CFLAGS} ${PHPCFLAGS} ${CFLAGS}  ${PHP_ENABLED} service_internal_php.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 ${XML2CFLAGS} ${JSCFLAGS} ${CFLAGS} ${JS_ENABLED} -c service_internal_js.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
+	g++ -g -O2 ${XML2CFLAGS} ${CFLAGS} ${PYTHONCFLAGS} ${JAVACFLAGS} ${JSCFLAGS} ${PERLCFLAGS} ${PHPCFLAGS} ${PYTHON_ENABLED} ${JS_ENABLED} ${PHP_ENABLED} ${PERL_ENABLED} ${JAVA_ENABLED} -c zoo_service_loader.c  -fno-common -DPIC -o zoo_service_loader.o
+
+zoo_loader.cgi: 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 service_internal.o ${MS_FILE} ${PYTHON_FILE} ${PHP_FILE} ${JAVA_FILE} ${JS_FILE} ${PERL_FILE}
+	g++ -g -O2 ${JSCFLAGS} ${PHPCFLAGS}  ${PERLCFLAGS}   ${JAVACFLAGS} ${XML2CFLAGS} ${PYTHONCFLAGS} ${CFLAGS} -c zoo_loader.c  -fno-common -DPIC -o zoo_loader.o
+	g++  ${JSCFLAGS} ${GDAL_CFLAGS} ${XML2CFLAGS} ${PHPCFLAGS} ${PERLCFLAGS} ${JAVACFLAGS} ${PYTHONCFLAGS} ${CFLAGS} zoo_loader.o zoo_service_loader.o service_internal.o ${MS_FILE} ${PYTHON_FILE}  ${PERL_FILE} ${PHP_FILE}  ${JS_FILE} ${JAVA_FILE} ulinet.o lex.cr.o lex.sr.o service_conf.tab.o main_conf_read.tab.o -o zoo_loader.cgi ${LDFLAGS}
+
+install:
+	@echo "##############################################################################"
+	@echo "# This won't install anything !!!                                            #"
+	@echo "#                                                                            #"
+	@echo "# Please copy the zoo_loader.cgi and its companion main.cfg into your cgbin  #"
+	@echo "# directory.                                                                 #"
+	@echo "##############################################################################"
+
+clean:
+	rm -f *.o *.zo *.eo *.tab.c *.tab.h *.sr.c* service_loader lex.* *.lreg *.sibling service_loader.dSYM 
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/README
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/README	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/README	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-kernel/ZOOMakefile.opts.in
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/ZOOMakefile.opts.in	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/ZOOMakefile.opts.in	(revision 417)
@@ -0,0 +1,25 @@
+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)
+endif
+
+GDAL_CFLAGS=@GDAL_CFLAGS@
+GDAL_LIBS=@GDAL_LIBS@
+
+XML2CFLAGS=@XML2_CPPFLAGS@
+XML2LDFLAGS=@XML2_LDFLAGS@
+
+PYTHONCFLAGS=@PYTHON_CPPFLAGS@
+PYTHONLDFLAGS=@PYTHON_LDFLAGS@
+
+JS_ENABLED=@JS_ENABLED@
+JSCFLAGS=@JS_CPPFLAGS@
+JSLDFLAGS=@JS_LDFLAGS@
+ifeq ($(JS_ENABLED),-DUSE_JS)
+     JS_LDFLAGS=${ZRPATH}/zoo-kernel/ulinet.o ${ZRPATH}/zoo-kernel/service_internal_js.o -lcurl 
+endif
+
+ZOO_CFLAGS=-I${ZRPATH}/../thirds/cgic206/ -I${ZRPATH}/zoo-kernel/
+ZOO_LDFLAGS=-lcrypto
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/configure.ac
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/configure.ac	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/configure.ac	(revision 417)
@@ -0,0 +1,417 @@
+AC_INIT([ZOO Kernel], [1.3.0], [bugs@zoo-project.org])
+
+# Checks for programs.
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_LEX
+AC_PROG_CXX
+AC_PROG_SED
+
+# Checks for libraries.
+AC_CHECK_LIB([cgic], [cgiMain])
+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([fl], [main])
+AC_CHECK_LIB([pthread], [main])
+AC_CHECK_LIB([fcgi], [main])
+AC_CHECK_LIB([ssl], [main])
+
+# Checks for header files.
+AC_FUNC_ALLOCA
+AC_CHECK_HEADERS([fcntl.h inttypes.h libintl.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 gdal is installed
+#============================================================================
+
+AC_ARG_WITH([gdal-config], 
+	[AS_HELP_STRING([--with-gdal-config=FILE], [specify 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 libxml2 is installed
+# ===========================================================================
+
+AC_ARG_WITH([xml2config], 
+	[AS_HELP_STRING([--with-xml2config=FILE], [specify 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 specify 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])
+
+#============================================================================
+# Detect if mapserver is installed
+#============================================================================
+
+AC_ARG_WITH([mapserver], 
+       [AS_HELP_STRING([--with-mapserver=PATH], [specify the path for MapServer compiled source tree])], 
+       [MS_SRC_PATH="$withval"], [MS_SRC_PATH=""])
+
+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 -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
+       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])
+
+# ===========================================================================
+# Detect if python is installed
+# ===========================================================================
+
+AC_ARG_WITH([python], 
+	[AS_HELP_STRING([--with-python=PATH], [To enable python support or specify 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
+		# PHP 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 --cflags`
+
+	# 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/^.*\(python2\..\)$/\1/'`
+	AC_CHECK_LIB([$PY_LIB], [PyObject_CallObject], [], [AC_MSG_ERROR([could not find libpython])], [])
+	AC_SUBST([PYTHON_CPPFLAGS])
+	AC_SUBST([PYTHON_LDFLAGS])
+fi
+
+AC_SUBST([PYTHON_ENABLED])
+AC_SUBST([PYTHON_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=""])
+
+
+if test -z "$PHP_ENABLED"
+then
+	PHP_FILE=""
+else
+	PHPCONFIG="$PHP_PATH/bin/php-config"
+	PHP_FILE="service_internal_php.o"
+	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 
+	PHP_LDFLAGS="-L/`$PHPCONFIG --prefix`/lib -lphp5"
+	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 :) ??
+	AC_CHECK_LIB([php5], [call_user_function], [], [AC_MSG_ERROR([could not find libphp])], [])
+	AC_SUBST([PHP_CPPFLAGS])
+	AC_SUBST([PHP_LDFLAGS])
+fi
+
+AC_SUBST([PHP_ENABLED])
+AC_SUBST([PHP_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 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=""])
+
+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"
+		JAVA_CPPFLAGS="-I/Applications/Xcode.app/Contents/Developer//Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/"
+	else
+		if test -d "$JDKHOME/jre/lib/i386";
+		then
+			JAVA_LDFLAGS="-L$JDKHOME/jre/lib/i386/client/ -ljvm -lpthread"
+			JAVA_CPPFLAGS="-I$JDKHOME/include -I$JDKHOME/include/linux"
+		else
+			JAVA_LDFLAGS="-L$JDKHOME/jre/lib/amd64/client/ -ljvm -lpthread"
+			JAVA_CPPFLAGS="-I$JDKHOME/include -I$JDKHOME/include/linux"
+		fi
+	fi
+
+	# 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 headers include related to libjava])])
+
+	# 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 libjava])], [])
+	fi
+
+	AC_SUBST([JAVA_CPPFLAGS])
+	AC_SUBST([JAVA_LDFLAGS])
+fi 
+
+AC_SUBST([JAVA_ENABLED])
+AC_SUBST([JAVA_FILE])
+
+# ===========================================================================
+# Detect if spidermonkey is installed
+# ===========================================================================
+
+AC_ARG_WITH([js], 
+	[AS_HELP_STRING([--with-js=PATH], [specify --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_CHECK_HEADERS([jsapi.h],
+        #                [], [AC_MSG_ERROR([could not find headers include related to libjs])])
+
+	
+	LIBS_SAVE="$LIBS"
+        LIBS="$JS_LDFLAGS"
+
+        AC_CHECK_LIB([$JS_LIB], [JS_CompileFile,JS_CallFunctionName], [], [AC_MSG_ERROR([could not find $JS_LIB])], [])
+			
+        AC_SUBST([JS_CPPFLAGS])
+        AC_SUBST([JS_LDFLAGS])
+fi
+
+AC_SUBST([JS_ENABLED])
+AC_SUBST([JS_FILE])
+
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([ZOOMakefile.opts])
+AC_OUTPUT
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/en_US.utf8.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/en_US.utf8.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/en_US.utf8.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-kernel/locale/po/fr_FR.utf8.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/fr_FR.utf8.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/fr_FR.utf8.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-kernel/locale/po/ja_JP.utf8.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/ja_JP.utf8.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/ja_JP.utf8.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-kernel/locale/po/messages.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/messages.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/locale/po/messages.po	(revision 417)
@@ -0,0 +1,1725 @@
+# 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.
+#
+#: 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
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-28 00:38+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=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: service_internal.c:34
+msgid "0123456789abcdef"
+msgstr ""
+
+#: service_internal.c:44 service_internal.c:88 service_internal.c:90
+#: service_internal.c:92 service_internal.c:108 service_internal.c:122
+#: service_internal.c:986 service_internal.c:1054 service_internal.c:1070
+#: service_internal.c:1075 service_internal.c:1398 service_internal.c:1585
+#: zoo_service_loader.c:1443
+msgid "lenv"
+msgstr ""
+
+#: service_internal.c:44 service_internal.c:108 service_internal.c:986
+#: service_internal.c:1398 zoo_service_loader.c:1446
+msgid "sid"
+msgstr ""
+
+#: service_internal.c:49 service_internal.c:113
+#, c-format
+msgid "shmget failed to update value\n"
+msgstr ""
+
+#: service_internal.c:54 service_internal.c:118
+#, c-format
+msgid "shmat failed to update value\n"
+msgstr ""
+
+#: service_internal.c:77
+#, c-format
+msgid "Number of arguments used to call the function : %i"
+msgstr ""
+
+#: service_internal.c:84 service_internal.c:988 zoo_service_loader.c:1445
+#, c-format
+msgid "%i"
+msgstr ""
+
+#: service_internal.c:88 service_internal.c:90 service_internal.c:92
+#: service_internal.c:122 service_internal.c:1054 service_internal.c:1285
+#: service_internal.c:1327 zoo_service_loader.c:1158 zoo_service_loader.c:1448
+msgid "status"
+msgstr ""
+
+#: service_internal.c:92
+msgid "15"
+msgstr ""
+
+#: service_internal.c:140
+#, c-format
+msgid "shmget failed in getStatus\n"
+msgstr ""
+
+#: service_internal.c:145
+#, c-format
+msgid "shmat failed in getStatus\n"
+msgstr ""
+
+#: service_internal.c:151
+msgid "-1"
+msgstr ""
+
+#: service_internal.c:223
+#, c-format
+msgid "zooXmlAddNs %d \n"
+msgstr ""
+
+#: service_internal.c:246 service_internal.c:250
+#, c-format
+msgid "zooXmlCleanup %d\n"
+msgstr ""
+
+#: service_internal.c:269 service_internal.c:276 service_internal.c:546
+#: service_internal.c:584 service_internal.c:940 service_internal.c:950
+msgid "http://www.opengis.net/wps/1.0.0"
+msgstr ""
+
+#: service_internal.c:269 service_internal.c:276 service_internal.c:546
+#: service_internal.c:579 service_internal.c:584 service_internal.c:606
+#: service_internal.c:940 service_internal.c:950
+msgid "wps"
+msgstr ""
+
+#: service_internal.c:271 service_internal.c:494 service_internal.c:961
+#: service_internal.c:1395 service_internal.c:1454 service_internal.c:1513
+#: service_internal.c:1517 service_internal.c:1518 zoo_service_loader.c:225
+#: zoo_service_loader.c:1683
+msgid "main"
+msgstr ""
+
+#: service_internal.c:273
+msgid "Capabilities"
+msgstr ""
+
+#: service_internal.c:274 service_internal.c:548 service_internal.c:582
+#: service_internal.c:608 service_internal.c:944 service_internal.c:1408
+#: service_internal.c:1410 service_internal.c:1456 service_internal.c:1460
+msgid "http://www.opengis.net/ows/1.1"
+msgstr ""
+
+#: service_internal.c:274 service_internal.c:548 service_internal.c:582
+#: service_internal.c:608 service_internal.c:944 service_internal.c:1408
+#: service_internal.c:1410 service_internal.c:1456 service_internal.c:1460
+msgid "ows"
+msgstr ""
+
+#: service_internal.c:277 service_internal.c:586 service_internal.c:948
+#: service_internal.c:1412 service_internal.c:1461
+msgid "http://www.w3.org/2001/XMLSchema-instance"
+msgstr ""
+
+#: service_internal.c:277 service_internal.c:586 service_internal.c:948
+#: service_internal.c:1412 service_internal.c:1461
+msgid "xsi"
+msgstr ""
+
+#: service_internal.c:279 service_internal.c:550 service_internal.c:585
+#: service_internal.c:610 service_internal.c:946 service_internal.c:1411
+#: service_internal.c:1463
+msgid "http://www.w3.org/1999/xlink"
+msgstr ""
+
+#: service_internal.c:279 service_internal.c:550 service_internal.c:585
+#: service_internal.c:610 service_internal.c:946 service_internal.c:1411
+#: service_internal.c:1463
+msgid "xlink"
+msgstr ""
+
+#: service_internal.c:281 service_internal.c:589 service_internal.c:952
+#: service_internal.c:1465
+msgid "schemaLocation"
+msgstr ""
+
+#: service_internal.c:281
+msgid ""
+"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/"
+"wpsGetCapabilities_response.xsd"
+msgstr ""
+
+#: service_internal.c:282 service_internal.c:590 service_internal.c:954
+msgid "service"
+msgstr ""
+
+#: service_internal.c:282 service_internal.c:340 service_internal.c:590
+#: service_internal.c:954
+msgid "WPS"
+msgstr ""
+
+#: service_internal.c:285 service_internal.c:287 service_internal.c:290
+#: service_internal.c:293 service_internal.c:306 service_internal.c:591
+#: service_internal.c:955 service_internal.c:1375 service_internal.c:1415
+#: service_internal.c:1468
+msgid "version"
+msgstr ""
+
+#: service_internal.c:290 service_internal.c:293 service_internal.c:343
+#: service_internal.c:591 service_internal.c:955 service_internal.c:1380
+#: service_internal.c:1383
+msgid "1.0.0"
+msgstr ""
+
+#: service_internal.c:297
+msgid "ServiceIdentification"
+msgstr ""
+
+#: service_internal.c:298
+msgid "identification"
+msgstr ""
+
+#: service_internal.c:302 service_internal.c:313 service_internal.c:364
+#: service_internal.c:407
+msgid "keywords"
+msgstr ""
+
+#: service_internal.c:303 service_internal.c:365 service_internal.c:455
+#: service_internal.c:963 service_internal.c:1518 zoo_service_loader.c:225
+msgid "serverAddress"
+msgstr ""
+
+#: service_internal.c:304 service_internal.c:366 service_internal.c:496
+msgid "lang"
+msgstr ""
+
+#: service_internal.c:305 service_internal.c:1293 service_internal.c:1362
+#: service_internal.c:1559 zoo_service_loader.c:840 zoo_service_loader.c:1073
+#: zoo_service_loader.c:1186 zoo_service_loader.c:1286
+msgid "encoding"
+msgstr ""
+
+#: service_internal.c:314 service_internal.c:408
+msgid "Keywords"
+msgstr ""
+
+#: service_internal.c:326 service_internal.c:334 service_internal.c:420
+#: service_internal.c:428
+msgid "Keyword"
+msgstr ""
+
+#: service_internal.c:339
+msgid "ServiceType"
+msgstr ""
+
+#: service_internal.c:342
+msgid "ServiceTypeVersion"
+msgstr ""
+
+#: service_internal.c:350 service_internal.c:438
+#, c-format
+msgid "TMP4 NOT FOUND !!"
+msgstr ""
+
+#: service_internal.c:355 zoo_service_loader.c:261 zoo_service_loader.c:335
+#: zoo_service_loader.c:1477 zoo_service_loader.c:1684
+#: zoo_service_loader.c:1728
+msgid "ServiceProvider"
+msgstr ""
+
+#: service_internal.c:356
+msgid "ServiceContact"
+msgstr ""
+
+#: service_internal.c:357
+msgid "ContactInfo"
+msgstr ""
+
+#: service_internal.c:358 service_internal.c:387 service_internal.c:390
+msgid "Phone"
+msgstr ""
+
+#: service_internal.c:359 service_internal.c:396 service_internal.c:399
+msgid "Address"
+msgstr ""
+
+#: service_internal.c:360
+msgid "provider"
+msgstr ""
+
+#: service_internal.c:368
+msgid "ProviderName"
+msgstr ""
+
+#: service_internal.c:374
+msgid "ProviderSite"
+msgstr ""
+
+#: service_internal.c:376 service_internal.c:472 service_internal.c:476
+#: service_internal.c:1320 zoo_service_loader.c:843 zoo_service_loader.c:942
+#: zoo_service_loader.c:968 zoo_service_loader.c:994
+msgid "href"
+msgstr ""
+
+#: service_internal.c:380
+msgid "IndividualName"
+msgstr ""
+
+#: service_internal.c:381
+msgid "PositionName"
+msgstr ""
+
+#: service_internal.c:447
+msgid "OperationsMetadata"
+msgstr ""
+
+#: service_internal.c:449 zoo_service_loader.c:188 zoo_service_loader.c:207
+#: zoo_service_loader.c:249
+msgid "GetCapabilities"
+msgstr ""
+
+#: service_internal.c:450 zoo_service_loader.c:189 zoo_service_loader.c:329
+msgid "DescribeProcess"
+msgstr ""
+
+#: service_internal.c:451 zoo_service_loader.c:190 zoo_service_loader.c:401
+msgid "Execute"
+msgstr ""
+
+#: service_internal.c:460 service_internal.c:463
+msgid "not_found"
+msgstr ""
+
+#: service_internal.c:466
+msgid "Operation"
+msgstr ""
+
+#: service_internal.c:467
+msgid "name"
+msgstr ""
+
+#: service_internal.c:468
+msgid "DCP"
+msgstr ""
+
+#: service_internal.c:469
+msgid "HTTP"
+msgstr ""
+
+#: service_internal.c:470
+msgid "Get"
+msgstr ""
+
+#: service_internal.c:471 zoo_service_loader.c:245 zoo_service_loader.c:277
+#: zoo_service_loader.c:363 zoo_service_loader.c:424 zoo_service_loader.c:1473
+#: zoo_service_loader.c:1478 zoo_service_loader.c:1727
+#: zoo_service_loader.c:1730
+#, c-format
+msgid "%s/%s"
+msgstr ""
+
+#: service_internal.c:475
+msgid "Post"
+msgstr ""
+
+#: service_internal.c:487
+msgid "ProcessOfferings"
+msgstr ""
+
+#: service_internal.c:490
+msgid "Languages"
+msgstr ""
+
+#: service_internal.c:491 service_internal.c:674 service_internal.c:679
+#: service_internal.c:830 service_internal.c:833
+msgid "Default"
+msgstr ""
+
+#: service_internal.c:492 service_internal.c:757 service_internal.c:761
+#: service_internal.c:876 service_internal.c:880
+msgid "Supported"
+msgstr ""
+
+#: service_internal.c:509 service_internal.c:517 service_internal.c:526
+msgid "Language"
+msgstr ""
+
+#: service_internal.c:514 service_internal.c:592 service_internal.c:956
+#: service_internal.c:1414 service_internal.c:1467
+msgid "xml:lang"
+msgstr ""
+
+#: service_internal.c:556 service_internal.c:1017
+msgid "Process"
+msgstr ""
+
+#: service_internal.c:557 service_internal.c:559 service_internal.c:615
+#: service_internal.c:624 service_internal.c:1018 service_internal.c:1021
+msgid "processVersion"
+msgstr ""
+
+#: service_internal.c:563 service_internal.c:638
+msgid "Metadata"
+msgstr ""
+
+#: service_internal.c:579 service_internal.c:606
+msgid "http://schemas.opengis.net/wps/1.0.0"
+msgstr ""
+
+#: service_internal.c:581
+msgid "ProcessDescriptions"
+msgstr ""
+
+#: service_internal.c:589
+msgid ""
+"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/"
+"wpsDescribeProcess_response.xsd"
+msgstr ""
+
+#: service_internal.c:592 service_internal.c:956 service_internal.c:1414
+#: service_internal.c:1467
+msgid "en"
+msgstr ""
+
+#: service_internal.c:613
+msgid "ProcessDescription"
+msgstr ""
+
+#: service_internal.c:616
+msgid "storeSupported"
+msgstr ""
+
+#: service_internal.c:617
+msgid "statusSupported"
+msgstr ""
+
+#: service_internal.c:630 service_internal.c:991 service_internal.c:1199
+#: service_internal.c:1227 zoo_service_loader.c:1458
+msgid "false"
+msgstr ""
+
+#: service_internal.c:644 service_internal.c:646
+msgid "Profile"
+msgstr ""
+
+#: service_internal.c:651 service_internal.c:1098 zoo_service_loader.c:597
+msgid "DataInputs"
+msgstr ""
+
+#: service_internal.c:655 service_internal.c:1103
+msgid "Input"
+msgstr ""
+
+#: service_internal.c:656 service_internal.c:805 service_internal.c:1626
+msgid "minOccurs"
+msgstr ""
+
+#: service_internal.c:660 service_internal.c:809
+msgid "maxOccurs"
+msgstr ""
+
+#: service_internal.c:673 service_internal.c:789 service_internal.c:827
+#: service_internal.c:1274 zoo_service_loader.c:1041
+msgid "LiteralData"
+msgstr ""
+
+#: service_internal.c:675 service_internal.c:758 service_internal.c:834
+#: service_internal.c:877
+msgid "Format"
+msgstr ""
+
+#: service_internal.c:678 service_internal.c:829
+msgid "UOMs"
+msgstr ""
+
+#: service_internal.c:687 service_internal.c:839
+#, c-format
+msgid "DATATYPE DEFAULT ? %s\n"
+msgstr ""
+
+#: service_internal.c:689 service_internal.c:690 service_internal.c:700
+#: service_internal.c:841 service_internal.c:842 service_internal.c:853
+#: service_internal.c:887
+msgid "DataType"
+msgstr ""
+
+#: service_internal.c:693 service_internal.c:845
+#, c-format
+msgid "http://www.w3.org/TR/xmlschema-2/#%s"
+msgstr ""
+
+#: service_internal.c:694 service_internal.c:846 service_internal.c:1324
+msgid "reference"
+msgstr ""
+
+#: service_internal.c:699 service_internal.c:852 service_internal.c:886
+#: service_internal.c:1197 service_internal.c:1199 service_internal.c:1225
+#: service_internal.c:1227 service_internal.c:1284 service_internal.c:1329
+#: service_internal.c:1510 zoo_service_loader.c:1189
+msgid "asReference"
+msgstr ""
+
+#: service_internal.c:701 service_internal.c:723 service_internal.c:724
+msgid "AllowedValues"
+msgstr ""
+
+#: service_internal.c:702 service_internal.c:718 service_internal.c:1282
+#: service_internal.c:1295 service_internal.c:1323 service_internal.c:1522
+#: service_internal.c:1544 service_internal.c:1640 service_internal.c:1642
+#: zoo_service_loader.c:667 zoo_service_loader.c:709 zoo_service_loader.c:870
+#: zoo_service_loader.c:890 zoo_service_loader.c:960 zoo_service_loader.c:1013
+#: zoo_service_loader.c:1093
+msgid "value"
+msgstr ""
+
+#: service_internal.c:703 service_internal.c:854 service_internal.c:888
+#: service_internal.c:1283 service_internal.c:1287 service_internal.c:1325
+#: service_internal.c:1512
+msgid "extension"
+msgstr ""
+
+#: service_internal.c:719
+msgid "DefaultValue"
+msgstr ""
+
+#: service_internal.c:726 service_internal.c:734 zoo_service_loader.c:344
+#: zoo_service_loader.c:382
+msgid ","
+msgstr ""
+
+#: service_internal.c:728
+msgid "Value"
+msgstr ""
+
+#: service_internal.c:732
+#, c-format
+msgid "strgin : %s\n"
+msgstr ""
+
+#: service_internal.c:745
+msgid "AnyValue"
+msgstr ""
+
+#: service_internal.c:800 service_internal.c:1131
+msgid "ProcessOutputs"
+msgstr ""
+
+#: service_internal.c:804 service_internal.c:1117 service_internal.c:1135
+#: zoo_service_loader.c:1179
+msgid "Output"
+msgstr ""
+
+#: service_internal.c:816
+msgid "LITERALDATA"
+msgstr ""
+
+#: service_internal.c:817 service_internal.c:826
+msgid "LiteralOutput"
+msgstr ""
+
+#: service_internal.c:819
+msgid "COMPLEXDATA"
+msgstr ""
+
+#: service_internal.c:820
+msgid "ComplexOutput"
+msgstr ""
+
+#: service_internal.c:884
+#, c-format
+msgid "DATATYPE SUPPORTED ? %s\n"
+msgstr ""
+
+#: service_internal.c:939 service_internal.c:1394 zoo_service_loader.c:259
+#: zoo_service_loader.c:333 zoo_service_loader.c:928
+msgid "1.0"
+msgstr ""
+
+#: service_internal.c:943
+msgid "ExecuteResponse"
+msgstr ""
+
+#: service_internal.c:952
+msgid ""
+"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/"
+"wpsExecute_response.xsd"
+msgstr ""
+
+#: service_internal.c:980
+#, c-format
+msgid "%s/GetStatus.zcfg"
+msgstr ""
+
+#: service_internal.c:984
+msgid "rewriteUrl"
+msgstr ""
+
+#: service_internal.c:990 service_internal.c:1439 service_internal.c:1571
+#: service_internal.c:1577 zoo_service_loader.c:247 zoo_service_loader.c:503
+#: zoo_service_loader.c:532 zoo_service_loader.c:604 zoo_service_loader.c:635
+#: zoo_service_loader.c:901 zoo_service_loader.c:938
+#, c-format
+msgid "%s"
+msgstr ""
+
+#: service_internal.c:992 service_internal.c:1000
+#, c-format
+msgid ""
+"%s/?request=Execute&amp;service=WPS&amp;version=1.0.0&amp;"
+"Identifier=GetStatus&amp;DataInputs=sid=%s&amp;RawDataOutput=Result"
+msgstr ""
+
+#: service_internal.c:995 service_internal.c:1511
+msgid "true"
+msgstr ""
+
+#: service_internal.c:996
+#, c-format
+msgid "%s/%s/GetStatus/%s"
+msgstr ""
+
+#: service_internal.c:998
+#, c-format
+msgid "%s/GetStatus/%s"
+msgstr ""
+
+#: service_internal.c:1003 service_internal.c:1517
+msgid "tmpUrl"
+msgstr ""
+
+#: service_internal.c:1005
+#, c-format
+msgid "%s/%s/%s_%i.xml"
+msgstr ""
+
+#: service_internal.c:1009 zoo_service_loader.c:426 zoo_service_loader.c:1475
+#: zoo_service_loader.c:1732
+#, c-format
+msgid "%s/"
+msgstr ""
+
+#: service_internal.c:1012
+msgid "serviceInstance"
+msgstr ""
+
+#: service_internal.c:1014
+msgid "statusLocation"
+msgstr ""
+
+#: service_internal.c:1028
+msgid "Status"
+msgstr ""
+
+#: service_internal.c:1040
+msgid "%Y-%m-%dT%I:%M:%SZ"
+msgstr ""
+
+#: service_internal.c:1042
+msgid "creationTime"
+msgstr ""
+
+#: service_internal.c:1047
+msgid "ProcessSucceeded"
+msgstr ""
+
+#: service_internal.c:1048
+#, c-format
+msgid "Service \"%s\" run successfully."
+msgstr ""
+
+#: service_internal.c:1053
+msgid "ProcessStarted"
+msgstr ""
+
+#: service_internal.c:1055
+msgid "percentCompleted"
+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 ""
+
+#: service_internal.c:1061
+msgid "ProcessAccepted"
+msgstr ""
+
+#: 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_internal.c:1067
+msgid "ProcessFailed"
+msgstr ""
+
+#: service_internal.c:1070 service_internal.c:1072 service_internal.c:1074
+#: service_internal.c:1419 service_internal.c:1472 service_internal.c:1547
+#: service_internal.c:1591 zoo_service_loader.c:1368
+msgid "code"
+msgstr ""
+
+#: service_internal.c:1074 service_internal.c:1423 service_internal.c:1476
+msgid "NoApplicableCode"
+msgstr ""
+
+#: service_internal.c:1075 service_internal.c:1585
+msgid "message"
+msgstr ""
+
+#: service_internal.c:1077 service_internal.c:1079 service_internal.c:1425
+#: service_internal.c:1478 service_internal.c:1546 service_internal.c:1590
+#: zoo_service_loader.c:1367 zoo_service_loader.c:1608
+#: zoo_service_loader.c:1652 zoo_service_loader.c:1830
+#: zoo_service_loader.c:1872
+msgid "text"
+msgstr ""
+
+#: service_internal.c:1079
+msgid "No more information available"
+msgstr ""
+
+#: service_internal.c:1084
+#, c-format
+msgid "error code not know : %i\n"
+msgstr ""
+
+#: service_internal.c:1093
+#, c-format
+msgid "printProcessResponse 1 161\n"
+msgstr ""
+
+#: service_internal.c:1096 zoo_service_loader.c:1157
+msgid "lineage"
+msgstr ""
+
+#: service_internal.c:1110
+#, c-format
+msgid "printProcessResponse 1 177\n"
+msgstr ""
+
+#: service_internal.c:1113
+msgid "OutputDefinitions"
+msgstr ""
+
+#: service_internal.c:1124
+#, c-format
+msgid "printProcessResponse 1 190\n"
+msgstr ""
+
+#: service_internal.c:1142
+#, c-format
+msgid "printProcessResponse 1 202\n"
+msgstr ""
+
+#: service_internal.c:1156 service_internal.c:1401 service_internal.c:1404
+#: service_internal.c:1406
+#, c-format
+msgid ""
+"Content-Type: text/xml; charset=%s\r\n"
+"Status: 200 OK\r\n"
+"\r\n"
+msgstr ""
+
+#: service_internal.c:1190
+msgid "MIMETYPE"
+msgstr ""
+
+#: service_internal.c:1191
+msgid "ENCODING"
+msgstr ""
+
+#: service_internal.c:1192
+msgid "SCHEMA"
+msgstr ""
+
+#: service_internal.c:1193
+msgid "UOM"
+msgstr ""
+
+#: service_internal.c:1245 service_internal.c:1342 zoo_service_loader.c:308
+#: zoo_service_loader.c:343 zoo_service_loader.c:427 zoo_service_loader.c:783
+#: zoo_service_loader.c:1212 zoo_service_loader.c:1318
+#: zoo_service_loader.c:1515 zoo_service_loader.c:1562
+#: zoo_service_loader.c:1757 zoo_service_loader.c:1801
+msgid "Identifier"
+msgstr ""
+
+#: service_internal.c:1268
+#, c-format
+msgid "FORMAT %s %s\n"
+msgstr ""
+
+#: service_internal.c:1270 service_internal.c:1319 service_internal.c:1521
+#: zoo_service_loader.c:828
+msgid "Reference"
+msgstr ""
+
+#: service_internal.c:1272 zoo_service_loader.c:1031
+msgid "Data"
+msgstr ""
+
+#: service_internal.c:1273
+msgid "LITERALOUTPUT"
+msgstr ""
+
+#: service_internal.c:1276
+msgid "COMPLEXOUTPUT"
+msgstr ""
+
+#: service_internal.c:1277 zoo_service_loader.c:1066
+msgid "ComplexData"
+msgstr ""
+
+#: service_internal.c:1286 service_internal.c:1328 zoo_service_loader.c:1156
+#: zoo_service_loader.c:1438
+msgid "storeExecuteResponse"
+msgstr ""
+
+#: service_internal.c:1292 service_internal.c:1294 service_internal.c:1553
+#: zoo_service_loader.c:839 zoo_service_loader.c:1072
+#: zoo_service_loader.c:1185 zoo_service_loader.c:1285
+msgid "mimeType"
+msgstr ""
+
+#: service_internal.c:1296
+msgid "base64"
+msgstr ""
+
+#: service_internal.c:1297
+msgid "image/"
+msgstr ""
+
+#: service_internal.c:1298
+msgid "application/"
+msgstr ""
+
+#: service_internal.c:1299 service_internal.c:1573
+msgid "size"
+msgstr ""
+
+#: service_internal.c:1302
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: service_internal.c:1303
+msgid "z"
+msgstr ""
+
+#: service_internal.c:1308
+msgid "text/js"
+msgstr ""
+
+#: service_internal.c:1309
+msgid "application/js"
+msgstr ""
+
+#: service_internal.c:1326
+msgid "abstract"
+msgstr ""
+
+#: service_internal.c:1347 zoo_service_loader.c:799 zoo_service_loader.c:1231
+msgid "Title"
+msgstr ""
+
+#: service_internal.c:1348 zoo_service_loader.c:800 zoo_service_loader.c:1232
+msgid "Abstract"
+msgstr ""
+
+#: service_internal.c:1367 service_internal.c:1370 zoo_service_loader.c:929
+msgid "UTF-8"
+msgstr ""
+
+#: service_internal.c:1409 service_internal.c:1457
+msgid "ExceptionReport"
+msgstr ""
+
+#: service_internal.c:1413
+msgid "xsi:schemaLocation"
+msgstr ""
+
+#: service_internal.c:1413 service_internal.c:1465
+msgid ""
+"http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/"
+"owsExceptionReport.xsd"
+msgstr ""
+
+#: service_internal.c:1415 service_internal.c:1468
+msgid "1.1.0"
+msgstr ""
+
+#: service_internal.c:1417 service_internal.c:1470
+msgid "Exception"
+msgstr ""
+
+#: service_internal.c:1421 service_internal.c:1423 service_internal.c:1474
+#: service_internal.c:1476
+msgid "exceptionCode"
+msgstr ""
+
+#: service_internal.c:1426 service_internal.c:1479
+msgid "ExceptionText"
+msgstr ""
+
+#: service_internal.c:1432 service_internal.c:1485
+msgid "No debug message available"
+msgstr ""
+
+#: service_internal.c:1498
+#, c-format
+msgid "printProcessResponse\n"
+msgstr ""
+
+#: service_internal.c:1500 zoo_service_loader.c:491 zoo_service_loader.c:1277
+msgid "RawDataOutput"
+msgstr ""
+
+#: service_internal.c:1507
+#, c-format
+msgid "REQUEST_OUTPUTS FINAL\n"
+msgstr ""
+
+#: service_internal.c:1513 zoo_service_loader.c:1683
+msgid "tmpPath"
+msgstr ""
+
+#: service_internal.c:1515
+#, c-format
+msgid "%s/%s_%i.%s"
+msgstr ""
+
+#: service_internal.c:1516
+msgid "w"
+msgstr ""
+
+#: service_internal.c:1520
+#, c-format
+msgid "%s/%s/%s_%i.%s"
+msgstr ""
+
+#: service_internal.c:1529
+msgid "serviceProvider"
+msgstr ""
+
+#: service_internal.c:1531
+#, c-format
+msgid "SERVICE : %s\n"
+msgstr ""
+
+#: service_internal.c:1546
+msgid "Unable to fetch any result"
+msgstr ""
+
+#: service_internal.c:1547 service_internal.c:1591 zoo_service_loader.c:120
+#: zoo_service_loader.c:147 zoo_service_loader.c:280 zoo_service_loader.c:367
+#: zoo_service_loader.c:420 zoo_service_loader.c:519 zoo_service_loader.c:530
+#: 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 zoo_service_loader.c:1700
+msgid "InternalError"
+msgstr ""
+
+#: service_internal.c:1555 service_internal.c:1557
+#, c-format
+msgid "SERVICE OUTPUTS\n"
+msgstr ""
+
+#: service_internal.c:1562
+#, c-format
+msgid ""
+"Content-Type: %s; charset=%s\r\n"
+"Status: 200 OK\r\n"
+"\r\n"
+msgstr ""
+
+#: service_internal.c:1567
+#, c-format
+msgid ""
+"Content-Type: %s; charset=UTF-8\r\n"
+"Status: 200 OK\r\n"
+"\r\n"
+msgstr ""
+
+#: service_internal.c:1570
+#, c-format
+msgid ""
+"Content-Type: text/plain; charset=utf-8\r\n"
+"Status: 200 OK\r\n"
+"\r\n"
+msgstr ""
+
+#: service_internal.c:1572
+msgid "image"
+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 ""
+
+#: service_internal.c:1589
+#, c-format
+msgid ""
+"Unable to run the Service. No more information was returned back by the "
+"Service."
+msgstr ""
+
+#: service_internal.c:1616
+#, c-format
+msgid "BASE64 [%s] \n"
+msgstr ""
+
+#: service_internal.c:1627 zoo_service_loader.c:1363
+msgid "inputs"
+msgstr ""
+
+#: service_internal.c:1642
+msgid "NULL"
+msgstr ""
+
+#: service_internal.c:1660
+#, c-format
+msgid "addDefaultValues %s => %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:27 zoo_service_loader.c:28 zoo_service_loader.c:31
+#: zoo_service_loader.c:1470 zoo_service_loader.c:1723
+msgid "C"
+msgstr ""
+
+#: zoo_service_loader.c:98
+msgid "SIGSEGV"
+msgstr ""
+
+#: zoo_service_loader.c:101
+msgid "SIGTERM"
+msgstr ""
+
+#: zoo_service_loader.c:104
+msgid "SIGINT"
+msgstr ""
+
+#: zoo_service_loader.c:107
+msgid "SIGILL"
+msgstr ""
+
+#: zoo_service_loader.c:110
+msgid "SIGFPE"
+msgstr ""
+
+#: zoo_service_loader.c:113
+msgid "SIGABRT"
+msgstr ""
+
+#: zoo_service_loader.c:116
+msgid "UNKNOWN"
+msgstr ""
+
+#: zoo_service_loader.c:119
+#, c-format
+msgid "ZOO Kernel failed to process your request receiving signal %d = %s"
+msgstr ""
+
+#: zoo_service_loader.c:122
+#, c-format
+msgid "Not this time!\n"
+msgstr ""
+
+#: 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 ""
+
+#: zoo_service_loader.c:155 zoo_service_loader.c:158 zoo_service_loader.c:160
+#: zoo_service_loader.c:165 zoo_service_loader.c:243 zoo_service_loader.c:1471
+#: zoo_service_loader.c:1725
+msgid "metapath"
+msgstr ""
+
+#: zoo_service_loader.c:162
+#, c-format
+msgid "ADD METAPATH\n"
+msgstr ""
+
+#: zoo_service_loader.c:168
+#, c-format
+msgid "%s/%s/main.cfg"
+msgstr ""
+
+#: zoo_service_loader.c:171
+#, c-format
+msgid "***** BEGIN MAPS\n"
+msgstr ""
+
+#: zoo_service_loader.c:173
+#, c-format
+msgid "***** END MAPS\n"
+msgstr ""
+
+#: zoo_service_loader.c:179
+msgid "Request"
+msgstr ""
+
+#: zoo_service_loader.c:181
+msgid "Parameter <request> was not specified"
+msgstr ""
+
+#: zoo_service_loader.c:181 zoo_service_loader.c:201 zoo_service_loader.c:210
+#: zoo_service_loader.c:311 zoo_service_loader.c:606 zoo_service_loader.c:1368
+msgid "MissingParameterValue"
+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 ""
+
+#: zoo_service_loader.c:191 zoo_service_loader.c:257 zoo_service_loader.c:322
+#: zoo_service_loader.c:402 zoo_service_loader.c:442
+msgid "InvalidParameterValue"
+msgstr ""
+
+#: zoo_service_loader.c:199
+msgid "Service"
+msgstr ""
+
+#: zoo_service_loader.c:201
+msgid "Parameter <service> was not specified"
+msgstr ""
+
+#: zoo_service_loader.c:208
+msgid "Version"
+msgstr ""
+
+#: zoo_service_loader.c:210
+msgid "Parameter <version> was not specified"
+msgstr ""
+
+#: zoo_service_loader.c:218 zoo_service_loader.c:220
+msgid "serviceprovider"
+msgstr ""
+
+#: zoo_service_loader.c:257
+msgid "The specified path doesn't exist."
+msgstr ""
+
+#: zoo_service_loader.c:275
+msgid ".zcfg"
+msgstr ""
+
+#: zoo_service_loader.c:283 zoo_service_loader.c:370
+#, c-format
+msgid ""
+"#################\n"
+"%s\n"
+"#################\n"
+msgstr ""
+
+#: zoo_service_loader.c:311
+msgid "Mandatory <identifier> was not specified"
+msgstr ""
+
+#: zoo_service_loader.c:322
+msgid "The specified path path doesn't exist."
+msgstr ""
+
+#: zoo_service_loader.c:355
+#, c-format
+msgid "%s.zcfg"
+msgstr ""
+
+#: zoo_service_loader.c:358
+#, c-format
+msgid ""
+"\n"
+"#######%s\n"
+"########\n"
+msgstr ""
+
+#: zoo_service_loader.c:404
+#, c-format
+msgid "No request found %s"
+msgstr ""
+
+#: zoo_service_loader.c:422
+msgid "MetaPath"
+msgstr ""
+
+#: zoo_service_loader.c:429
+#, c-format
+msgid "%s/%s.zcfg"
+msgstr ""
+
+#: zoo_service_loader.c:432 zoo_service_loader.c:1481
+#: zoo_service_loader.c:1737
+#, c-format
+msgid "Trying to load %s\n"
+msgstr ""
+
+#: 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 ""
+
+#: zoo_service_loader.c:470 zoo_service_loader.c:974
+msgid "ZooWPSClient"
+msgstr ""
+
+#: zoo_service_loader.c:476 zoo_service_loader.c:978
+#, c-format
+msgid "WARNING : hInternet handle failed to initialize"
+msgstr ""
+
+#: zoo_service_loader.c:481
+msgid "xrequest"
+msgstr ""
+
+#: zoo_service_loader.c:488 zoo_service_loader.c:494
+#, c-format
+msgid "OUTPUT Parsing ... \n"
+msgstr ""
+
+#: zoo_service_loader.c:490 zoo_service_loader.c:1135
+msgid "ResponseDocument"
+msgstr ""
+
+#: zoo_service_loader.c:498
+#, c-format
+msgid "OUTPUT Parsing start now ... \n"
+msgstr ""
+
+#: zoo_service_loader.c:514
+#, c-format
+msgid "OUTPUT [%s]\n"
+msgstr ""
+
+#: zoo_service_loader.c:516 zoo_service_loader.c:533 zoo_service_loader.c:620
+#: zoo_service_loader.c:639
+msgid ";"
+msgstr ""
+
+#: zoo_service_loader.c:519 zoo_service_loader.c:530
+msgid "Unable to allocate memory"
+msgstr ""
+
+#: zoo_service_loader.c:524 zoo_service_loader.c:526 zoo_service_loader.c:572
+#: zoo_service_loader.c:628 zoo_service_loader.c:632
+#, c-format
+msgid "***%s***\n"
+msgstr ""
+
+#: zoo_service_loader.c:540 zoo_service_loader.c:574 zoo_service_loader.c:647
+#: zoo_service_loader.c:670 zoo_service_loader.c:716
+msgid "@"
+msgstr ""
+
+#: zoo_service_loader.c:555 zoo_service_loader.c:652 zoo_service_loader.c:675
+msgid "="
+msgstr ""
+
+#: zoo_service_loader.c:561
+#, c-format
+msgid "OUTPUT DEF [%s]=[%s]\n"
+msgstr ""
+
+#: zoo_service_loader.c:599
+#, c-format
+msgid "DATA INPUTS [%s]\n"
+msgstr ""
+
+#: zoo_service_loader.c:606
+msgid "Parameter <DataInputs> was not specified"
+msgstr ""
+
+#: zoo_service_loader.c:650
+#, c-format
+msgid ""
+"***\n"
+"***%s***\n"
+msgstr ""
+
+#: zoo_service_loader.c:659
+#, c-format
+msgid ""
+"***\n"
+"*** %s = %s ***\n"
+msgstr ""
+
+#: zoo_service_loader.c:673
+#, c-format
+msgid ""
+"*** KVP NON URL-ENCODED \n"
+"***%s***\n"
+msgstr ""
+
+#: zoo_service_loader.c:677 zoo_service_loader.c:685
+#, c-format
+msgid ""
+"*** VALUE NON URL-ENCODED \n"
+"***%s***\n"
+msgstr ""
+
+#: zoo_service_loader.c:684
+#, c-format
+msgid ""
+"*** NAME NON URL-ENCODED \n"
+"***%s***\n"
+msgstr ""
+
+#: zoo_service_loader.c:687
+msgid "xlink:href"
+msgstr ""
+
+#: zoo_service_loader.c:691
+#, c-format
+msgid "REQUIRE TO DOWNLOAD A FILE FROM A SERVER : url(%s)\n"
+msgstr ""
+
+#: zoo_service_loader.c:700
+#, c-format
+msgid "(%s) content-length : %d,,res.nDataAlloc %d \n"
+msgstr ""
+
+#: zoo_service_loader.c:745
+#, c-format
+msgid "BEFORE %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:751
+#, c-format
+msgid "AFTER\n"
+msgstr ""
+
+#: zoo_service_loader.c:759
+msgid "/*/*/*[local-name()='Input']"
+msgstr ""
+
+#: zoo_service_loader.c:762 zoo_service_loader.c:1132
+#: zoo_service_loader.c:1274
+#, c-format
+msgid "*****%d*****\n"
+msgstr ""
+
+#: zoo_service_loader.c:772
+#, c-format
+msgid "= element 0 node \"%s\"\n"
+msgstr ""
+
+#: zoo_service_loader.c:808 zoo_service_loader.c:1240
+msgid "missingIndetifier"
+msgstr ""
+
+#: zoo_service_loader.c:835
+#, c-format
+msgid "REFERENCE\n"
+msgstr ""
+
+#: zoo_service_loader.c:841 zoo_service_loader.c:1074
+#: zoo_service_loader.c:1187 zoo_service_loader.c:1287
+msgid "schema"
+msgstr ""
+
+#: zoo_service_loader.c:842 zoo_service_loader.c:855
+msgid "method"
+msgstr ""
+
+#: zoo_service_loader.c:847
+#, c-format
+msgid "*** %s ***"
+msgstr ""
+
+#: zoo_service_loader.c:857
+msgid "POST"
+msgstr ""
+
+#: zoo_service_loader.c:875 zoo_service_loader.c:909 zoo_service_loader.c:1061
+#: zoo_service_loader.c:1087 zoo_service_loader.c:1173
+#: zoo_service_loader.c:1202 zoo_service_loader.c:1308
+#: zoo_service_loader.c:1507
+#, c-format
+msgid "%s\n"
+msgstr ""
+
+#: zoo_service_loader.c:880
+#, c-format
+msgid "Parse Header and Body from Reference \n"
+msgstr ""
+
+#: zoo_service_loader.c:885
+msgid "Header"
+msgstr ""
+
+#: zoo_service_loader.c:889
+msgid "key"
+msgstr ""
+
+#: zoo_service_loader.c:897
+#, c-format
+msgid "%s = %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:907
+#, c-format
+msgid "%s: %s"
+msgstr ""
+
+#: zoo_service_loader.c:918
+#, c-format
+msgid "Try to fetch the body part of the request ...\n"
+msgstr ""
+
+#: zoo_service_loader.c:920
+msgid "Body"
+msgstr ""
+
+#: zoo_service_loader.c:922
+#, c-format
+msgid "Body part found !!!\n"
+msgstr ""
+
+#: zoo_service_loader.c:935
+#, c-format
+msgid "Body part found !!! %s %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:945 zoo_service_loader.c:997
+#, c-format
+msgid "%s %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:962 zoo_service_loader.c:1015
+#, c-format
+msgid "DL CONTENT : (%s)\n"
+msgstr ""
+
+#: zoo_service_loader.c:967
+msgid "BodyReference"
+msgstr ""
+
+#: zoo_service_loader.c:1023
+#, c-format
+msgid "Header and Body was parsed from Reference \n"
+msgstr ""
+
+#: zoo_service_loader.c:1027
+#, c-format
+msgid "= element 2 node \"%s\" = (%s)\n"
+msgstr ""
+
+#: zoo_service_loader.c:1033
+#, c-format
+msgid "DATA\n"
+msgstr ""
+
+#: zoo_service_loader.c:1047
+msgid "dataType"
+msgstr ""
+
+#: zoo_service_loader.c:1048 zoo_service_loader.c:1188
+#: zoo_service_loader.c:1288
+msgid "uom"
+msgstr ""
+
+#: zoo_service_loader.c:1051
+#, c-format
+msgid "*** LiteralData %s ***"
+msgstr ""
+
+#: zoo_service_loader.c:1077
+#, c-format
+msgid "*** ComplexData %s ***"
+msgstr ""
+
+#: zoo_service_loader.c:1099
+#, c-format
+msgid "cur2 next \n"
+msgstr ""
+
+#: zoo_service_loader.c:1105
+#, c-format
+msgid "ADD MAPS TO REQUEST MAPS !\n"
+msgstr ""
+
+#: zoo_service_loader.c:1111
+#, c-format
+msgid "******TMPMAPS*****\n"
+msgstr ""
+
+#: zoo_service_loader.c:1113
+#, c-format
+msgid "******REQUESTMAPS*****\n"
+msgstr ""
+
+#: zoo_service_loader.c:1125
+#, c-format
+msgid "Search for response document node\n"
+msgstr ""
+
+#: zoo_service_loader.c:1129
+msgid "/*/*/*[local-name()='ResponseDocument']"
+msgstr ""
+
+#: zoo_service_loader.c:1148 zoo_service_loader.c:1300
+msgid "unknownIdentifier"
+msgstr ""
+
+#: zoo_service_loader.c:1162 zoo_service_loader.c:1192
+#: zoo_service_loader.c:1291
+#, c-format
+msgid "*** %s ***\t"
+msgstr ""
+
+#: zoo_service_loader.c:1271
+msgid "/*/*/*[local-name()='RawDataOutput']"
+msgstr ""
+
+#: zoo_service_loader.c:1353
+#, c-format
+msgid ""
+"\n"
+"%i\n"
+msgstr ""
+
+#: 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 ""
+
+#: zoo_service_loader.c:1383
+msgid "outputs"
+msgstr ""
+
+#: zoo_service_loader.c:1386
+#, c-format
+msgid "REQUEST_INPUTS\n"
+msgstr ""
+
+#: zoo_service_loader.c:1388
+#, c-format
+msgid "REQUEST_OUTPUTS\n"
+msgstr ""
+
+#: zoo_service_loader.c:1392
+msgid "env"
+msgstr ""
+
+#: zoo_service_loader.c:1400 zoo_service_loader.c:1423
+#, c-format
+msgid "[ZOO: setenv (%s=%s)]\n"
+msgstr ""
+
+#: zoo_service_loader.c:1404
+#, c-format
+msgid "[ZOO: Env var finish with \r]\n"
+msgstr ""
+
+#: zoo_service_loader.c:1410
+#, c-format
+msgid "setting variable... %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:1414
+msgid "OK"
+msgstr ""
+
+#: zoo_service_loader.c:1414
+msgid "FAILED"
+msgstr ""
+
+#: zoo_service_loader.c:1448
+msgid "0"
+msgstr ""
+
+#: zoo_service_loader.c:1465 zoo_service_loader.c:1504
+#: zoo_service_loader.c:1718 zoo_service_loader.c:1752
+msgid "serviceType"
+msgstr ""
+
+#: zoo_service_loader.c:1467
+#, c-format
+msgid "LOAD A %s SERVICE PROVIDER IN NORMAL MODE \n"
+msgstr ""
+
+#: zoo_service_loader.c:1492
+#, c-format
+msgid "%s loaded (%d) \n"
+msgstr ""
+
+#: zoo_service_loader.c:1501 zoo_service_loader.c:1799
+#, c-format
+msgid "Library loaded %s \n"
+msgstr ""
+
+#: zoo_service_loader.c:1502
+#, c-format
+msgid "Service Shared Object = %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:1510 zoo_service_loader.c:1756
+msgid "C-FORTRAN"
+msgstr ""
+
+#: zoo_service_loader.c:1517 zoo_service_loader.c:1763
+#, c-format
+msgid "%s_"
+msgstr ""
+
+#: zoo_service_loader.c:1519 zoo_service_loader.c:1564
+#: zoo_service_loader.c:1759 zoo_service_loader.c:1765
+#: zoo_service_loader.c:1803
+#, c-format
+msgid "Try to load function %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:1534 zoo_service_loader.c:1583
+#: zoo_service_loader.c:1816
+#, c-format
+msgid "Function loaded %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:1552
+#, c-format
+msgid "Function run successfully \n"
+msgstr ""
+
+#: zoo_service_loader.c:1559 zoo_service_loader.c:1571
+#, c-format
+msgid "Function %s failed to load because of %d\n"
+msgstr ""
+
+#: zoo_service_loader.c:1587
+#, c-format
+msgid "Now run the function \n"
+msgstr ""
+
+#: zoo_service_loader.c:1592 zoo_service_loader.c:1889
+#, c-format
+msgid "Function loaded and returned %d\n"
+msgstr ""
+
+#: zoo_service_loader.c:1607 zoo_service_loader.c:1829
+#, c-format
+msgid "C Library can't be loaded %s \n"
+msgstr ""
+
+#: zoo_service_loader.c:1615 zoo_service_loader.c:1839
+msgid "PYTHON"
+msgstr ""
+
+#: zoo_service_loader.c:1622 zoo_service_loader.c:1844
+msgid "JAVA"
+msgstr ""
+
+#: zoo_service_loader.c:1629 zoo_service_loader.c:1851
+msgid "PHP"
+msgstr ""
+
+#: zoo_service_loader.c:1637 zoo_service_loader.c:1858
+msgid "PERL"
+msgstr ""
+
+#: zoo_service_loader.c:1644 zoo_service_loader.c:1864
+msgid "JS"
+msgstr ""
+
+#: 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 ""
+
+#: zoo_service_loader.c:1661
+#, c-format
+msgid ""
+"\n"
+"PID : %d\n"
+msgstr ""
+
+#: zoo_service_loader.c:1675
+#, c-format
+msgid "father pid continue (origin %d) %d ...\n"
+msgstr ""
+
+#: zoo_service_loader.c:1686
+#, c-format
+msgid "%s/%s_%d.xml"
+msgstr ""
+
+#: zoo_service_loader.c:1688
+#, c-format
+msgid "%s/%s_%d_error.log"
+msgstr ""
+
+#: zoo_service_loader.c:1690
+#, c-format
+msgid "RUN IN BACKGROUND MODE \n"
+msgstr ""
+
+#: zoo_service_loader.c:1691
+#, c-format
+msgid "son pid continue (origin %d) %d ...\n"
+msgstr ""
+
+#: zoo_service_loader.c:1692
+#, c-format
+msgid ""
+"\n"
+"FILE TO STORE DATA %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:1694 zoo_service_loader.c:1696
+msgid "w+"
+msgstr ""
+
+#: zoo_service_loader.c:1700
+msgid "Unable to run the child process properly"
+msgstr ""
+
+#: zoo_service_loader.c:1720
+#, c-format
+msgid "LOAD A %s SERVICE PROVIDER IN BACKGROUND MODE \n"
+msgstr ""
+
+#: zoo_service_loader.c:1754
+#, c-format
+msgid "r_inputs->value = %s\n"
+msgstr ""
+
+#: zoo_service_loader.c:1918
+#, c-format
+msgid "Processed response \n"
+msgstr ""
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main.cfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main.cfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main.cfg	(revision 417)
@@ -0,0 +1,30 @@
+[main]
+encoding = utf-8
+version = 1.0.0
+serverAddress = http://www.zoo-project.org/zoo/
+lang = fr-FR,en-CA
+tmpPath=/YourFullTmpPathHere/
+tmpUrl = ../TmpPathRelativeToServerAdress/
+dataPath = /YouFullDataPathHere/
+
+[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=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@geolabs.fr
+phoneVoice=False
+phoneFacsimile=False
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main_conf_read.l
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main_conf_read.l	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main_conf_read.l	(revision 417)
@@ -0,0 +1,119 @@
+/* Line number from bison */
+%option yylineno
+
+%{
+//======================================================
+/**
+Zoo main configuration file parser
+**/
+//======================================================
+
+
+#include <string.h>
+#include "main_conf_read.tab.h"
+static int affichetrace = 0 ;
+static int attentionImpossibleDeTrouverXMLDeclapres = 0 ;
+static int attentionImpossibleDeTrouverPIapres = 0 ;
+
+%}
+
+
+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	[%\*,;@a-zA-Z0-9_\-.:" "\"\'/\\\(\)\+\x41-\xff]+
+
+attvalue		\"[^"]*\"|\'[^']*\'
+
+virgule	[,]+
+
+whitespace                      [ ]{0,}
+whitesp                      [ ]
+newline                 [\r\n]|[\n]
+newlines                 [\r\n]{1,}|[\n]{1,}
+
+
+
+%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;}
+
+<INITIAL>"<?"[Xx][Mm][Ll]  { if (attentionImpossibleDeTrouverXMLDeclapres == 1 || attentionImpossibleDeTrouverPIapres == 1) { printf("\nerror : LINE %d : comment ot PI before xml declaration\n",yylineno); exit (10) ; } ; if (affichetrace==1) printf ("\n\nSTARTXMLDECL:%s\n",yytext) ;return STARTXMLDECL;}
+
+<INITIAL>"version"{egalevolue}\"1.0\"|"version"{egalevolue}\'1.0\'  {if (affichetrace==1) printf ("\n\nVERSIONDECL:%s\n",yytext) ;return VERSIONDECL;}
+<INITIAL>"version"{egalevolue}\"[^"]*\"|"version"{egalevolue}\'[^']*\'  {/* erreur de version encoding */ 	printf("\nerror : LINE %d : XML Version not supported : %s\n",yylineno,yytext); exit (9) ; }
+
+
+<INITIAL>"encoding"{egalevolue}\"[Ii][Ss][Oo]"-8859-1"\"|"encoding"{egalevolue}\'[Ii][Ss][Oo]"-8859-1"\'  {if (affichetrace==1) printf ("\n\nENCODINGDECL:%s\n",yytext) ; return ENCODINGDECL;}
+<INITIAL>"encoding"{egalevolue}\"[^"]*\"|"encoding"{egalevolue}\'[^']*\'  {/* erreur de version encoding */ 	printf("\nerror : LINE %d : encoding version not supported : %s\n",yylineno,yytext); exit (8) ; }
+
+
+<INITIAL>"standalone"{egalevolue}\"yes\"|"standalone"{egalevolue}\'yes\'|"standalone"{egalevolue}\"no\"|"standalone"{egalevolue}\'no\'  {if (affichetrace==1) printf ("\n\nSDDECL:%s\n",yytext) ; return SDDECL;}
+
+<INITIAL>"standalone"{egalevolue}\"[^"]*\"|"standalone"{egalevolue}\'[^']*\'|"standalone"{egalevolue}\"[^"]*\"|"standalone"{egalevolue}\'[^']*\'  {/* erreur de version encoding */ 	printf("\nerror : LINE %d : standalone version not supported : %s\n",yylineno,yytext); exit (7) ; }
+
+
+<INITIAL>"?>"  {if (affichetrace==1) printf ("\n\nENDXMLDECL:%s\n",yytext) ; BEGIN(HORSBALISE);return ENDXMLDECL;}
+
+
+<DANSBALISE,INITIAL,HORSBALISE>{S}   {if (affichetrace==1) printf ("\n\nS:'%s'\n",yytext) ; }
+
+
+<HORSBALISE>"<?"[Xx][Mm][Ll]{S}({S}|{chardata})*"?>"|"<?"[Xx][Mm][Ll]"?>"	{if (affichetrace==1) printf ("\n\nPIERROR:%s\n",yytext) ; return PIERROR;}
+<INITIAL,HORSBALISE>"<?"([^xX]|([xX][^mM])|([xX][mM][^lL]))({S}|([^?]|("?"[^>])))*"?>"		{attentionImpossibleDeTrouverPIapres=1 ;  if (affichetrace==1) printf ("\n\nPI:%s\n",yytext) ; return PI;}
+
+
+<INITIAL,HORSBALISE>{newline}*"<"		    {if (affichetrace==1) printf ("\n\nINFCAR:%s\n",yytext) ; BEGIN(DANSBALISE);return INFCAR;}
+
+
+<DANSBALISE>">"			{if (affichetrace==1) printf ("\n\nSUPCAR:%s\n",yytext) ; BEGIN(HORSBALISE);return SUPCAR;}
+
+
+<DANSBALISE>"/"		{if (affichetrace==1) printf ("\n\nSLASH:%s\n",yytext) ; return SLASH;}
+
+
+<DANSBALISE>{egalevolue}			{if (affichetrace==1) printf ("\n\nEq:'%s'\n",yytext) ; return Eq;}
+
+
+<DANSBALISE>{Name}			{if (affichetrace==1) printf ("\n\nID:%s\n",yytext) ; crlval.s=yytext;return ID;}
+
+
+<DANSBALISE>{attvalue}		{if (affichetrace==1) printf ("\n\nATTVALUE:%s\n",yytext) ; return ATTVALUE;}
+
+
+<INITIAL,HORSBALISE>"<!--"([^-]|"-"[^-])*"-->"		{attentionImpossibleDeTrouverXMLDeclapres=1; }
+
+
+<INITIAL,DANSBALISE,HORSBALISE>.|\n	{if (affichetrace==1)printf("error : LINE %d : character not supported '%s'\n",yylineno,yytext); }
+
+%%
+
+
+int crwrap()
+{return 1;}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main_conf_read.y
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main_conf_read.y	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/main_conf_read.y	(revision 417)
@@ -0,0 +1,342 @@
+%{
+//======================================================
+/**
+   Zoo main configuration file parser
+**/
+//======================================================
+
+#include <string>
+#include <stdio.h>
+#include <ctype.h>
+#include <service.h>
+#include <vector>
+
+static int defaultsc=0;
+static maps* my_maps=NULL;
+static maps* current_maps=NULL;
+static map* previous_content=NULL;
+static map* current_content=NULL;
+static elements* current_element=NULL;
+static map* scontent=NULL;
+static char* curr_key;
+static int debug=0;
+static int previous_data=0;
+static int current_data=0;
+using namespace std;
+
+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);
+
+%}
+
+
+
+//======================================================
+/* le type des lval des jetons et des elements non terminaux bison */
+//======================================================
+%union { char* s;char* chaine; char* key;char* val;}
+//======================================================
+
+// jetons //
+//======================================================
+/* les jetons que l on retrouve dans FLEX */
+//======================================================
+/* texte on a besoin de récupérer une valeur char* pour la comparer */
+%token <s> ID
+%token <s> CHAINE
+/* STARTXMLDECL et ENDXMLDECL qui sont <?xml et ?>*/
+%token STARTXMLDECL ENDXMLDECL
+//======================================================
+/* version="xxx" et encoding="xxx" */
+%token VERSIONDECL ENCODINGDECL SDDECL
+//======================================================
+/* < et > */
+%token INFCAR SUPCAR 
+//======================================================
+/* / = a1  texte "texte" */
+%token SLASH Eq CHARDATA ATTVALUE PAIR SPAIR EPAIR EPAIRS ANID
+%type <chaine> PAIR
+%type <chaine> EPAIRS
+%type <chaine> EPAIR
+%type <chaine> SPAIR
+
+//======================================================
+/* <!-- xxx -> <? xxx yyy ?> */
+%token PI PIERROR /** COMMENT **/
+//======================================================
+/* <!-- xxx -> <? xxx yyy ?> */
+%token ERREURGENERALE CDATA WHITESPACE NEWLINE
+//======================================================
+// non terminaux typés
+//======================================================
+/* elements non terminaux de type char *     */
+/* uniquement ceux qui devrons etre comparés */
+//======================================================
+%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 {crerror("processing instruction begining 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	
+{
+  /* les non terminaux rendent les valeurs de leur identifiants de balise */
+  /* en char*, donc on peut comparer ces valeurs avec la fonction C++ strcmp(const char*;const char*) */
+  /* de string */
+  if (strcmp($1,$3) != 0)
+    {
+      crerror("Opening and ending tag mismatch");
+      printf("\n  ::details : tag '%s' et '%s' \n",$1,$3);
+      return 1;
+      // on retourne different de 0
+      // sinon yyparse rendra 0
+      // et dans le main on croira a le fichier xml est valide !
+    }
+}
+// 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
+	printf("* Identifiant : %s\n",$2);
+#endif
+	
+	$$ = $2 ;
+}
+ ;
+//======================================================
+// 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		
+{
+	// on verifie que les attributst ne sont pas en double
+	// sinon on ajoute au vector
+}
+ ;
+//======================================================
+// 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	{}
+ ;
+//======================================================
+// ETag
+//======================================================
+// regle 42
+// BALISE FERMANTE
+// les separateurs après ID sont filtrés
+//======================================================
+ETag
+ : INFCAR SLASH ID SUPCAR
+{
+  /* on renvoie l'identifiant de la balise pour pouvoir comparer les 2 */
+  /* /!\ une balise fermante n'a pas d'attributs (c.f. : W3C) */
+  $$ = $3;
+}
+ ;
+//======================================================
+// 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	          {crerror("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 {curr_key=strdup($1);/*printf("START 0 PAIR FOUND !! \n [%s]\n",$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);
+  }
+| SPAIR  {curr_key=strdup($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=(maps*)malloc(MAPS_SIZE);
+     current_maps->next->name=strdup($1);
+     current_maps->next->content=NULL;
+     current_maps->next->next=NULL;
+     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;
+   }
+ }
+ ;
+
+%%
+
+// crerror
+//======================================================
+/* fonction qui affiche l erreur si il y en a une */
+//======================================================
+void crerror(const char *s)
+{
+  if(debug)
+    printf("\nligne %d : %s\n",crlineno,s);
+}
+
+// main
+//======================================================
+/* fonction principale : entrée dans le programme */
+//======================================================
+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);
+  }
+
+  fclose(crin);
+#ifndef WIN32
+  crlex_destroy();
+#endif
+
+  return resultatYYParse;
+}
+
+
+//======================================================
+// FIN //
+//======================================================
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/makefile.vc	(revision 417)
@@ -0,0 +1,67 @@
+# 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:  zoo_loader.cgi
+
+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
+
+service_internal.obj: service_internal.c
+	$(CPP) $(CFLAGS) /c service_internal.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_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
+
+dirent.obj:
+	$(CPP) /EHsc /c $(CFLAGS) ..\..\thirds\dirent-win32\dirent.c
+
+zoo_loader.cgi: zoo_loader.obj zoo_service_loader.obj service_internal.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) ulinet.obj lex.cr.obj lex.sr.obj service_conf.tab.obj main_conf_read.tab.obj dirent.obj
+	link zoo_loader.obj dirent.obj service_internal.obj $(PY_FILE) $(JAVA_FILE) $(MS_FILE) $(JS_FILE) ulinet.obj main_conf_read.tab.obj lex.cr.obj service_conf.tab.obj lex.sr.obj  zoo_service_loader.obj /out:zoo_loader.cgi $(LDFLAGS) $(LDFLAGSCGI)
+
+clean:
+	erase -f *.cgi *.obj *.tab.c* *.tab.h *.sr.c* lex.* *.lreg *.sibling
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/nmake.opt
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/nmake.opt	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/nmake.opt	(revision 417)
@@ -0,0 +1,41 @@
+
+CC=cl $(CFLAGS)
+CPP=cl /TP $(CFLAGS)
+
+!IFDEF JS_DIR
+JS_CFLAGS=-DXP_WIN -DUSE_JS -I$(JS_DIR)
+JS_LDFLAGS=$(JS_DIR)/mozjs185-1.0.lib
+JS_FILE=service_internal_js.obj
+!ENDIF
+
+!IFDEF MS_DIR
+MS_CFLAGS=-DUSE_MS -I$(MS_DIR)
+MS_LDFLAGS=$(MS_DIR)/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
+
+!IFNDEF ZOOK_DIR
+ZOOK_DIR=.
+!ENDIF
+
+TROOT=$(ZOOK_DIR)
+TPATH=$(ZOOK_DIR)\..\..\..\tools
+LIBINTL_CPATH=$(ZOOK_DIR)\..\..\..\
+PYTHON_CPATH=$(PY_DIR)
+
+CFLAGS=$(CFLAGS1) /nologo /MD /W3 /EHsc /Ox /D_CRT_SECURE_NO_WARNINGS /DWIN32 $(CJFLAGS) -I$(ZOOK_DIR) -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) -DLINUX_FREE_ISSUE #-DDEBUG #-DDEBUG_SERVICE_CONF
+
+LDFLAGSCGI=$(TROOT)/../../thirds/cgic206/libcgic.lib 
+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) /machine:i386
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service.h	(revision 417)
@@ -0,0 +1,902 @@
+/**
+ * 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.
+ */
+
+#ifndef ZOO_SERVICE_H
+#define ZOO_SERVICE_H 1
+
+#pragma once
+
+#ifdef WIN32
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#ifndef snprintf
+#define snprintf sprintf_s
+#else
+
+#endif
+#endif 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef WIN32
+#define bool int
+#define true 1
+#define false -1
+#else
+  //#include <stdbool.h>
+#endif
+
+#define SERVICE_ACCEPTED 0
+#define SERVICE_STARTED 1
+#define SERVICE_PAUSED 2
+#define SERVICE_SUCCEEDED 3
+#define SERVICE_FAILED 4
+
+#define ELEMENTS_SIZE (sizeof(char*)+(((2*sizeof(char*))+sizeof(maps*))*2)+sizeof(char*)+(((2*sizeof(char*))+sizeof(iotype*))*2)+sizeof(elements*))
+#define MAP_SIZE (2*sizeof(char*))+sizeof(NULL)
+#define IOTYPE_SIZE MAP_SIZE+sizeof(NULL)
+#define MAPS_SIZE (2*sizeof(char*))+sizeof(map*)+MAP_SIZE
+#define SERVICE_SIZE (ELEMENTS_SIZE*2)+(MAP_SIZE*2)+sizeof(char*)
+
+#define SHMSZ     27
+
+
+#ifdef DEBUG_STACK
+  void debugStack(const char* file,const int line){
+    int stack;
+    fprintf(stderr,"stack %p (%s: %d) \n",&stack,file,line);
+  }
+#endif
+
+  /**
+   * \struct map
+   * \brief KVP linked list
+   *
+   * Deal with WPS KVP (name,value).
+   * A map is defined as:
+   *  - name : a key,
+   *  - value: a value,
+   *  - next : a pointer to the next map if any.
+   */
+  typedef struct map{
+    char* name;
+    char* value;
+    struct map* next;
+  } map;
+
+#ifdef WIN32
+#define NULLMAP ((map*) 0)
+#else
+#define NULLMAP NULL
+#endif
+
+  /**
+   * \struct maps
+   * \brief linked list of map pointer
+   *
+   * Small object to store WPS KVP set.
+   * Maps is defined as:
+   *  - a name, 
+   *  - a content map,
+   *  - a pointer to the next maps if any.
+   */
+  typedef struct maps{
+    char* name;          
+    struct map* content; 
+    struct maps* next;   
+  } maps;
+
+  /**
+   * \brief Dump a map on stderr
+   */
+  static 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);
+    }
+  }
+
+  static void dumpMap(map* t){
+    map* tmp=t;
+    while(tmp!=NULL){
+      _dumpMap(tmp);
+      tmp=tmp->next;
+    }
+  }
+
+  static void dumpMapToFile(map* t,FILE* file){
+    map* tmp=t;
+    while(tmp!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"%s = %s\n",tmp->name,tmp->value);
+#endif
+      fprintf(file,"%s = %s\n",tmp->name,tmp->value);
+      tmp=tmp->next;
+    }
+  }
+
+  static void dumpMaps(maps* m){
+    maps* tmp=m;
+    while(tmp!=NULL){
+      fprintf(stderr,"MAP => [%s] \n",tmp->name);
+      dumpMap(tmp->content);
+      tmp=tmp->next;
+    }
+  }
+
+  static void dumpMapsToFile(maps* m,char* file_path){
+    FILE* file=fopen(file_path,"w");
+    maps* tmp=m;
+    if(tmp!=NULL){
+      fprintf(file,"[%s]\n",tmp->name);
+      dumpMapToFile(tmp->content,file);
+      fflush(file);
+    }
+    fclose(file);
+  }
+
+  static map* createMap(const char* name,const char* value){
+    map* tmp=(map *)malloc(MAP_SIZE);
+    tmp->name=strdup(name);
+    tmp->value=strdup(value);
+    tmp->next=NULL;
+    return tmp;
+  }
+
+  static int count(map* m){
+    map* tmp=m;
+    int c=0;
+    while(tmp!=NULL){
+      c++;
+      tmp=tmp->next;
+    }
+    return c;
+  }
+    
+  static 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;
+  }
+
+  static 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;
+  }
+
+  static 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;
+  }
+
+
+  static map* getLastMap(map* m){
+    map* tmp=m;
+    while(tmp!=NULL){
+      if(tmp->next==NULL){
+	return tmp;
+      }
+      tmp=tmp->next;
+    }
+    return NULL;
+  }
+
+  static 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;
+  }
+
+  static char* getMapsAsKVP(maps* m,int length,int type){
+    char *dataInputsKVP=(char*) malloc(length*sizeof(char));
+    maps* curs=m;
+    int i=0;
+    while(curs!=NULL){
+      if(i==0)
+	if(type==0)
+	  sprintf(dataInputsKVP,"%s=",curs->name);
+	else
+	  sprintf(dataInputsKVP,"%s",curs->name);
+      else{
+	char *temp=strdup(dataInputsKVP);
+	if(type==0)
+	  sprintf(dataInputsKVP,"%s;%s=",temp,curs->name);
+	else
+	  sprintf(dataInputsKVP,"%s;%s",temp,curs->name);
+	free(temp);
+      }
+      map* icurs=curs->content;
+      if(type==0){
+	map* tmp=getMap(curs->content,"value");
+	char *temp=strdup(dataInputsKVP);
+	if(getMap(m->content,"xlink:href")!=NULL)
+	  sprintf(dataInputsKVP,"%sReference",temp);
+	else
+	  sprintf(dataInputsKVP,"%s%s",temp,icurs->value);
+	free(temp);
+      }
+      int j=0;
+      while(icurs!=NULL){
+	if(strcasecmp(icurs->name,"value")!=0 &&
+	   strcasecmp(icurs->name,"Reference")!=0 &&
+	   strcasecmp(icurs->name,"minOccurs")!=0 &&
+	   strcasecmp(icurs->name,"maxOccurs")!=0 &&
+	   strcasecmp(icurs->name,"inRequest")!=0){
+	  char *itemp=strdup(dataInputsKVP);
+	  sprintf(dataInputsKVP,"%s@%s=%s",itemp,icurs->name,icurs->value);
+	  free(itemp);
+	}
+	icurs=icurs->next;
+      }
+      curs=curs->next;
+      i++;
+    }
+    return dataInputsKVP;
+  }
+
+
+  static 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);
+      }
+    }
+  }
+
+  static void freeMaps(maps** mo){
+    maps* _cursor=*mo;
+    fflush(stderr);
+    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->next!=NULL){
+	freeMaps(&_cursor->next);
+	free(_cursor->next);
+      }
+    }
+  }
+
+  /**
+   * \brief Not named linked list
+   *
+   * Used to store informations about formats, such as mimeType, encoding ... 
+   *
+   * An iotype is defined as :
+   *  - a content map,
+   *  - a pointer to the next iotype if any.
+   */
+  typedef struct iotype{
+    struct map* content;
+    struct iotype* next;
+  } iotype;
+
+  /**
+   * \brief Metadata information about input or output.
+   *
+   * The elements are used to store metadata informations defined in the ZCFG.
+   *
+   * An elements is defined as :
+   *  - a name,
+   *  - a content map,
+   *  - a metadata map,
+   *  - a format (possible values are LiteralData, ComplexData or 
+   * BoundingBoxData),
+   *  - a default iotype,
+   *  - a pointer to the next elements id any.
+   */
+  typedef struct elements{
+    char* name;
+    struct map* content;
+    struct map* metadata;
+    char* format;
+    struct iotype* defaults;
+    struct iotype* supported;
+    struct elements* next;
+  } elements;
+
+  typedef struct service{
+    char* name;
+    struct map* content;
+    struct map* metadata;
+    struct elements* inputs;
+    struct elements* outputs; 
+  } service;
+
+  typedef struct services{
+    struct service* content; 
+    struct services* next; 
+  } services;
+
+  static 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;
+  }
+
+  static 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;
+  }
+
+
+  static 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);
+    }
+  }
+
+  static 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);
+      if(tmp->format!=NULL)
+	free(tmp->format);
+      freeIOType(&tmp->defaults);
+      if(tmp->defaults!=NULL)
+	free(tmp->defaults);
+      freeIOType(&tmp->supported);
+      if(tmp->supported!=NULL){
+	free(tmp->supported);
+      }
+      freeElements(&tmp->next);
+      if(tmp->next!=NULL)
+	free(tmp->next);
+    }
+  }
+
+  static 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);
+      freeElements(&tmp->inputs);
+      if(tmp->inputs!=NULL)
+	free(tmp->inputs);
+      freeElements(&tmp->outputs);
+      if(tmp->outputs!=NULL)
+	free(tmp->outputs);
+    }
+  }
+
+  static void addToMap(map* m,const char* n,const char* v){
+    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=strdup(v);
+    }
+  }
+
+  static void addMapToMap(map** mo,map* mi){
+    map* tmp=mi;
+    map* _cursor=*mo;
+    if(tmp==NULL){
+      if(_cursor!=NULL){
+	while(_cursor!=NULL)
+	  _cursor=_cursor->next;
+	_cursor=NULL;
+      }else
+	*mo=NULL;
+    }
+    while(tmp!=NULL){
+      if(_cursor==NULL){
+	if(*mo==NULL)
+	  *mo=createMap(tmp->name,tmp->value);
+	else
+	  addToMap(*mo,tmp->name,tmp->value);
+      }
+      else{
+#ifdef DEBUG
+	fprintf(stderr,"_CURSOR\n");
+	dumpMap(_cursor);
+#endif
+	while(_cursor!=NULL)
+	  _cursor=_cursor->next;
+	_cursor=createMap(tmp->name,tmp->value);
+	_cursor->next=NULL;
+      }
+      tmp=tmp->next;
+#ifdef DEBUG
+      fprintf(stderr,"MO\n");
+      dumpMap(*mo);
+#endif
+    }
+  }
+
+  static 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;
+  }
+
+  static map* getMapOrFill(map* m,const char *key,char* value){
+    map* tmp=m;
+    map* tmpMap=getMap(tmp,key);
+    if(tmpMap==NULL){
+      if(tmp!=NULL)
+	addToMap(tmp,key,value);
+      else
+	tmp=createMap(key,value);
+      tmpMap=getMap(tmp,key);
+    }
+    return tmpMap;
+  }
+
+  static 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;
+  }
+
+  static iotype* getIoTypeFromElement(elements* e,char *name, map* values){
+    elements* cursor=e;
+    while(cursor!=NULL){
+      if(strcasecmp(cursor->name,name)==0){
+	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;
+    }
+    return NULL;
+  }
+
+  static maps* dupMaps(maps** mo){
+    maps* _cursor=*mo;
+    maps* res=NULL;
+    if(_cursor!=NULL){
+      res=(maps*)malloc(MAPS_SIZE);
+      res->name=strdup(_cursor->name);
+      res->content=NULL;
+      res->next=NULL;
+      map* mc=_cursor->content;
+      map* tmp=getMap(mc,"size");
+      char* tmpSized=NULL;
+      if(tmp!=NULL){
+	map* tmpV=getMap(mc,"value");
+	tmpSized=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
+	memmove(tmpSized,tmpV->value,atoi(tmp->value)*sizeof(char));
+      }
+      if(mc!=NULL){
+	addMapToMap(&res->content,mc);
+      }
+      if(tmp!=NULL){
+	map* tmpV=getMap(res->content,"value");
+	free(tmpV->value);
+	tmpV->value=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
+	memmove(tmpV->value,tmpSized,atoi(tmp->value)*sizeof(char));
+	tmpV->value[atoi(tmp->value)]=0;
+	free(tmpSized);
+      }
+      res->next=dupMaps(&_cursor->next);
+    }
+    return res;
+  }
+
+  static void addMapsToMaps(maps** mo,maps* mi){
+    maps* tmp=mi;
+    maps* _cursor=*mo;
+    while(tmp!=NULL){
+      if(_cursor==NULL){
+	*mo=dupMaps(&mi);
+	(*mo)->next=NULL;
+      }
+      else{
+	while(_cursor->next!=NULL)
+	  _cursor=_cursor->next;
+	_cursor->next=dupMaps(&tmp);
+      }
+      tmp=tmp->next;
+    }
+  }
+
+  static map* getMapArray(map* m,char* key,int index){
+    char tmp[1024];
+    if(index>0)
+      sprintf(tmp,"%s_%d",key,index);
+    else
+      sprintf(tmp,"%s",key);
+#ifdef DEBUG
+    fprintf(stderr,"** KEY %s\n",tmp);
+#endif
+    map* tmpMap=getMap(m,tmp);
+#ifdef DEBUG
+    if(tmpMap!=NULL)
+      dumpMap(tmpMap);
+#endif
+    return tmpMap;
+  }
+
+
+  static void setMapArray(map* m,char* key,int index,char* value){
+    char tmp[1024];
+    if(index>0)
+      sprintf(tmp,"%s_%d",key,index);
+    else
+      sprintf(tmp,"%s",key);
+    map* tmpSize=getMapArray(m,"size",index);
+    if(tmpSize!=NULL && strncasecmp(key,"value",5)==0){
+#ifdef DEBUG
+      fprintf(stderr,"%s\n",tmpSize->value);
+#endif
+      map* ptr=getMapOrFill(m,tmp,"");
+      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);
+  }
+
+  static map* getMapType(map* mt){
+    map* tmap=getMap(mt,"mimeType");
+    if(tmap==NULL){
+      tmap=getMap(mt,"dataType");
+      if(tmap==NULL){
+	tmap=getMap(mt,"CRS");
+      }
+    }
+#ifdef DEBUG
+	dumpMap(tmap);
+#endif
+    return tmap;
+  }
+
+  static int addMapsArrayToMaps(maps** mo,maps* mi,char* typ){
+    maps* tmp=mi;    
+    maps* _cursor=getMaps(*mo,tmp->name);
+
+    if(_cursor==NULL)
+      return -1;
+
+    map* tmpLength=getMap(_cursor->content,"length");
+    char tmpLen[10];
+    int len=1;
+    if(tmpLength!=NULL){
+      len=atoi(tmpLength->value);
+    }
+
+    map* tmpValI=getMap(tmp->content,"value");
+    char *tmpV[8]={
+      "size",
+      "value",
+      "uom",
+      "Reference",
+      "xlink:href",
+      typ,
+      "schema",
+      "encoding"
+    };
+    sprintf(tmpLen,"%d",len+1);
+    addToMap(_cursor->content,"length",tmpLen);
+    int i=0;
+    map* tmpSizeI=getMap(tmp->content,tmpV[i]);
+    for(0;i<8;i++){
+      map* tmpVI=getMap(tmp->content,tmpV[i]);
+      if(tmpVI!=NULL){
+#ifdef DEBUG
+	fprintf(stderr,"%s = %s\n",tmpV[i],tmpVI->value);
+#endif
+	if(i<5)
+	  setMapArray(_cursor->content,tmpV[i],len,tmpVI->value);
+	else
+	  if(strncasecmp(tmpV[5],"mimeType",8)==0)
+	    setMapArray(_cursor->content,tmpV[i],len,tmpVI->value);
+      }
+    }
+    
+    addToMap(_cursor->content,"isArray","true");
+    return 0;
+  }
+
+  static 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=strdup(value);
+      }else{
+	addToMap(_tmpm->content,subkey,value);
+      }
+    }else{
+      maps *tmp=(maps*)malloc(MAPS_SIZE);
+      tmp->name=strdup(key);
+      tmp->content=createMap(subkey,value);
+      tmp->next=NULL;
+      addMapsToMaps(&m,tmp);
+      freeMaps(&tmp);
+      free(tmp);
+    }
+  }
+
+
+  static void dumpElements(elements* e){
+    elements* tmp=e;
+    while(tmp!=NULL){
+      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," > FORMAT [%s]\n",tmp->format);
+      iotype* tmpio=tmp->defaults;
+      int ioc=0;
+      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++;
+      }
+      fprintf(stderr,"------------------\n");
+      tmp=tmp->next;
+    }
+  }
+
+  static elements* dupElements(elements* e){
+    elements* cursor=e;
+    elements* tmp=NULL;
+    if(cursor!=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=strdup(e->name);
+      tmp->content=NULL;
+      addMapToMap(&tmp->content,e->content);
+      tmp->metadata=NULL;
+      addMapToMap(&tmp->metadata,e->metadata);
+      tmp->format=strdup(e->format);
+      if(e->defaults!=NULL){
+	tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
+	tmp->defaults->content=NULL;
+	addMapToMap(&tmp->defaults->content,e->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(e->supported!=NULL){
+	tmp->supported=(iotype*)malloc(IOTYPE_SIZE);
+	tmp->supported->content=NULL;
+	addMapToMap(&tmp->supported->content,e->supported->content);
+	tmp->supported->next=NULL;
+	iotype *tmp2=e->supported->next;
+	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;
+      tmp->next=dupElements(cursor->next);
+    }
+    return tmp;
+  }
+
+  static void addToElements(elements** m,elements* e){
+    elements* tmp=e;
+    if(*m==NULL){
+      *m=dupElements(tmp);
+    }else{
+      addToElements(&(*m)->next,tmp);
+    }
+  }
+
+  static void dumpService(service* s){
+    fprintf(stderr,"++++++++++++++++++\nSERVICE [%s]\n++++++++++++++++++\n",s->name);
+    if(s->content!=NULL){
+      fprintf(stderr,"CONTENT MAP\n");
+      dumpMap(s->content);
+      fprintf(stderr,"CONTENT METADATA\n");
+      dumpMap(s->metadata);
+    }
+    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");
+  }
+
+  static 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){
+      if(i>=10)
+	break;
+      strcpy(tmp[i][j],"name");
+      j++;
+      strcpy(tmp[i][j],tm->name);
+      j++;
+      map* tc=tm->content;
+      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);
+  }
+
+  static 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;
+  }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_conf.l
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_conf.l	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_conf.l	(revision 417)
@@ -0,0 +1,123 @@
+%option noyywrap
+%option yylineno
+
+
+%{
+//======================================================
+/**
+
+ authors : Jean-Marie CODOL, Naitan GROLLEMUND
+
+**/
+//======================================================
+
+
+#include <string.h>
+#include "service_conf.tab.h"
+
+#ifdef DEBUG_SERVICE_CONF
+int affichetrace = 1;
+#else
+int affichetrace = 0;
+#endif
+
+
+int attentionImpossibleDeTrouverXMLDeclapres = 0 ;
+
+int attentionImpossibleDeTrouverPIapres = 0 ;
+
+%}
+
+
+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	[\^\*\+,;@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" {  if (affichetrace==1) fprintf (stderr,"\n\nNEWLINE\n") ;return NEWLINE;}
+
+{newline}+{whitesp}*			{  if (affichetrace==1) fprintf (stderr,"\n\nNEWLINE 1\n") ; 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,DANSBALISE>{newline}+{whitesp}*             { BEGIN(INITIAL);  return NEWLINE;}
+
+<INITIAL>"<?"[Xx][Mm][Ll]  {   if (attentionImpossibleDeTrouverXMLDeclapres == 1 || attentionImpossibleDeTrouverPIapres == 1) {/* il y a eut un commentaire ou une balise applicative avant la declaration xml */ fprintf(stderr,"\nerror : a la ligne %d : il y a eut un commentaire ou un PI avant la declaration xml\n",srlineno); exit (10) ; } ; return STARTXMLDECL;}
+
+<INITIAL>"version"{egalevolue}\"1.0\"|"version"{egalevolue}\'1.0\'  { return VERSIONDECL;  }
+<INITIAL>"version"{egalevolue}\"[^"]*\"|"version"{egalevolue}\'[^']*\'  {/* erreur de version encoding */ fprintf(stderr,"\nerror : a la ligne %d : la version xml n est pas reconnue : %s\n",srlineno,yytext); exit (9) ; }
+
+
+<INITIAL>"encoding"{egalevolue}\"[Ii][Ss][Oo]"-8859-1"\"|"encoding"{egalevolue}\'[Ii][Ss][Oo]"-8859-1"\'  { return ENCODINGDECL;}
+<INITIAL>"encoding"{egalevolue}\"[^"]*\"|"encoding"{egalevolue}\'[^']*\'  {/* erreur de version encoding */ 	fprintf(stderr,"\nerror : a la ligne %d : la version d encodage n est pas reconnue : %s\n",srlineno,yytext); exit (8) ; }
+
+
+<INITIAL>"standalone"{egalevolue}\"yes\"|"standalone"{egalevolue}\'yes\'|"standalone"{egalevolue}\"no\"|"standalone"{egalevolue}\'no\'  { return SDDECL;}
+
+<INITIAL>"standalone"{egalevolue}\"[^"]*\"|"standalone"{egalevolue}\'[^']*\'|"standalone"{egalevolue}\"[^"]*\"|"standalone"{egalevolue}\'[^']*\'  { /* erreur de version encoding */ 	fprintf(stderr,"\nerror : a la ligne %d : la version standalone n est pas reconnue : %s\n",srlineno,yytext); exit (7) ; }
+
+
+<INITIAL>"?>"  { BEGIN(HORSBALISE); return ENDXMLDECL;}
+
+
+<DANSBALISE,INITIAL,HORSBALISE>{S}   {  }
+
+
+<HORSBALISE>"<?"[Xx][Mm][Ll]{S}({S}|{chardata})*"?>"|"<?"[Xx][Mm][Ll]"?>"	{ return PIERROR;}
+<INITIAL,HORSBALISE>"<?"([^xX]|([xX][^mM])|([xX][mM][^lL]))({S}|([^?]|("?"[^>])))*"?>"		{ attentionImpossibleDeTrouverPIapres=1 ; return PI;}
+
+
+<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,HORSBALISE>"<!--"([^-]|"-"[^-])*"-->"		{attentionImpossibleDeTrouverXMLDeclapres=1; }
+
+
+<INITIAL,DANSBALISE,HORSBALISE>.|\n	{fprintf(stderr,"error : ligne %d : caractere non reconnu '%s'\n",srlineno,yytext);}
+
+%%
+
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_conf.y
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_conf.y	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_conf.y	(revision 417)
@@ -0,0 +1,856 @@
+%{
+//======================================================
+/**
+ * Thx to Jean-Marie CODOL and Naitan GROLLEMUND
+ * copyright 2009 GeoLabs SARL 
+ * Author : Gérald FENOY
+ *
+ */
+//======================================================
+
+#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_metadata=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 int services_c=0;
+static service* my_service=NULL;
+static map* previous_content=NULL;
+static map* current_content=NULL;
+static elements* current_element=NULL;
+static map* scontent=NULL;
+static char* curr_key;
+static int debug=0;
+static int data=-1;
+static int previous_data=0;
+static int current_data=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);
+
+//vector<char*> lattribute;
+
+%}
+
+
+
+%union 
+{char * s;char* chaine;char* key;char* val;}
+
+// jetons //
+%token <s> ID
+%token <s> CHAINE
+/* STARTXMLDECL et ENDXMLDECL qui sont <?xml et ?>*/
+%token STARTXMLDECL ENDXMLDECL
+//======================================================
+/* version="xxx" et encoding="xxx" */
+%token VERSIONDECL ENCODINGDECL SDDECL
+//======================================================
+/* < et > */
+%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 begining 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,"(%s %d) %s\n",__FILE__,__LINE__,$2);
+  fflush(stderr);
+#endif
+  if(my_service->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;
+    wait_maincontent=false;
+  }
+  if(strncasecmp($2,"DataInputs",10)==0){
+    if(wait_mainmetadata==true){
+      addMapToMap(&my_service->metadata,current_content);
+      freeMap(&current_content);
+      free(current_content);
+      current_content=NULL;
+      wait_mainmetadata=false;
+    }
+    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=(elements*)malloc(ELEMENTS_SIZE);
+      current_element->name=NULL;
+      current_element->content=NULL;
+      current_element->metadata=NULL;
+      current_element->format=NULL;
+      current_element->defaults=NULL;
+      current_element->supported=NULL;
+      current_element->next=NULL;
+    }
+    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){
+	  my_service->inputs=dupElements(current_element);
+	  my_service->inputs->next=NULL;
+	}
+	else if(current_element!=NULL && current_element->name!=NULL){
+	  addToElements(&my_service->inputs,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
+	freeElements(&current_element);
+	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=(elements*)malloc(ELEMENTS_SIZE);
+	current_element->name=NULL;
+	current_element->content=NULL;
+	current_element->metadata=NULL;
+	current_element->format=NULL;
+	current_element->defaults=NULL;
+	current_element->supported=NULL;
+	current_element->next=NULL;
+      }
+      wait_outputs=true;
+      current_data=2;
+      previous_data=2;
+    }
+    else
+      if(strncasecmp($2,"MetaData",8)==0){
+	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;
+	  if(wait_metadata==true){
+	    if(current_content!=NULL){
+#ifdef DEBUG_SERVICE_CONF
+	      fprintf(stderr,"add current_content to current_element->content\n");
+	      fprintf(stderr,"LINE %d",__LINE__);
+#endif
+	      addMapToMap(&current_element->metadata,current_content);
+	      current_element->next=NULL;
+	      if($2!=NULL)
+		current_element->format=strdup($2);
+	      
+	      current_element->defaults=NULL;
+	      current_element->supported=NULL;
+	      freeMap(&current_content);
+	      free(current_content);
+	    }
+	  }else{ 
+	    // No MainMetaData
+	    addMapToMap(&current_element->content,current_content);
+	    freeMap(&current_content);
+	    free(current_content);
+	    current_element->metadata=NULL;
+	    current_element->next=NULL;
+	    if($2!=NULL)
+	      current_element->format=strdup($2);
+	    current_element->defaults=NULL;
+	    current_element->supported=NULL;
+	  }
+	  current_content=NULL;
+	  wait_metadata=false;
+	}
+	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
+  printf("* Identifiant : %s\n",$2);
+  fflush(stdout);
+#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->next=NULL;
+   }
+ }
+ ;
+
+//======================================================
+// ETag
+//======================================================
+// regle 42
+// BALISE FERMANTE
+// les separateurs après ID sont filtrés
+//======================================================
+ETag
+ : INFCAR SLASH ID SUPCAR
+{
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"(%s %d)\n",__FILE__,__LINE__);
+#endif
+  if(strcmp($3,"DataInputs")==0){
+    current_data=1;
+  }
+  if(strcmp($3,"DataOutputs")==0){
+    current_data=2;
+  }
+  if(strcmp($3,"MetaData")==0){
+    current_data=previous_data;
+  }
+  if(strcmp($3,"ComplexData")==0 || strcmp($3,"LiteralData")==0 
+     || strcmp($3,"ComplexOutput")==0 || strcmp($3,"LiteralOutput")==0){
+    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->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->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,"(%s %d)\n",__FILE__,__LINE__);
+  fprintf(stderr,"EPAIR FOUND !! \n"); 
+  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($1!=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=strdup($1);if(debug) fprintf(stderr,"SPAIR FOUND !!\n"); }
+ ;
+
+
+processid
+: ANID  {
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"(%s %d)\n",__FILE__,__LINE__);
+#endif
+  if(data==-1){
+    data=1;
+    if($1!=NULL){
+      char *cen=strdup($1);
+      my_service->name=(char*)malloc((strlen(cen)-1)*sizeof(char*));
+      cen[strlen(cen)-1]=0;
+      cen+=1;
+      sprintf(my_service->name,"%s",cen);
+      cen-=1;
+      free(cen);
+      my_service->content=NULL;
+      my_service->metadata=NULL;
+      my_service->inputs=NULL;
+      my_service->outputs=NULL;
+    }
+  } 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{
+	  addToElements(&my_service->inputs,current_element);
+	}
+#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=(elements*)malloc(ELEMENTS_SIZE);
+	current_element->name=NULL;
+	current_element->content=NULL;
+	current_element->metadata=NULL;
+	current_element->format=NULL;
+	current_element->defaults=NULL;
+	current_element->supported=NULL;
+	current_element->next=NULL;
+      }
+      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=strdup($1);
+	  current_element->name=(char*)malloc((strlen(cen)-1)*sizeof(char*));
+	  cen[strlen(cen)-1]=0;
+	  cen+=1;
+	  sprintf(current_element->name,"%s",cen);
+	  cen-=1;
+	  free(cen);
+#ifdef DEBUG_SERVICE_CONF
+	  fprintf(stderr,"NAME IN %s (current - %s)\n",$1,current_element->name);
+#endif
+	  current_element->content=NULL;
+	  current_element->metadata=NULL;
+	  current_element->format=NULL;
+	  current_element->defaults=NULL;
+	  current_element->supported=NULL;
+	  current_element->next=NULL;
+#ifdef DEBUG_SERVICE_CONF
+	  fprintf(stderr,"NAME IN %s (current - %s)\n",$1,current_element->name);
+#endif
+	}
+      }
+    }
+    else
+      if(current_data==2){ 
+	wait_outputs=true;
+	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=(elements*)malloc(ELEMENTS_SIZE);
+	    current_element->name=NULL;
+	    current_element->content=NULL;
+	    current_element->metadata=NULL;
+	    current_element->format=NULL;
+	    current_element->defaults=NULL;
+	    current_element->supported=NULL;
+	    current_element->next=NULL;
+	  }
+	  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=strdup($1);
+	      current_element->name=(char*)malloc((strlen(cen)-1)*sizeof(char));
+	      cen[strlen(cen)-1]=0;
+	      cen+=1;
+	      sprintf(current_element->name,"%s",cen);
+	      cen-=1;
+	      free(cen);
+	      current_element->content=NULL;
+	      current_element->metadata=NULL;
+	      current_element->format=NULL;
+	      current_element->defaults=NULL;
+	      current_element->supported=NULL;
+	      current_element->next=NULL;
+	    }
+	  }
+
+	  current_content=NULL;
+	}
+	else
+	  if(current_element!=NULL && current_element->name!=NULL){
+	    if(my_service->outputs==NULL)
+	      my_service->outputs=dupElements(current_element);
+	    else
+	      addToElements(&my_service->outputs,current_element);
+#ifdef DEBUG_SERVICE_CONF
+	    fprintf(stderr,"ADD TO OUTPUTS Elements\n");
+	    dupElements(current_element);
+#endif
+	    freeElements(&current_element);
+	    free(current_element);
+	    current_element=NULL;
+	    current_element=(elements*)malloc(ELEMENTS_SIZE);
+	    char *cen=strdup($1);
+	    current_element->name=(char*)malloc((strlen(cen)-1)*sizeof(char));
+	    cen[strlen(cen)-1]=0;
+	    cen+=1;
+	    sprintf(current_element->name,"%s",cen);
+	    cen-=1;
+	    free(cen);
+	    current_element->content=NULL;
+	    current_element->metadata=NULL;
+	    current_element->format=NULL;
+	    current_element->defaults=NULL;
+	    current_element->supported=NULL;
+	    current_element->next=NULL;
+	  }
+	  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=strdup($1);
+	      current_element->name=(char*)malloc((strlen(cen))*sizeof(char*));
+	      cen[strlen(cen)-1]=0;
+#ifdef DEBUG
+	      fprintf(stderr,"tmp %s\n",cen);
+#endif
+	      cen+=1;
+	      sprintf(current_element->name,"%s",cen);
+	      cen-=1;
+	      free(cen);
+	      current_element->content=NULL;
+	      current_element->metadata=NULL;
+	      current_element->format=NULL;
+	      current_element->defaults=NULL;
+	      current_element->supported=NULL;
+	      current_element->next=NULL;
+	    }
+	  }
+	wait_inputs=false;
+	wait_outputs=true;
+	//wait_outputs=true;
+      }
+  }
+ }
+ ;
+
+%%
+
+// srerror
+//======================================================
+/* fonction qui affiche l erreur si il y en a une */
+//======================================================
+void srerror(const char *s)
+{
+  if(debug)
+    fprintf(stderr,"\nligne %d : %s\n",srlineno,s);
+}
+
+/**
+ * getServiceFromFile :
+ * set service given as second parameter with informations extracted from the
+ * definition file.
+ */
+int getServiceFromFile(const char* file,service** service){
+
+  freeMap(&previous_content);
+  previous_content=NULL;
+  freeMap(&current_content);
+  current_content=NULL;
+  freeMap(&scontent);
+#ifdef DEBUG_SERVICE_CONF
+  fprintf(stderr,"(STARTING)FREE current_element\n");
+#endif
+  freeElements(&current_element);
+  free(current_element);
+  current_element=NULL;
+  my_service=NULL;
+  scontent=NULL;
+
+  wait_maincontent=true;
+  wait_mainmetadata=false;
+  wait_metadata=false;
+  wait_inputs=false;
+  wait_defaults=false;
+  wait_supporteds=false;
+  wait_outputs=false;
+  wait_data=false;
+  data=-1;
+  previous_data=1;
+  current_data=0;
+  
+  my_service=*service;
+
+  srin = fopen(file,"r");
+  if (srin==NULL){
+    fprintf(stderr,"error : file not found\n") ;
+    return -1;
+  }
+
+  int resultatYYParse = srparse() ;
+  
+  if(wait_outputs && current_element!=NULL && current_element->name!=NULL){
+    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
+      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;
+  }
+  if(current_content!=NULL){
+    freeMap(&current_content);
+    free(current_content);
+    current_content=NULL;
+  }
+  fclose(srin);
+#ifdef DEBUG_SERVICE_CONF
+  dumpService(my_service);
+#endif
+  *service=my_service;
+
+#ifndef WIN32
+  srlex_destroy();
+#endif
+  return resultatYYParse;
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal.c	(revision 417)
@@ -0,0 +1,2608 @@
+/**
+ * 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.h"
+#ifdef USE_MS
+#include "service_internal_ms.h"
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE -1
+#endif
+
+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;
+    }
+  }
+}
+
+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");
+}
+
+/* Converts a hex character to its integer value */
+char from_hex(char ch) {
+  return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+/* Converts an integer value to its hex character*/
+char to_hex(char code) {
+  static char hex[] = "0123456789abcdef";
+  return hex[code & 15];
+}
+
+#ifdef WIN32
+
+#include <windows.h>
+#include <stdio.h>
+#include <conio.h>
+#include <tchar.h>
+
+#define SHMEMSIZE 4096
+
+static LPVOID lpvMemG = NULL;      // pointer to shared memory
+static HANDLE hMapObjectG = NULL;  // handle to file mapping
+
+void updateStatus(maps *conf){
+  LPWSTR lpszTmp;
+  BOOL fInit;
+  char *s=NULL;
+  map *tmpMap=getMapFromMaps(conf,"lenv","sid");
+  if(hMapObjectG==NULL)
+    hMapObjectG = CreateFileMapping( 
+				    INVALID_HANDLE_VALUE,   // use paging file
+				    NULL,                   // default security attributes
+				    PAGE_READWRITE,         // read/write access
+				    0,                      // size: high 32-bits
+				    SHMEMSIZE,              // size: low 32-bits
+				    TEXT(tmpMap->value));   // name of map object
+  if (hMapObjectG == NULL){
+    fprintf(stderr,"Unable to create share memory segment %s !! \n",tmpMap->value);
+    return ;
+  }
+  fInit = (GetLastError() != ERROR_ALREADY_EXISTS); 
+  if(lpvMemG==NULL)
+    lpvMemG = MapViewOfFile( 
+			    hMapObjectG,     // object to map view of
+			    FILE_MAP_WRITE, // read/write access
+			    0,              // high offset:  map from
+			    0,              // low offset:   beginning
+			    0);             // default: map entire file
+  if (lpvMemG == NULL){
+    fprintf(stderr,"Unable to create or access the shared memory segment %s !! \n",tmpMap->value);
+    return ;
+  } 
+  if (fInit)
+    memset(lpvMemG, '\0', SHMEMSIZE);
+  tmpMap=getMapFromMaps(conf,"lenv","status");
+  lpszTmp = (LPWSTR) lpvMemG;
+  for(s=tmpMap->value;*s!=NULL;s++)
+    *lpszTmp++ = *s;
+  *lpszTmp = '\0'; 
+}
+
+char* getStatus(int pid){
+  LPWSTR lpszBuf=NULL;
+  LPWSTR lpszTmp=NULL;
+  LPVOID lpvMem = NULL;
+  HANDLE hMapObject = NULL;
+  BOOL fIgnore,fInit;
+  char tmp[100];
+  sprintf(tmp,"%i",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) 
+    return FALSE;
+  if((GetLastError() != ERROR_ALREADY_EXISTS)){
+    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) 
+    return "-1"; 
+  lpszTmp = (LPWSTR) lpvMem;
+  return (char*)lpszTmp;
+}
+
+void unhandleStatus(maps *conf){
+  BOOL fIgnore;
+  fIgnore = UnmapViewOfFile(lpvMemG); 
+  fIgnore = CloseHandle(hMapObjectG);
+}
+#else
+
+void unhandleStatus(maps *conf){
+  int shmid,i;
+  key_t key;
+  void *shm;
+  struct shmid_ds shmids;
+  char *s,*s1;
+  map *tmpMap=getMapFromMaps(conf,"lenv","sid");
+  if(tmpMap!=NULL){
+    key=atoi(tmpMap->value);
+    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
+#ifdef DEBUG
+      fprintf(stderr,"shmget failed to update value\n");
+#endif
+    }else{
+      if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
+#ifdef DEBUG
+	fprintf(stderr,"shmat failed to update value\n");
+#endif
+      }else{
+	shmdt(shm);
+	shmctl(shmid,IPC_RMID,&shmids);
+      }
+    }
+  }
+}
+
+void updateStatus(maps *conf){
+  int shmid,i;
+  key_t key;
+  char *shm,*s,*s1;
+  map *tmpMap=NULL;
+  tmpMap=getMapFromMaps(conf,"lenv","sid");
+  if(tmpMap!=NULL){
+    key=atoi(tmpMap->value);
+    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
+#ifdef DEBUG
+      fprintf(stderr,"shmget failed to create new Shared memory segment\n");
+#endif
+    }else{
+      if ((shm = (char*) shmat(shmid, NULL, 0)) == (char *) -1) {
+#ifdef DEBUG
+	fprintf(stderr,"shmat failed to update value\n");
+#endif
+      }
+      else{
+	tmpMap=getMapFromMaps(conf,"lenv","status");
+	s1=shm;
+	for(s=tmpMap->value;*s!=NULL && *s!=0;s++){
+	  *s1++=*s;
+	}
+	*s1=NULL;
+	shmdt((void *)shm);
+      }
+    }
+  }
+}
+
+char* getStatus(int pid){
+  int shmid,i;
+  key_t key;
+  void *shm;
+  char *s;
+  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{
+      return (char*)shm;
+    }
+  }
+  return "-1";
+}
+
+#endif
+
+#ifdef USE_JS
+
+JSBool
+JSUpdateStatus(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  JS_MaybeGC(cx);
+  char *sid;
+  int istatus=0;
+  char *status=NULL;
+  maps *conf;
+  int i=0;
+  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){
+    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);
+  JS_MaybeGC(cx);
+  return JS_TRUE;
+}
+
+#endif
+
+
+
+/* Returns a url-encoded version of str */
+/* IMPORTANT: 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;
+}
+
+/* Returns a url-decoded version of str */
+/* IMPORTANT: 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;
+}
+
+char *zCapitalize1(char *tmp){
+        char *res=strdup(tmp);
+        if(res[0]>=97 && res[0]<=122)
+                res[0]-=32;
+        return res;
+}
+
+char *zCapitalize(char *tmp){
+  int i=0;
+  char *res=strdup(tmp);
+  for(i=0;i<strlen(res);i++)
+    if(res[i]>=97 && res[i]<=122)
+      res[i]-=32;
+  return res;
+}
+
+
+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;
+}
+
+int zooXmlAddNs(xmlNodePtr nr,const char* url,const char* name){
+#ifdef DEBUG
+  fprintf(stderr,"zooXmlAddNs %d \n",nbNs);
+#endif
+  int currId=-1;
+  int currNode=-1;
+  if(nbNs==0){
+    nbNs++;
+    currId=0;
+    nsName[currId]=strdup(name);
+    usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
+  }else{
+    currId=zooXmlSearchForNs(name);
+    if(currId<0){
+      nbNs++;
+      currId=nbNs-1;
+      nsName[currId]=strdup(name);
+      usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
+    }
+  }
+  return currId;
+}
+
+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;
+}
+
+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]=strdup("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]=strdup("soap");
+    usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
+    nbNs++;
+    nsName[nbNs]=strdup("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;
+}
+
+xmlNodePtr printGetCapabilitiesHeader(xmlDocPtr doc,const char* service,maps* m){
+
+  xmlNsPtr ns,ns_ows,ns_xlink,ns_xsi;
+  xmlNodePtr n,nc,nc1,nc2,nc3,nc4,nc5,nc6,pseudor;
+  xmlChar *xmlbuff;
+  int buffersize;
+  /**
+   * Create the document and its temporary root.
+   */
+  int wpsId=zooXmlAddNs(NULL,"http://www.opengis.net/wps/1.0.0","wps");
+  ns=usedNs[wpsId];
+  maps* toto1=getMaps(m,"main");
+
+  n = xmlNewNode(ns, BAD_CAST "Capabilities");
+  int owsId=zooXmlAddNs(n,"http://www.opengis.net/ows/1.1","ows");
+  ns_ows=usedNs[owsId];
+  xmlNewNs(n,BAD_CAST "http://www.opengis.net/wps/1.0.0",BAD_CAST "wps");
+  int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
+  ns_xsi=usedNs[xsiId];
+  int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+  xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsGetCapabilities_response.xsd"); 
+  xmlNewProp(n,BAD_CAST "service",BAD_CAST "WPS");
+  addLangAttr(n,m);
+  
+  if(toto1!=NULL){
+    map* tmp=getMap(toto1->content,"version");
+    if(tmp!=NULL){
+      xmlNewProp(n,BAD_CAST "version",BAD_CAST tmp->value);
+    }
+    else
+      xmlNewProp(n,BAD_CAST "version",BAD_CAST "1.0.0");
+  }
+  else
+    xmlNewProp(n,BAD_CAST "version",BAD_CAST "1.0.0");
+
+  char tmp[256];
+  
+  nc = xmlNewNode(ns_ows, BAD_CAST "ServiceIdentification");
+  maps* tmp4=getMaps(m,"identification");
+  if(tmp4!=NULL){
+    map* tmp2=tmp4->content;
+    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");
+	    xmlAddChild(nc2,xmlNewText(BAD_CAST "1.0.0"));
+	    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;
+    char *tmpAddress[6];
+    tmpAddress[0]="addressDeliveryPoint";
+    tmpAddress[1]="addressCity";
+    tmpAddress[2]="addressAdministrativeArea";
+    tmpAddress[3]="addressPostalCode";
+    tmpAddress[4]="addressCountry";
+    tmpAddress[5]="addressElectronicMailAddress";
+    char *tmpPhone[2];
+    tmpPhone[0]="phoneVoice";
+    tmpPhone[1]="phoneFacsimile";
+    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 *toto=NULL;
+		      char *toto1=tmp2->name;
+		      toto=strstr(toto1,"Phone");
+		      nc1 = xmlNewNode(ns_ows, BAD_CAST toto1+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 *toto=NULL;
+			char *toto1=tmp2->name;
+			toto=strstr(toto1,"Address");
+			nc1 = xmlNewNode(ns_ows, BAD_CAST toto1+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");
+  char *tmp2[3];
+  tmp2[0]=strdup("GetCapabilities");
+  tmp2[1]=strdup("DescribeProcess");
+  tmp2[2]=strdup("Execute");
+  int j=0;
+
+  if(toto1!=NULL){
+    map* tmp=getMap(toto1->content,"serverAddress");
+    if(tmp!=NULL){
+      SERVICE_URL = strdup(tmp->value);
+    }
+    else
+      SERVICE_URL = strdup("not_found");
+  }
+  else
+    SERVICE_URL = strdup("not_found");
+
+  for(j=0;j<3;j++){
+    nc1 = xmlNewNode(ns_ows, BAD_CAST "Operation");
+    xmlNewProp(nc1,BAD_CAST "name",BAD_CAST tmp2[j]);
+    nc2 = xmlNewNode(ns_ows, BAD_CAST "DCP");
+    nc3 = xmlNewNode(ns_ows, BAD_CAST "HTTP");
+    nc4 = xmlNewNode(ns_ows, BAD_CAST "Get");
+    sprintf(tmp,"%s/%s",SERVICE_URL,service);
+    xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST tmp);
+    xmlAddChild(nc3,nc4);
+    if(j>0){
+      nc4 = xmlNewNode(ns_ows, BAD_CAST "Post");
+      xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST tmp);
+      xmlAddChild(nc3,nc4);
+    }
+    xmlAddChild(nc2,nc3);
+    xmlAddChild(nc1,nc2);    
+    xmlAddChild(nc,nc1);    
+  }
+  for(j=2;j>=0;j--)
+    free(tmp2[j]);
+  xmlAddChild(n,nc);
+
+  nc = xmlNewNode(ns, BAD_CAST "ProcessOfferings");
+  xmlAddChild(n,nc);
+
+  nc1 = xmlNewNode(ns, BAD_CAST "Languages");
+  nc2 = xmlNewNode(ns, BAD_CAST "Default");
+  nc3 = xmlNewNode(ns, BAD_CAST "Supported");
+  
+  toto1=getMaps(m,"main");
+  if(toto1!=NULL){
+    map* tmp1=getMap(toto1->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{
+	nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
+	xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
+	if(dcount==0){
+	  xmlAddChild(nc2,nc4);
+	  xmlAddChild(nc1,nc2);
+	  dcount++;
+	}
+	nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
+	xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
+	xmlAddChild(nc3,nc4);
+	j=0;
+	buff[j]=0;
+      }
+      i++;
+    }
+    if(strlen(buff)>0){
+      nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
+      xmlAddChild(nc4,xmlNewText(BAD_CAST buff));	      
+      xmlAddChild(nc3,nc4);
+    }
+  }
+  xmlAddChild(nc1,nc3);
+  xmlAddChild(n,nc1);
+  
+  xmlNodePtr fn=soapEnvelope(m,n);
+  xmlDocSetRootElement(doc, fn);
+  //xmlFreeNs(ns);
+  free(SERVICE_URL);
+  return nc;
+}
+
+void printGetCapabilitiesForProcess(maps* m,xmlNodePtr nc,service* serv){
+  xmlNsPtr ns,ns_ows,ns_xlink;
+  xmlNodePtr nr,n,nc1,nc2,nc3,nc4,nc5,nc6,pseudor;
+  /**
+   * Initialize or get existing namspaces
+   */
+  int wpsId=zooXmlAddNs(NULL,"http://www.opengis.net/wps/1.0.0","wps");
+  ns=usedNs[wpsId];
+  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
+  ns_ows=usedNs[owsId];
+  int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+
+  int cursor=0;
+  map* tmp1;
+  if(serv->content!=NULL){
+    nc1 = xmlNewNode(ns, BAD_CAST "Process");
+    tmp1=getMap(serv->content,"processVersion");
+    if(tmp1!=NULL)
+      xmlNewNsProp(nc1,ns,BAD_CAST "processVersion",BAD_CAST tmp1->value);
+    printDescription(nc1,ns_ows,serv->name,serv->content);
+    tmp1=serv->metadata;
+    while(tmp1!=NULL){
+      nc2 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
+      xmlNewNsProp(nc2,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
+      xmlAddChild(nc1,nc2);
+      tmp1=tmp1->next;
+    }
+    xmlAddChild(nc,nc1);
+  }
+}
+
+xmlNodePtr printDescribeProcessHeader(xmlDocPtr doc,const char* service,maps* m){
+
+  xmlNsPtr ns,ns_ows,ns_xlink,ns_xsi;
+  xmlNodePtr n,nr;
+  xmlChar *xmlbuff;
+  int buffersize;
+
+  int wpsId=zooXmlAddNs(NULL,"http://schemas.opengis.net/wps/1.0.0","wps");
+  ns=usedNs[wpsId];
+  n = xmlNewNode(ns, BAD_CAST "ProcessDescriptions");
+  int owsId=zooXmlAddNs(n,"http://www.opengis.net/ows/1.1","ows");
+  ns_ows=usedNs[owsId];
+  xmlNewNs(n,BAD_CAST "http://www.opengis.net/wps/1.0.0",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];
+  
+  xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsDescribeProcess_response.xsd");
+  xmlNewProp(n,BAD_CAST "service",BAD_CAST "WPS");
+  xmlNewProp(n,BAD_CAST "version",BAD_CAST "1.0.0");
+  addLangAttr(n,m);
+
+  xmlNodePtr fn=soapEnvelope(m,n);
+  xmlDocSetRootElement(doc, fn);
+
+  return n;
+}
+
+void printDescribeProcessForProcess(maps* m,xmlNodePtr nc,service* serv,int sc){
+  xmlNsPtr ns,ns_ows,ns_xlink,ns_xsi;
+  xmlNodePtr nr,n,nc1,nc2,nc3,nc4,nc5,nc6,pseudor;
+
+  char tmp[256];
+  n=nc;
+  
+  int wpsId=zooXmlAddNs(NULL,"http://schemas.opengis.net/wps/1.0.0","wps");
+  ns=usedNs[wpsId];
+  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
+  ns_ows=usedNs[owsId];
+  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+
+  nc = xmlNewNode(NULL, BAD_CAST "ProcessDescription");
+  char *tmp4[3];
+  tmp4[0]="processVersion";
+  tmp4[1]="storeSupported";
+  tmp4[2]="statusSupported";
+  int j=0;
+  map* tmp1=NULL;
+  for(j=0;j<3;j++){
+    tmp1=getMap(serv->content,tmp4[j]);
+    if(tmp1!=NULL){
+      if(j==0)
+	xmlNewNsProp(nc,ns,BAD_CAST "processVersion",BAD_CAST tmp1->value);      
+      else
+	xmlNewProp(nc,BAD_CAST tmp4[j],BAD_CAST tmp1->value);      
+    }
+    else{
+      if(j>0)
+	xmlNewProp(nc,BAD_CAST tmp4[j],BAD_CAST "false");      
+    }
+  }
+  
+  printDescription(nc,ns_ows,serv->name,serv->content);
+
+  tmp1=serv->metadata;
+  while(tmp1!=NULL){
+    nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
+    xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
+    xmlAddChild(nc,nc1);
+    tmp1=tmp1->next;
+  }
+
+  tmp1=getMap(serv->content,"Profile");
+  if(tmp1!=NULL){
+    nc1 = xmlNewNode(ns, BAD_CAST "Profile");
+    xmlAddChild(nc1,xmlNewText(BAD_CAST tmp1->value));
+    xmlAddChild(nc,nc1);
+  }
+
+  nc1 = xmlNewNode(NULL, BAD_CAST "DataInputs");
+  elements* e=serv->inputs;
+  printFullDescription(e,"Input",ns_ows,nc1);
+  xmlAddChild(nc,nc1);
+
+  nc1 = xmlNewNode(NULL, BAD_CAST "ProcessOutputs");
+  e=serv->outputs;
+  printFullDescription(e,"Output",ns_ows,nc1);
+  xmlAddChild(nc,nc1);
+
+  xmlAddChild(n,nc);
+
+}
+
+void printFullDescription(elements *elem,const char* type,xmlNsPtr ns_ows,xmlNodePtr nc1){
+  char *orderedFields[7];
+  orderedFields[0]="mimeType";
+  orderedFields[1]="encoding";
+  orderedFields[2]="schema";
+  orderedFields[3]="dataType";
+  orderedFields[4]="uom";
+  orderedFields[5]="CRS";
+  orderedFields[6]="value";
+
+  xmlNodePtr nc2,nc3,nc4,nc5,nc6,nc7;
+  elements* e=elem;
+  map* tmp1=NULL;
+  while(e!=NULL){
+    int default1=0;
+    int isAnyValue=1;
+    nc2 = xmlNewNode(NULL, BAD_CAST type);
+    tmp1=getMap(e->content,"minOccurs");
+    if(tmp1){
+      xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
+    }
+    tmp1=getMap(e->content,"maxOccurs");
+    if(tmp1){
+      xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
+    }
+
+    printDescription(nc2,ns_ows,e->name,e->content);
+
+    if(strncmp(type,"Output",6)==0){
+      if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0)
+	nc3 = xmlNewNode(NULL, BAD_CAST "LiteralOutput");
+      else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
+	nc3 = xmlNewNode(NULL, BAD_CAST "ComplexOutput");
+      else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
+	nc3 = xmlNewNode(NULL, BAD_CAST "BoundingBoxOutput");
+      else
+	nc3 = xmlNewNode(NULL, BAD_CAST e->format);
+    }else{
+      if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0){
+	nc3 = xmlNewNode(NULL, BAD_CAST "LiteralData");
+      }
+      else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
+	nc3 = xmlNewNode(NULL, BAD_CAST "ComplexData");
+      else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
+	nc3 = xmlNewNode(NULL, BAD_CAST "BoundingBoxData");
+      else
+	nc3 = xmlNewNode(NULL, BAD_CAST e->format);
+    }
+    iotype* _tmp=e->defaults;
+    int datatype=0;
+    bool hasDefault=false;
+    bool hasUOM=false;
+    if(_tmp!=NULL){
+      if(strcmp(e->format,"LiteralOutput")==0 ||
+	 strcmp(e->format,"LiteralData")==0){
+     	datatype=1;
+	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;
+	//nc4 = xmlNewNode(NULL, BAD_CAST "BoundingBoxOutput");
+	nc5 = xmlNewNode(NULL, BAD_CAST "Default");
+      }
+      else{
+	nc4 = xmlNewNode(NULL, BAD_CAST "Default");
+	nc5 = xmlNewNode(NULL, BAD_CAST "Format");
+      }
+      
+      tmp1=_tmp->content;
+      int avcnt=0;
+      int dcnt=0;
+      int oI=0;
+      for(oI=0;oI<7;oI++)
+	if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
+	  //while(tmp1!=NULL){
+#ifdef DEBUG
+	  printf("DATATYPE DEFAULT ? %s\n",tmp1->name);
+#endif
+	  if(strncasecmp(tmp1->name,"DataType",8)==0){
+	    nc6 = xmlNewNode(ns_ows, BAD_CAST "DataType");
+	    xmlAddChild(nc6,xmlNewText(BAD_CAST tmp1->value));
+	    char tmp[1024];
+	    sprintf(tmp,"http://www.w3.org/TR/xmlschema-2/#%s",tmp1->value);
+	    xmlNewNsProp(nc6,ns_ows,BAD_CAST "reference",BAD_CAST tmp);
+	    xmlAddChild(nc3,nc6);
+	    tmp1=tmp1->next;
+	    datatype=1;
+	    continue;
+	  }
+	  if(strcmp(tmp1->name,"asReference")!=0 &&
+	     strncasecmp(tmp1->name,"DataType",8)!=0 &&
+	     strcasecmp(tmp1->name,"extension")!=0 &&
+	     strcasecmp(tmp1->name,"value")!=0 &&
+	     strncasecmp(tmp1->name,"AllowedValues",13)!=0){
+	    if(datatype!=1){
+	      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);
+	    }
+	    xmlAddChild(nc6,xmlNewText(BAD_CAST tmp1->value));
+	    xmlAddChild(nc5,nc6);
+	    hasUOM=true;
+	  }else 
+	    if(strncmp(type,"Input",5)==0){
+	      if(strcmp(tmp1->name,"value")==0){
+		nc7 = xmlNewNode(NULL, BAD_CAST "DefaultValue");
+		xmlAddChild(nc7,xmlNewText(BAD_CAST tmp1->value));
+		default1=1;
+	      }
+	      if(strncasecmp(tmp1->name,"AllowedValues",13)==0){
+		nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
+		fprintf(stderr,"ALLOWED VALUE %s\n",tmp1->value);
+		char *token,*saveptr1;
+		token=strtok_r(tmp1->value,",",&saveptr1);
+		while(token!=NULL){
+		  nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
+		  char *tmps=strdup(token);
+		  tmps[strlen(tmps)]=0;
+		  xmlAddChild(nc7,xmlNewText(BAD_CAST tmps));
+		  fprintf(stderr,"strgin : %s\n",tmps);
+		  xmlAddChild(nc6,nc7);
+		  token=strtok_r(NULL,",",&saveptr1);
+		}
+		xmlAddChild(nc3,nc6);
+		isAnyValue=-1;
+	      }
+	      hasDefault=true;
+	    }
+	  tmp1=tmp1->next;
+	  if(datatype!=2){
+	    if(hasUOM==true){
+	      xmlAddChild(nc4,nc5);
+	      xmlAddChild(nc3,nc4);
+	    }
+	  }else{
+	    xmlAddChild(nc3,nc5);
+	  }
+	 
+	  if(strncmp(type,"Input",5)==0){
+	    if(datatype==1 && isAnyValue==1 && avcnt==0){
+	      xmlAddChild(nc3,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
+	      hasDefault=true;
+	      avcnt++;
+	    }
+	    if(datatype==1 && default1>0){
+	      xmlAddChild(nc3,nc7);
+	    }
+	  }
+	}
+    }
+
+    _tmp=e->supported;
+    if(_tmp==NULL && (getMap(e->defaults->content,"uom")!=NULL || datatype!=1))
+      _tmp=e->defaults;
+
+    int hasSupported=-1;
+    while(_tmp!=NULL){
+      if(hasSupported<0){
+	if(datatype==0){
+	  nc4 = xmlNewNode(NULL, BAD_CAST "Supported");
+	  nc5 = xmlNewNode(NULL, BAD_CAST "Format");
+	}
+	else
+	  nc5 = xmlNewNode(NULL, BAD_CAST "Supported");
+	hasSupported=0;
+      }else
+	if(datatype==0)
+	  nc5 = xmlNewNode(NULL, BAD_CAST "Format");
+      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,"DataType")!=0 &&
+	     strcasecmp(tmp1->name,"extension")!=0){
+	    if(datatype!=1){
+	      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));
+		xmlAddChild(nc5,nc6);
+		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));
+	      xmlAddChild(nc5,nc6);
+	    }
+	  }
+	  tmp1=tmp1->next;
+	}
+      if(hasSupported<=0){
+	if(datatype!=2){
+	  xmlAddChild(nc4,nc5);
+	  xmlAddChild(nc3,nc4);
+	}else
+	  xmlAddChild(nc3,nc5);
+	hasSupported=1;
+      }
+      else
+	if(datatype!=2){
+	  xmlAddChild(nc4,nc5);
+	}
+	else
+	  xmlAddChild(nc3,nc5);
+      _tmp=_tmp->next;
+    }
+    xmlAddChild(nc2,nc3);
+    
+    if(datatype!=2 && hasUOM==true){
+      xmlAddChild(nc3,nc4);
+      xmlAddChild(nc2,nc3);
+    }else if(datatype!=2){
+      if(hasDefault!=true && strncmp(type,"Input",5)==0)
+	xmlAddChild(nc3,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
+    }
+    
+    xmlAddChild(nc1,nc2);
+    
+    e=e->next;
+  }
+}
+
+void printProcessResponse(maps* m,map* request, int pid,service* serv,const char* service,int status,maps* inputs,maps* outputs){
+  xmlNsPtr ns,ns1,ns_ows,ns_xlink,ns_xsi;
+  xmlNodePtr nr,n,nc,nc1,nc2,nc3,pseudor;
+  xmlDocPtr doc;
+  xmlChar *xmlbuff;
+  int buffersize;
+  time_t time1;  
+  time(&time1);
+  nr=NULL;
+  /**
+   * Create the document and its temporary root.
+   */
+  doc = xmlNewDoc(BAD_CAST "1.0");
+  int wpsId=zooXmlAddNs(NULL,"http://www.opengis.net/wps/1.0.0","wps");
+  ns=usedNs[wpsId];
+
+  n = xmlNewNode(ns, BAD_CAST "ExecuteResponse");
+  xmlNewNs(n,BAD_CAST "http://www.opengis.net/wps/1.0.0",BAD_CAST "wps");
+  int owsId=zooXmlAddNs(n,"http://www.opengis.net/ows/1.1","ows");
+  ns_ows=usedNs[owsId];
+  int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
+  ns_xlink=usedNs[xlinkId];
+  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/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsExecute_response.xsd");
+  
+  xmlNewProp(n,BAD_CAST "service",BAD_CAST "WPS");
+  xmlNewProp(n,BAD_CAST "version",BAD_CAST "1.0.0");
+  addLangAttr(n,m);
+
+  char tmp[256];
+  char url[1024];
+  char stored_path[1024];
+  memset(tmp,0,256);
+  memset(url,0,1024);
+  memset(stored_path,0,1024);
+  maps* tmp_maps=getMaps(m,"main");
+  if(tmp_maps!=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 ...
+     */
+    char ntmp[1024];
+#ifndef WIN32
+    getcwd(ntmp,1024);
+#else
+    _getcwd(ntmp,1024);
+#endif
+    struct stat myFileInfo;
+    int statRes;
+    char file_path[1024];
+    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","sid");
+      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{
+      map* tmpm2=getMap(tmp_maps->content,"tmpUrl");
+      if(tmpm1!=NULL && tmpm2!=NULL){
+	if(strncasecmp(tmpm2->value,"http://",7)==0){
+	  sprintf(url,"%s/%s_%i.xml",tmpm2->value,service,pid);
+	}else
+	  sprintf(url,"%s/%s/%s_%i.xml",tmpm1->value,tmpm2->value,service,pid);
+      }
+    }
+    if(tmpm1!=NULL)
+      sprintf(tmp,"%s",tmpm1->value);
+    tmpm1=getMapFromMaps(m,"main","TmpPath");
+    sprintf(stored_path,"%s/%s_%i.xml",tmpm1->value,service,pid);
+  }
+
+
+
+  xmlNewProp(n,BAD_CAST "serviceInstance",BAD_CAST tmp);
+  map* test=getMap(request,"storeExecuteResponse");
+  bool hasStoredExecuteResponse=false;
+  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);
+  
+  printDescription(nc,ns_ows,serv->name,serv->content);
+
+  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,_("Service \"%s\" run 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,_("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,_("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."),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 1 161\n");
+#endif
+
+  map* lineage=getMap(request,"lineage");
+  if(lineage!=NULL && strcasecmp(lineage->value,"true")==0){
+    nc = xmlNewNode(ns, BAD_CAST "DataInputs");
+    int i;
+    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");
+      mcursor=mcursor->next;
+    }
+    xmlAddChild(n,nc);
+    
+#ifdef DEBUG
+    fprintf(stderr,"printProcessResponse 1 177\n");
+#endif
+
+    nc = xmlNewNode(ns, BAD_CAST "OutputDefinitions");
+    mcursor=outputs;
+    scursor=NULL;
+    while(mcursor!=NULL){
+      scursor=getElements(serv->outputs,mcursor->name);
+      printOutputDefinitions1(doc,nc,ns,ns_ows,scursor,mcursor,"Output");
+      mcursor=mcursor->next;
+    }
+    xmlAddChild(n,nc);
+  }
+#ifdef DEBUG
+  fprintf(stderr,"printProcessResponse 1 190\n");
+#endif
+
+  /**
+   * Display the process output only when requested !
+   */
+  if(status==SERVICE_SUCCEEDED){
+    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)
+	  printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output");
+	else
+	  if(tmp0!=NULL && strncmp(tmp0->value,"true",4)==0)
+	    printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output");
+      }
+      mcursor=mcursor->next;
+    }
+    xmlAddChild(n,nc);
+  }
+
+#ifdef DEBUG
+  fprintf(stderr,"printProcessResponse 1 202\n");
+#endif
+  nr=soapEnvelope(m,n);
+  xmlDocSetRootElement(doc, nr);
+
+  if(hasStoredExecuteResponse==true){
+    /* 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);
+      map * errormap = createMap("text",tmpMsg);
+      addToMap(errormap,"code", "InternalError");
+      printExceptionReportResponse(m,errormap);
+      freeMap(&errormap);
+      free(errormap);
+      xmlCleanupParser();
+      zooXmlCleanupNs();
+      return;
+    }
+    xmlChar *xmlbuff;
+    int buffersize;
+    xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, "UTF-8", 1);
+    fwrite(xmlbuff,1,xmlStrlen(xmlbuff)*sizeof(char),output);
+    xmlFree(xmlbuff);
+    fclose(output);
+  }
+  printDocument(m,doc,pid);
+
+  xmlCleanupParser();
+  zooXmlCleanupNs();
+}
+
+
+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);
+  }
+  fflush(stdout);
+  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();
+}
+
+void printOutputDefinitions1(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);
+
+  xmlAddChild(nc,nc1);
+
+}
+
+void printOutputDefinitions(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,elements* e,map* m,const char* type){
+  xmlNodePtr nc1,nc2,nc3;
+  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){
+    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);
+
+  xmlAddChild(nc,nc1);
+
+}
+
+void printIOType(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,elements* e,maps* m,const char* type){
+  xmlNodePtr nc1,nc2,nc3;
+  nc1=xmlNewNode(ns_wps, BAD_CAST type);
+  map *tmp=NULL;
+  if(e!=NULL)
+    tmp=e->content;
+  else
+    tmp=m->content;
+#ifdef DEBUG
+  dumpMap(tmp);
+  dumpElements(e);
+#endif
+  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);
+  // Extract Title required to be first element in the ZCFG file !
+  bool isTitle=TRUE;
+  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);
+  }
+
+  /**
+   * IO type Reference or full Data ?
+   */
+#ifdef DEBUG
+  fprintf(stderr,"FORMAT %s %s\n",e->format,e->format);
+#endif
+  map *tmpMap=getMap(m->content,"Reference");
+  if(tmpMap==NULL){
+    nc2=xmlNewNode(ns_wps, BAD_CAST "Data");
+    if(e!=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 "LitteralData");
+    } 
+    tmp=m->content;
+#ifdef USE_MS
+    map* testMap=getMap(tmp,"requestedMimeType");
+#endif
+    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)
+#ifdef USE_MS
+	if(testMap==NULL || (testMap!=NULL && strncasecmp(testMap->value,"text/xml",8)==0)){
+#endif
+	xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
+#ifdef USE_MS
+	}
+      else
+	if(strcasecmp(tmp->name,"mimeType")==0)
+	  if(testMap!=NULL)
+	    xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST testMap->value);
+	  else 
+	    xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
+#endif
+      tmp=tmp->next;
+      xmlAddChild(nc2,nc3);
+    }
+    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)
+	tmp=getMap(e->defaults->content,"mimeType");
+      else
+	tmp=NULL;
+#ifdef USE_MS
+      /**
+       * In case of OGC WebServices output use, as the data was requested
+       * with asReference=false we have to download the resulting OWS request
+       * stored in the Reference map value.
+       */
+      map* testMap=getMap(m->content,"requestedMimeType");
+      if(testMap!=NULL){
+	HINTERNET hInternet;
+	hInternet=InternetOpen(
+#ifndef WIN32
+			       (LPCTSTR)
+#endif
+			       "ZooWPSClient\0",
+			       INTERNET_OPEN_TYPE_PRECONFIG,
+			       NULL,NULL, 0);
+	testMap=getMap(m->content,"Reference");
+	loadRemoteFile(m,m->content,hInternet,testMap->value);
+	InternetCloseHandle(hInternet);
+      }
+#endif
+      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)
+	 || (tmp2!=NULL && (strncmp(tmp2->value,"image/",6)==0 ||
+			    (strncmp(tmp2->value,"application/",12)==0) &&
+			    strncmp(tmp2->value,"application/json",16)!=0&&
+			    strncmp(tmp2->value,"application/vnd.google-earth.kml",32)!=0)
+	     )) {
+	map* rs=getMap(m->content,"size");
+	bool isSized=true;
+	if(rs==NULL){
+	  char tmp1[1024];
+	  sprintf(tmp1,"%d",strlen(tmp3->value));
+	  rs=createMap("size",tmp1);
+	  isSized=false;
+	}
+
+	xmlAddChild(nc3,xmlNewText(BAD_CAST base64(tmp3->value, atoi(rs->value))));
+	if(!isSized){
+	  freeMap(&rs);
+	  free(rs);
+	}
+      }
+      else if(tmp2!=NULL){
+	if(strncmp(tmp2->value,"text/js",7)==0 ||
+	   strncmp(tmp2->value,"application/json",16)==0)
+	  xmlAddChild(nc3,xmlNewCDataBlock(doc,BAD_CAST tmp3->value,strlen(tmp3->value)));
+	else{
+	  if(strncmp(tmp2->value,"text/xml",8)==0 ||
+	     strncmp(tmp2->value,"application/vnd.google-earth.kml",32)==0){
+	    xmlDocPtr doc =
+	      xmlParseMemory(tmp3->value,strlen(tmp3->value));
+	    xmlNodePtr ir = xmlDocGetRootElement(doc);
+	    xmlAddChild(nc3,ir);
+	  }
+	  else
+	    xmlAddChild(nc3,xmlNewText(BAD_CAST tmp3->value));
+	}
+	xmlAddChild(nc2,nc3);
+      }
+      else{
+	xmlAddChild(nc3,xmlNewText(BAD_CAST tmp3->value));
+      }
+      if(hasValue<0){
+	freeMap(&tmp3);
+	free(tmp3);
+      }
+    }
+  }
+  else{
+    tmpMap=getMap(m->content,"Reference");
+    nc3=nc2=xmlNewNode(ns_wps, BAD_CAST "Reference");
+    if(strcasecmp(type,"Output")==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;
+#ifdef USE_MS
+    map* testMap=getMap(tmp,"requestedMimeType");
+#endif
+    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)
+#ifdef USE_MS
+	if(testMap!=NULL  && strncasecmp(testMap->value,"text/xml",8)!=0){
+	  if(strcasecmp(tmp->name,"mimeType")==0)
+	    xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST testMap->value);
+	}
+	else
+#endif
+	xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
+      tmp=tmp->next;
+      xmlAddChild(nc2,nc3);
+    }
+  }
+  xmlAddChild(nc1,nc2);
+  xmlAddChild(nc,nc1);
+
+}
+
+void printDescription(xmlNodePtr root,xmlNsPtr ns_ows,const char* identifier,map* amap){
+  xmlNodePtr nc2 = xmlNewNode(ns_ows, BAD_CAST "Identifier");
+  xmlAddChild(nc2,xmlNewText(BAD_CAST identifier));
+  xmlAddChild(root,nc2);
+  map* tmp=amap;
+  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);
+    }
+  }
+}
+
+char* getEncoding(maps* m){
+  if(m!=NULL){
+    map* tmp=getMap(m->content,"encoding");
+    if(tmp!=NULL){
+      return tmp->value;
+    }
+    else
+      return "UTF-8";
+  }
+  else
+    return "UTF-8";  
+}
+
+char* getVersion(maps* m){
+  if(m!=NULL){
+    map* tmp=getMap(m->content,"version");
+    if(tmp!=NULL){
+      return tmp->value;
+    }
+    else
+      return "1.0.0";
+  }
+  else
+    return "1.0.0";
+}
+
+void printExceptionReportResponse(maps* m,map* s){
+  int buffersize;
+  xmlDocPtr doc;
+  xmlChar *xmlbuff;
+  xmlNodePtr n;
+
+  doc = xmlNewDoc(BAD_CAST "1.0");
+  maps* tmpMap=getMaps(m,"main");
+  char *encoding=getEncoding(tmpMap);
+  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: 200 OK\r\n\r\n",encoding);
+      }
+    }
+    else{
+      printHeaders(m);
+      printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
+    }
+  }else{
+    printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
+  }
+  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();
+}
+
+xmlNodePtr createExceptionReportNode(maps* m,map* s,int use_ns){
+  
+  int buffersize;
+  xmlChar *xmlbuff;
+  xmlNsPtr ns,ns_ows,ns_xlink,ns_xsi;
+  xmlNodePtr n,nc,nc1,nc2;
+
+  maps* tmpMap=getMaps(m,"main");
+
+  int nsid=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
+  ns=usedNs[nsid];
+  n = xmlNewNode(ns, BAD_CAST "ExceptionReport");
+
+  if(use_ns==1){
+    ns_ows=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];
+    int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
+    ns_xlink=usedNs[xlinkId];
+    xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd");
+  }
+  addLangAttr(n,m);
+  xmlNewProp(n,BAD_CAST "version",BAD_CAST "1.1.0");
+  
+  nc = xmlNewNode(ns, BAD_CAST "Exception");
+
+  map* 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=getMap(s,"text");
+  nc1 = xmlNewNode(ns, BAD_CAST "ExceptionText");
+  nc2=NULL;
+  if(tmp!=NULL){
+    xmlNodeSetContent(nc1, BAD_CAST tmp->value);
+  }
+  else{
+    xmlNodeSetContent(nc1, BAD_CAST _("No debug message available"));
+  }
+  xmlAddChild(nc,nc1);
+  xmlAddChild(n,nc);
+  return n;
+}
+
+
+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;
+  
+  maps* tmpSess=getMaps(m,"senv");
+  if(tmpSess!=NULL){
+    map *_tmp=getMapFromMaps(m,"lenv","cookie");
+    char* sessId;
+    if(_tmp!=NULL){
+      printf("Set-Cookie: %s\r\n",_tmp->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=strdup(session_file_path);
+    }else{
+      maps* t=getMaps(m,"senv");
+      map*p=t->content;
+      while(p!=NULL){
+	if(strstr(p->name,"ID")!=NULL){
+	  sessId=strdup(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);
+      map * errormap = createMap("text",tmpMsg);
+      addToMap(errormap,"code", "InternalError");
+      printExceptionReportResponse(m,errormap);
+      freeMap(&errormap);
+      free(errormap);
+      return;
+    }
+    else{
+      fclose(teste);
+      dumpMapsToFile(tmpSess,session_file_path);
+    }
+  }
+  
+  if(asRaw==0){
+#ifdef DEBUG
+    fprintf(stderr,"REQUEST_OUTPUTS FINAL\n");
+    dumpMaps(request_outputs);
+#endif
+    maps* tmpI=request_outputs;
+    while(tmpI!=NULL){
+#ifdef USE_MS
+      map* testMap=getMap(tmpI->content,"useMapserver");	
+#endif
+      toto=getMap(tmpI->content,"asReference");
+#ifdef USE_MS
+      if(toto!=NULL && strcasecmp(toto->value,"true")==0 && testMap==NULL){
+#else
+      if(toto!=NULL && strcasecmp(toto->value,"true")==0){
+#endif
+	elements* in=getElements(s->outputs,tmpI->name);
+	char *format=NULL;
+	if(in!=NULL){
+	  format=strdup(in->format);
+	}else
+	  format=strdup("LiteralData");
+	if(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");
+	}
+	map *ext=getMap(tmpI->content,"extension");
+	map *tmp1=getMapFromMaps(m,"main","tmpPath");
+	char *file_name;
+	bool hasExt=true;
+	if(ext==NULL){
+	  // We can fallback to a default list of supported formats using
+	  // mimeType information if present here. Maybe we can add more formats
+	  // here.
+	  // If mimeType was not found, we then set txt as the default extension
+	  map* mtype=getMap(tmpI->content,"mimeType");
+	  if(mtype!=NULL){
+	    if(strcasecmp(mtype->value,"text/xml")==0)
+	      ext=createMap("extension","xml");
+	    else if(strcasecmp(mtype->value,"application/json")==0)
+	      ext=createMap("extension","js");
+	    else if(strncmp(mtype->value,"application/vnd.google-earth.kml",32)==0)
+	      ext=createMap("extension","kml");
+	    else if(strncmp(mtype->value,"image/",6)==0)
+	      ext=createMap("extension",strstr(mtype->value,"/")+1);
+	    else
+	      ext=createMap("extension","txt");
+	  }
+	  else
+	    ext=createMap("extension","txt");
+	  hasExt=false;
+	}
+	file_name=(char*)malloc((strlen(tmp1->value)+strlen(s->name)+strlen(ext->value)+strlen(tmpI->name)+13)*sizeof(char));
+	sprintf(file_name,"%s/%s_%s_%i.%s",tmp1->value,s->name,tmpI->name,cpid+100000,ext->value);
+	FILE *ofile=fopen(file_name,"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);
+	  map * errormap = createMap("text",tmpMsg);
+	  addToMap(errormap,"code", "InternalError");
+	  printExceptionReportResponse(m,errormap);
+	  freeMap(&errormap);
+	  free(errormap);
+	  return;
+	}
+	map *tmp2=getMapFromMaps(m,"main","tmpUrl");
+	map *tmp3=getMapFromMaps(m,"main","serverAddress");
+	char *file_url;
+	if(strncasecmp(tmp2->value,"http://",7)==0){
+	  file_url=(char*)malloc((strlen(tmp2->value)+strlen(s->name)+strlen(ext->value)+strlen(tmpI->name)+13)*sizeof(char));
+	  sprintf(file_url,"%s/%s_%s_%i.%s",tmp2->value,s->name,tmpI->name,cpid+100000,ext->value);
+	}else{
+	  file_url=(char*)malloc((strlen(tmp3->value)+strlen(tmp2->value)+strlen(s->name)+strlen(ext->value)+strlen(tmpI->name)+13)*sizeof(char));
+	  sprintf(file_url,"%s/%s/%s_%s_%i.%s",tmp3->value,tmp2->value,s->name,tmpI->name,cpid+100000,ext->value);
+	}
+	addToMap(tmpI->content,"Reference",file_url);
+	if(!hasExt){
+	  freeMap(&ext);
+	  free(ext);
+	}
+	toto=getMap(tmpI->content,"value");
+	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);
+	}
+	free(format);
+	fclose(ofile);
+	free(file_name);
+	free(file_url);	
+      }
+#ifdef USE_MS
+      else{
+	if(testMap!=NULL){
+	  setReferenceUrl(m,tmpI);
+	}
+      }
+#endif
+      tmpI=tmpI->next;
+    }
+    map *r_inputs=getMap(s->content,"serviceProvider");
+#ifdef DEBUG
+    fprintf(stderr,"SERVICE : %s\n",r_inputs->value);
+    dumpMaps(m);
+#endif
+    printProcessResponse(m,request_inputs1,cpid,
+			 s,r_inputs->value,res,
+			 request_inputs,
+			 request_outputs);
+  }
+  else
+    if(res!=SERVICE_FAILED){
+      /**
+       * 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{
+	toto=getMap(tmpI->content,"value");
+	if(toto==NULL){
+	  char tmpMsg[1024];
+	  sprintf(tmpMsg,_("Wrong RawDataOutput parameter, unable to fetch any result for the name your provided : \"%s\"."),tmpI->name);
+	  map * errormap = createMap("text",tmpMsg);
+	  addToMap(errormap,"code", "InvalidParameterValue");
+	  printExceptionReportResponse(m,errormap);
+	  freeMap(&errormap);
+	  free(errormap);
+	  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
+      }
+    }else{
+      char tmp[1024];
+      map * errormap;
+      map *lenv;
+      lenv=getMapFromMaps(m,"lenv","message");
+      if(lenv!=NULL)
+	sprintf(tmp,_("Unable to run the Service. The message returned back by the Service was the following : %s"),lenv->value);
+      else
+	sprintf(tmp,_("Unable to run the Service. No more information was returned back by the Service."));
+      errormap = createMap("text",tmp);      
+      addToMap(errormap,"code", "InternalError");
+      printExceptionReportResponse(m,errormap);
+      freeMap(&errormap);
+      free(errormap);
+    }
+}
+
+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)*sizeof(char));
+  memcpy(buff, bptr->data, bptr->length-1);
+  buff[bptr->length-1] = 0;
+
+  BIO_free_all(b64);
+
+  return buff;
+}
+
+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;
+}
+
+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");
+      addToMap(cursor->content,"base64_value",tmp->value);
+      int size=0;
+      char *s=strdup(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);
+    }
+    cursor=cursor->next;
+  }
+}
+
+char* addDefaultValues(maps** out,elements* in,maps* m,int type){
+  elements* tmpInputs=in;
+  maps* out1=*out;
+  if(type==1){
+    while(out1!=NULL){
+      if(getElements(in,out1->name)==NULL)
+	return out1->name;
+      out1=out1->next;
+    }
+    out1=*out;
+  }
+  while(tmpInputs!=NULL){
+    maps *tmpMaps=getMaps(out1,tmpInputs->name);
+    if(tmpMaps==NULL){
+      maps* tmpMaps2=(maps*)malloc(MAPS_SIZE);
+      tmpMaps2->name=strdup(tmpInputs->name);
+      tmpMaps2->content=NULL;
+      tmpMaps2->next=NULL;
+      
+      if(type==0){
+	map* tmpMapMinO=getMap(tmpInputs->content,"minOccurs");
+	if(tmpMapMinO!=NULL)
+	  if(atoi(tmpMapMinO->value)>=1){
+	    freeMaps(&tmpMaps2);
+	    free(tmpMaps2);
+	    return tmpInputs->name;
+	  }
+	  else{
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("minOccurs",tmpMapMinO->value);
+	    else
+	      addToMap(tmpMaps2->content,"minOccurs",tmpMapMinO->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);
+      }
+
+      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;
+	}
+      }
+      addToMap(tmpMaps2->content,"inRequest","false");
+      if(type==0){
+	map *tmpMap=getMap(tmpMaps2->content,"value");
+	if(tmpMap==NULL)
+	  addToMap(tmpMaps2->content,"value","NULL");
+      }
+      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{
+      iotype* 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.
+	 */
+	map* tmpMap1=getMap(tmpInputs->content,"minOccurs");
+	if(tmpMap1!=NULL){
+	  if(tmpMaps->content==NULL)
+	    tmpMaps->content=createMap("minOccurs",tmpMap1->value);
+	  else
+	    addToMap(tmpMaps->content,"minOccurs",tmpMap1->value);
+	}
+	map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
+	if(tmpMaxO!=NULL){
+	  if(tmpMaps->content==NULL)
+	    tmpMaps->content=createMap("maxOccurs",tmpMap1->value);
+	  else
+	    addToMap(tmpMaps->content,"maxOccurs",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(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=strdup(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);
+	    }
+	  }
+	}
+      }
+
+      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=strdup(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
+	 */
+	map* tmpCheck=getMap(tmpIoType->content,"useMapServer");
+	if(tmpCheck!=NULL){
+	  // Get the default value
+	  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");
+
+    }
+    tmpInputs=tmpInputs->next;
+  }
+  return "";
+}
+
+/**
+ * parseBoundingBox : parse a BoundingBox string
+ *
+ * OGC 06-121r3 : 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
+ *
+ * Need to create a map to store boundingbox informations :
+ *  - 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.
+ */
+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;
+}
+
+/**
+ * printBoundingBox : fill a BoundingBox node (ows:BoundingBox or 
+ * wps:BoundingBoxData). Set crs and dimensions attributes, add 
+ * Lower/UpperCorner nodes to a pre-existing XML node.
+ */
+void printBoundingBox(xmlNsPtr ns_ows,xmlNodePtr n,map* boundingbox){
+
+  xmlNodePtr bb,lw,uc;
+
+  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);
+
+}
+
+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();
+  
+}
+
+
+char* getMd5(char* url){
+  EVP_MD_CTX md5ctx;
+  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_cleanup(&md5ctx);
+  int i;
+  for(i = 0; i < len; i++){
+    if(i>0){
+      char *tmp=strdup(fresult);
+      sprintf(fresult,"%s%02x", tmp,result[i]);
+      free(tmp);
+    }
+    else
+      sprintf(fresult,"%02x",result[i]);
+  }
+  return fresult;
+}
+
+/**
+ * Cache a file for a given request
+ */
+void addToCache(maps* conf,char* request,char* content,int length){
+  map* tmp=getMapFromMaps(conf,"main","cacheDir");
+  if(tmp!=NULL){
+    char* md5str=getMd5(request);
+    char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+    sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+#ifdef DEBUG
+    fprintf(stderr,"Cache list : %s\n",fname);
+    fflush(stderr);
+#endif
+    FILE* fo=fopen(fname,"w+");
+    fwrite(content,sizeof(char),length,fo);
+    fclose(fo);
+    free(md5str);
+    free(fname);
+  }
+}
+
+char* isInCache(maps* conf,char* request){
+  map* tmpM=getMapFromMaps(conf,"main","cacheDir");
+  if(tmpM!=NULL){
+    char* md5str=getMd5(request);
+#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);
+    struct stat f_status;
+    int s=stat(fname, &f_status);
+    if(s==0 && f_status.st_size>0){
+      free(md5str);
+      return fname;
+    }
+    free(md5str);
+    free(fname);
+  }
+  return NULL;
+}
+
+/**
+ * loadRemoteFile:
+ * Try to load file from cache or download a remote file if not in cache
+ */
+int loadRemoteFile(maps* m,map* content,HINTERNET hInternet,char *url){
+  HINTERNET res;
+  char* fcontent;
+  char* cached=isInCache(m,url);
+  int fsize;
+  int hasF=-1;
+  if(cached!=NULL){
+    struct stat f_status;
+    int s=stat(cached, &f_status);
+    if(s==0){
+      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(cached,"rb");
+      int len=fread(fcontent,f_status.st_size,1,f);
+      fsize=f_status.st_size;
+      fcontent[fsize]=0;
+    }
+  }else{
+    res=InternetOpenUrl(hInternet,url,NULL,0,INTERNET_FLAG_NO_CACHE_WRITE,0);
+    fcontent=(char*)malloc((res.nDataLen+1)*sizeof(char));
+    if(fcontent == NULL){
+      return errorException(m, _("Unable to allocate memory."), "InternalError");
+    }
+    size_t dwRead;
+    InternetReadFile(res, (LPVOID)fcontent, res.nDataLen, &dwRead);
+    fcontent[res.nDataLen]=0;
+    fsize=res.nDataLen;
+  }
+  if(fsize==0){
+    return errorException(m, _("Unable to download the file."), "InternalError");
+  }
+
+  map* tmpMap=getMapOrFill(content,"value","");
+    
+  free(tmpMap->value);
+  tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
+  if(tmpMap->value==NULL)
+    fprintf(stderr,"Unable to allocate memory!\n");
+  //snprintf(tmpMap->value,(fsize+1)*sizeof(char),fcontent);
+  memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+  
+  char ltmp1[256];
+  sprintf(ltmp1,"%d",fsize);
+  addToMap(content,"size",ltmp1);
+  if(cached==NULL)
+    addToCache(m,url,fcontent,fsize);
+  else{
+    free(cached);
+  }
+  return 0;
+}
+
+int errorException(maps *m, const char *message, const char *errorcode) 
+{
+  map* errormap = createMap("text", message);
+  addToMap(errormap,"code", errorcode);
+  printExceptionReportResponse(m,errormap);
+  freeMap(&errormap);
+  free(errormap);
+  return -1;
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal.h	(revision 417)
@@ -0,0 +1,141 @@
+/**
+ * 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 
+
+#define DEFAULT_SERVICE_URL "http://www.zoo-project.org/"
+#define TIME_SIZE 40
+
+#include <libintl.h>
+#include <locale.h>
+#define _(String) dgettext ("zoo-kernel",String)
+#define _ss(String) dgettext ("zoo-services",String)
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#else
+#include <direct.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <ctype.h>
+#ifndef WIN32
+#include <xlocale.h>
+#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 "ulinet.h"
+
+extern   int getServiceFromFile(const char*,service**);
+extern   int conf_read(const char*,maps*);
+
+#ifdef USE_JS
+#ifdef WIN32
+#define XP_WIN 1
+#else
+#define XP_UNIX 0
+#endif
+#include "service_internal_js.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+  static char* SERVICE_URL;
+  static xmlNsPtr usedNs[10];
+  static char* nsName[10];
+  static int nbNs=0;
+
+  void printHeaders(maps*);
+  void unhandleStatus(maps*);
+  void updateStatus(maps*);
+  char* getStatus(int);
+
+#ifdef USE_JS
+  char* JSValToChar(JSContext*,jsval*);
+  JSBool JSUpdateStatus(JSContext*,uintN,jsval *);
+#endif
+  
+  void URLDecode(char *);
+  char *url_encode(char *);
+  char *url_decode(char *);
+  char* getEncoding(maps*);
+
+  int zooXmlSearchForNs(const char*);
+  int zooXmlAddNs(xmlNodePtr,const char*,const char*);
+  void zooXmlCleanupNs();
+  
+  void printExceptionReportResponse(maps*,map*);
+  xmlNodePtr createExceptionReportNode(maps*,map*,int);
+  void printProcessResponse(maps*,map*,int,service*,const char*,int,maps*,maps*);
+  xmlNodePtr printGetCapabilitiesHeader(xmlDocPtr,const char*,maps*);
+  void printGetCapabilitiesForProcess(maps*,xmlNodePtr,service*);
+  xmlNodePtr printDescribeProcessHeader(xmlDocPtr,const char*,maps*);
+  void printDescribeProcessForProcess(maps*,xmlNodePtr,service*,int);
+  void printFullDescription(elements*,const char*,xmlNsPtr,xmlNodePtr);
+  void printDocument(maps*,xmlDocPtr,int);
+  void printDescription(xmlNodePtr,xmlNsPtr,const char*,map*);
+  void printIOType(xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,xmlNsPtr,elements*,maps*,const char*);
+  map* parseBoundingBox(const char*);
+  void printBoundingBox(xmlNsPtr,xmlNodePtr,map*);
+  void printBoundingBoxDocument(maps*,maps*,FILE*);
+  void printOutputDefinitions1(xmlDocPtr,xmlNodePtr,xmlNsPtr,xmlNsPtr,elements*,maps*,const char*);
+  
+  void outputResponse(service*,maps*,maps*,map*,int,maps*,int);
+
+  char *base64(const char*,int);
+  char *base64d(const char*,int,int*);
+  void ensureDecodedBase64(maps**);
+
+  char* addDefaultValues(maps**,elements*,maps*,int);
+
+  int errorException(maps *m, const char *message, const char *errorcode);
+
+  int checkForSoapEnvelope(xmlDocPtr);
+
+  void addToCache(maps*,char*,char*,int);
+  char* isInCache(maps*,char*);
+  int loadRemoteFile(maps*,map*,HINTERNET,char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_java.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_java.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_java.c	(revision 417)
@@ -0,0 +1,635 @@
+/**
+ * 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"
+
+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;
+  char ntmp[1024];
+  getcwd(ntmp,1024);
+  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);
+    }
+    sprintf(oclasspath,"-Djava.class.path=%s",classpath);
+  }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);
+
+  }
+  sprintf(oclasspath,"-Djava.class.path=%s",classpath);
+
+#ifdef DEBUG
+  fprintf(stderr,"CLASSPATH=%s\n",classpath);
+  fprintf(stderr,"(%s)\n",oclasspath);
+#endif
+
+#ifdef WIN32
+  JavaVMOption options[2];
+#else
+  JavaVMOption options[1];
+#endif
+  JavaVMInitArgs vm_args;
+  JavaVM *jvm;
+  JNIEnv *env;
+  long result;
+  jmethodID pmid;
+  jfieldID fid;
+  jobject jobj;
+  jclass cls;
+#ifdef JAVA7
+  jobject cls_gr;
+#else
+  jclass cls_gr;
+#endif
+  int i;
+
+  options[0].optionString = oclasspath;
+#ifdef WIN32
+  options[1].optionString = "-Xmx512m";
+  /*options[2].optionString = "-Xms128m";
+  options[3].optionString = "-XX:MaxPermSize=256m";
+  options[4].optionString = "-XX:MaxHeapFreeRatio=70";*/
+#endif
+
+  JNI_GetDefaultJavaVMInitArgs(&vm_args);
+  vm_args.version = JNI_VERSION_1_6;
+  vm_args.options = options;
+#ifdef WIN32
+  vm_args.nOptions = 2;
+#else
+  vm_args.nOptions = 1;
+#endif
+  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);
+  cls_gr = env->NewGlobalRef(cls);
+#else
+  cls = (*env)->FindClass(env,tmp->value);
+  cls_gr = (*env)->NewGlobalRef(env, cls);
+#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
+
+  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;
+	m=mapsFromHashMap(env,arg1,scHashMapClass);
+	*main_conf=m;
+	outputs=mapsFromHashMap(env,arg3,scHashMapClass);
+	*real_outputs=outputs;
+
+#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
+      (*jvm).DestroyJavaVM();
+#else
+      (*jvm)->DestroyJavaVM(jvm);
+#endif
+      return -1;
+    }
+  }
+#ifdef JAVA7
+      (*jvm).DestroyJavaVM();
+#else
+  (*jvm)->DestroyJavaVM(jvm);
+#endif
+  return res;
+}
+
+/**
+ * Error handling: display stack trace in an ExceptionReport Document
+ */
+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+");
+  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);
+}
+
+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* 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){
+#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),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
+	  }
+	  else{
+	    int alen1=atoi(alen->value);
+	    fprintf(stderr,"LENGTH %d \n",alen1);
+	    
+	    jclass scArrayListClass,scArrayList_class;
+	    jmethodID scArrayList_constructor;
+	    jobject scObject2;
+#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);
+
+	    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);
+
+	    add_mid = (*env)->GetMethodID(env,scArrayListClass,
+					  "add","(Ljava/lang/Object;)Z");
+#endif	    
+	    int i;
+	    
+	    for(i=0;i<alen1;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){
+#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
+	      }
+	      
+	    }
+
+#ifdef JAVA7
+	    (*env).CallObjectMethod(scObject1, put_mid, (*env).NewStringUTF(tmp1->name), scObject2);
+#else	    
+	    (*env)->CallObjectMethod(env,scObject1, put_mid, (*env)->NewStringUTF(env,tmp1->name), scObject2);
+#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;
+}
+
+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 scHashMap_class,scSetClass,scIteratorClass,scMapEntryClass,scSet_class,scMapClass;
+  jmethodID entrySet_mid,containsKey_mid,get_mid,iterator_mid,hasNext_mid,next_mid,getKey_mid,getValue_mid;
+  jobject scObject,scObject1;
+  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=(maps*)malloc(sizeof(maps));
+#ifdef JAVA7
+    cmap->name=(char*)(*env).GetStringUTFChars((jstring)jk, NULL);
+#else
+    cmap->name=(*env)->GetStringUTFChars(env, jk, NULL);
+#endif
+#ifdef DEBUG
+    fprintf(stderr," / %s \n",cmap->name);
+#endif
+    cmap->content=res;
+    cmap->next=NULL;
+    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.3.0-rc1/zoo-project/zoo-kernel/service_internal_java.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_java.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_java.h	(revision 417)
@@ -0,0 +1,48 @@
+/**
+ * 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*);
+
+  int zoo_java_support(maps**,map*,service*,maps**,maps**);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_js.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_js.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_js.c	(revision 417)
@@ -0,0 +1,828 @@
+/**
+ * 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.h"
+
+#ifndef JSCLASS_GLOBAL_FLAGS
+#define JSCLSAS_GLOBAL_FLAGS 0
+#endif
+
+static char dbg[1024];
+
+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]);
+    fprintf(stderr,"[ZOO-API:JS] %s\n",JS_EncodeString(cx,jsmsg));
+  }
+  JS_MaybeGC(cx);
+  
+  return JS_TRUE;
+}
+
+JSBool 
+JSLoadScripts(JSContext *cx, uintN argc, jsval *argv1)
+{
+  //map* request = JS_GetContextPrivate(cx);
+  //map* tmpm1=getMap(request,"metapath");
+  JS_MaybeGC(cx);
+
+  char ntmp[1024];
+  getcwd(ntmp,1024);
+
+  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 *filename = JSValToChar(cx,&argv[i]);
+    char *api0=(char*)malloc((strlen(ntmp)+strlen(filename)+2)*sizeof(char));
+    sprintf(api0,"%s/%s",ntmp,filename);
+#ifdef JS_DEBUG
+    fprintf(stderr,"Trying to load %s\n",api0);
+    fflush(stderr);
+#endif
+    JSObject *api_script1=loadZooApiFile(cx,JS_GetGlobalObject(cx),api0);
+  }
+  JS_MaybeGC(cx);
+  JS_SET_RVAL(cx, argv1, JSVAL_VOID);
+  
+  return JS_TRUE;
+}
+
+
+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, "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];
+  getcwd(ntmp,1024);
+
+  /**
+   * Load the first part of the ZOO-API
+   */
+  char *api0=(char*)malloc(strlen(tmpm1->value)+strlen(ntmp)+17);
+  sprintf(api0,"%s/%s/ZOO-proj4js.js",ntmp,tmpm1->value);
+#ifdef JS_DEBUG
+  fprintf(stderr,"Trying to load %s\n",api0);
+#endif
+  JSObject *api_script1=loadZooApiFile(cx,global,api0);
+  fflush(stderr);
+
+  char *api1=(char*)malloc(strlen(tmpm1->value)+strlen(ntmp)+13);
+  sprintf(api1,"%s/%s/ZOO-api.js",ntmp,tmpm1->value);
+#ifdef JS_DEBUG
+  fprintf(stderr,"Trying to load %s\n",api1);
+#endif
+  JSObject *api_script2=loadZooApiFile(cx,global,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);
+    map* err=createMap("text",tmp1);
+    addMapToMap(&err,createMap("code","NoApplicableCode"));
+    printExceptionReportResponse(mc,err);
+    JS_DestroyContext(cx);
+    JS_DestroyRuntime(rt);
+    JS_ShutDown();
+    exit(-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
+    map* err=createMap("text",tmp1);
+    addToMap(err,"code","NoApplicableCode");
+    printExceptionReportResponse(*main_conf,err);
+    freeMap(&err);
+    free(err);
+    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
+    exit(-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();
+#ifdef JS_DEBUG
+  fprintf(stderr,"Returned value %d\n",res);
+#endif
+  return res;
+}
+
+JSObject * loadZooApiFile(JSContext *cx,JSObject  *global, char* filename){
+  struct stat api_status;
+  int s=stat(filename, &api_status);
+  if(s==0){
+    jsval rval;
+    JSBool ok ;
+    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;
+}
+
+JSObject* JSObject_FromMaps(JSContext *cx,maps* t){
+
+  JSObject* res=JS_NewObject(cx, NULL, NULL, NULL);
+  //JSObject *res = JS_NewArrayObject(cx, 0, NULL);
+  if(res==NULL)
+    fprintf(stderr,"Array Object is NULL!\n");
+  maps* tmp=t;
+  while(tmp!=NULL){
+    jsuint len;
+    JSObject* res1=JS_NewObject(cx, NULL, NULL, NULL);
+    JSObject *pval=JSObject_FromMap(cx,tmp->content);
+    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;
+}
+
+JSObject* JSObject_FromMap(JSContext *cx,map* t){
+  JSObject* res=JS_NewObject(cx, NULL, NULL, NULL);
+  jsval resf =  OBJECT_TO_JSVAL(res);
+  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(tmpm!=NULL){
+    jsval jsstr;
+    if((isArray==NULL && 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;
+    int i=0;
+    for(i=0;i<cnt;i++){
+      tmpm1=getMapArray(t,"value",i);
+      tmpm2=getMapArray(t,tmap->name,i);
+      if(tmpm1!=NULL){
+	jsval 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);
+  }
+  return res;
+}
+
+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;
+	JSString* str; 
+	JS_IdToValue(cx,id,&vp);
+	char *c, *tmp;
+	JSString *jsmsg;
+	size_t len1;
+	jsmsg = JS_ValueToString(cx,vp);
+	len1 = JS_GetStringLength(jsmsg);
+
+	tres=(maps*)malloc(MAPS_SIZE);
+	tres->name=strdup(JS_EncodeString(cx,jsmsg));
+	tres->content=NULL;
+	tres->next=NULL;
+
+	jsval nvp=JSVAL_NULL;
+	if((JS_GetProperty(cx, tt, JS_EncodeString(cx,jsmsg), &nvp)==JS_FALSE)){
+#ifdef JS_DEBUG
+	  fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,JS_EncodeString(cx,jsmsg));
+#endif
+	}
+	
+	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);
+	}
+
+	if(res==NULL)
+	  res=dupMaps(&tres);
+	else
+	  addMapsToMaps(&res,tres);
+	freeMaps(&tres);
+	free(tres);
+	tres=NULL;
+		
+      }
+    }
+  }
+
+  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;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;
+	JSString* str; 
+	JS_IdToValue(cx,id,&vp);
+	char *c, *tmp;
+	JSString *jsmsg;
+	size_t len1;
+	jsmsg = JS_ValueToString(cx,vp);
+	len1 = JS_GetStringLength(jsmsg);
+#ifdef JS_DEBUG
+	fprintf(stderr,"Enumerate id : %d => %s\n",oi,JS_EncodeString(cx,jsmsg));
+#endif
+	jsval nvp=JSVAL_NULL;
+	if((JS_GetProperty(cx, JSVAL_TO_OBJECT(tmp1), JS_EncodeString(cx,jsmsg), &nvp)==JS_FALSE)){
+#ifdef JS_DEBUG
+	  fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,JS_EncodeString(cx,jsmsg));
+#endif
+	}
+	
+	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;
+	  JSObject *nvp2=JSVAL_TO_OBJECT(JSVAL_NULL);
+	  jsmsg1 = JS_ValueToString(cx,nvp1j);
+	  len1 = JS_GetStringLength(jsmsg1);
+#ifdef JS_DEBUG
+	  fprintf(stderr,"JSVAL NVP1J IS OBJECT %s = %s\n",JS_EncodeString(cx,jsmsg),JS_EncodeString(cx,jsmsg1));
+#endif
+	  if(strcasecmp(JS_EncodeString(cx,jsmsg1),"[object Object]")==0){
+	    tres->name=strdup(JS_EncodeString(cx,jsmsg));
+	    tres->content=mapFromJSObject(cx,nvp1j);
+	  }
+	  else
+	    if(strcasecmp(JS_EncodeString(cx,jsmsg),"name")==0){
+	      tres->name=strdup(JS_EncodeString(cx,jsmsg1));
+	    }
+	    else{
+	      if(tres->content==NULL)
+		tres->content=createMap(JS_EncodeString(cx,jsmsg),JS_EncodeString(cx,jsmsg1));
+	      else
+		addToMap(tres->content,JS_EncodeString(cx,jsmsg),JS_EncodeString(cx,jsmsg1));
+	    }
+	}
+#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;
+
+    }
+  }
+#ifdef JS_DEBUG
+  dumpMaps(res);
+#endif
+  return res;
+}
+
+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;
+      JSString* str; 
+      JS_IdToValue(cx,id,&vp);
+      char *c, *tmp;
+      JSString *jsmsg,*jsmsg1;
+      size_t len,len1;
+      jsmsg = JS_ValueToString(cx,vp);
+      len = JS_GetStringLength(jsmsg);
+      jsval nvp;
+      JS_GetProperty(cx, JSVAL_TO_OBJECT(t), JS_EncodeString(cx,jsmsg), &nvp);
+      jsmsg1 = JS_ValueToString(cx,nvp);
+      len1 = JS_GetStringLength(jsmsg1);
+#ifdef JS_DEBUG
+      fprintf(stderr,"Enumerate id : %d [ %s => %s ]\n",index,JS_EncodeString(cx,jsmsg),JS_EncodeString(cx,jsmsg1));
+#endif
+      if(res!=NULL){
+#ifdef JS_DEBUG
+	fprintf(stderr,"%s - %s\n",JS_EncodeString(cx,jsmsg),JS_EncodeString(cx,jsmsg1));
+#endif
+	addToMap(res,JS_EncodeString(cx,jsmsg),JS_EncodeString(cx,jsmsg1));
+      }
+      else{
+	res=createMap(JS_EncodeString(cx,jsmsg),JS_EncodeString(cx,jsmsg1));
+	res->next=NULL;
+      }
+#ifdef JS_DEBUG
+      dumpMap(res);
+#endif
+    }
+  }
+#ifdef JS_DEBUG
+  dumpMap(res);
+#endif
+  return res;
+}
+
+/* The error reporter callback. */
+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);
+}
+
+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;
+}
+
+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.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.handle,CURLOPT_VERBOSE,1);
+      fprintf(stderr,"Element of array n° %d, value : %s\n",i,tmp1);
+#endif
+      handle.header=curl_slist_append(handle.header, tmp1);
+      free(tmp1);
+    }
+  }
+  else{
+    fprintf(stderr,"not an array !!!!!!!\n");
+  }
+  return handle;
+}
+
+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;
+}
+
+JSBool
+JSRequest(JSContext *cx, uintN argc, jsval *argv1)
+{
+  jsval *argv = JS_ARGV(cx,argv1);
+  HINTERNET hInternet;
+  HINTERNET res;
+  HINTERNET res1;
+  JSObject *header;
+  char *url;
+  char *method;
+  char* tmpValue;
+  size_t dwRead;
+  int i=0;
+  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=strdup("GET");
+    url=JSValToChar(cx,argv);
+  }
+  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))
+      res1=setHeader(hInternet,cx,header);
+#ifdef ULINET_DEBUG
+    fprintf(stderr,"BODY (%s)\n",body);
+#endif
+    res=InternetOpenUrl(res1,url,body,strlen(body),
+			INTERNET_FLAG_NO_CACHE_WRITE,0);    
+    free(body);
+  }else{
+    if(argc==3){
+      char *body=JSValToChar(cx,&argv[2]);
+      res=InternetOpenUrl(hInternet,url,body,strlen(body),
+			  INTERNET_FLAG_NO_CACHE_WRITE,0);
+      free(body);
+    }
+    res=InternetOpenUrl(hInternet,url,NULL,0,
+			INTERNET_FLAG_NO_CACHE_WRITE,0);
+  }
+  tmpValue=(char*)malloc((res.nDataLen+1)*sizeof(char));
+  InternetReadFile(res,(LPVOID)tmpValue,res.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);
+  if(argc==4 && res.header!=NULL){
+    curl_slist_free_all(res.header);
+  }
+  InternetCloseHandle(hInternet);
+  JS_MaybeGC(cx);
+  return JS_TRUE;
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_js.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_js.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_js.h	(revision 417)
@@ -0,0 +1,61 @@
+/**
+ * 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*);
+
+  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.3.0-rc1/zoo-project/zoo-kernel/service_internal_ms.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_ms.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_ms.c	(revision 417)
@@ -0,0 +1,1075 @@
+/**
+ * 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.
+ */
+
+#ifdef USE_MS
+#ifndef WIN32
+#define CLASS class
+#else
+#define CLASS _class
+#endif
+#include "service_internal_ms.h"
+
+/**
+ * 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
+ */
+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;
+}
+
+void setMapSize(maps* output,double minx,double miny,double maxx,double maxy){
+  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){
+    addToMap(output->content,"width",sWidth);
+    addToMap(output->content,"height",sHeight);
+  }
+}
+
+void setReferenceUrl(maps* m,maps* tmpI){
+  outputMapfile(m,tmpI);
+  map *msUrl=getMapFromMaps(m,"main","mapserverAddress");
+  map *msOgcVersion=getMapFromMaps(m,"main","msOgcVersion");
+  map *dataPath=getMapFromMaps(m,"main","dataPath");
+  map *sid=getMapFromMaps(m,"lenv","sid");
+  map* format=getMap(tmpI->content,"mimeType");
+  map* rformat=getMap(tmpI->content,"requestedMimeType");
+  map* width=getMap(tmpI->content,"width");
+  map* height=getMap(tmpI->content,"height");
+  map* protoMap=getMap(tmpI->content,"msOgc");
+  map* versionMap=getMap(tmpI->content,"msOgcVersion");
+  char options[3][5][25]={
+    {"WMS","1.3.0","GetMap","layers=%s","wms_extent"},
+    {"WFS","1.1.0","GetFeature","typename=%s","wms_extent"},
+    {"WCS","1.1.0","GetCoverage","coverage=%s","wcs_extent"}
+  };
+  int proto=0;
+  if(rformat==NULL){
+    rformat=getMap(tmpI->content,"mimeType");
+  }
+  if(strncasecmp(rformat->value,"text/xml",8)==0)
+    proto=1;
+  if(strncasecmp(rformat->value,"image/tiff",10)==0)
+    proto=2;
+  if(protoMap!=NULL)
+    if(strncasecmp(protoMap->value,"WMS",3)==0)
+      proto=0;
+    else if(strncasecmp(protoMap->value,"WFS",3)==0)
+      proto=1;
+    else 
+      proto=2;
+  
+  char *protoVersion=options[proto][1];
+  if(proto==1){
+    if(msOgcVersion!=NULL)
+      protoVersion=msOgcVersion->value;
+    if(versionMap!=NULL)
+      protoVersion=versionMap->value;
+  }
+
+  map* extent=getMap(tmpI->content,options[proto][4]);
+  map* crs=getMap(tmpI->content,"crs");
+  int hasCRS=1;
+  if(crs==NULL){
+    crs=getMapFromMaps(m,"main","crs");
+    if(crs==NULL){
+      crs=createMap("crs","epsg:4326");
+      hasCRS=0;
+    }
+  }
+  char layers[128];
+  sprintf(layers,options[proto][3],tmpI->name);
+
+  char* webService_url=(char*)malloc((strlen(msUrl->value)+strlen(format->value)+strlen(tmpI->name)+strlen(width->value)+strlen(height->value)+strlen(extent->value)+256)*sizeof(char));
+
+  if(proto>0){
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%s.map&request=%s&service=%s&version=%s&%s&format=%s&bbox=%s&crs=%s",
+	    msUrl->value,
+	    dataPath->value,
+	    tmpI->name,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+  }
+  else{
+    sprintf(webService_url,
+	    "%s?map=%s/%s_%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,
+	    sid->value,
+	    options[proto][2],
+	    options[proto][0],
+	    protoVersion,
+	    layers,
+	    width->value,
+	    height->value,
+	    rformat->value,
+	    extent->value,
+	    crs->value
+	    );
+  }
+  if(hasCRS==0){
+    freeMap(&crs);
+    free(crs);
+  }
+  addToMap(tmpI->content,"Reference",webService_url);
+
+}
+
+/**
+ * Set projection using Authority Code and Name if available or fallback to 
+ * proj4 definition if available or fallback to default EPSG:4326
+ */
+void setSrsInformations(maps* output,mapObj* m,layerObj* myLayer,
+			char* pszProjection){
+  OGRSpatialReferenceH  hSRS;
+  map* msSrs=NULL;
+  hSRS = OSRNewSpatialReference(NULL);
+  if( pszProjection!=NULL && strlen(pszProjection)>1 &&
+      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 %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)
+	  addToMap(output->content,"crs_isGeographic","true");
+	else
+	  addToMap(output->content,"crs_isGeographic","false");
+	addToMap(output->content,"crs",tmpSrs);
+      }
+    }
+    else{
+      OSRExportToProj4(hSRS,&proj4Str);
+      if(proj4Str!=NULL){
+#ifdef DEBUGMS
+	fprintf(stderr,"PROJ (%s)\n",proj4Str);
+#endif
+	msLoadProjectionString(&(m->projection),proj4Str);
+	msLoadProjectionString(&(myLayer->projection),proj4Str);
+	if(output!=NULL){ 
+	  if(OSRIsGeographic(hSRS)==TRUE)
+	    addToMap(output->content,"crs_isGeographic","true");
+	  else
+	    addToMap(output->content,"crs_isGeographic","false");
+	}
+      }
+      else{
+	msLoadProjectionStringEPSG(&m->projection,"EPSG:4326");
+	msLoadProjectionStringEPSG(&myLayer->projection,"EPSG:4326");
+	if(output!=NULL){
+	  addToMap(output->content,"crs_isGeographic","true");
+	}
+      }
+      if(output!=NULL){
+	addToMap(output->content,"crs","EPSG:4326");
+        addToMap(output->content,"real_extent","true");
+      }
+      msInsertHashTable(&(m->web.metadata),"ows_srs", "EPSG:4326 EPSG:900913");
+      msInsertHashTable(&(myLayer->metadata),"ows_srs","EPSG:4326 EPSG:900913");
+
+
+    }
+  }
+  else{
+    if(output!=NULL){
+      msSrs=getMap(output->content,"msSrs");
+    }
+    if(msSrs!=NULL){
+      msLoadProjectionStringEPSG(&m->projection,msSrs->value);
+      msLoadProjectionStringEPSG(&myLayer->projection,msSrs->value);
+      char tmpSrs[128];
+      sprintf(tmpSrs,"%s EPSG:4326 EPSG:900913",msSrs);
+      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");
+      msInsertHashTable(&(myLayer->metadata),"ows_srs","EPSG:4326 EPSG:900913");
+    }
+    if(output!=NULL){
+      addToMap(output->content,"crs",msSrs->value);
+      addToMap(output->content,"crs_isGeographic","true");
+    }
+  }
+
+  OSRDestroySpatialReference( hSRS );
+}
+
+void setMsExtent(maps* output,mapObj* m,layerObj* myLayer,
+		 double minX,double minY,double maxX,double maxY){
+  msMapSetExtent(m,minX,minY,maxX,maxY);
+#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=getMap(output->content,"real_extent");
+    if(test!=NULL){
+      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(&(m->projection),&tempSrs,&min);
+      msProjectPoint(&m->projection,&tempSrs,&max);
+      
+      sprintf(tmpExtent,"%.3f,%.3f,%.3f,%.3f",min.y,min.x,max.y,max.x);
+      map* isGeo=getMap(output->content,"crs_isGeographic");
+      fprintf(stderr,"isGeo = %s\n",isGeo->value);
+      if(isGeo!=NULL && strcasecmp("true",isGeo->value)==0)
+        sprintf(tmpExtent,"%f,%f,%f,%f", minY,minX, maxY, maxX);
+      addToMap(output->content,"wms_extent",tmpExtent);
+      sprintf(tmpSrsStr,"%.3f,%.3f,%.3f,%.3f",min.x,min.y,max.x,max.y);
+      addToMap(output->content,"wcs_extent",tmpExtent);
+    }else{
+      sprintf(tmpExtent,"%f,%f,%f,%f",minX, minY, maxX, maxY);
+      map* isGeo=getMap(output->content,"crs_isGeographic");
+      if(isGeo!=NULL){
+	fprintf(stderr,"isGeo = %s\n",isGeo->value);
+	if(isGeo!=NULL && strcasecmp("true",isGeo->value)==0)
+	  sprintf(tmpExtent,"%f,%f,%f,%f", minY,minX, maxY, maxX);
+      }
+      addToMap(output->content,"wms_extent",tmpExtent); 
+      sprintf(tmpExtent,"%.3f,%.3f,%.3f,%.3f",minX,minY,maxX,maxY);
+      addToMap(output->content,"wcs_extent",tmpExtent);
+    }
+  }
+
+  setMapSize(output,minX,minY,maxX,maxY);
+}
+
+int tryOgr(maps* conf,maps* output,mapObj* m){
+
+  map* tmpMap=getMap(output->content,"storage");
+  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=strdup(pszDataSource);
+  char *sdsName=strdup(pszDataSource);
+  char *demo=strstr(odsName,".");
+  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");
+  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);
+  fprintf(stderr,"Try loading %s",dsName);
+  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");
+    OGR_DS_Destroy(poDS1);
+  }else{
+    fprintf(stderr,"The DataSource is a  ZIP File\n");
+    char** demo=VSIReadDir(dsName);
+    int i=0;
+    mkdir(sdsName
+#ifndef WIN32
+		,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH 
+#endif
+		);
+    while(demo[i]!=NULL){
+      fprintf(stderr,"ZIP File content : %s\n",demo[i]);
+      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");
+      fprintf(stderr,"open : %s\n",tmpDs);
+      VSIFSeekL(vsif,0,SEEK_END);
+      int size=VSIFTellL(vsif);
+      fprintf(stderr,"size : %d\n",size);
+      VSIFSeekL(vsif,0,SEEK_SET);
+      char *vsifcontent=(char*) malloc((size+1)*sizeof(char));
+      VSIFReadL(vsifcontent,1,size,vsif);
+      char *fpath=(char*) malloc((strlen(sdsName)+strlen(demo[1])+2)*sizeof(char));
+      sprintf(fpath,"%s/%s",sdsName,demo[i]);
+      int f=open(fpath,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+      write(f,vsifcontent,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){
+	fprintf(stderr,"*** DEBUG %s\n",strstr(tmpP,"."));
+	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;
+	  fprintf(stderr,"*** DEBUG %s\n",pszDataSource);
+	}
+      }
+      VSIFCloseL(vsif);
+      i++;
+    }
+
+  }
+
+  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");
+    OGR_DS_Destroy(poDS);
+    OGRCleanupAll();
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to access the DataSource, exit! \n"); 
+#endif
+    return -1;
+  }
+
+  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
+     */
+    if(msGrowMapLayers(m)==NULL){
+      return -1;
+    }
+    if(initLayer((m->layers[m->numlayers]), m) == -1){
+      return -1;
+    }
+
+    layerObj* myLayer=m->layers[m->numlayers];
+    dumpMaps(output);
+    myLayer->name = strdup(output->name);
+    myLayer->tileitem=NULL;
+    myLayer->data = strdup(OGR_L_GetName(poLayer));
+    myLayer->connection = strdup(pszDataSource);
+    myLayer->index = m->numlayers;
+    myLayer->dump = MS_TRUE;
+    myLayer->status = MS_ON;
+    msConnectLayer(myLayer,MS_OGR,pszDataSource);
+
+    /**
+     * 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);
+    }
+    else{
+      addToMap(output->content,"crs","EPSG:4326");
+      addToMap(output->content,"crs_isGeographic","true");
+      msLoadProjectionStringEPSG(&m->projection,"EPSG:4326");
+      msInsertHashTable(&(m->web.metadata), "ows_srs", "EPSG:4326 EPSG:900913");
+      msInsertHashTable(&(myLayer->metadata), "ows_srs", "EPSG:4326 EPSG:900913");
+    }
+
+    map* crs=getMap(output->content,"crs");
+    map* isGeo=getMap(output->content,"crs_isGeographic");
+
+    OGREnvelope oExt;
+    if (OGR_L_GetExtent(poLayer,&oExt, TRUE) == OGRERR_NONE){
+      setMsExtent(output,m,myLayer,oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY);
+    }
+  
+    /**
+     * 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=getMap(output->content,"title");
+    if(tmpMap!=NULL)
+      msInsertHashTable(&(myLayer->metadata), "ows_title", tmpMap->value);
+    else
+      msInsertHashTable(&(myLayer->metadata), "ows_title", "Default Title");
+    
+    if(msGrowLayerClasses(myLayer) == NULL)
+      return -1;
+    if(initClass((myLayer->CLASS[myLayer->numclasses])) == -1)
+      return -1;
+    myLayer->CLASS[myLayer->numclasses]->type = myLayer->type;
+    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)
+      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;
+}
+
+
+int tryGdal(maps* conf,maps* output,mapObj* m){
+  map* tmpMap=getMap(output->content,"storage");
+  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_ReadOnly );
+  if( hDataset == NULL ){
+#ifdef DEBUGMS
+    fprintf(stderr,"Unable to access the DataSource %s \n",pszFilename);
+#endif
+    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
+
+  /**
+   * Add a new layer set name, data
+   */
+  if(msGrowMapLayers(m)==NULL){
+    return -1;
+  }
+  if(initLayer((m->layers[m->numlayers]), m) == -1){
+    return -1;
+  }
+
+  layerObj* myLayer=m->layers[m->numlayers];
+  myLayer->name = strdup(output->name);
+  myLayer->tileitem=NULL;
+  myLayer->data = strdup(pszFilename);
+  myLayer->index = m->numlayers;
+  myLayer->dump = MS_TRUE;
+  myLayer->status = MS_ON;
+  myLayer->type = MS_LAYER_RASTER;
+
+  char *title=output->name;
+  tmpMap=getMap(output->content,"title");
+  if(tmpMap!=NULL)
+    title=tmpMap->value;
+  char *abstract=output->name;
+  tmpMap=getMap(output->content,"abstract");
+  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 );
+  
+  /**
+   * 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 ){
+    OGRSpatialReferenceH  hSRS;
+    char *pszProjection;
+    pszProjection = (char *) GDALGetProjectionRef( hDataset );
+#ifdef DEBUGMS
+    fprintf(stderr,"Accessing the DataSource %s\n",GDALGetProjectionRef( hDataset ));
+#endif
+    setSrsInformations(output,m,myLayer,pszProjection);
+    }
+
+
+  /**
+   * 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);
+
+    }
+  }
+
+  /**
+   * Extract information about available bands to set the bandcount and the
+   * processing directive
+   */
+  char nBands[2];
+  int nBandsI=GDALGetRasterCount( hDataset );
+  sprintf(nBands,"%d",GDALGetRasterCount( hDataset ));
+  msInsertHashTable(&(myLayer->metadata), "ows_bandcount", nBands);
+  if(nBandsI>=3)
+    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[6];
+  char *nameBands=NULL;
+  for( iBand = 0; iBand < nBandsI; iBand++ ){
+    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=strdup(nameBands);
+	nameBands=(char*)realloc(nameBands,(strlen(nameBands)+strlen(lBands)+1)*sizeof(char));
+	sprintf(nameBands,"%s %s",tmpS,lBands);
+	free(tmpS);
+      }
+    }
+  }
+  msInsertHashTable(&(myLayer->metadata), "ows_bandnames", nameBands);
+  
+  /**
+   * Loops over metadata informations to setup specific informations
+   */
+  for( iBand = 0; iBand < nBandsI; iBand++ ){
+    int         bGotNodata, bSuccess;
+    double      adfCMinMax[2], dfNoData;
+    int         nBlockXSize, nBlockYSize, nMaskFlags;
+    double      dfMean, dfStdDev;
+    hBand = GDALGetRasterBand( hDataset, iBand+1 );
+
+    CPLErrorReset();
+    GDALComputeRasterMinMax( hBand, FALSE, adfCMinMax );
+    char tmpN[21];
+    sprintf(tmpN,"Band%d",iBand+1);
+    if (CPLGetLastErrorType() == CE_None){
+      char tmpMm[100];
+      sprintf(tmpMm,"%.3f %.3f",adfCMinMax[0],adfCMinMax[1]);
+      char tmpI[21];
+      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=adfCMinMax[1]-adfCMinMax[0];
+	  double interval=delta/10;
+	  double cstep=adfCMinMax[0];
+	  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;
+	    myLayer->CLASS[myLayer->numclasses]->type = myLayer->type;
+	    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=strdup(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",adfCMinMax[0],adfCMinMax[1]);
+	  
+	}
+      }
+    }
+    if( strlen(GDALGetRasterUnitType(hBand)) > 0 ){
+      char tmpU[21];
+      sprintf(tmpU,"%s_band_uom",tmpN);
+      msInsertHashTable(&(myLayer->metadata), tmpU, GDALGetRasterUnitType(hBand));
+    }
+
+  }
+
+  m->layerorder[m->numlayers] = m->numlayers;
+  m->numlayers++;
+  GDALClose( hDataset );
+  GDALDestroyDriverManager();
+  CPLCleanupTLS();
+  return 1;
+}
+
+/**
+ * Create a MapFile for WMS, WFS or WCS Service output
+ */
+void outputMapfile(maps* conf,maps* outputs){
+
+  /**
+   * Firs store the value on disk
+   */
+  map* mime=getMap(outputs->content,"mimeType");
+  char *ext="data";
+  if(mime!=NULL)
+    if(strncasecmp(mime->value,"application/json",16)==0)
+      ext="json";
+  
+  map* tmpMap=getMapFromMaps(conf,"main","dataPath");
+  map* sidMap=getMapFromMaps(conf,"lenv","sid");
+  char *pszDataSource=(char*)malloc((strlen(tmpMap->value)+strlen(sidMap->value)+strlen(outputs->name)+17)*sizeof(char));
+  sprintf(pszDataSource,"%s/ZOO_DATA_%s_%s.%s",tmpMap->value,outputs->name,sidMap->value,ext);
+  int f=open(pszDataSource,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+  map* sizeMap=getMap(outputs->content,"size");
+  map* vData=getMap(outputs->content,"value");
+  if(sizeMap!=NULL){
+    write(f,vData->value,atoi(sizeMap->value)*sizeof(char));
+  }
+  else{
+    write(f,vData->value,strlen(vData->value)*sizeof(char));
+  }
+  close(f);
+  //exit(-1);
+  addToMap(outputs->content,"storage",pszDataSource);
+
+  /*
+   * Create an empty map, set name, default size and extent
+   */
+  mapObj *myMap=msNewMapObj();
+  free(myMap->name);
+  myMap->name=strdup("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=strdup(tmp1->value);
+  tmp1=getMapFromMaps(conf,"main","tmpUrl");
+  myMap->web.imageurl=strdup(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");
+  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_BYTE;
+    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_INT16;
+    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
+
+  /*
+   * Set default projection to EPSG:4326
+   */
+  msLoadProjectionStringEPSG(&myMap->projection,"EPSG:4326");
+  myMap->transparent=1;
+
+  /**
+   * Set metadata extracted from main.cfg file maps
+   */
+  maps* cursor=conf;
+  map* correspondance=getCorrespondance();
+  while(cursor!=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
+	  return;
+	}
+      }
+      _cursor=_cursor->next;
+    }
+    cursor=cursor->next;
+  }
+
+  /*
+   * 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");
+
+  if(tryOgr(conf,outputs,myMap)<0)
+    if(tryGdal(conf,outputs,myMap)<0)
+      return ;
+
+  tmp1=getMapFromMaps(conf,"main","dataPath");
+  char *tmpPath=(char*)malloc((13+strlen(tmp1->value))*sizeof(char));
+  sprintf(tmpPath,"%s/symbols.sym",tmp1->value);
+  msInitSymbolSet(&myMap->symbolset);
+  myMap->symbolset.filename=strdup(tmpPath);
+  free(tmpPath);
+
+  map* sid=getMapFromMaps(conf,"lenv","sid");
+  char *mapPath=
+    (char*)malloc((16+strlen(outputs->name)+strlen(tmp1->value))*sizeof(char));
+  sprintf(mapPath,"%s/%s_%s.map",tmp1->value,outputs->name,sid->value);
+  msSaveMap(myMap,mapPath);
+  msFreeMap(myMap);
+}
+
+#endif
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_ms.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_ms.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_ms.h	(revision 417)
@@ -0,0 +1,80 @@
+/**
+ * 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
+#ifdef USE_MS
+
+#include <sys/stat.h>
+#include "service_internal.h"
+#include "service.h"
+#include "cpl_conv.h"
+#include "cpl_multiproc.h"
+#include "ogr_api.h"
+#include "gdal.h"
+#include "ogr_srs_api.h"
+#include "ulinet.h"
+#ifdef WIN32
+#include <unistd.h>
+#endif
+
+#include <mapserver.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  //#include <mapserver.h>
+  /**
+   * 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
+   */
+  map* getCorrespondance();
+  void setMapSize(maps* output,double minx,double miny,double maxy,double maxx);
+  void setReferenceUrl(maps* m,maps* tmpI);
+
+  /**
+   * Set projection using Authority Code and Name if available or fallback to 
+   * proj4 definition if available or fallback to default EPSG:4326
+   */
+  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);
+  /**
+   * Create a MapFile for WMS, WFS or WCS Service output
+   */
+  void outputMapfile(maps* conf,maps* outputs);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
+ 
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_perl.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_perl.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_perl.c	(revision 417)
@@ -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);
+	*m = (maps *)malloc(MAPS_SIZE);
+	maps * tmp = *m;
+	HE * he = hv_iternext(hh);
+	map *mm;
+	while (he != NULL) {
+		//fprintf(stderr,"key ===> %s \n",HeKEY(he));
+		tmp->name = HeKEY(he);
+		hash_to_map((HV *) SvRV(HeVAL(he)),&mm);
+		tmp->content = mm;
+		he = hv_iternext(hh);
+		if (he != NULL){
+			tmp->next = (maps *)malloc(MAPS_SIZE);
+			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.3.0-rc1/zoo-project/zoo-kernel/service_internal_perl.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_perl.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_perl.h	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-kernel/service_internal_php.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_php.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_php.c	(revision 417)
@@ -0,0 +1,238 @@
+/**
+ * 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.
+ */
+
+#include "service_internal_php.h"
+
+#ifdef ZTS
+void ***tsrm_ls;
+#endif
+
+int zoo_php_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
+  fprintf(stderr,"STARING PHP SCRIPT\n");
+  maps* m=*main_conf;
+  maps* inputs=*real_inputs;
+  maps* outputs=*real_outputs;
+  char ntmp[1024];
+  getcwd(ntmp,1024);
+  map* tmp=getMap(request,"metapath");
+
+  int res=SERVICE_FAILED;
+
+  tmp=getMap(s->content,"serviceProvider");
+  zend_file_handle iscript;
+  iscript.type=ZEND_HANDLE_FP;
+  iscript.filename=tmp->value;
+  iscript.opened_path=NULL;
+  //iscript.free_filname=0;
+  if(!(iscript.handle.fp=fopen(iscript.filename,"rb"))){
+    char tmp1[1024];
+    sprintf(tmp1,"Unable to load PHP file %s",tmp->value);
+    map* err=createMap("text",tmp1);
+    addToMap(err,"code","NoApplicableCode");
+    printExceptionReportResponse(m,err);
+    exit(-1);
+  }
+
+  php_embed_init(0,NULL,&tsrm_ls);
+
+  fprintf(stderr,"PHP EMBEDED\n");
+  
+  zend_try {
+    fprintf(stderr,"PHP EMBEDED include script %s\n",tmp->value);
+    php_execute_script(&iscript TSRMLS_CC);
+    fprintf(stderr,"PHP EMBEDED include script done\n");
+
+    zval *iargs[3];
+    zval iret, ifunc,ifile;
+      
+    ZVAL_STRING(&ifunc, s->name, 0);
+    fprintf(stderr,"PHP EMBEDED include script done\n");
+    iargs[0] = php_Array_from_maps(*main_conf);
+    fprintf(stderr,"PHP EMBEDED include script done\n");
+    iargs[1] = php_Array_from_maps(*real_inputs);
+    fprintf(stderr,"PHP EMBEDED include script done\n");
+    iargs[2] = php_Array_from_maps(*real_outputs);
+    fprintf(stderr,"PHP EMBEDED include script done\n");
+    
+    call_user_function(EG(function_table), NULL, &ifunc, &iret, 3, iargs TSRMLS_CC);
+
+    HashTable* t=HASH_OF(iargs[2]);
+    *real_outputs=php_maps_from_Array(t);
+    
+    dumpMaps(*real_outputs);
+
+    char tmp1[1024];
+
+    sprintf(tmp1,"PHP EMBEDED ran function successfully and return %d !?",Z_STRVAL(iret));
+
+    res=SERVICE_SUCCEEDED;
+
+  } zend_catch { 
+    map* err=createMap("text","Unable to process.");
+    addToMap(err,"code","NoApplicableCode");
+    printExceptionReportResponse(m,err);
+    exit(-1);
+  } zend_end_try();
+
+  php_embed_shutdown(TSRMLS_C);
+
+  return res;
+}
+
+zval *php_Array_from_maps(maps* t){
+  zval *mapArray;
+  zval *mapArrayTmp;
+  maps* tmp=t;
+  int tres=0;
+  fprintf(stderr,"arra_init\n");
+  MAKE_STD_ZVAL(mapArray);
+  tres=array_init(mapArray);
+  fprintf(stderr,"arra_init %d\n",tres);
+  while(tmp!=NULL){
+    add_assoc_zval(mapArray,tmp->name,php_Array_from_map(tmp->content));
+    tmp=tmp->next;
+  }
+  return mapArray;
+}
+
+zval *php_Array_from_map(map* t){
+  zval *mapArray;
+  zval *mapArrayTmp;
+  map* tmp=t;
+  int tres=0;
+  fprintf(stderr,"arra_init\n");
+  MAKE_STD_ZVAL(mapArray);
+  tres=array_init(mapArray);
+  fprintf(stderr,"arra_init\n");
+  while(tmp!=NULL){
+    fprintf(stderr,"=> %s %d %s %d \n",tmp->name,strlen(tmp->name),tmp->value,strlen(tmp->value));
+    tres=add_assoc_string(mapArray,tmp->name,tmp->value,1);
+    tmp=tmp->next;
+  }
+  return mapArray;
+}
+
+maps* php_maps_from_Array(HashTable *t){
+  //#ifdef DEBUG
+  fprintf(stderr,"mapsFromPHPArray start\n");
+  //#endif
+  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); 
+    fprintf(stderr,"key : %s\n",key);
+    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;
+    fprintf(stderr,"key : %s\n",key);
+    zval_copy_ctor(&tmpcopy); 
+    fprintf(stderr,"key : %s\n",key);
+    /**
+     * Reset refcount & Convert
+     */
+    INIT_PZVAL(&tmpcopy); 
+    //convert_to_string(&tmpcopy); 
+    if (type == HASH_KEY_IS_STRING) { 
+      /**
+       * String Key / Associative
+       */
+      cursor=(maps*)malloc(MAPS_SIZE);
+      cursor->name=strdup(key);
+    }
+    fprintf(stderr,"key : %s\n",key);
+    HashTable* t=HASH_OF(*ppzval);
+    fprintf(stderr,"key : %s\n",key);
+    cursor->content=php_map_from_HasTable(t);
+    cursor->next=NULL;
+    if(final_res==NULL)
+      final_res=cursor;
+    else
+      addMapsToMaps(&final_res,cursor);
+    fprintf(stderr,"key : %s\n",key);
+    /**
+     * Toss out old copy
+     */
+    zval_dtor(&tmpcopy);
+  }
+  return final_res;
+}
+
+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; 
+    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(final_res==NULL){
+      fprintf(stderr,"%s => %s\n",key,Z_STRVAL(tmpcopy));
+      final_res=createMap(key,Z_STRVAL(tmpcopy));
+    }
+    else{
+      fprintf(stderr,"%s => %s\n",key,Z_STRVAL(tmpcopy));
+      addMapToMap(&final_res,createMap(key,Z_STRVAL(tmpcopy)));
+    }
+    /* Toss out old copy */ 
+    zval_dtor(&tmpcopy); 
+  }
+  return final_res;
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_php.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_php.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_php.h	(revision 417)
@@ -0,0 +1,49 @@
+/**
+ * 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>
+#include <sapi/embed/php_embed.h>
+#include <zend_stream.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  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);
+  int zoo_php_support(maps**,map*,service*,maps**,maps**);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_python.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_python.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_python.c	(revision 417)
@@ -0,0 +1,675 @@
+/**
+ * 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_python.h"
+
+struct module_state {
+    PyObject *error;
+};
+
+#if PY_MAJOR_VERSION >= 3
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
+#else
+#define GETSTATE(m) (&_state)
+static struct module_state _state;
+#endif
+
+static PyObject* ZooError;
+
+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
+
+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);
+#if PY_MAJOR_VERSION >= 3
+  tmp = PyLong_FromLong(3);
+#else
+  tmp = PyInt_FromLong(3);
+#endif
+  PyDict_SetItemString(d, "SERVICE_SUCCEEDED", tmp);
+  Py_DECREF(tmp);
+
+#if PY_MAJOR_VERSION >= 3
+  tmp = PyLong_FromLong(4);
+#else
+  tmp = PyInt_FromLong(4);
+#endif
+  PyDict_SetItemString(d, "SERVICE_FAILED", tmp);
+  Py_DECREF(tmp);
+
+  ZooError = PyErr_NewException("zoo.error", NULL, NULL);
+  Py_INCREF(ZooError);
+  PyModule_AddObject(module, "error", ZooError);
+#if PY_MAJOR_VERSION >= 3
+  return module;
+#endif
+}
+
+int zoo_python_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;
+  tmp=getMapFromMaps(*main_conf,"env","PYTHONPATH");
+  char *python_path;
+#ifdef DEBUG
+  fprintf(stderr,"PYTHON SUPPORT \n");
+#endif
+  fflush(stderr);
+  if(tmp!=NULL){
+#ifdef DEBUG
+    fprintf(stderr,"PYTHON SUPPORT (%i)\n",strlen(tmp->value));
+#endif
+    python_path=(char*)malloc((strlen(tmp->value))*sizeof(char));
+    sprintf(python_path,"%s",tmp->value);
+  }
+  else{
+    python_path=strdup(".");
+  }
+  tmp=NULL;
+  tmp=getMap(request,"metapath");
+  char *pythonpath;//=(char*)malloc((1+strlen(python_path)+2048)*sizeof(char));
+  if(tmp!=NULL && strcmp(tmp->value,"")!=0){
+    pythonpath=(char*)malloc((4+strlen(python_path)+strlen(ntmp)+strlen(tmp->value))*sizeof(char));
+#ifdef WIN32
+    sprintf(pythonpath,"%s/%s/;%s",ntmp,tmp->value,python_path);
+#else
+    sprintf(pythonpath,"%s/%s/:%s",ntmp,tmp->value,python_path);
+#endif
+  }
+  else{
+    pythonpath=(char*)malloc((2+strlen(python_path)+strlen(ntmp))*sizeof(char));
+#ifdef WIN32
+    sprintf(pythonpath,"%s;%s",ntmp,python_path);
+#else
+    sprintf(pythonpath,"%s:%s",ntmp,python_path);
+#endif
+  }
+#ifdef DEBUG
+    fprintf(stderr,"PYTHONPATH=%s\n",pythonpath);
+#endif
+#ifndef WIN32
+  setenv("PYTHONPATH",pythonpath,1);
+#else
+  SetEnvironmentVariable("PYTHONPATH",pythonpath);
+  char* toto=(char*)malloc((strlen(pythonpath)+12)*sizeof(char));
+  sprintf(toto,"PYTHONPATH=%s",pythonpath);
+  putenv(toto);
+#endif
+  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");
+  if(tmp!=NULL)
+    pName = 
+#if PY_MAJOR_VERSION >= 3
+      PyUnicode_FromString(tmp->value);
+#else
+      PyString_FromString(tmp->value);
+#endif
+  else{
+    map* err=createMap("text","Unable to parse serviceProvider please check your zcfg file.");
+    addToMap(err,"code","NoApplicableCode");
+    printExceptionReportResponse(m,err);
+    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);
+      tmp=getMap(request,"storeExecuteResponse");
+#ifdef DEBUG
+      fprintf(stderr,"RUN IN NORMAL MODE \n");
+      fflush(stderr);
+#endif
+      pValue = PyObject_CallObject(pFunc, pArgs);
+      if (pValue != NULL) {
+#if PY_MAJOR_VERSION >= 3
+	res=PyLong_AsLong(pValue);
+#else
+	res=PyInt_AsLong(pValue);
+#endif
+	freeMaps(real_outputs);
+	free(*real_outputs);
+	freeMaps(main_conf);
+	free(*main_conf);
+	*main_conf=mapsFromPyDict(arg1);
+	*real_outputs=mapsFromPyDict(arg3);
+#ifdef DEBUG
+#if PY_MAJOR_VERSION >= 3
+	fprintf(stderr,"Result of call: %i\n", PyLong_AsLong(pValue));
+#else
+	fprintf(stderr,"Result of call: %i\n", PyInt_AsLong(pValue));
+#endif
+	dumpMaps(inputs);
+	dumpMaps(*real_outputs);
+#endif
+      }else{	  
+	PyObject *ptype,*pvalue, *ptraceback;
+	PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+	PyObject *trace=PyObject_Str(pvalue);
+	char pbt[10240];
+#if PY_MAJOR_VERSION >= 3
+	if(PyUnicode_Check(trace))
+	  sprintf(pbt,"TRACE : %s",_PyUnicode_AsString(trace));
+#else
+	if(PyString_Check(trace))
+	  sprintf(pbt,"TRACE : %s",PyString_AsString(trace));
+#endif
+	else
+	  fprintf(stderr,"EMPTY TRACE ?");
+	trace=NULL;
+	trace=PyObject_Str(ptype);
+#if PY_MAJOR_VERSION >= 3
+	if(PyUnicode_Check(trace)){
+#else
+	if(PyString_Check(trace)){
+#endif
+	  char *tpbt=strdup(pbt);
+#if PY_MAJOR_VERSION >= 3
+	  sprintf(pbt,"%s\n%s\0",tpbt,_PyUnicode_AsString(trace));
+#else
+	  sprintf(pbt,"%s\n%s\0",tpbt,PyString_AsString(trace));
+#endif
+	  free(tpbt);
+	}
+	else
+	  fprintf(stderr,"EMPTY TRACE ?");
+	
+	char *tpbt=strdup(pbt);
+#if PY_MAJOR_VERSION >= 3
+	pName = PyUnicode_FromString("traceback");
+#else
+	pName = PyString_FromString("traceback");
+#endif
+	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 PY_MAJOR_VERSION >= 3
+	if(PyUnicode_Check(trace))
+	  sprintf(pbt,"%s\nUnable to run your python process properly. Please check the following messages : %s",tpbt,_PyUnicode_AsString(trace));
+#else
+	if(PyString_Check(trace))
+	  sprintf(pbt,"%s\nUnable to run your python process properly. Please check the following messages : %s",tpbt,PyString_AsString(trace));
+#endif
+	else
+	  sprintf(pbt,"%s \n Unable to run your python process properly. Unable to provide any futher informations. %s",tpbt);
+	free(tpbt);
+	map* err=createMap("text",pbt);
+	addToMap(err,"code","NoApplicableCode");
+	printExceptionReportResponse(m,err);
+	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;
+    }
+  } else{
+    char tmpS[1024];
+    sprintf(tmpS, "Python module %s cannot be loaded.\n", tmp->value);
+    map* tmps=createMap("text",tmpS);
+    printExceptionReportResponse(m,tmps);
+    if (PyErr_Occurred())
+      PyErr_Print();
+    PyErr_Clear();
+    res=-1;
+    //exit(-1);
+  } 
+#if PY_MAJOR_VERSION < 3
+  PyGILState_Release(gstate);
+  PyEval_AcquireLock();
+#endif
+  PyThreadState_Swap(mainstate);
+  Py_Finalize();
+  return res;
+}
+
+PyDictObject* PyDict_FromMaps(maps* t){
+  PyObject* res=PyDict_New( );
+  maps* tmp=t;
+  while(tmp!=NULL){
+    PyObject* value=(PyObject*)PyDict_FromMap(tmp->content);
+    PyObject* name=
+#if PY_MAJOR_VERSION >= 3
+      PyUnicode_FromString(tmp->name);
+#else
+      PyString_FromString(tmp->name);
+#endif
+    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;
+}
+
+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* tmap=getMapType(tmp);
+  while(tmp!=NULL){
+    PyObject* name=
+#if PY_MAJOR_VERSION >= 3
+      PyUnicode_FromString(tmp->name);
+#else
+      PyString_FromString(tmp->name);
+#endif
+    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);
+
+	for(int i=0;i<cnt;i++){
+	  
+	  map* vMap=getMapArray(tmp,"value",i);	    
+	  map* sMap=getMapArray(tmp,"size",i);
+
+	  if(vMap!=NULL){
+	    
+	    PyObject* lvalue;
+	    PyObject* lsvalue;
+	    if(sMap==NULL){
+#if PY_MAJOR_VERSION >= 3
+	      lvalue=PyUnicode_FromString(vMap->value);
+#else
+	      lvalue=PyString_FromString(vMap->value);
+#endif
+	      lsvalue=Py_None;
+	    }
+	    else{
+#if PY_MAJOR_VERSION >= 3
+	      lvalue=PyUnicode_FromStringAndSize(vMap->value,atoi(sMap->value));
+	      lsvalue=PyUnicode_FromString(sMap->value);
+#else
+	      lvalue=PyString_FromStringAndSize(vMap->value,atoi(sMap->value));
+	      lsvalue=PyString_FromString(sMap->value);
+#endif
+	      hasSize=1;
+	    }
+
+	    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;
+	    } 
+	  }
+	  
+	  map* mMap=getMapArray(tmp,tmap->name,i);
+	  PyObject* lmvalue;
+	  if(mMap!=NULL){
+#if PY_MAJOR_VERSION >= 3
+	    lmvalue=PyUnicode_FromString(mMap->value);
+#else
+	    lmvalue=PyString_FromString(mMap->value);
+#endif
+	  }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 PY_MAJOR_VERSION >= 3
+	if(PyDict_SetItem(res,PyUnicode_FromString(tmap->name),mvalue)<0){
+#else
+	if(PyDict_SetItem(res,PyString_FromString(tmap->name),mvalue)<0){
+#endif
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+	if(hasSize>0)
+#if PY_MAJOR_VERSION >= 3
+	  if(PyDict_SetItem(res,PyUnicode_FromString("size"),svalue)<0){
+#else
+	  if(PyDict_SetItem(res,PyString_FromString("size"),svalue)<0){
+#endif
+	    fprintf(stderr,"Unable to set key value pair...");
+	    return NULL;
+	  }
+      }
+      else if(size!=NULL){
+	PyObject* value=
+#if PY_MAJOR_VERSION >= 3
+	  PyUnicode_FromStringAndSize(tmp->value,atoi(size->value));
+#else
+	  PyString_FromStringAndSize(tmp->value,atoi(size->value));
+#endif
+	if(PyDict_SetItem(res,name,value)<0){
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+      }
+      else{
+	PyObject* value=
+#if PY_MAJOR_VERSION >= 3
+	  PyUnicode_FromString(tmp->value);
+#else
+	  PyString_FromString(tmp->value);
+#endif
+	if(PyDict_SetItem(res,name,value)<0){
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+      }
+    }
+    else{
+      if(PyDict_GetItem(res,name)==NULL){
+	PyObject* value=
+#if PY_MAJOR_VERSION >= 3
+	  PyUnicode_FromString(tmp->value);
+#else
+	  PyString_FromString(tmp->value);
+#endif
+	if(PyDict_SetItem(res,name,value)<0){
+	  fprintf(stderr,"Unable to set key value pair...");
+	  return NULL;
+	}
+      }
+    }
+    Py_DECREF(name);
+    tmp=tmp->next;
+  }
+  return (PyDictObject*) res;
+}
+
+maps* mapsFromPyDict(PyDictObject* t){
+  maps* res=NULL;
+  maps* cursor=res;
+  PyObject* list=PyDict_Keys((PyObject*)t);
+  int nb=PyList_Size(list);
+  int i;
+  for(i=0;i<nb;i++){
+#ifdef DEBUG
+    fprintf(stderr,">> parsing maps %d\n",i);
+#endif
+    PyObject* key=PyList_GetItem(list,i);
+    PyObject* value=PyDict_GetItem((PyObject*)t,key);
+#ifdef DEBUG
+    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
+	    PyString_AsString(key),PyString_AsString(value));
+#endif
+    cursor=(maps*)malloc(MAPS_SIZE);
+#if PY_MAJOR_VERSION >= 3
+    cursor->name=_PyUnicode_AsString(key);
+#else
+    cursor->name=PyString_AsString(key);
+#endif
+    cursor->content=mapFromPyDict((PyDictObject*)value);
+#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
+  }
+  return res;
+}
+
+map* mapFromPyDict(PyDictObject* t){
+  map* res=NULL;
+  PyObject* list=PyDict_Keys((PyObject*)t);
+  int nb=PyList_Size(list);
+  int i;
+  for(i=0;i<nb;i++){
+    PyObject* key=PyList_GetItem(list,i);
+    PyObject* value=PyDict_GetItem((PyObject*)t,key);
+#ifdef DEBUG
+    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
+	    PyString_AsString(key),PyString_AsString(value));
+#endif
+#if PY_MAJOR_VERSION >= 3
+    if(strcmp(_PyUnicode_AsString(key),"value")==0){
+#else
+    if(strcmp(PyString_AsString(key),"value")==0){
+#endif
+      char *buffer=NULL;
+      Py_ssize_t size;
+#if PY_MAJOR_VERSION >= 3
+      buffer=_PyUnicode_AsStringAndSize(value,&size);
+#else
+      PyString_AsStringAndSize(value,&buffer,&size);
+#endif
+      if(res!=NULL){
+#if PY_MAJOR_VERSION >= 3
+	addToMap(res,_PyUnicode_AsString(key),"");
+#else
+	addToMap(res,PyString_AsString(key),"");
+#endif
+      }else{
+#if PY_MAJOR_VERSION >= 3
+	res=createMap(_PyUnicode_AsString(key),"");
+#else
+	res=createMap(PyString_AsString(key),"");
+#endif
+      }
+      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){
+	if(PyString_Size(value)>0)
+#if PY_MAJOR_VERSION >= 3
+	  addToMap(res,_PyUnicode_AsString(key),_PyUnicode_AsString(value));
+#else
+	  addToMap(res,PyString_AsString(key),PyString_AsString(value));
+#endif
+      }
+      else{
+	if(PyString_Size(value)>0)
+	  res=
+#if PY_MAJOR_VERSION >= 3
+	    createMap(_PyUnicode_AsString(key),_PyUnicode_AsString(value));
+#else
+	    createMap(PyString_AsString(key),PyString_AsString(value));
+#endif
+      }
+    }
+  }
+  return res;
+}
+
+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;
+  }
+#if PY_MAJOR_VERSION >= 3
+  return PyUnicode_FromString(_ss(str));
+#else
+  return PyString_FromString(_ss(str));
+#endif
+}
+
+PyObject*
+PythonUpdateStatus(PyObject* self, PyObject* args)
+{
+  maps* conf;
+  PyObject* confdict;
+  int istatus;
+  char* status;
+  if (!PyArg_ParseTuple(args, "O!i", &PyDict_Type, &confdict, &istatus)){
+#ifdef DEBUG
+    fprintf(stderr,"Incorrect arguments to update status function");
+#endif
+    return NULL;
+  }
+  if (istatus < 0 || istatus > 100){
+     PyErr_SetString(ZooError, "Status must be a percentage.");
+     return NULL;
+  }else{
+     char tmpStatus[4];
+     snprintf(tmpStatus, 4, "%i", istatus);
+     status = strdup(tmpStatus);
+  }
+  /* now update the map */
+  {
+    PyObject* lenv = PyMapping_GetItemString(confdict, "lenv");
+    if (lenv && PyMapping_Check(lenv)){
+      PyObject* valobj = 
+#if PY_MAJOR_VERSION >= 3
+	PyUnicode_FromString(status);
+#else
+	PyString_FromString(status);
+#endif
+      PyMapping_SetItemString(lenv, "status", valobj);
+      Py_DECREF(valobj);
+    }
+    Py_DECREF(lenv);
+  }
+  conf = mapsFromPyDict((PyDictObject*)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);
+  Py_RETURN_NONE;
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_python.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_python.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_internal_python.h	(revision 417)
@@ -0,0 +1,50 @@
+/**
+ * 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_PYTHON_H
+#define ZOO_SERVICE_INTERNAL_PYTHON_H 1
+
+#pragma once 
+
+#include "service.h"
+#include "service_internal.h"
+#include <Python.h>
+#ifdef WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+
+PyDictObject* PyDict_FromMaps(maps* t);
+PyDictObject* PyDict_FromMap(map* t);
+
+maps* mapsFromPyDict(PyDictObject* t);
+void createMapsFromPyDict(maps**,PyDictObject*);
+map* mapFromPyDict(PyDictObject* t);
+
+int zoo_python_support(maps**,map*,service*,maps**,maps**);
+
+PyObject* PythonTranslate(PyObject*, PyObject*);
+PyObject* PythonUpdateStatus(PyObject*, PyObject*);
+
+#endif
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_loader.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_loader.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/service_loader.c	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-kernel/ulinet.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/ulinet.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/ulinet.c	(revision 417)
@@ -0,0 +1,375 @@
+/**
+ *  ulinet.c
+ *
+ * Author : Gérald FENOY
+ *
+ * Copyright (c) 2008-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.
+ *
+ */
+
+#define _ULINET
+#include "ulinet.h"
+#include <assert.h>
+
+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=(char*)realloc(psInternet->pabyData,psInternet->nDataLen+realsize+1);
+    psInternet->nDataAlloc+=psInternet->nDataLen+realsize+1;
+  }
+  else{
+    psInternet->pabyData=(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;
+}
+
+size_t header_write_data(void *buffer, size_t size, size_t nmemb, void *data){
+  if(strncmp("Set-Cookie: ",buffer,12)==0){
+    int i;
+    char env[1024];
+    char path[1024];
+    char domain[1024];
+	char* tmp;
+    for(i=0;i<12;i++)
+#ifndef WIN32
+      buffer++;
+#else
+	;
+#endif
+    sscanf(buffer,"%s; path=%s; domain=%s",env,path,domain);
+    tmp=strcat(env,CCookie);
+#ifdef MSG_LAF_OUT
+    printf("\n**Cookie env : [%s] , path : [%s], domain : [%s]**\n",env,path,domain);
+    printf("buffer : %d (%s) (%s) (%s)\n",(buffer==NULL),buffer,tmp,CCookie);
+#endif
+    strcpy(CCookie,tmp);
+  }
+  return size * nmemb;//write_data_into(buffer,size,nmemb,data,HEADER);
+};
+
+
+void setProxy(CURL* handle,char* host,long port){
+}
+
+/**
+ * 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;
+  CFStringRef key_host;
+  CFStringRef key_port;
+  
+  bool proxy_enabled;
+  char *proxy_host;
+  long proxy_port;
+  
+  proxyDict = NULL;
+  proxies = NULL;
+
+  err = noErr;
+  proxyDict = SCDynamicStoreCopyProxies(NULL);
+
+  if(proto=="http"){
+      key_enabled=kSCPropNetProxiesHTTPEnable;
+      key_host=kSCPropNetProxiesHTTPProxy;
+      key_port=kSCPropNetProxiesHTTPPort;
+  }
+  else
+    if(proto=="https"){
+      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
+/**
+ * Linux (Gnome)
+ */
+bool setProxiesForProtcol(CURL* handle,const char *proto){
+#ifdef MSG_LAF_VERBOSE
+  fprintf( stderr, "setProxiesForProtocol (do nothing) ...\n" );
+#endif
+}
+#endif
+
+HINTERNET InternetOpen(char* lpszAgent,int dwAccessType,char* lpszProxyName,char* lpszProxyBypass,int dwFlags){
+  
+  HINTERNET ret;
+  struct MemoryStruct header;
+  ret.hasCacheFile=0;
+  ret.nDataAlloc = 0;
+
+  ret.handle=curl_easy_init();
+
+  curl_easy_setopt(ret.handle, CURLOPT_COOKIEFILE, "ALL");
+#ifndef TIGER
+  curl_easy_setopt(ret.handle, CURLOPT_COOKIELIST, "ALL");
+#endif
+  curl_easy_setopt(ret.handle, CURLOPT_USERAGENT, lpszAgent);
+  
+  curl_easy_setopt(ret.handle,CURLOPT_FOLLOWLOCATION,1);
+  curl_easy_setopt(ret.handle,CURLOPT_MAXREDIRS,3);
+  
+  header.memory=NULL;
+  header.size = 0;
+
+  curl_easy_setopt(ret.handle, CURLOPT_HEADERFUNCTION, header_write_data);
+  curl_easy_setopt(ret.handle, CURLOPT_WRITEHEADER, (void *)&header);
+
+#ifdef MSG_LAF_VERBOSE
+  curl_easy_setopt(ret.handle, CURLOPT_VERBOSE, 1);
+#endif
+
+  return ret;
+}
+
+static size_t 
+CurlWriteCB(void *buffer, size_t size, size_t nmemb, void *reqInfo){
+  HINTERNET *psInternet = (HINTERNET *) reqInfo;
+
+  memcpy( psInternet->pabyData + psInternet->nDataLen, buffer,  nmemb * size );
+  psInternet->nDataLen += nmemb * size;
+  psInternet->pabyData[psInternet->nDataLen] = 0;
+
+  return nmemb *size;
+}
+
+void InternetCloseHandle(HINTERNET handle){
+  if(handle.hasCacheFile>0){
+    fclose(handle.file);
+    unlink(handle.filename);
+  }
+  else{
+    handle.pabyData = NULL;
+    handle.nDataAlloc = handle.nDataLen = 0;
+  }
+  if(handle.handle)
+    curl_easy_cleanup(handle.handle);
+  curl_global_cleanup();
+}
+
+HINTERNET InternetOpenUrl(HINTERNET hInternet,LPCTSTR lpszUrl,LPCTSTR lpszHeaders,size_t dwHeadersLength,size_t dwFlags,size_t dwContext){
+
+  char filename[255];
+  hInternet.nDataLen = 0;
+
+  hInternet.nDataAlloc = 0;
+  hInternet.pabyData= NULL;
+      
+  switch(dwFlags)
+    {
+    case INTERNET_FLAG_NO_CACHE_WRITE:    
+      hInternet.hasCacheFile=-1;
+      curl_easy_setopt(hInternet.handle, CURLOPT_WRITEFUNCTION, write_data_into);
+      curl_easy_setopt(hInternet.handle, CURLOPT_WRITEDATA, &hInternet);
+      break;
+    default:
+      sprintf(filename,"/tmp/ZOO_Cache%d",(int)time(NULL));
+      filename[24]=0;
+      fprintf(stderr,"file=%s",filename);
+#ifdef MSG_LAF_VERBOSE
+      fprintf(stderr,"file=%s",filename);
+#endif
+      hInternet.filename=filename;
+      hInternet.file=fopen(hInternet.filename,"w+");
+    
+      hInternet.hasCacheFile=1;
+      curl_easy_setopt(hInternet.handle, CURLOPT_WRITEFUNCTION, NULL);
+      curl_easy_setopt(hInternet.handle, CURLOPT_WRITEDATA, hInternet.file);
+      hInternet.nDataLen=0;
+      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\n",lpszHeaders);
+#endif
+    //curl_easy_setopt(hInternet.handle,CURLOPT_COOKIE,lpszHeaders);
+    curl_easy_setopt(hInternet.handle,CURLOPT_POST,1);
+#ifdef ULINET_DEBUG
+    fprintf(stderr,"** (%s) %d **\n",lpszHeaders,dwHeadersLength);
+    curl_easy_setopt(hInternet.handle,CURLOPT_VERBOSE,1);
+#endif
+    curl_easy_setopt(hInternet.handle,CURLOPT_POSTFIELDS,lpszHeaders);
+    //curl_easy_setopt(hInternet.handle,CURLOPT_POSTFIELDSIZE,dwHeadersLength+1);
+    if(hInternet.header!=NULL)
+      curl_easy_setopt(hInternet.handle,CURLOPT_HTTPHEADER,hInternet.header);
+  }
+
+  curl_easy_setopt(hInternet.handle,CURLOPT_URL,lpszUrl);
+  curl_easy_perform(hInternet.handle);
+
+  return hInternet;
+};
+
+int freeCookieList(HINTERNET hInternet){
+  memset(&CCookie[0],0,1024);
+#ifndef TIGER
+  curl_easy_setopt(hInternet.handle, CURLOPT_COOKIELIST, "ALL");
+#endif
+  return 1;
+}
+
+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
+    rewind (hInternet.file);
+  }
+  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
+  printf("\nfile size : %dko\n",dwDataSize/1024);
+#endif
+
+  if(hInternet.hasCacheFile>0){
+    *lpdwNumberOfBytesRead = fread(lpBuffer,1,dwDataSize,hInternet.file); 
+  }
+  else{
+    *lpdwNumberOfBytesRead = hInternet.nDataLen;
+    free( hInternet.pabyData );
+    hInternet.pabyData = NULL;
+    hInternet.nDataAlloc = hInternet.nDataLen = 0;
+  }
+
+  CCookie[0]=0;
+
+  if( *lpdwNumberOfBytesRead < dwDataSize )
+      return 0;
+  else
+      return 1; // TRUE
+}
+
+bool InternetGetCookie(LPCTSTR lpszUrl,LPCTSTR lpszCookieName,LPTSTR lpszCookieData,LPDWORD lpdwSize){
+
+  bool ret=1;  
+  int count=0;
+  int hasCookie=-1;
+  char TMP[1024];
+  int j;
+  int tmpC=0;
+  lpszUrl=NULL;
+
+  for(j=0;j<strlen(CCookie);j++){
+    if(lpszCookieName[count]==CCookie[j]){
+      hasCookie=1;
+      count++;
+      if(count==strlen(lpszCookieName))
+	break;
+      continue;
+    }
+  }
+
+  if(hasCookie>0){
+    if(CCookie[count]=='='){
+      int i=0;
+      count++;
+      for(i=count;i<strlen(CCookie);i++){
+	if(CCookie[i]!=';'){
+	  TMP[tmpC]=CCookie[i];
+	  tmpC++;
+	}
+	else{
+	  break;
+	}
+      }
+    }
+  }
+  else
+    return -1;
+
+  TMP[tmpC]=0;
+  strncpy(lpszCookieData,TMP,strlen(TMP)+1);
+  lpdwSize=(size_t*) strlen(lpszCookieData);
+
+#ifdef MSG_LAF_VERBOSE
+  printf("Cookie returned : (%s)",(char*)lpszCookieData);
+#endif
+
+  return ret;
+
+}
+
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/ulinet.h
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/ulinet.h	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/ulinet.h	(revision 417)
@@ -0,0 +1,148 @@
+/**
+ * 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.
+ */
+
+#ifndef _ULINET_H
+#define _ULINET_H
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <curl/curl.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <string.h>
+#include "time.h"
+#ifdef USE_JS
+#ifdef WIN32
+# define XP_WIN
+#else
+#define XP_UNIX 0
+#endif
+#include "jsapi.h"
+#endif
+
+
+#ifdef _ULINET
+static char CCookie[1024];
+#else
+extern char HEADER[3072];
+extern char CCookie[1024];
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  //static pthread_mutex_t hMutexConnect = PTHREAD_MUTEX_INITIALIZER;
+
+struct MemoryStruct {
+  char *memory;
+  size_t size;
+};
+
+typedef struct {
+  CURL *handle;
+  struct curl_slist *header;
+  char* filename;
+  FILE* file;
+  size_t size;
+  int hasCacheFile;
+  int nDataLen;
+  int nDataAlloc;
+  unsigned char *pabyData;
+} HINTERNET;
+
+size_t write_data_into(void *buffer, size_t size, size_t nmemb, void *data);
+
+size_t content_write_data(void *buffer, size_t size, size_t nmemb, void *data);
+
+size_t header_write_data(void *buffer, size_t size, size_t nmemb, void *data);
+
+
+void setProxy(CURL* handle,char* host,long port);
+
+
+#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
+
+#include <CoreServices/CoreServices.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+char* CFStringToCString(CFStringRef dest,char * buffer);
+OSStatus setProxiesForProtcol(CURL* handle,const char *proto);
+
+#else
+
+//#include <gconf/gconf-client.h>
+int setProxiesForProtcol(CURL* handle,const char *proto);
+
+#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* lpszAgent,int dwAccessType,char* lpszProxyName,char* lpszProxyBypass,int dwFlags);
+
+void InternetCloseHandle(HINTERNET handle);
+
+#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
+#ifndef bool
+#define bool int
+#endif
+
+#  define CHECK_INET_HANDLE(h) (h.handle != 0)
+
+HINTERNET InternetOpenUrl(HINTERNET hInternet,LPCTSTR lpszUrl,LPCTSTR lpszHeaders,size_t dwHeadersLength,size_t dwFlags,size_t dwContext);
+
+int freeCookieList(HINTERNET hInternet);
+
+int InternetReadFile(HINTERNET hInternet,LPVOID lpBuffer,int dwNumberOfBytesToRead,size_t *lpdwNumberOfBytesRead);
+
+bool InternetGetCookie(LPCTSTR lpszUrl,LPCTSTR lpszCookieName,LPTSTR lpszCookieData,LPDWORD lpdwSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/zoo_loader.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/zoo_loader.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/zoo_loader.c	(revision 417)
@@ -0,0 +1,340 @@
+/**
+ * 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
+ */
+#ifndef WIN32
+#include "fcgio.h"
+#include "fcgi_config.h" 
+#include "fcgi_stdio.h"
+#endif
+#include <sys/types.h>
+#include <unistd.h>
+#include "service_internal.h"
+#ifdef WIN32
+#include "windows.h"
+#define strtok_r strtok_s
+#endif
+
+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>
+}
+
+#include "service_internal.h"
+
+xmlXPathObjectPtr extractFromDoc(xmlDocPtr,const char*);
+int runRequest(map*);
+
+using namespace std;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE -1
+#endif
+
+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=strdup(cgiQueryString);
+  map* tmpMap=NULL;
+
+  if(strncmp(cgiContentType,"text/xml",8)==0 || 
+     strncasecmp(cgiRequestMethod,"post",4)==0){
+    if(cgiContentLength==NULL){
+       cgiContentLength=0;
+       char *buffer=new char[2];
+       char *res=NULL;
+       int r=0;
+       while((r=fread(buffer,sizeof(char),1,cgiIn))){
+	 cgiContentLength+=r;
+	 if(res==NULL){
+	   res=(char*)malloc(1*sizeof(char));
+	   sprintf(res,"%s",buffer);
+	 }
+	 else{
+	   res=(char*)realloc(res,(cgiContentLength+1)*sizeof(char));
+	   char *tmp=strdup(res);
+	   sprintf(res,"%s%s",tmp,buffer);
+	   free(tmp);
+	 }
+       }
+       if(res==NULL && (strQuery==NULL || strlen(strQuery)==0)){
+	 return errorException(NULL,"ZOO-Kernel failed to process your request cause the request was emtpty.","InternalError");
+       }else{
+	 if(strQuery==NULL || strlen(strQuery)==0)
+	   tmpMap=createMap("request",res);
+       }
+    }else{
+      char *buffer=new char[cgiContentLength+1];
+      int r=0;
+      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)+1)*sizeof(char));
+	  sprintf(tmpValueFinal,"%s=%s",*arrayStep,ivalue);
+	  if(strlen(buffer)==0){
+	    sprintf(buffer,"%s",tmpValueFinal);
+	  }else{
+	    char *tmp=strdup(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++;
+	}
+	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);
+  }
+
+  /**
+   * 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)){
+    /**
+     * First include the MetaPath and the ServiceProvider default parameters
+     * (which should be always available in GET params so in cgiQueryString)
+     */
+    char *str1;
+    str1=cgiQueryString;
+    /**
+     * 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 = xmlParseMemory(t1->value,cgiContentLength);
+      {
+	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");
+	    int k=0;
+	    for(k;k < req->nodeNr;k++){
+	      xmlNsPtr ns=xmlNewNs(req->nodeTab[k],BAD_CAST "http://www.w3.org/2001/XMLSchema-instance",BAD_CAST "xsi");
+	      xmlDocSetRootElement(doc, req->nodeTab[k]);
+	      xmlChar *xmlbuff;
+	      int buffersize;
+	      xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, "utf-8", 1);
+	      addToMap(tmpMap,"xrequest",(char*)xmlbuff);
+	      char *tmp=(char*)xmlbuff;
+	      xmlFree(xmlbuff);
+	    }
+	  }
+	}
+      }
+
+      xmlNodePtr cur = xmlDocGetRootElement(doc);
+      char *tval;
+      tval=NULL;
+      tval = (char*) xmlGetProp(cur,BAD_CAST "service");
+      if(tval!=NULL)
+	addToMap(tmpMap,"service",tval);
+      tval=NULL;
+      tval = (char*) xmlGetProp(cur,BAD_CAST "language");
+      if(tval!=NULL)
+	addToMap(tmpMap,"language",tval);
+      const char* requests[3]={"GetCapabilities","DescribeProcess","Execute"};
+      for(int j=0;j<3;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){
+	    t1->value=strdup(requests[j]);
+	    j=2;
+	  }
+	  xmlXPathFreeObject(reqptr);
+	}
+      }
+      if(strncasecmp(t1->value,"GetCapabilities",15)==0){
+	xmlXPathObjectPtr versptr=extractFromDoc(doc,"/*/*/*[local-name()='Version']");
+	xmlNodeSet* vers=versptr->nodesetval;
+	xmlChar* content=xmlNodeListGetString(doc, vers->nodeTab[0]->xmlChildrenNode,1);
+	addToMap(tmpMap,"version",(char*)content);
+	xmlXPathFreeObject(versptr);
+	xmlFree(content);
+      }else{
+	tval=NULL;
+	tval = (char*) xmlGetProp(cur,BAD_CAST "version");
+	if(tval!=NULL)
+	  addToMap(tmpMap,"version",tval);
+	tval = (char*) xmlGetProp(cur,BAD_CAST "language");
+	if(tval!=NULL)
+	  addToMap(tmpMap,"language",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=strdup(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);
+	    addToMap(tmpMap,"Identifier",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=strdup(token1);
+	else
+	  value=strdup(token1);
+	token1=strtok_r(NULL,"=",&saveptr1);
+      }
+      addToMap(tmpMap,name,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){
+      addToMap(tmpMap,"dataInputs",strstr(strQuery,"dataInputs=")+11);
+    }
+  }
+
+  if(strQuery!=NULL)
+    free(strQuery);
+  runRequest(tmpMap);
+
+  /** 
+   * Required but can't be made after executing a process using POST requests.
+   */
+  if(strncasecmp(cgiRequestMethod,"post",4)!=0 && count(tmpMap)!=1 && tmpMap!=NULL){
+    freeMap(&tmpMap);
+    free(tmpMap);
+  }
+  return 0;
+
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/zoo_service_loader.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/zoo_service_loader.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-kernel/zoo_service_loader.c	(revision 417)
@@ -0,0 +1,2336 @@
+/**
+ * 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.
+ */
+
+#define length(x) (sizeof(x) / sizeof(x[0]))
+
+extern "C" int yylex();
+extern "C" int crlex();
+
+#include "cgic.h"
+
+extern "C" {
+#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"
+
+#ifdef USE_PYTHON
+#include "service_internal_python.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_PERL
+#include "service_internal_perl.h"
+#endif
+
+#include <dirent.h>
+#include <signal.h>
+#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>
+
+#ifdef WIN32
+extern "C" {
+  __declspec(dllexport) char *strcasestr(char const *a, char const *b)
+#ifndef USE_MS
+ { 
+  char *x=_strdup(a); 
+  char *y=_strdup(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
+
+#define _(String) dgettext ("zoo-kernel",String)
+#define __(String) dgettext ("zoo-service",String)
+
+
+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;
+  }
+}
+
+/**
+ * Create (or append to) an array valued maps
+ * value = "["",""]"
+ */
+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);
+  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){
+      if(addMapsArrayToMaps(&mo,mi,tmap->name)<0){
+	char emsg[1024];
+	sprintf(emsg,_("You set maximum occurences for <%s> as %i but you tried to use it more than the limit you set. Please correct your ZCFG file or your request."),mi->name,atoi(testMap->value));
+	errorException(m,emsg,"InternalError");
+	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");
+	  return -1;
+	}
+      }
+      else{
+	char emsg[1024];
+	sprintf(emsg,_("You set maximum occurences for <%s> to one but you tried to use it more than once. Please correct your ZCFG file or your request."),mi->name);
+	errorException(m,emsg,"InternalError");
+	return -1;
+      }
+    }
+  }
+  return 0;
+}
+
+xmlXPathObjectPtr extractFromDoc(xmlDocPtr doc,const char* search){
+  xmlXPathContextPtr xpathCtx;
+  xmlXPathObjectPtr xpathObj;
+  xpathCtx = xmlXPathNewContext(doc);
+  xpathObj = xmlXPathEvalExpression(BAD_CAST search,xpathCtx);
+  xmlXPathFreeContext(xpathCtx);
+  return xpathObj;
+}
+
+void donothing(int sig){
+  fprintf(stderr,"Signal %d after the ZOO-Kernel returned result !\n",sig);
+  exit(0);
+}
+
+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");
+#ifdef DEBUG
+  fprintf(stderr,"Not this time!\n");
+#endif
+  exit(0);
+}
+
+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;
+#ifndef WIN32
+  char* pntmp=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
+  if(strlen(r_inputs->value)==1 && strncasecmp(r_inputs->value,"C",1)==0){
+    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=strdup(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 DEBUG
+#ifdef WIN32
+    DWORD errstr;
+    errstr = GetLastError();
+    fprintf(stderr,"%s loaded (%d) \n",tmps1,errstr);
+#else
+    char *errstr;
+    errstr = dlerror();
+#endif
+#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 = GetLastError();
+#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 = GetLastError();
+	fprintf(stderr,"Function %s failed to load because of %d\n",r_inputs->value,errstr);
+#endif
+#endif
+	r_inputs=getMap(request_inputs,"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
+
+#ifdef DEBUG
+#ifdef WIN32
+	errstr = GetLastError();
+#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
+      DWORD errstr = GetLastError();
+#else
+      char* errstr = dlerror();
+#endif
+      sprintf(tmps,_("C Library can't be loaded %s"),errstr);
+      map* tmps1=createMap("text",tmps);
+      printExceptionReportResponse(m,tmps1);
+      *eres=-1;
+    }
+  }
+  else
+#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_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
+	      {
+		char tmpv[1024];
+		sprintf(tmpv,_("Programming Language (%s) set in ZCFG file is not currently supported by ZOO Kernel.\n"),r_inputs->value);
+		map* tmps=createMap("text",tmpv);
+		printExceptionReportResponse(m,tmps);
+		*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");
+
+  char *dataInputsKVP=getMapsAsKVP(inputs,cgiContentLength,0);
+  char *dataOutputsKVP=getMapsAsKVP(outputs,cgiContentLength,1);
+#ifdef DEBUG
+  fprintf(stderr,"DATAINPUTSKVP %s\n",dataInputsKVP);
+  fprintf(stderr,"DATAOUTPUTSKVP %s\n",dataOutputsKVP);
+#endif
+  map *sid=getMapFromMaps(m,"lenv","sid");
+  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(s1->content,"ResponseDocument");
+  if(r_inputs2==NULL)
+    r_inputs2=getMap(s1->content,"RawDataOutput");
+  map *tmpPath=getMapFromMaps(m,"lenv","cwd");
+
+  if(r_inputs2!=NULL){
+    sprintf(tmp,"\"metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s&%s=%s&cgiSid=%s\"",r_inputs1->value,req->value,id->value,dataInputsKVP,r_inputs2->name,r_inputs2->value,sid->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\"",r_inputs1->value,req->value,id->value,dataInputsKVP,sid->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=strdup(tmp);
+  sprintf(tmp,"zoo_loader.cgi %s \"%s\"",tmp1,sid->value);
+  
+  free(dataInputsKVP);
+  free(dataOutputsKVP);
+  //printf("REQUEST IS : %s \n",tmp);
+#ifdef DEBUG
+  fprintf(stderr,"REQUEST IS : %s \n",tmp);
+#endif
+  SetEnvironmentVariable("CGISID",TEXT(sid->value));
+  SetEnvironmentVariable("QUERY_STRING",TEXT(tmpq));
+  char clen[1000];
+  sprintf(clen,"%d",strlen(tmpq));
+  SetEnvironmentVariable("CONTENT_LENGTH",TEXT(clen));
+
+  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
+      ) 
+    { 
+      //printf("CreateProcess failed (%d).\n",GetLastError() );
+#ifdef DEBUG
+      fprintf( stderr, "CreateProcess failed (%d).\n", GetLastError() );
+#endif
+      return ;
+    }else{
+    //printf("CreateProcess successfull (%d).\n",GetLastError() );
+#ifdef DEBUG
+    fprintf( stderr, "CreateProcess successfull (%d).\n\n\n\n", GetLastError() );
+#endif
+  }
+  CloseHandle( pi.hProcess );
+  CloseHandle( pi.hThread );
+  //printf("CreateProcess finished !\n");
+#ifdef DEBUG
+  fprintf(stderr,"CreateProcess finished !\n");
+#endif
+}
+#endif
+
+int runRequest(map* request_inputs)
+{
+
+#ifndef USE_GDB
+  (void) signal(SIGSEGV,sig_handler);
+  (void) signal(SIGTERM,sig_handler);
+  (void) signal(SIGINT,sig_handler);
+  (void) signal(SIGILL,sig_handler);
+  (void) signal(SIGFPE,sig_handler);
+  (void) signal(SIGABRT,sig_handler);
+#endif
+
+  map* r_inputs=NULL;
+  maps* m=NULL;
+
+  char* REQUEST=NULL;
+  /**
+   * Parsing service specfic configuration file
+   */
+  m=(maps*)malloc(MAPS_SIZE);
+  if(m == NULL){
+    return errorException(m, _("Unable to allocate memory."), "InternalError");
+  }
+  char ntmp[1024];
+#ifndef WIN32
+  char *pntmp=getcwd(ntmp,1024);
+#else
+  _getcwd(ntmp,1024);
+#endif
+  r_inputs=getMapOrFill(request_inputs,"metapath","");
+
+
+  char conf_file[10240];
+  snprintf(conf_file,10240,"%s/%s/main.cfg",ntmp,r_inputs->value);
+  if(conf_read(conf_file,m)==2){
+    errorException(NULL, _("Unable to load the main.cfg file."),"InternalError");
+    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","/usr/share/locale/");
+    bindtextdomain ("zoo-services","/usr/share/locale/");
+  }
+
+
+  /**
+   * 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=getMapFromMaps(m,"main","language");
+  if(r_inputs!=NULL){
+    char *tmp=strdup(r_inputs->value);
+    setMapInMaps(m,"main","language",tmp);
+    translateChar(tmp,'-','_');
+    setlocale (LC_ALL, tmp);
+#ifdef WIN32
+    char tmp1[12];
+    sprintf(tmp1,"LC_ALL=%s",tmp);
+    putenv(tmp1);
+#endif
+    free(tmp);
+  }
+  else{
+    setlocale (LC_ALL, "en_US");
+#ifdef WIN32
+    char tmp1[12];
+    sprintf(tmp1,"LC_ALL=en_US");
+    putenv(tmp1);
+#endif
+    setMapInMaps(m,"main","language","en-US");
+  }
+  setlocale (LC_NUMERIC, "en_US");
+  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");
+
+
+  /**
+   * Check for minimum inputs
+   */
+  r_inputs=getMap(request_inputs,"Request");
+  if(request_inputs==NULL || r_inputs==NULL){ 
+    errorException(m, _("Parameter <request> was not specified"),"MissingParameterValue");
+    freeMaps(&m);
+    free(m);
+    return 1;
+  }
+  else{
+    REQUEST=strdup(r_inputs->value);
+    if(strncasecmp(r_inputs->value,"GetCapabilities",15)!=0
+       && strncasecmp(r_inputs->value,"DescribeProcess",15)!=0
+       && strncasecmp(r_inputs->value,"Execute",7)!=0){ 
+      errorException(m, _("Unenderstood <request> value. Please check that it was set to GetCapabilities, DescribeProcess or Execute."), "InvalidParameterValue");
+      freeMaps(&m);
+      free(m);
+      free(REQUEST);
+      return 1;
+    }
+  }
+  r_inputs=NULL;
+  r_inputs=getMap(request_inputs,"Service");
+  if(r_inputs==NULLMAP){
+    errorException(m, _("Parameter <service> was not specified"),"MissingParameterValue");
+    freeMaps(&m);
+    free(m);
+    free(REQUEST);
+    return 1;
+  }
+  if(strncasecmp(REQUEST,"GetCapabilities",15)!=0){
+    r_inputs=getMap(request_inputs,"Version");
+    if(r_inputs==NULL){ 
+      errorException(m, _("Parameter <version> was not specified"),"MissingParameterValue");
+      freeMaps(&m);
+      free(m);
+      free(REQUEST);
+      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=strdup(tmpm->value);
+  else
+    SERVICE_URL=strdup(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");
+  if(r_inputs!=NULL)
+    snprintf(conf_dir,1024,"%s/%s",ntmp,r_inputs->value);
+  else
+    snprintf(conf_dir,1024,"%s",ntmp);
+
+  if(strncasecmp(REQUEST,"GetCapabilities",15)==0){
+    struct dirent *dp;
+#ifdef DEBUG
+    dumpMap(r_inputs);
+#endif
+    DIR *dirp = opendir(conf_dir);
+    if(dirp==NULL){
+      return errorException(m, _("The specified path doesn't exist."),"InvalidParameterValue");
+    }
+    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
+    r_inputs=NULL;
+    r_inputs=getMap(request_inputs,"ServiceProvider");
+    xmlNodePtr n;
+    if(r_inputs!=NULL)
+      n = printGetCapabilitiesHeader(doc,r_inputs->value,m);
+    else
+      n = printGetCapabilitiesHeader(doc,"",m);
+    /**
+     * Here we need to close stdout to ensure that not supported chars 
+     * has been found in the zcfg and then printed on stdout
+     */
+    int saved_stdout = dup(fileno(stdout));
+    dup2(fileno(stderr),fileno(stdout));
+    while ((dp = readdir(dirp)) != NULL)
+      if(strstr(dp->d_name,".zcfg")!=0){
+	memset(tmps1,0,1024);
+	snprintf(tmps1,1024,"%s/%s",conf_dir,dp->d_name);
+	s1=(service*)malloc(SERVICE_SIZE);
+	if(s1 == NULL){ 
+	  return errorException(m, _("Unable to allocate memory."),"InternalError");
+	}
+#ifdef DEBUG
+	fprintf(stderr,"#################\n%s\n#################\n",tmps1);
+#endif
+	t=getServiceFromFile(tmps1,&s1);
+#ifdef DEBUG
+	dumpService(s1);
+	fflush(stdout);
+	fflush(stderr);
+#endif
+	printGetCapabilitiesForProcess(m,n,s1);
+	freeService(&s1);
+	free(s1);
+	scount++;
+      }
+    (void)closedir(dirp);
+    fflush(stdout);
+    dup2(saved_stdout,fileno(stdout));
+    printDocument(m,doc,getpid());
+    freeMaps(&m);
+    free(m);
+    free(REQUEST);
+    free(SERVICE_URL);
+    fflush(stdout);
+    return 0;
+  }
+  else{
+    r_inputs=getMap(request_inputs,"Identifier");
+    if(r_inputs==NULL 
+       || strlen(r_inputs->name)==0 || strlen(r_inputs->value)==0){ 
+      errorException(m, _("Mandatory <identifier> was not specified"),"MissingParameterValue");
+      freeMaps(&m);
+      free(m);
+      free(REQUEST);
+      free(SERVICE_URL);
+      return 0;
+    }
+
+    struct dirent *dp;
+    DIR *dirp = opendir(conf_dir);
+    if(dirp==NULL){
+      errorException(m, _("The specified path path doesn't exist."),"InvalidParameterValue");
+      freeMaps(&m);
+      free(m);
+      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,"ServiceProvider");
+
+      xmlNodePtr n;
+      if(r_inputs!=NULL)
+	n = printDescribeProcessHeader(doc,r_inputs->value,m);
+      else
+	n = printDescribeProcessHeader(doc,"",m);
+
+      r_inputs=getMap(request_inputs,"Identifier");
+      char *tmps=strtok(r_inputs->value,",");
+      
+      char buff[256];
+      char buff1[1024];
+      int saved_stdout = dup(fileno(stdout));
+      dup2(fileno(stderr),fileno(stdout));
+      while(tmps){
+	memset(buff,0,256);
+	snprintf(buff,256,"%s.zcfg",tmps);
+	memset(buff1,0,1024);
+#ifdef DEBUG
+	printf("\n#######%s\n########\n",buff1);
+#endif
+	while ((dp = readdir(dirp)) != NULL)
+	  if((strcasecmp("all.zcfg",buff)==0 && strstr(dp->d_name,".zcfg")>0)
+	     || strcasecmp(dp->d_name,buff)==0){
+	    memset(buff1,0,1024);
+	    snprintf(buff1,1024,"%s/%s",conf_dir,dp->d_name);
+	    s1=(service*)malloc(SERVICE_SIZE);
+	    if(s1 == NULL){
+	      dup2(saved_stdout,fileno(stdout));
+	      return errorException(m, _("Unable to allocate memory."),"InternalError");
+	    }
+#ifdef DEBUG
+	    printf("#################\n%s\n#################\n",buff1);
+#endif
+	    t=getServiceFromFile(buff1,&s1);
+#ifdef DEBUG
+	    dumpService(s1);
+#endif
+	    printDescribeProcessForProcess(m,n,s1,1);
+	    freeService(&s1);
+	    free(s1);
+	    scount++;
+	  }
+	rewinddir(dirp);
+	tmps=strtok(NULL,",");
+      }
+      closedir(dirp);
+      fflush(stdout);
+      dup2(saved_stdout,fileno(stdout));
+      printDocument(m,doc,getpid());
+      freeMaps(&m);
+      free(m);
+      free(REQUEST);
+      free(SERVICE_URL);
+      fflush(stdout);
+      return 0;
+    }
+    else
+      if(strncasecmp(REQUEST,"Execute",strlen(REQUEST))!=0){
+	errorException(m, _("Unenderstood <request> value. Please check that it was set to GetCapabilities, DescribeProcess or Execute."), "InvalidParameterValue");
+#ifdef DEBUG
+	fprintf(stderr,"No request found %s",REQUEST);
+#endif	
+	closedir(dirp);
+	freeMaps(&m);
+	free(m);
+	free(REQUEST);
+	free(SERVICE_URL);
+	fflush(stdout);
+	return 0;
+      }
+    closedir(dirp);
+  }
+  
+  s1=NULL;
+  s1=(service*)malloc(SERVICE_SIZE);
+  if(s1 == NULL){
+    freeMaps(&m);
+    free(m);
+    free(REQUEST);
+    free(SERVICE_URL);
+    return errorException(m, _("Unable to allocate memory."),"InternalError");
+  }
+  r_inputs=getMap(request_inputs,"MetaPath");
+  if(r_inputs!=NULL)
+    snprintf(tmps1,1024,"%s/%s",ntmp,r_inputs->value);
+  else
+    snprintf(tmps1,1024,"%s/",ntmp);
+  r_inputs=getMap(request_inputs,"Identifier");
+  char *ttmp=strdup(tmps1);
+  snprintf(tmps1,1024,"%s/%s.zcfg",ttmp,r_inputs->value);
+  free(ttmp);
+#ifdef DEBUG
+  fprintf(stderr,"Trying to load %s\n", tmps1);
+#endif
+  int saved_stdout = dup(fileno(stdout));
+  dup2(fileno(stderr),fileno(stdout));
+  t=getServiceFromFile(tmps1,&s1);
+  fflush(stdout);
+  dup2(saved_stdout,fileno(stdout));
+  if(t<0){
+    char *tmpMsg=(char*)malloc(2048+strlen(r_inputs->value));
+    
+    sprintf(tmpMsg,_("The value for <indetifier> seems to be wrong (%s). Please, ensure that the process exist using the GetCapabilities request."),r_inputs->value);
+    errorException(m, tmpMsg, "InvalidParameterValue");
+    free(tmpMsg);
+    free(s1);
+    freeMaps(&m);
+    free(m);
+    free(REQUEST);
+    free(SERVICE_URL);
+    return 0;
+  }
+  close(saved_stdout);
+
+#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;
+  map* postRequest=NULL;
+  postRequest=getMap(request_inputs,"xrequest");
+  if(postRequest==NULLMAP){
+    /**
+     * Parsing outputs provided as KVP
+     */
+    r_inputs=NULL;
+#ifdef DEBUG
+    fprintf(stderr,"OUTPUT Parsing ... \n");
+#endif
+    r_inputs=getMap(request_inputs,"ResponseDocument");	
+    if(r_inputs==NULL) r_inputs=getMap(request_inputs,"RawDataOutput");
+    
+#ifdef DEBUG
+    fprintf(stderr,"OUTPUT Parsing ... \n");
+#endif
+    if(r_inputs!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"OUTPUT Parsing start now ... \n");
+#endif
+      char cursor_output[10240];
+      char *cotmp=strdup(r_inputs->value);
+      snprintf(cursor_output,10240,"%s",cotmp);
+      free(cotmp);
+      j=0;
+	
+      /**
+       * Put each Output into the outputs_as_text array
+       */
+      char * pToken;
+      maps* tmp_output=NULL;
+#ifdef DEBUG
+      fprintf(stderr,"OUTPUT [%s]\n",cursor_output);
+#endif
+      pToken=strtok(cursor_output,";");
+      char** outputs_as_text=(char**)malloc(128*sizeof(char*));
+      if(outputs_as_text == NULL) {
+	return errorException(m, _("Unable to allocate memory"), "InternalError");
+      }
+      i=0;
+      while(pToken!=NULL){
+#ifdef DEBUG
+	fprintf(stderr,"***%s***\n",pToken);
+	fflush(stderr);
+	fprintf(stderr,"***%s***\n",pToken);
+#endif
+	outputs_as_text[i]=(char*)malloc((strlen(pToken)+1)*sizeof(char));
+	if(outputs_as_text[i] == NULL) {
+	  return errorException(m, _("Unable to allocate memory"), "InternalError");
+	}
+	snprintf(outputs_as_text[i],strlen(pToken)+1,"%s",pToken);
+	pToken = strtok(NULL,";");
+	i++;
+      }
+      for(j=0;j<i;j++){
+	char *tmp=strdup(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=(maps*)malloc(MAPS_SIZE);
+	      if(tmp_output == NULL){
+		return errorException(m, _("Unable to allocate memory."), "InternalError");
+	      }
+	      tmp_output->name=strdup(tmpc);
+	      tmp_output->content=NULL;
+	      tmp_output->next=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;
+#ifdef DEBUG
+	    fprintf(stderr,"OUTPUT DEF [%s]=[%s]\n",tmpn,tmpv+1);
+#endif
+	    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++;
+#ifdef DEBUG
+	  fprintf(stderr,"***%s***\n",tmpc);
+#endif
+	  tmpc=strtok(NULL,"@");
+	}
+	if(request_output_real_format==NULL)
+	  request_output_real_format=dupMaps(&tmp_output);
+	else
+	  addMapsToMaps(&request_output_real_format,tmp_output);
+	freeMaps(&tmp_output);
+	free(tmp_output);
+	tmp_output=NULL;
+#ifdef DEBUG
+	dumpMaps(tmp_output);
+	fflush(stderr);
+#endif
+	free(tmp);
+      }
+      free(outputs_as_text);
+    }
+
+
+    /**
+     * Parsing inputs provided as KVP
+     */
+    r_inputs=getMap(request_inputs,"DataInputs");
+#ifdef DEBUG
+    fprintf(stderr,"DATA INPUTS [%s]\n",r_inputs->value);
+#endif
+    char cursor_input[40960];
+    if(r_inputs!=NULL)
+      snprintf(cursor_input,40960,"%s",r_inputs->value);
+    else{
+      errorException(m, _("Parameter <DataInputs> was not specified"),"MissingParameterValue");
+      freeMaps(&m);
+      free(m);
+      free(REQUEST);
+      free(SERVICE_URL);
+      InternetCloseHandle(hInternet);
+      freeService(&s1);
+      free(s1);
+      return 0;
+    }
+    j=0;
+  
+    /**
+     * Put each DataInputs into the inputs_as_text array
+     */
+    char *tmp1=strdup(cursor_input);
+    char * pToken;
+    pToken=strtok(cursor_input,";");
+    if(pToken!=NULL && strncasecmp(pToken,tmp1,strlen(tmp1))==0){
+      char* tmp2=url_decode(tmp1);
+      snprintf(cursor_input,(strlen(tmp2)+1)*sizeof(char),"%s",tmp2);
+      free(tmp2);
+      pToken=strtok(cursor_input,";");
+    }
+    free(tmp1);
+
+    char** inputs_as_text=(char**)malloc(100*sizeof(char*));
+    if(inputs_as_text == NULL){
+      return errorException(m, _("Unable to allocate memory."), "InternalError");
+    }
+    i=0;
+    while(pToken!=NULL){
+#ifdef DEBUG
+      fprintf(stderr,"***%s***\n",pToken);
+#endif
+      fflush(stderr);
+#ifdef DEBUG
+      fprintf(stderr,"***%s***\n",pToken);
+#endif
+      inputs_as_text[i]=(char*)malloc((strlen(pToken)+1)*sizeof(char));
+      snprintf(inputs_as_text[i],strlen(pToken)+1,"%s",pToken);
+      if(inputs_as_text[i] == NULL){
+	return errorException(m, _("Unable to allocate memory."), "InternalError");
+      }
+      pToken = strtok(NULL,";");
+      i++;
+    }
+
+    for(j=0;j<i;j++){
+      char *tmp=strdup(inputs_as_text[j]);
+      free(inputs_as_text[j]);
+      char *tmpc;
+      tmpc=strtok(tmp,"@");
+      while(tmpc!=NULL){
+#ifdef DEBUG
+	fprintf(stderr,"***\n***%s***\n",tmpc);
+#endif
+	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;
+	}
+#ifdef DEBUG
+	fprintf(stderr,"***\n*** %s = %s ***\n",tmpn,tmpv+1);
+#endif
+	if(tmpmaps==NULL){
+	  tmpmaps=(maps*)malloc(MAPS_SIZE);
+	  if(tmpmaps == NULL){
+	    return errorException(m, _("Unable to allocate memory."), "InternalError");
+	  }
+	  tmpmaps->name=strdup(tmpn);
+	  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){
+#ifdef DEBUG
+	  fprintf(stderr,"*** KVP NON URL-ENCODED \n***%s***\n",tmpc);
+#endif
+	  char *tmpv1=strstr(tmpc,"=");
+#ifdef DEBUG
+	  fprintf(stderr,"*** VALUE NON URL-ENCODED \n***%s***\n",tmpv1+1);
+#endif
+	  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=strdup(tmpValue);
+	    free(tmpValue);
+	    tmpc=strtok(NULL,"@");
+	    continue;
+	  }
+#ifdef DEBUG
+	  fprintf(stderr,"*** NAME NON URL-ENCODED \n***%s***\n",tmpn1);
+	  fprintf(stderr,"*** VALUE NON URL-ENCODED \n***%s***\n",tmpv1+1);
+#endif
+	  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){
+		char emsg[1024];
+		sprintf(emsg,_("Unable to find a valid protocol to download the remote file %s"),tmpv1+1);
+		errorException(m,emsg,"InternalError");
+		freeMaps(&m);
+		free(m);
+		free(REQUEST);
+		free(SERVICE_URL);
+		InternetCloseHandle(hInternet);
+		freeService(&s1);
+		free(s1);
+		return 0;
+	      }
+#ifdef DEBUG
+	      fprintf(stderr,"REQUIRE TO DOWNLOAD A FILE FROM A SERVER : url(%s)\n",tmpv1+1);
+#endif
+	      addToMap(tmpmaps->content,tmpn1,tmpx2);
+	      
+#ifndef WIN32
+	      if(CHECK_INET_HANDLE(hInternet))
+#endif
+		{
+		  if(loadRemoteFile(m,tmpmaps->content,hInternet,tmpx2)<0){
+		    freeMaps(&m);
+		    free(m);
+		    free(REQUEST);
+		    free(SERVICE_URL);
+		    InternetCloseHandle(hInternet);
+		    freeService(&s1);
+		    free(s1);
+		    return 0;
+		  }
+		}
+	      free(tmpx2);
+	      addToMap(tmpmaps->content,"Reference",tmpv1+1);
+	    }
+	  tmpc=strtok(NULL,"@");
+	}
+#ifdef DEBUG
+	dumpMaps(tmpmaps);
+	fflush(stderr);
+#endif
+	if(request_input_real_format==NULL)
+	  request_input_real_format=dupMaps(&tmpmaps);
+	else{
+	  maps* testPresence=getMaps(request_input_real_format,tmpmaps->name);
+	  if(testPresence!=NULL){
+	    elements* elem=getElements(s1->inputs,tmpmaps->name);
+	    if(elem!=NULL){
+	      if(appendMapsToMaps(m,request_input_real_format,tmpmaps,elem)<0){
+		freeMaps(&m);
+		free(m);
+		free(REQUEST);
+		free(SERVICE_URL);
+		InternetCloseHandle(hInternet);
+		freeService(&s1);
+		free(s1);
+		return 0;
+	      }
+	    }
+	  }
+	  else
+	    addMapsToMaps(&request_input_real_format,tmpmaps);
+	}
+	freeMaps(&tmpmaps);
+	free(tmpmaps);
+	tmpmaps=NULL;
+	free(tmp);
+      }
+    }
+    free(inputs_as_text);
+  }
+  else {
+    /**
+     * Parse XML request
+     */ 
+    xmlInitParser();
+#ifdef DEBUG
+    fflush(stderr);
+    fprintf(stderr,"BEFORE %s\n",postRequest->value);
+    fflush(stderr);
+#endif
+    xmlDocPtr doc =
+      xmlParseMemory(postRequest->value,cgiContentLength);
+#ifdef DEBUG
+    fprintf(stderr,"AFTER\n");
+    fflush(stderr);
+#endif
+    /**
+     * Parse every Input in DataInputs node.
+     */
+    xmlXPathObjectPtr tmpsptr=extractFromDoc(doc,"/*/*/*[local-name()='Input']");
+    xmlNodeSet* tmps=tmpsptr->nodesetval;
+#ifdef DEBUG
+    fprintf(stderr,"*****%d*****\n",tmps->nodeNr);
+#endif
+    for(int k=0;k<tmps->nodeNr;k++){
+      maps *tmpmaps=NULL;
+      xmlNodePtr cur=tmps->nodeTab[k];
+      if(tmps->nodeTab[k]->type == XML_ELEMENT_NODE) {
+	/**
+	 * A specific Input node.
+	 */
+#ifdef DEBUG
+	fprintf(stderr, "= element 0 node \"%s\"\n", cur->name);
+#endif
+	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){
+	      tmpmaps=(maps*)malloc(MAPS_SIZE);
+	      if(tmpmaps == NULL){
+		return errorException(m, _("Unable to allocate memory."), "InternalError");
+	      }
+	      tmpmaps->name=strdup((char*)val);
+	      tmpmaps->content=NULL;
+	      tmpmaps->next=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);
+	    if(tmpmaps==NULL){
+	      tmpmaps=(maps*)malloc(MAPS_SIZE);
+	      if(tmpmaps == NULL){
+		return errorException(m, _("Unable to allocate memory."), "InternalError");
+	      }
+	      tmpmaps->name=strdup("missingIndetifier");
+	      tmpmaps->content=createMap((char*)cur2->name,(char*)val);
+	      tmpmaps->next=NULL;
+	    }
+	    else{
+	      if(tmpmaps->content!=NULL)
+		addToMap(tmpmaps->content,
+			 (char*)cur2->name,(char*)val);
+	      else
+		tmpmaps->content=
+		  createMap((char*)cur2->name,(char*)val);
+	    }
+#ifdef DEBUG
+	    dumpMaps(tmpmaps);
+#endif
+	    xmlFree(val);
+	  }
+	  /**
+	   * InputDataFormChoice (Reference or Data ?) 
+	   */
+	  if(xmlStrcasecmp(cur2->name,BAD_CAST "Reference")==0){
+	    /**
+	     * Get every attribute from a Reference node
+	     * mimeType, encoding, schema, href, method
+	     * Header and Body gesture should be added here
+	     */
+#ifdef DEBUG
+	    fprintf(stderr,"REFERENCE\n");
+#endif
+	    const char *refs[5]={"mimeType","encoding","schema","method","href"};
+	    for(int l=0;l<5;l++){
+#ifdef DEBUG
+	      fprintf(stderr,"*** %s ***",refs[l]);
+#endif
+	      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 && strcmp(ltmp->value,"POST")==0)
+		     && CHECK_INET_HANDLE(hInternet)){
+		    if(loadRemoteFile(m,tmpmaps->content,hInternet,(char*)val)!=0){
+		      freeMaps(&m);
+		      free(m);
+		      free(REQUEST);
+		      free(SERVICE_URL);
+		      InternetCloseHandle(hInternet);
+		      freeService(&s1);
+		      free(s1);
+		      return 0;
+		    }
+		  }
+		}
+	      }
+#ifdef DEBUG
+	      fprintf(stderr,"%s\n",val);
+#endif
+	      xmlFree(val);
+	    }
+#ifdef POST_DEBUG
+	    fprintf(stderr,"Parse Header and Body from Reference \n");
+#endif
+	    xmlNodePtr cur3=cur2->children;
+	    hInternet.header=NULL;
+	    while(cur3){
+	      while(cur3!=NULL && cur3->type!=XML_ELEMENT_NODE)
+		cur2=cur3->next;
+	      if(xmlStrcasecmp(cur3->name,BAD_CAST "Header")==0 ){
+		const char *ha[2];
+		ha[0]="key";
+		ha[1]="value";
+		int hai;
+		char *has;
+		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=(char*)malloc((1+strlen((char*)val))*sizeof(char));
+		    snprintf(key,1+strlen((char*)val),"%s",(char*)val);
+		  }else{
+		    has=(char*)malloc((3+strlen((char*)val)+strlen(key))*sizeof(char));
+		    if(has == NULL){
+		      return errorException(m, _("Unable to allocate memory."), "InternalError");
+		    }
+		    snprintf(has,(3+strlen((char*)val)+strlen(key)),"%s: %s",key,(char*)val);
+#ifdef POST_DEBUG
+		    fprintf(stderr,"%s\n",has);
+#endif
+		  }
+		}
+		hInternet.header=curl_slist_append(hInternet.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 !!!\n",(char*)cur3->content);
+#endif
+		  char *tmp=new char[cgiContentLength];
+		  memset(tmp,0,cgiContentLength);
+		  xmlNodePtr cur4=cur3->children;
+		  while(cur4!=NULL){
+		    while(cur4->type!=XML_ELEMENT_NODE)
+		      cur4=cur4->next;
+		    xmlDocPtr bdoc = xmlNewDoc(BAD_CAST "1.0");
+		    bdoc->encoding = xmlCharStrdup ("UTF-8");
+		    xmlDocSetRootElement(bdoc,cur4);
+		    xmlChar* btmps;
+		    int bsize;
+		    xmlDocDumpMemory(bdoc,&btmps,&bsize);
+#ifdef POST_DEBUG
+		    fprintf(stderr,"Body part found !!! %s %s\n",tmp,(char*)btmps);
+#endif
+		    if(btmps!=NULL)
+		      sprintf(tmp,"%s",(char*)btmps);
+		    xmlFreeDoc(bdoc);
+		    cur4=cur4->next;
+		  }
+		  map *btmp=getMap(tmpmaps->content,"href");
+		  if(btmp!=NULL){
+#ifdef POST_DEBUG
+		    fprintf(stderr,"%s %s\n",btmp->value,tmp);
+		    curl_easy_setopt(hInternet.handle, CURLOPT_VERBOSE, 1);
+#endif
+		    res=InternetOpenUrl(hInternet,btmp->value,tmp,strlen(tmp),
+					INTERNET_FLAG_NO_CACHE_WRITE,0);
+		    char* tmpContent = (char*)malloc((res.nDataLen+1)*sizeof(char));
+		    if(tmpContent == NULL){
+		      return errorException(m, _("Unable to allocate memory."), "InternalError");
+		    }
+		    size_t dwRead;
+		    InternetReadFile(res, (LPVOID)tmpContent,
+				     res.nDataLen, &dwRead);
+		    tmpContent[res.nDataLen]=0;
+		    if(hInternet.header!=NULL)
+		      curl_slist_free_all(hInternet.header);
+		    addToMap(tmpmaps->content,"value",tmpContent);
+#ifdef POST_DEBUG
+		    fprintf(stderr,"DL CONTENT : (%s)\n",tmpContent);
+#endif
+		  }
+		}
+		else
+		  if(xmlStrcasecmp(cur3->name,BAD_CAST "BodyReference")==0 ){
+		    xmlChar *val=xmlGetProp(cur3,BAD_CAST "href");
+		    HINTERNET bInternet,res1;
+		    bInternet=InternetOpen(
+#ifndef WIN32
+					   (LPCTSTR)
+#endif
+					   "ZooWPSClient\0",
+					   INTERNET_OPEN_TYPE_PRECONFIG,
+					   NULL,NULL, 0);
+		    if(!CHECK_INET_HANDLE(bInternet))
+		      fprintf(stderr,"WARNING : hInternet handle failed to initialize");
+#ifdef POST_DEBUG
+		    curl_easy_setopt(bInternet.handle, CURLOPT_VERBOSE, 1);
+#endif
+		    res1=InternetOpenUrl(bInternet,(char*)val,NULL,0,
+					 INTERNET_FLAG_NO_CACHE_WRITE,0);
+		    char* tmp=
+		      (char*)malloc((res1.nDataLen+1)*sizeof(char));
+		    if(tmp == NULL){
+		      return errorException(m, _("Unable to allocate memory."), "InternalError");
+		    }
+		    size_t bRead;
+		    InternetReadFile(res1, (LPVOID)tmp,
+				     res1.nDataLen, &bRead);
+		    tmp[res1.nDataLen]=0;
+		    InternetCloseHandle(bInternet);
+		    map *btmp=getMap(tmpmaps->content,"href");
+		    if(btmp!=NULL){
+#ifdef POST_DEBUG
+		      fprintf(stderr,"%s %s\n",btmp->value,tmp);
+		      curl_easy_setopt(hInternet.handle, CURLOPT_VERBOSE, 1);
+#endif
+		      res=InternetOpenUrl(hInternet,btmp->value,tmp,
+					  strlen(tmp),
+					  INTERNET_FLAG_NO_CACHE_WRITE,0);
+		      char* tmpContent = (char*)malloc((res.nDataLen+1)*sizeof(char));
+		      if(tmpContent == NULL){
+			return errorException(m, _("Unable to allocate memory."), "InternalError");
+		      }
+		      size_t dwRead;
+		      InternetReadFile(res, (LPVOID)tmpContent,
+				       res.nDataLen, &dwRead);
+		      tmpContent[res.nDataLen]=0;
+		      if(hInternet.header!=NULL)
+			curl_slist_free_all(hInternet.header);
+		      addToMap(tmpmaps->content,"value",tmpContent);
+#ifdef POST_DEBUG
+		      fprintf(stderr,"DL CONTENT : (%s)\n",tmpContent);
+#endif
+		    }
+		  }
+	      }
+	      cur3=cur3->next;
+	    }
+#ifdef POST_DEBUG
+	    fprintf(stderr,"Header and Body was parsed from Reference \n");
+#endif
+#ifdef DEBUG
+	    dumpMap(tmpmaps->content);
+	    fprintf(stderr, "= element 2 node \"%s\" = (%s)\n", 
+		    cur2->name,cur2->content);
+#endif
+	  }
+	  else if(xmlStrcasecmp(cur2->name,BAD_CAST "Data")==0){
+#ifdef DEBUG
+	    fprintf(stderr,"DATA\n");
+#endif
+	    xmlNodePtr cur4=cur2->children;
+	    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]=strdup("dataType");
+		list[1]=strdup("uom");
+		for(int l=0;l<2;l++){
+#ifdef DEBUG
+		  fprintf(stderr,"*** LiteralData %s ***",list[l]);
+#endif
+		  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);
+#ifdef DEBUG
+		    fprintf(stderr,"%s\n",val);
+#endif
+		  }
+		  xmlFree(val);
+		  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(int l=0;l<3;l++){
+#ifdef DEBUG
+		  fprintf(stderr,"*** ComplexData %s ***\n",coms[l]);
+#endif
+		  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);
+#ifdef DEBUG
+		    fprintf(stderr,"%s\n",val);
+#endif
+		  }
+		  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(strcasecmp(test->value,"base64")!=0){
+		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=cur5->next;
+		  xmlDocSetRootElement(doc1,cur5);
+		  xmlDocDumpFormatMemoryEnc(doc1, &mv, &buffersize, "utf-8", 1);
+		  char size[1024];
+		  sprintf(size,"%d",buffersize);
+		  addToMap(tmpmaps->content,"size",size);
+		}
+		addToMap(tmpmaps->content,"value",(char*)mv);
+		xmlFree(mv);
+	      }else{
+		xmlChar* tmp=xmlNodeListGetRawString(doc,cur4->xmlChildrenNode,0);
+		addToMap(tmpmaps->content,"value",(char*)tmp);
+		map* tmpv=getMap(tmpmaps->content,"value");
+		char *res=NULL;
+		char *curs=tmpv->value;
+		for(int i=0;i<=strlen(tmpv->value)/64;i++) {
+		  if(res==NULL)
+		    res=(char*)malloc(67*sizeof(char));
+		  else
+		    res=(char*)realloc(res,(((i+1)*65)+i)*sizeof(char));
+		  int csize=i*65;
+		  strncpy(res + csize,curs,64);
+		  if(i==xmlStrlen(tmp)/64)
+		    strcat(res,"\n\0");
+		  else{
+		    strncpy(res + (((i+1)*64)+i),"\n\0",2);
+		    curs+=64;
+		  }
+		}
+		free(tmpv->value);
+		tmpv->value=strdup(res);
+		free(res);
+		xmlFree(tmp);
+	      }
+	      cur4=cur4->next;
+	    }
+	  }
+#ifdef DEBUG
+	  fprintf(stderr,"cur2 next \n");
+	  fflush(stderr);
+#endif
+	  cur2=cur2->next;
+	}
+#ifdef DEBUG
+	fprintf(stderr,"ADD MAPS TO REQUEST MAPS !\n");
+	fflush(stderr);
+#endif
+
+	{
+	  maps* testPresence=getMaps(request_input_real_format,tmpmaps->name);
+	  if(testPresence!=NULL){
+	    elements* elem=getElements(s1->inputs,tmpmaps->name);
+	    if(elem!=NULL){
+	      if(appendMapsToMaps(m,request_input_real_format,tmpmaps,elem)<0){
+		freeMaps(&m);
+		free(m);
+		free(REQUEST);
+		free(SERVICE_URL);
+		InternetCloseHandle(hInternet);
+		freeService(&s1);
+		free(s1);
+		return 0;
+	      }
+	    }
+	  }
+	  else
+	    addMapsToMaps(&request_input_real_format,tmpmaps);
+	}
+	
+#ifdef DEBUG
+	fprintf(stderr,"******TMPMAPS*****\n");
+	dumpMaps(tmpmaps);
+	fprintf(stderr,"******REQUESTMAPS*****\n");
+	dumpMaps(request_input_real_format);
+#endif
+	freeMaps(&tmpmaps);
+	free(tmpmaps);
+	tmpmaps=NULL;	      
+      }
+#ifdef DEBUG
+      dumpMaps(tmpmaps); 
+#endif
+    }
+#ifdef DEBUG
+    fprintf(stderr,"Search for response document node\n");
+#endif
+    xmlXPathFreeObject(tmpsptr);
+    
+    tmpsptr=extractFromDoc(doc,"/*/*/*[local-name()='ResponseDocument']");
+    bool asRaw=false;
+    tmps=tmpsptr->nodesetval;
+    if(tmps->nodeNr==0){
+      tmpsptr=extractFromDoc(doc,"/*/*/*[local-name()='RawDataOutput']");
+      tmps=tmpsptr->nodesetval;
+      asRaw=true;
+    }
+#ifdef DEBUG
+    fprintf(stderr,"*****%d*****\n",tmps->nodeNr);
+#endif
+    for(int k=0;k<tmps->nodeNr;k++){
+      if(asRaw==true)
+	addToMap(request_inputs,"RawDataOutput","");
+      else
+	addToMap(request_inputs,"ResponseDocument","");
+      maps *tmpmaps=NULL;
+      xmlNodePtr cur=tmps->nodeTab[k];
+      if(cur->type == XML_ELEMENT_NODE) {
+	/**
+	 * A specific responseDocument node.
+	 */
+	if(tmpmaps==NULL){
+	  tmpmaps=(maps*)malloc(MAPS_SIZE);
+	  if(tmpmaps == NULL){
+	    return errorException(m, _("Unable to allocate memory."), "InternalError");
+	  }
+	  tmpmaps->name=strdup("unknownIdentifier");
+	  tmpmaps->content=NULL;
+	  tmpmaps->next=NULL;
+	}
+	/**
+	 * Get every attribute: storeExecuteResponse, lineage, status
+	 */
+	const char *ress[3]={"storeExecuteResponse","lineage","status"};
+	xmlChar *val;
+	for(int l=0;l<3;l++){
+#ifdef DEBUG
+	  fprintf(stderr,"*** %s ***\t",ress[l]);
+#endif
+	  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);
+	    addToMap(request_inputs,ress[l],(char*)val);
+	  }
+#ifdef DEBUG
+	  fprintf(stderr,"%s\n",val);
+#endif
+	  xmlFree(val);
+	}
+	xmlNodePtr cur1=cur->children;
+	while(cur1!=NULL && cur1->type != XML_ELEMENT_NODE)
+	  cur1=cur1->next;
+	while(cur1){
+	  /**
+	   * Indentifier
+	   */
+	  if(xmlStrncasecmp(cur1->name,BAD_CAST "Identifier",xmlStrlen(cur1->name))==0){
+	    xmlChar *val=
+	      xmlNodeListGetString(doc,cur1->xmlChildrenNode,1);
+	    if(tmpmaps==NULL){
+	      tmpmaps=(maps*)malloc(MAPS_SIZE);
+	      if(tmpmaps == NULL){
+		return errorException(m, _("Unable to allocate memory."), "InternalError");
+	      }
+	      tmpmaps->name=strdup((char*)val);
+	      tmpmaps->content=NULL;
+	      tmpmaps->next=NULL;
+	    }
+	    else{
+	      //free(tmpmaps->name);
+	      tmpmaps->name=strdup((char*)val);
+	    }
+	    xmlFree(val);
+	  }
+	  /**
+	   * Title, Asbtract
+	   */
+	  else if(xmlStrncasecmp(cur1->name,BAD_CAST "Title",xmlStrlen(cur1->name))==0 ||
+		  xmlStrncasecmp(cur1->name,BAD_CAST "Abstract",xmlStrlen(cur1->name))==0){
+	    xmlChar *val=
+	      xmlNodeListGetString(doc,cur1->xmlChildrenNode,1);
+	    if(tmpmaps==NULL){
+	      tmpmaps=(maps*)malloc(MAPS_SIZE);
+	      if(tmpmaps == NULL){
+		return errorException(m, _("Unable to allocate memory."), "InternalError");
+	      }
+	      tmpmaps->name=strdup("missingIndetifier");
+	      tmpmaps->content=createMap((char*)cur1->name,(char*)val);
+	      tmpmaps->next=NULL;
+	    }
+	    else{
+	      if(tmpmaps->content!=NULL)
+		addToMap(tmpmaps->content,(char*)cur1->name,(char*)val);
+	      else
+		tmpmaps->content=createMap((char*)cur1->name,(char*)val);
+	    }
+	    xmlFree(val);
+	  }
+	  else if(xmlStrncasecmp(cur1->name,BAD_CAST "Output",xmlStrlen(cur1->name))==0){
+	    /**
+	     * Get every attribute from a Output node
+	     * mimeType, encoding, schema, uom, asReference
+	     */
+	    const char *outs[5]={"mimeType","encoding","schema","uom","asReference"};
+	    for(int l=0;l<5;l++){
+#ifdef DEBUG
+	      fprintf(stderr,"*** %s ***\t",outs[l]);
+#endif
+	      val=xmlGetProp(cur1,BAD_CAST outs[l]);
+	      if(val!=NULL && strlen((char*)val)>0){
+		if(tmpmaps->content!=NULL)
+		  addToMap(tmpmaps->content,outs[l],(char*)val);
+		else
+		  tmpmaps->content=createMap(outs[l],(char*)val);
+	      }
+#ifdef DEBUG
+	      fprintf(stderr,"%s\n",val);
+#endif
+	      xmlFree(val);
+	    }
+	    xmlNodePtr cur2=cur1->children;
+	    while(cur2!=NULL && cur2->type != XML_ELEMENT_NODE)
+	      cur2=cur2->next;
+	    while(cur2){
+	      /**
+	       * Indentifier
+	       */
+	      if(xmlStrncasecmp(cur2->name,BAD_CAST "Identifier",xmlStrlen(cur2->name))==0){
+		xmlChar *val=
+		  xmlNodeListGetString(doc,cur2->xmlChildrenNode,1);
+		if(tmpmaps==NULL){
+		  tmpmaps=(maps*)malloc(MAPS_SIZE);
+		  if(tmpmaps == NULL){
+		    return errorException(m, _("Unable to allocate memory."), "InternalError");
+		  }
+		  tmpmaps->name=strdup((char*)val);
+		  tmpmaps->content=NULL;
+		  tmpmaps->next=NULL;
+		}
+		else{
+		  if(tmpmaps->name!=NULL)
+		    free(tmpmaps->name);
+		  tmpmaps->name=strdup((char*)val);;
+		}
+		xmlFree(val);
+	      }
+	      /**
+	       * Title, Asbtract
+	       */
+	      else 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);
+		if(tmpmaps==NULL){
+		  tmpmaps=(maps*)malloc(MAPS_SIZE);
+		  if(tmpmaps == NULL){
+		    return errorException(m, _("Unable to allocate memory."), "InternalError");
+		  }
+		  tmpmaps->name=strdup("missingIndetifier");
+		  tmpmaps->content=createMap((char*)cur2->name,(char*)val);
+		  tmpmaps->next=NULL;
+		}
+		else{
+		  if(tmpmaps->content!=NULL)
+		    addToMap(tmpmaps->content,
+			     (char*)cur2->name,(char*)val);
+		  else
+		    tmpmaps->content=
+		      createMap((char*)cur2->name,(char*)val);
+		}
+		xmlFree(val);
+	      }
+	      if(request_output_real_format==NULL)
+		request_output_real_format=dupMaps(&tmpmaps);
+	      else
+		addMapsToMaps(&request_output_real_format,tmpmaps);
+	      cur2=cur2->next;
+	      while(cur2!=NULL && cur2->type != XML_ELEMENT_NODE)
+		cur2=cur2->next;
+	    }
+	  }
+	  cur1=cur1->next;
+	  while(cur1!=NULL && cur1->type != XML_ELEMENT_NODE)
+	    cur1=cur1->next;
+	}
+      }
+      if(tmpmaps!=NULL){
+	freeMaps(&tmpmaps);
+	free(tmpmaps);
+	tmpmaps=NULL;
+      }
+    }
+    xmlXPathFreeObject(tmpsptr);
+    xmlCleanupParser();
+  }
+  
+
+  //  if(CHECK_INET_HANDLE(hInternet))
+  InternetCloseHandle(hInternet);
+
+#ifdef DEBUG
+  fprintf(stderr,"\n%d\n",__LINE__);
+  fflush(stderr);
+  dumpMaps(request_input_real_format);
+  dumpMaps(request_output_real_format);
+  dumpMap(request_inputs);
+  fprintf(stderr,"\n%d\n",__LINE__);
+  fflush(stderr);
+#endif
+
+  /**
+   * Ensure that each requested arguments are present in the request
+   * DataInputs and ResponseDocument / RawDataOutput
+   */
+  char *dfv=addDefaultValues(&request_input_real_format,s1->inputs,m,0);
+  char *dfv1=addDefaultValues(&request_output_real_format,s1->outputs,m,1);
+  if(strcmp(dfv1,"")!=0 || strcmp(dfv,"")!=0){
+    char tmps[1024];
+    if(strcmp(dfv,"")!=0){
+      snprintf(tmps,1024,_("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."),dfv);
+    }
+    else if(strcmp(dfv1,"")!=0){
+      snprintf(tmps,1024,_("The <%s> argument was specified as Output identifier but not defined in the ZOO Configuration File. Please, correct your query or the ZOO Configuration File."),dfv1);
+    }
+    map* tmpe=createMap("text",tmps);
+    addToMap(tmpe,"code","MissingParameterValue");
+    printExceptionReportResponse(m,tmpe);
+    freeService(&s1);
+    free(s1);
+    freeMap(&tmpe);
+    free(tmpe);
+    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;
+  }
+  maps* tmpReqI=request_input_real_format;
+  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;
+	mode_t mode;
+	char storageNameOnServer[2048];
+	char fileNameOnServer[64];
+	char contentType[1024];
+	char buffer[1024];
+	char *tmpStr=NULL;
+	int size;
+	int got,t;
+	map *path=getMapFromMaps(m,"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;
+	  }
+	  strcpy(fileNameOnServer,name+t+1);
+	  
+	  sprintf(storageNameOnServer,"%s/%s",path->value,fileNameOnServer);
+#ifdef DEBUG
+	  fprintf(stderr,"Name on server %s\n",storageNameOnServer);
+	  fprintf(stderr,"fileNameOnServer: %s\n",fileNameOnServer);
+#endif
+	  mode=S_IRWXU|S_IRGRP|S_IROTH;
+	  targetFile = open (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);
+	  close(targetFile);
+#ifdef DEBUG
+	  fprintf(stderr,"File \"%s\" has been uploaded",fileNameOnServer);
+#endif
+	}
+      }
+    }
+    tmpReqI=tmpReqI->next;
+  }
+
+  ensureDecodedBase64(&request_input_real_format);
+
+#ifdef DEBUG
+  fprintf(stderr,"REQUEST_INPUTS\n");
+  dumpMaps(request_input_real_format);
+  fprintf(stderr,"REQUEST_OUTPUTS\n");
+  dumpMaps(request_output_real_format);
+#endif
+
+  maps* curs=getMaps(m,"env");
+  if(curs!=NULL){
+    map* mapcs=curs->content;
+    while(mapcs!=NULLMAP){
+#ifndef WIN32
+      setenv(mapcs->name,mapcs->value,1);
+#else
+#ifdef DEBUG
+      fprintf(stderr,"[ZOO: setenv (%s=%s)]\n",mapcs->name,mapcs->value);
+#endif
+      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
+      fflush(stderr);
+      fprintf(stderr,"setting variable... %s\n",(
+#endif
+	      SetEnvironmentVariable(mapcs->name,mapcs->value)
+#ifdef DEBUG
+	      ==0)? "OK" : "FAILED");
+#else
+      ;
+#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
+
+  /**
+   * Need to check if we need to fork to load a status enabled 
+   */
+  r_inputs=NULL;
+  map* store=getMap(request_inputs,"storeExecuteResponse");
+  map* status=getMap(request_inputs,"status");
+  /**
+   * 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, _("Status cannot be set to true with storeExecuteResponse to false. Please, modify your request parameters."), "InvalidParameterValue");
+    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");
+  int eres=SERVICE_STARTED;
+  int cpid=getpid();
+
+  maps *_tmpMaps=(maps*)malloc(MAPS_SIZE);
+  _tmpMaps->name=strdup("lenv");
+  char tmpBuff[100];
+  sprintf(tmpBuff,"%i",cpid);
+  _tmpMaps->content=createMap("sid",tmpBuff);
+  _tmpMaps->next=NULL;
+  addToMap(_tmpMaps->content,"status","0");
+  addToMap(_tmpMaps->content,"cwd",ntmp);
+  map* ltmp=getMap(request_inputs,"soap");
+  if(ltmp!=NULL)
+    addToMap(_tmpMaps->content,"soap",ltmp->value);
+  else
+    addToMap(_tmpMaps->content,"soap","false");
+  if(cgiCookie!=NULL && strlen(cgiCookie)>0){
+    int hasValidCookie=-1;
+    char *tcook=strdup(cgiCookie);
+    if(strstr(cgiCookie,";")!=NULL){
+      char *token,*saveptr;
+      token=strtok_r(cgiCookie,";",&saveptr);
+      while(token!=NULL){
+	if(strcasestr(token,"ID=")!=NULL){
+	  if(tcook!=NULL)
+	    free(tcook);
+	  tcook=strdup(token);
+	  hasValidCookie=1;
+	}
+	token=strtok_r(NULL,";",&saveptr);
+      }
+    }else{
+      if(strstr(cgiCookie,"=")!=NULL && strcasestr(cgiCookie,"ID=")!=NULL){
+	tcook=strdup(cgiCookie);
+	hasValidCookie=1;
+      }
+    }
+    if(hasValidCookie>0){
+      addToMap(_tmpMaps->content,"sessid",strstr(tcook,"=")+1);
+      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,strstr(tmp1,"=")+1);
+      else
+	sprintf(session_file_path,"%s/sess_%s.cfg",tmpPath->value,strstr(cgiCookie,"=")+1);
+      free(tcook);
+      maps *tmpSess=(maps*)malloc(MAPS_SIZE);
+      struct stat file_status;
+      int istat = stat(session_file_path, &file_status);
+      if(istat==0 && file_status.st_size>0){
+	conf_read(session_file_path,tmpSess);
+	addMapsToMaps(&m,tmpSess);
+	freeMaps(&tmpSess);
+      }else{
+	errorException(m, _("Unable to read your session file."), "InternalError");
+	free(tmpSess);
+	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;
+      }
+      free(tmpSess);
+    }
+  }
+  addMapsToMaps(&m,_tmpMaps);
+  freeMaps(&_tmpMaps);
+  free(_tmpMaps);
+
+#ifdef DEBUG
+  dumpMap(request_inputs);
+#endif
+#ifdef WIN32
+  char *cgiSidL=NULL;
+  if(getenv("CGISID")!=NULL)
+    addToMap(request_inputs,"cgiSid",getenv("CGISID"));
+  map* test1=getMap(request_inputs,"cgiSid");
+  if(test1!=NULL){
+    cgiSid=test1->value;
+    addToMap(request_inputs,"storeExecuteResponse","true");
+    addToMap(request_inputs,"status","true");
+    setMapInMaps(m,"lenv","sid",test1->value);
+    status=getMap(request_inputs,"status");
+    printf("cgiSid %s\n",cgiSid);
+  }
+#endif
+  int hrstd=-1;
+  char *fbkp,*fbkp1;
+  FILE *f0,*f1;
+  if(status!=NULL)
+    if(strcasecmp(status->value,"false")==0)
+      status=NULLMAP;
+  if(status==NULLMAP){
+    loadServiceAndRun(&m,s1,request_inputs,&request_input_real_format,&request_output_real_format,&eres);
+  }
+  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);
+      printf("cgiSid %s\n",cgiSid);
+    }
+    //printf("pid cpid %d %d\n",pid,cpid);
+    //fflush(stderr);
+#endif
+    if (pid > 0) {
+      /**
+       * dady :
+       * set status to SERVICE_ACCEPTED
+       */
+#ifdef DEBUG
+      fprintf(stderr,"father pid continue (origin %d) %d ...\n",cpid,getpid());
+#endif
+      eres=SERVICE_ACCEPTED;
+    }else if (pid == 0) {
+      /**
+       * son : have to close the stdout, stdin and stderr to let the parent
+       * process answer to http client.
+       */
+      r_inputs=getMapFromMaps(m,"main","tmpPath");
+      map* r_inputs1=getMap(s1->content,"ServiceProvider");
+      fbkp=(char*)malloc((strlen(r_inputs->value)+strlen(r_inputs1->value)+1024)*sizeof(char));
+      sprintf(fbkp,"%s/%s_%d.xml",r_inputs->value,r_inputs1->value,cpid);
+      char* flog=(char*)malloc((strlen(r_inputs->value)+strlen(r_inputs1->value)+1024)*sizeof(char));
+      sprintf(flog,"%s/%s_%d_error.log",r_inputs->value,r_inputs1->value,cpid);
+#ifdef DEBUG
+      fprintf(stderr,"RUN IN BACKGROUND MODE \n");
+      fprintf(stderr,"son pid continue (origin %d) %d ...\n",cpid,getpid());
+      fprintf(stderr,"\nFILE TO STORE DATA %s\n",r_inputs->value);
+#endif
+      freopen(flog,"w+",stderr);
+      f0=freopen(fbkp , "w+", stdout);
+      fclose(stdin);
+      free(flog);
+      /**
+       * set status to SERVICE_STARTED and flush stdout to ensure full 
+       * content was outputed (the file used to store the ResponseDocument).
+       * The rewind stdout to restart writing from the bgining 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);
+#ifndef WIN32
+      fflush(stdout);
+      rewind(stdout);
+#else
+#endif
+      fbkp1=(char*)malloc((strlen(r_inputs->value)+strlen(r_inputs1->value)+1024)*sizeof(char));
+      sprintf(fbkp1,"%s/%s_final_%d.xml",r_inputs->value,r_inputs1->value,cpid);
+      f1=freopen(fbkp1 , "w+", stdout);
+      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");
+    }
+  }
+
+#ifdef DEBUG
+  dumpMaps(request_output_real_format);
+#endif
+  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
+  (void) signal(SIGSEGV,donothing);
+  (void) signal(SIGTERM,donothing);
+  (void) signal(SIGINT,donothing);
+  (void) signal(SIGILL,donothing);
+  (void) signal(SIGFPE,donothing);
+  (void) signal(SIGABRT,donothing);
+#endif
+
+  if(((int)getpid())!=cpid){
+    fclose(stdout);
+    fclose(stderr);
+    unhandleStatus(m);
+    /**
+     * Dump back the final file fbkp1 to fbkp
+     */
+    fclose(f0);
+    fclose(f1);
+    FILE* f2=fopen(fbkp1,"rb");
+    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);
+    fwrite(tmps1,1,flen,f3);
+    fclose(f2);
+    fclose(f3);
+    unlink(fbkp1);
+    free(fbkp1);
+  }
+
+  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
+
+  return 0;
+}
+
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/Makefile	(revision 417)
@@ -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
+
+clean:
+	rm -f cgi-env/test_service.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/cgi-env/Multiply.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/cgi-env/Multiply.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/cgi-env/Multiply.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/arithmetics/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/makefile.vc	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/arithmetics/test_service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/test_service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/arithmetics/test_service.c	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/cgal/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/cgal/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/cgal/Makefile	(revision 417)
@@ -0,0 +1,10 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+CC=gcc
+
+cgi-env/cgal_service.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/cgal_service.zo ./service.c ${GDAL_LIBS} ${MACOS_LD_FLAGS} -lCGAL
+
+clean:
+	rm -f cgi-env/*.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/cgal/cgi-env/Voronoi.zcfg	(revision 417)
@@ -0,0 +1,59 @@
+[Voronoi]
+ Title = Voronoi Diagram. 
+ Abstract = Computes the edges of Voronoi diagram of 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 = 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.3.0-rc1/zoo-project/zoo-services/cgal/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/cgal/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/cgal/service.c	(revision 417)
@@ -0,0 +1,272 @@
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Triangulation_euclidean_traits_xy_3.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"
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
+
+typedef CGAL::Delaunay_triangulation_2<K>  Triangulation;
+typedef Triangulation::Edge_iterator  Edge_iterator;
+typedef Triangulation::Point          Point;
+
+typedef CGAL::Constrained_Delaunay_triangulation_2<K> CDT;
+typedef CDT::Point Point;
+typedef CDT::Vertex_handle Vertex_handle;
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
+typedef CGAL::Triangulation_euclidean_traits_xy_3<K>  Gt;
+typedef CGAL::Delaunay_triangulation_2<Gt> DelaunayTriangulation;
+
+typedef Triangulation::Vertex_circulator Vertex_circulator;
+
+typedef K::Point_3   Point1;
+
+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>
+
+  xmlNodeSet* extractFromDoc(xmlDocPtr,char*);
+  void printExceptionReportResponse(maps*,map*);
+
+  int Voronoi(maps*& conf,maps*& inputs,maps*& outputs){
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\nStarting\n");
+#endif
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    int bufferDistance;
+    xmlInitParser();
+    map* tmpm=NULL;
+    tmpm=getMapFromMaps(inputs,"InputPoints","value");
+    
+    xmlInitParser();
+    xmlDocPtr doc =
+      xmlParseMemory(tmpm->value,strlen(tmpm->value));
+    xmlNodePtr cur = xmlDocGetRootElement(doc);
+    /**
+     * Parse every Input in DataInputs node.
+     */
+    maps* tempMaps=NULL;
+    xmlXPathContextPtr xpathCtx;
+    xmlXPathObjectPtr xpathObj;
+    xpathCtx = xmlXPathNewContext(doc);
+    xpathObj = xmlXPathEvalExpression(BAD_CAST "/*/*[local-name()='featureMember']/*/*/*[local-name()='Point']/*[local-name()='coordinates']",xpathCtx);
+    xmlXPathFreeContext(xpathCtx); 
+    xmlNodeSet* nSet=xpathObj->nodesetval;
+
+    if(nSet==NULL){
+      setMapInMaps(conf,"lenv","message","Unable to continue !!!");
+      return SERVICE_FAILED;
+    }
+    char filepath[2048];
+    map* tmpMap=getMapFromMaps(conf,"main","tmpPath");
+    if(tmpMap!=NULL){
+      sprintf(filepath,"%s/varonoi_%d.tmp",tmpMap->value,getpid());
+    }
+    FILE *fo=fopen(filepath,"w");
+#ifdef DEBUG
+    fprintf(stderr,"File Creation (%s) OK\nPrinting %d Points.\n",filepath,nSet->nodeNr);
+#endif
+    for(int k=0;k<nSet->nodeNr;k++){
+      xmlNodePtr cur=nSet->nodeTab[k];
+      char *val=
+	(char*)xmlNodeListGetString(doc,cur->xmlChildrenNode,1);
+      char *tmp=strstr(val,",");
+      char tmp1[1024];
+      strncpy(tmp1,val,strlen(val)-strlen(tmp));
+      tmp1[strlen(val)-strlen(tmp)]=0;
+      char buff[1024];
+      sprintf(buff,"%s %s\n",tmp1,tmp+1);
+      fwrite(buff,1,strlen(buff)*sizeof(char),fo);
+    }
+    fclose(fo);
+#ifdef DEBUG
+    fprintf(stderr,"File Close (%s) OK\n",filepath);
+#endif
+
+    std::ifstream in(filepath);
+    std::istream_iterator<Point> begin(in);
+    std::istream_iterator<Point> end;
+    Triangulation T;
+    T.insert(begin, end);
+
+    OGRRegisterAll();
+    /* -------------------------------------------------------------------- */
+    /*      Try opening the output datasource as an existing, writable      */
+    /* -------------------------------------------------------------------- */
+    OGRDataSource       *poODS;
+    
+    OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
+    OGRSFDriver          *poDriver = NULL;
+    int                  iDriver;
+
+    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
+	fprintf(stderr,"D:%s\n",poR->GetDriver(iDriver)->GetName());
+#endif
+	if( EQUAL(poR->GetDriver(iDriver)->GetName(),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++ )
+	  {
+	    sprintf( emessage,  "%s  -> `%s'\n", emessage, poR->GetDriver(iDriver)->GetName() );
+	  }
+
+	setMapInMaps(conf,"lenv","message",emessage);
+	return SERVICE_FAILED;
+
+      }
+
+    if( !poDriver->TestCapability( ODrCCreateDataSource ) ){
+      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(strlen(tpath->value)+20);
+    char **papszDSCO=NULL;
+    sprintf(pszDestDataSource,"%s/result_%d.json",tpath->value,getpid());
+    poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+    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;
+    Edge_iterator eit =T.edges_begin();
+    for ( ; eit !=T.edges_end(); ++eit) {
+      CGAL::Object o = T.dual(eit);
+      if (const K::Segment_2 *tmp=CGAL::object_cast<K::Segment_2>(&o)) {
+	const K::Point_2 p1=tmp->source();
+	const K::Point_2 p2=tmp->target();
+#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 (CGAL::object_cast<K::Ray_2>(&o)) {++nr;}
+    }
+    OGR_DS_Destroy( poODS );
+    OGRCleanupAll();
+
+#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 tmp1[1024];
+
+    FILE * fichier=fopen(pszDestDataSource,"r"); 
+    struct stat file_status;
+    stat(pszDestDataSource, &file_status);
+    char *res1=(char *)malloc(file_status.st_size*sizeof(char));
+    if(fichier==NULL){
+      char tmp[1024];
+      sprintf(tmp,"Failed to open file %s for reading purpose.\n",
+	      pszDestDataSource);
+      setMapInMaps(conf,"lenv","message",tmp);
+      return SERVICE_FAILED;
+    }
+    fread(res1,1,(file_status.st_size)*sizeof(char),fichier);
+    res1[strlen(res1)]=0;
+    fclose(fichier);
+    unlink(pszDestDataSource);
+    
+    setMapInMaps(outputs,"Result","value",res1);
+    
+    if(strcmp(oDriver,"GML")==0)
+      setMapInMaps(outputs,"Result","mimeType","text/xml");
+    else
+      setMapInMaps(outputs,"Result","mimeType","text/plain");
+
+    setMapInMaps(outputs,"Result","encoding","UTF-8");
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\n===\n");
+#endif
+    xmlCleanupParser();
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/Makefile	(revision 417)
@@ -0,0 +1,10 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=-DZOO_SERVICE ${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}
+
+clean:
+	rm -f cgi-env/*.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/cgi-env/Gdal_Dem.zcfg	(revision 417)
@@ -0,0 +1,56 @@
+[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>
+ </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.3.0-rc1/zoo-project/zoo-services/gdal/dem/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/makefile.vc	(revision 417)
@@ -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
+
+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.3.0-rc1/zoo-project/zoo-services/gdal/dem/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/dem/service.c	(revision 417)
@@ -0,0 +1,2899 @@
+/******************************************************************************
+ * $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=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);
+    map* 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.3.0-rc1/zoo-project/zoo-services/gdal/grid/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/grid/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/grid/Makefile	(revision 417)
@@ -0,0 +1,10 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${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}
+
+clean:
+	rm -f cgi-env/*.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/grid/cgi-env/Gdal_Grid.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/grid/cgi-env/Gdal_Grid.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/grid/cgi-env/Gdal_Grid.zcfg	(revision 417)
@@ -0,0 +1,69 @@
+[Gdal_Grid]
+ Title = Convert raster data from one format to another. 
+ Abstract = Converts raster data between different formats.
+ 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.3.0-rc1/zoo-project/zoo-services/gdal/grid/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/grid/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/grid/service.c	(revision 417)
@@ -0,0 +1,1258 @@
+/* ****************************************************************************
+ * $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();
+        exit( 2 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      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.3.0-rc1/zoo-project/zoo-services/gdal/ndvi/cgi-env/ExtractNDVI.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/ndvi/cgi-env/ExtractNDVI.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/ndvi/cgi-env/ExtractNDVI.zcfg	(revision 417)
@@ -0,0 +1,58 @@
+[ExtractNDVI]
+ Title = Normalized Difference Vegetation Index. 
+ Abstract = Create raster file containing the Normalized Difference Vegetation Index. 
+ 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.3.0-rc1/zoo-project/zoo-services/gdal/ndvi/cgi-env/ndvi.py
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/ndvi/cgi-env/ndvi.py	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/ndvi/cgi-env/ndvi.py	(revision 417)
@@ -0,0 +1,103 @@
+#! /usr/bin/env python
+
+
+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 informations 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.3.0-rc1/zoo-project/zoo-services/gdal/profile/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/Makefile	(revision 417)
@@ -0,0 +1,10 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${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}
+
+clean:
+	rm -f cgi-env/*.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/cgi-env/GdalExtractProfile.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/cgi-env/GdalExtractProfile.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/cgi-env/GdalExtractProfile.zcfg	(revision 417)
@@ -0,0 +1,57 @@
+[GdalExtractProfile]
+ Title = Convert raster data from one format to another. 
+ Abstract = Converts raster data between different formats.
+ processVersion = 1
+ storeSupported = true
+ statusSupported = true
+ serviceType = C
+ serviceProvider = gdal_profile_service.zo
+ <MetaData>
+   title = My Demo
+ </MetaData>
+ <DataInputs>
+  [RasterFile]
+   Title = The name fo 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 Z 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.3.0-rc1/zoo-project/zoo-services/gdal/profile/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/makefile.vc	(revision 417)
@@ -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
+
+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\gdal_service.*
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/profile/service.c	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/gdal/translate/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/Makefile	(revision 417)
@@ -0,0 +1,10 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${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}
+
+clean:
+	rm -f cgi-env/*.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/cgi-env/Gdal_Translate.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/cgi-env/Gdal_Translate.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/cgi-env/Gdal_Translate.zcfg	(revision 417)
@@ -0,0 +1,61 @@
+[Gdal_Translate]
+ Title = Convert raster data from one format to another. 
+ Abstract = Converts raster data between different formats.
+ 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.3.0-rc1/zoo-project/zoo-services/gdal/translate/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/makefile.vc	(revision 417)
@@ -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
+
+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.3.0-rc1/zoo-project/zoo-services/gdal/translate/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/translate/service.c	(revision 417)
@@ -0,0 +1,911 @@
+/******************************************************************************
+ * $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,"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.3.0-rc1/zoo-project/zoo-services/gdal/warp/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/Makefile	(revision 417)
@@ -0,0 +1,10 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${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}
+
+clean:
+	rm -f cgi-env/warp_service.*
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/cgi-env/Gdal_Warp.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/cgi-env/Gdal_Warp.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/cgi-env/Gdal_Warp.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/gdal/warp/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/makefile.vc	(revision 417)
@@ -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
+
+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.3.0-rc1/zoo-project/zoo-services/gdal/warp/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/gdal/warp/service.c	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-fortran/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-fortran/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-fortran/Makefile	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-fortran/cgi-env/hellof.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-fortran/cgi-env/hellof.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-fortran/cgi-env/hellof.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-fortran/service.f
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-fortran/service.f	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-fortran/service.f	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-java/HelloJava.java
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-java/HelloJava.java	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-java/HelloJava.java	(revision 417)
@@ -0,0 +1,38 @@
+/**
+ * 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.*;
+
+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"));
+        String v=tmp.get("value").toString();
+        hm1.put("value","Hello "+v+" from JAVA World !!");
+        outputs.put("Result",hm1);
+        return 3;
+  }
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-java/cgi-env/HelloWorldJava.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-java/cgi-env/HelloWorldJava.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-java/cgi-env/HelloWorldJava.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hello.js
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hello.js	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hello.js	(revision 417)
@@ -0,0 +1,13 @@
+
+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.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hellojs.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hellojs.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hellojs.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hellojs1.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hellojs1.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-js/cgi-env/hellojs1.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-perl/Hello.pl
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-perl/Hello.pl	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-perl/Hello.pl	(revision 417)
@@ -0,0 +1,7 @@
+sub HelloPL {
+	my ($main_conf,$real_inputs,$real_outputs) = @_;
+	
+	$real_outputs->{"Result"}->{"value"}=$real_inputs->{"a"}->{"value"};
+	return 3;
+}
+
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-perl/cgi-env/HelloPL.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-perl/cgi-env/HelloPL.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-perl/cgi-env/HelloPL.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-php/cgi-env/HelloPHP.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-php/cgi-env/HelloPHP.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-php/cgi-env/HelloPHP.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-php/hello.php
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-php/hello.php	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-php/hello.php	(revision 417)
@@ -0,0 +1,9 @@
+<?
+
+function HelloPHP(&$main_conf,&$inputs,&$outputs){
+  $outputs=Array();
+  $outputs["Result"]["value"]="Hello ".$inputs[S][value]." from the PHP world !!";
+  return 3;
+}
+
+?>
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-py/cgi-env/HelloPy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-py/cgi-env/HelloPy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-py/cgi-env/HelloPy.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/hello-py/test_service.py
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-py/test_service.py	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/hello-py/test_service.py	(revision 417)
@@ -0,0 +1,5 @@
+import sys
+def HelloPy(conf,inputs,outputs):
+	outputs["Result"]["value"]="Hello "+inputs["a"]["value"]+" from Python World !"
+	return 3
+
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BoundaryPy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BoundaryPy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BoundaryPy.zcfg	(revision 417)
@@ -0,0 +1,56 @@
+[BoundaryPy]
+ Title = Compute 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BufferPy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BufferPy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/BufferPy.zcfg	(revision 417)
@@ -0,0 +1,68 @@
+[BufferPy]
+ Title = Create a buffer around a polygon. 
+ Abstract = Create 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/CentroidPy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/CentroidPy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/CentroidPy.zcfg	(revision 417)
@@ -0,0 +1,53 @@
+[CentroidPy]
+ Title = Get the centroid of a polygon. 
+ Abstract = Compute the geometry centroid.
+ Profile = urn:ogc:wps:1.0.0:centroid
+ processVersion = 2
+ storeSupported = true
+ statusSupported = true
+ serviceProvider = ogr_sp
+ serviceType = Python
+ <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://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
+   <MetaData>
+    title = Mon test  
+   </MetaData>   
+   <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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ConvexHullPy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ConvexHullPy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ConvexHullPy.zcfg	(revision 417)
@@ -0,0 +1,51 @@
+[ConvexHullPy]
+ Title = Compute 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/DifferencePy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/DifferencePy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/DifferencePy.zcfg	(revision 417)
@@ -0,0 +1,75 @@
+[DifferencePy]
+ Title = Compute 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/IntersectionPy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/IntersectionPy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/IntersectionPy.zcfg	(revision 417)
@@ -0,0 +1,75 @@
+[IntersectionPy]
+ 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_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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/SymDifferencePy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/SymDifferencePy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/SymDifferencePy.zcfg	(revision 417)
@@ -0,0 +1,83 @@
+[SymDifferencePy]
+ Title = Compute 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/UnionPy.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/UnionPy.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/UnionPy.zcfg	(revision 417)
@@ -0,0 +1,73 @@
+[UnionPy]
+ Title = Compute 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops-py/cgi-env/ogr_sp.py	(revision 417)
@@ -0,0 +1,299 @@
+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',''))
+    except:
+        geom=None
+    try:
+        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["mimeType"]=="application/json":
+        return createLayerFromJson(conf,obj["value"])
+    else:
+        return createGeometryFromWFS(conf,obj["value"])
+    
+def outputResult(conf,obj,geom):
+    driverName = "GML"
+    extension = [ ".xml" , ".xsd" ]
+    if obj["mimeType"]=="application/json":
+        driverName = "GeoJSON"
+        extension = [ ".js" ]
+    if obj.keys().count("schema")>0 and \
+            obj["schema"]=="http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd":
+        driverName = "KML"
+        extension = [ ".kml" ]
+    drv = osgeo.ogr.GetDriverByName( driverName )
+    # Create virtual file 
+    ds = drv.CreateDataSource( "/vsimem/store"+conf["lenv"]["sid"]+extension[0] )
+    lyr = ds.CreateLayer( "Result", None, osgeo.ogr.wkbUnknown )
+    i=0
+    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 )
+        lyr.CreateFeature(geom[i])
+        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 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/Makefile	(revision 417)
@@ -0,0 +1,9 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${ZOO_CFLAGS} ${JSCFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} `geos-config --cflags` -DLINUX_FREE_ISSUE #-DDEBUG
+
+cgi-env/ogr_service.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/ogr_service.zo ./service.c ../../../zoo-kernel/service_internal.o ${JS_LDFLAGS} ${JSLDFLAGS} ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} `geos-config --libs`
+
+clean:
+	rm -f cgi-env/ogr_service.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg	(revision 417)
@@ -0,0 +1,60 @@
+[Boundary]
+ Title = Compute 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_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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Buffer.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Buffer.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Buffer.zcfg	(revision 417)
@@ -0,0 +1,76 @@
+[Buffer]
+ Title = Create a buffer around a polygon. 
+ Abstract = Create 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_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 = text/xml
+     encoding = base64
+     schema = http://fooa/gml/3.1.0/polygon.xsd
+     extension = xml
+    </Supported>
+    <Supported>
+     mimeType = application/json
+     encoding = UTF-8
+     extension = js
+    </Supported>
+   </ComplexData>
+ </DataOutputs>  
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Centroid.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Centroid.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Centroid.zcfg	(revision 417)
@@ -0,0 +1,55 @@
+[Centroid]
+ Title = Get the centroid of a polygon. 
+ Abstract = Compute the geometry centroid.
+ 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/ConvexHull.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/ConvexHull.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/ConvexHull.zcfg	(revision 417)
@@ -0,0 +1,54 @@
+[ConvexHull]
+ Title = Compute 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_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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Difference.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Difference.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Difference.zcfg	(revision 417)
@@ -0,0 +1,75 @@
+[Difference]
+ Title = Compute 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_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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Distance.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Distance.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Distance.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/GetArea.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/GetArea.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/GetArea.zcfg	(revision 417)
@@ -0,0 +1,50 @@
+[GetArea]
+ Title = Compute geometry area.
+ Abstract = Computes the area for 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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersection.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersection.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Intersection.zcfg	(revision 417)
@@ -0,0 +1,75 @@
+[Intersection]
+ 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
+ <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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/SymDifference.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/SymDifference.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/SymDifference.zcfg	(revision 417)
@@ -0,0 +1,75 @@
+[SymDifference]
+ Title = Compute 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_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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Union.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Union.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/cgi-env/Union.zcfg	(revision 417)
@@ -0,0 +1,75 @@
+[Union]
+ Title = Compute 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_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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/fr_FR.utf8.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/fr_FR.utf8.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/fr_FR.utf8.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/ja_JP.utf8.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/ja_JP.utf8.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/ja_JP.utf8.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/messages.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/messages.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/locale/po/messages.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/makefile.vc	(revision 417)
@@ -0,0 +1,25 @@
+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
+
+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  $(FILES) ./service.obj $(LDFLAGS) $(GEOS_DIR)/src/geos_c_i.lib /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\ogr_service.*
+
+#	link /dll /out:cgi-env/ogr_service.zo ../../../zoo-kernel/service_internal.obj ./service.obj -L$(TOOLS)/lib/libssl32.dll.a $(GEODIR)/lib/libxml2.lib $(GEODIR)/lib/gdal_i.lib $(GEODIR)/lib/geos_c_i.lib $(TPATH)/lib/libeay32.dll.a $(TPATH)/lib/libcrypto.a $(TPATH)/lib/libssl32.dll.a $(LIBINTL_CPATH)/lib/libintl.lib 
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/base-vect-ops/service.c	(revision 417)
@@ -0,0 +1,622 @@
+/**
+ * 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"
+#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);
+  int errorException(maps *m, const char *message, const char *errorcode);
+
+  OGRGeometryH createGeometryFromGML(maps* conf,char* inputStr){
+    xmlInitParser();
+    xmlDocPtr doc = xmlParseMemory(inputStr,strlen(inputStr));
+    xmlChar *xmlbuff;
+    int buffersize;
+    xmlXPathContextPtr xpathCtx;
+    xmlXPathObjectPtr xpathObj;
+    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){
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+    double tolerance;
+    map* tmp0=getMapFromMaps(cursor,"Tolerance","value");
+    if(tmp0==NULL){
+      tolerance=atof("2.0");
+    }
+    else
+      tolerance=atof(tmp0->value);
+#ifdef DEBUG
+    fprintf(stderr,"Tolerance for Simplify %f",tolerance);
+#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;
+    }
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+    if(tmp1!=NULL){
+      if(strncmp(tmp1->value,"text/js",7)==0 ||
+	 strncmp(tmp1->value,"application/json",16)==0)
+        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+      else
+        geometry=createGeometryFromGML(conf,tmp->value);
+    }
+    else{
+      setMapInMaps(conf,"lenv","message",_ss("Unable to find any geometry for InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    if(geometry==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse the input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+#ifdef DEBUG
+    fprintf(stderr,"Create GEOSGeometry object");
+#endif
+    GEOSGeometry* ggeometry=((OGRGeometry *) geometry)->exportToGEOS();
+    GEOSGeometry* gres=GEOSTopologyPreserveSimplify(ggeometry,tolerance);
+    res=(OGRGeometryH)OGRGeometryFactory::createFromGEOS(gres);
+    tmp1=getMapFromMaps(outputs,"Result","mimeType");
+    if(tmp1!=NULL){
+      if(strncmp(tmp1->value,"text/js",7)==0 ||
+	 strncmp(tmp1->value,"application/json",16)==0){
+	char *tmpS=OGR_G_ExportToJson(res);
+	setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+	setMapInMaps(outputs,"Result","mimeType","text/plain");
+	setMapInMaps(outputs,"Result","encoding","UTF-8");
+	free(tmpS);
+#endif
+      }
+      else{
+	char *tmpS=OGR_G_ExportToGML(res);
+	setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+	setMapInMaps(outputs,"Result","mimeType","text/xml");
+	setMapInMaps(outputs,"Result","encoding","UTF-8");
+	setMapInMaps(outputs,"Result","schema","http://fooa/gml/3.1.0/polygon.xsd");
+	free(tmpS);
+#endif
+      }
+    }else{
+      char *tmpS=OGR_G_ExportToJson(res);
+      setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+      setMapInMaps(outputs,"Result","mimeType","text/plain");
+      setMapInMaps(outputs,"Result","encoding","UTF-8");
+      free(tmpS);
+#endif
+    }
+    outputs->next=NULL;
+    //GEOSFree(ggeometry);
+    //GEOSFree(gres);
+    OGR_G_DestroyGeometry(res);
+    OGR_G_DestroyGeometry(geometry);
+    return SERVICE_SUCCEEDED;
+  }
+
+
+  int applyOne(maps*& conf,maps*& inputs,maps*& outputs,OGRGeometryH (*myFunc)(OGRGeometryH),char* schema){
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print\n");
+#endif
+    maps* cursor=inputs;
+    OGRGeometryH geometry,res;
+#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;
+    }
+#ifdef DEBUG
+    fprintf(stderr,"Service internal print \n");
+    dumpMaps(inputs);
+    fprintf(stderr,"/Service internal print \n");
+#endif
+    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+#ifdef DEBUG
+    fprintf(stderr,"Service internal print \n");
+    dumpMap(tmp1);
+    fprintf(stderr,"/Service internal print \n");
+#endif
+    if(tmp1!=NULL){
+      if(strncmp(tmp1->value,"text/js",7)==0 ||
+	 strncmp(tmp1->value,"application/json",7)==0)
+        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+      else
+        geometry=createGeometryFromGML(conf,tmp->value);
+    }
+    else
+      geometry=createGeometryFromGML(conf,tmp->value);
+    if(geometry==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse the input geometry from InputPolygon"));
+      return SERVICE_FAILED;
+    }
+    res=(*myFunc)(geometry);
+#ifdef DEBUG
+    fprintf(stderr,"Service internal print \n");
+    dumpMaps(outputs);
+    fprintf(stderr,"/Service internal print \n");
+#endif
+    map *tmp_2=getMapFromMaps(outputs,"Result","mimeType");
+#ifdef DEBUG
+    fprintf(stderr,"Service internal print \n");
+    dumpMap(tmp_2);
+    fprintf(stderr,"/Service internal print \n");
+#endif
+    if(tmp_2!=NULL){
+      if(strncmp(tmp_2->value,"text/js",7)==0 ||
+	 strncmp(tmp_2->value,"application/json",16)==0){
+	char *tmpS=OGR_G_ExportToJson(res);
+	setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+	setMapInMaps(outputs,"Result","mimeType","text/plain");
+	setMapInMaps(outputs,"Result","encoding","UTF-8");
+	free(tmpS);
+#endif
+      }
+      else{
+	char *tmpS=OGR_G_ExportToGML(res);
+	setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+	setMapInMaps(outputs,"Result","mimeType","text/xml");
+	setMapInMaps(outputs,"Result","encoding","UTF-8");
+	setMapInMaps(outputs,"Result","schema",schema);
+	free(tmpS);
+#endif
+      }
+    }else{
+      char *tmpS=OGR_G_ExportToJson(res);
+      setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+      setMapInMaps(outputs,"Result","mimeType","text/plain");
+      setMapInMaps(outputs,"Result","encoding","UTF-8");
+      free(tmpS);
+#endif
+    }
+    //outputs->next=NULL;
+#ifdef DEBUG
+    dumpMaps(outputs);
+    fprintf(stderr,"\nService internal print\n===\n");
+#endif
+    OGR_G_DestroyGeometry(res);
+    OGR_G_DestroyGeometry(geometry);
+    //CPLFree(res);
+    //CPLFree(geometry);
+#ifdef DEBUG
+    fprintf(stderr,"Service internal print \n");
+    dumpMaps(outputs);
+    fprintf(stderr,"/Service internal print \n");
+#endif
+    return SERVICE_SUCCEEDED;
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+int Buffer(maps*& conf,maps*& inputs,maps*& outputs){
+   OGRGeometryH geometry,res;
+   map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
+   if(tmp==NULL){
+     setMapInMaps(conf,"lenv","message",_ss("Unable to fetch input geometry"));
+     return SERVICE_FAILED;
+   }else
+     if(strlen(tmp->value)<=0){
+       setMapInMaps(conf,"lenv","message",_ss("Unable to fetch input geometry"));
+       return SERVICE_FAILED;
+     }
+   map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
+   if(strncmp(tmp1->value,"application/json",16)==0)
+     geometry=OGR_G_CreateGeometryFromJson(tmp->value);
+   else
+     geometry=createGeometryFromGML(conf,tmp->value);
+   if(geometry==NULL){
+     setMapInMaps(conf,"lenv","message",_ss("Unable to parse input geometry"));
+     return SERVICE_FAILED;
+   }
+   double bufferDistance;
+   tmp=getMapFromMaps(inputs,"BufferDistance","value");
+   if(tmp==NULL){
+     bufferDistance=atof("10.0");
+   }
+   else
+     bufferDistance=atof(tmp->value);
+   res=OGR_G_Buffer(geometry,bufferDistance,30);
+   dumpMap(tmp);
+   tmp1=getMapFromMaps(outputs,"Result","mimeType");
+   dumpMap(tmp);
+   if(strncmp(tmp1->value,"application/json",16)==0){
+     char *tmpS=OGR_G_ExportToJson(res);
+     setMapInMaps(outputs,"Result","value",tmpS);
+     dumpMap(tmp);
+#ifndef WIN32
+     setMapInMaps(outputs,"Result","mimeType","text/plain");
+     setMapInMaps(outputs,"Result","encoding","UTF-8");
+     free(tmpS);
+#endif
+   }
+   else{
+     char *tmpS=OGR_G_ExportToGML(res);
+     setMapInMaps(outputs,"Result","value",tmpS);
+     dumpMap(tmp);
+#ifndef WIN32
+     free(tmpS);
+     setMapInMaps(outputs,"Result","mimeType","text/xml");
+     setMapInMaps(outputs,"Result","encoding","UTF-8");
+     setMapInMaps(outputs,"Result","schema","http://fooa/gml/3.1.0/polygon.xsd");
+#endif
+   }
+   //outputs->next=NULL;
+   OGR_G_DestroyGeometry(geometry);
+   OGR_G_DestroyGeometry(res);
+   return SERVICE_SUCCEEDED;
+}
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Boundary(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyOne(conf,inputs,outputs,&OGR_G_GetBoundary,"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,&OGR_G_ConvexHull,"http://fooa/gml/3.1.0/polygon.xsd");
+  }
+
+
+  OGRGeometryH MY_OGR_G_Centroid(OGRGeometryH hTarget){
+    OGRGeometryH res;
+    res=OGR_G_CreateGeometryFromJson("{\"type\": \"Point\", \"coordinates\": [0,0] }");
+    OGRwkbGeometryType gtype=OGR_G_GetGeometryType(hTarget);
+    if(gtype!=wkbPolygon){
+      hTarget=OGR_G_ConvexHull(hTarget);
+    }
+    int c=OGR_G_Centroid(hTarget,res);
+    return res;
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Centroid(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyOne(conf,inputs,outputs,&MY_OGR_G_Centroid,"http://fooa/gml/3.1.0/point.xsd");
+  }
+
+  int applyTwo(maps*& conf,maps*& inputs,maps*& outputs,OGRGeometryH (*myFunc)(OGRGeometryH,OGRGeometryH)){
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print1\n");
+    fflush(stderr);
+    fprintf(stderr,"\nService internal print1\n");
+    dumpMaps(inputs);
+    fprintf(stderr,"\nService internal print1\n");
+#endif
+
+    maps* cursor=inputs;
+    OGRGeometryH geometry1,geometry2;
+    OGRGeometryH res;
+    {
+      map* tmp=getMapFromMaps(inputs,"InputEntity1","value");
+      map* tmp1=getMapFromMaps(inputs,"InputEntity1","mimeType");
+      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."));
+#ifdef DEBUG
+      fprintf(stderr,"SERVICE FAILED !\n");
+#endif
+      return SERVICE_FAILED;
+    }
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print1 InputEntity1\n");
+#endif
+    {
+      map* tmp=getMapFromMaps(inputs,"InputEntity2","value");
+      map* tmp1=getMapFromMaps(inputs,"InputEntity2","mimeType");
+#ifdef DEBUG
+      fprintf(stderr,"MY MAP \n[%s] - %i\n",tmp1->value,strncmp(tmp1->value,"application/json",16));
+      //dumpMap(tmp);
+      fprintf(stderr,"MY MAP\n");
+      fprintf(stderr,"\nService internal print1 InputEntity2\n");
+#endif
+      if(tmp1!=NULL){
+        if(strncmp(tmp1->value,"application/json",16)==0){
+#ifdef DEBUG
+	  fprintf(stderr,"\nService internal print1 InputEntity2 as JSON\n");
+#endif
+      	  geometry2=OGR_G_CreateGeometryFromJson(tmp->value);
+	}
+	else{
+#ifdef DEBUG
+	  fprintf(stderr,"\nService internal print1 InputEntity2 as GML\n");
+#endif
+	  geometry2=createGeometryFromGML(conf,tmp->value);
+	}
+      }
+      else
+      	geometry2=createGeometryFromGML(conf,tmp->value);
+#ifdef DEBUG
+      fprintf(stderr,"\nService internal print1 InputEntity2 PreFinal\n");
+#endif
+    }
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print1 InputEntity2 Final\n");
+#endif
+    if(geometry2==NULL){
+      setMapInMaps(conf,"lenv","message",_ss("Unable to parse input geometry for InputEntity2."));
+#ifdef DEBUG
+      fprintf(stderr,"SERVICE FAILED !\n");
+#endif
+      return SERVICE_FAILED;
+    }
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print1\n");
+#endif
+    res=(*myFunc)(geometry1,geometry2);
+#ifdef DEBUG
+    fprintf(stderr,"\nService internal print1\n");
+#endif    
+    /* nuova parte */
+    map* tmp2=getMapFromMaps(outputs,"Result","mimeType");
+    if(strncmp(tmp2->value,"application/json",16)==0){
+      char *tmpS=OGR_G_ExportToJson(res);
+      setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+      setMapInMaps(outputs,"Result","mimeType","text/plain");
+      setMapInMaps(outputs,"Result","encoding","UTF-8");
+      free(tmpS);
+#endif
+    }
+    else{
+      char *tmpS=OGR_G_ExportToGML(res);
+      setMapInMaps(outputs,"Result","value",tmpS);
+#ifndef WIN32
+      setMapInMaps(outputs,"Result","mimeType","text/xml");
+      setMapInMaps(outputs,"Result","encoding","UTF-8");
+      setMapInMaps(outputs,"Result","schema","http://fooa/gml/3.1.0/polygon.xsd");
+      free(tmpS);
+#endif
+    }
+    
+    /* vecchia da togliere */
+    /*
+    char *tmpS=OGR_G_ExportToJson(res);
+    setMapInMaps(outputs,"Result","value",tmpS);
+    setMapInMaps(outputs,"Result","mimeType","text/plain");
+    setMapInMaps(outputs,"Result","encoding","UTF-8");
+    free(tmpS);
+    */
+    OGR_G_DestroyGeometry(geometry1);
+    OGR_G_DestroyGeometry(geometry2);
+    OGR_G_DestroyGeometry(res);
+    return SERVICE_SUCCEEDED;
+  }
+  
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Difference(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGR_G_Difference);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int SymDifference(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGR_G_SymmetricDifference);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Intersection(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGR_G_Intersection);
+  }
+
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int Union(maps*& conf,maps*& inputs,maps*& outputs){
+    return applyTwo(conf,inputs,outputs,&OGR_G_Union);
+  }
+
+#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_GetArea(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.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/Makefile	(revision 417)
@@ -0,0 +1,26 @@
+GDAL_SRC=./gdal_src/
+
+include $(GDAL_SRC)GDALmake.opt
+
+CPPFLAGS        :=      $(GDAL_INCLUDE) -I$(GDAL_ROOT)/frmts $(CPPFLAGS)
+DEP_LIBS        =       $(EXE_DEP_LIBS) $(XTRAOBJ)
+BIN_LIST = cgi-env/ogr2ogr_service.zo
+
+default:        $(BIN_LIST)
+
+all: default
+
+lib-depend:
+	(cd $(GDAL_SRC)/gcore ; $(MAKE) )
+	(cd $(GDAL_SRC)/port ; $(MAKE) )
+
+CFLAGS=-DZOO_SERVICE -I../../../zoo-kernel/
+
+#cgi-env/ogr2ogr_service.zo: service.c
+#	g++  -DZOO_SERVICE ${CFLAGS} -shared -fpic -o cgi-env/ogr2ogr_service.zo ./service.c -lgdal
+
+cgi-env/ogr2ogr_service.zo: service.c $(DEP_LIBS)
+	g++ $(CFLAGS) $(CPPFLAGS) -shared -fpic $< `gdal-config --libs` -o $@
+
+clean:
+	rm -f cgi-env/*zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/cgi-env/Ogr2Ogr.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/cgi-env/Ogr2Ogr.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/cgi-env/Ogr2Ogr.zcfg	(revision 417)
@@ -0,0 +1,62 @@
+[Ogr2Ogr]
+ Title = Convert vector data from one format to another. 
+ Abstract = Converts vector data between different formats.
+ 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.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/makefile.vc	(revision 417)
@@ -0,0 +1,11 @@
+GEODIR=c:/OSGeo4W/
+TOOLS=c:/Users/djay/GeoLabs/tools/
+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 ../../../zoo-kernel/service_internal.obj ./service.obj -L$(TOOLS)/lib/libssl32.dll.a $(GEODIR)/lib/libxml2.lib $(GEODIR)/lib/gdal_i.lib $(TOOLS)/lib/libeay32.dll.a $(TOOLS)/lib/libcrypto.a $(TOOLS)/lib/libssl32.dll.a 
+
+clean:
+	rm -f cgi-env/ogr_service.zso
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/ogr/ogr2ogr/service.c	(revision 417)
@@ -0,0 +1,1303 @@
+/******************************************************************************
+ * $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"
+#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( OGRDataSource *poSrcDS, 
+                           OGRLayer * poSrcLayer,
+                           OGRDataSource *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
+{
+    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=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,"segmentize","value");
+    if(tmpMap!=NULL){
+	  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.                                               */
+/* -------------------------------------------------------------------- */
+    OGRDataSource       *poDS;
+        
+    poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE );
+
+/* -------------------------------------------------------------------- */
+/*      Report failure                                                  */
+/* -------------------------------------------------------------------- */
+    if( poDS == NULL )
+    {
+        OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
+        
+        fprintf( stderr, "FAILURE:\n"
+                "Unable to open datasource `%s' with the following drivers.\n",
+                pszDataSource );
+
+        for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
+        {
+            fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+        }
+#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      */
+/* -------------------------------------------------------------------- */
+    OGRDataSource       *poODS;
+    
+    if( bUpdate )
+    {
+        poODS = OGRSFDriverRegistrar::Open( pszDestDataSource, TRUE );
+        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
+    {
+        OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
+        OGRSFDriver          *poDriver = NULL;
+        int                  iDriver;
+
+        for( iDriver = 0;
+             iDriver < poR->GetDriverCount() && poDriver == NULL;
+             iDriver++ )
+        {
+            if( EQUAL(poR->GetDriver(iDriver)->GetName(),pszFormat) )
+            {
+                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++ )
+            {
+                fprintf( stderr,  "  -> `%s'\n", poR->GetDriver(iDriver)->GetName() );
+            }
+#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( !poDriver->TestCapability( ODrCCreateDataSource ) )
+        {
+            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.                                  */
+/* -------------------------------------------------------------------- */
+        poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+        if( poODS == NULL )
+        {
+            fprintf( stderr,  "%s driver failed to create %s\n", 
+                    pszFormat, pszDestDataSource );
+#ifdef ZOO_SERVICE
+	    char tmp[1024];
+	    sprintf(tmp,"%s driver failed to create %s",pszFormat, pszDestDataSource);
+	    setMapInMaps(conf,"lenv","message",tmp);
+	    return SERVICE_FAILED;
+#else
+            exit( 1 );
+#endif
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      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, 
+                                        NULL );
+
+        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 );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      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
+    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
+    return SERVICE_SUCCEEDED;
+#else
+    return 0;
+#endif
+}
+
+/************************************************************************/
+/*                               Usage()                                */
+/************************************************************************/
+
+static void Usage()
+
+{
+    OGRSFDriverRegistrar        *poR = OGRSFDriverRegistrar::GetRegistrar();
+
+#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++ )
+    {
+        OGRSFDriver *poDriver = poR->GetDriver(iDriver);
+
+        if( poDriver->TestCapability( ODrCCreateDataSource ) )
+            printf( "     -f \"%s\"\n", poDriver->GetName() );
+    }
+
+#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( OGRDataSource *poSrcDS, 
+                           OGRLayer * poSrcLayer,
+                           OGRDataSource *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.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/Exporter.py
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/Exporter.py	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/Exporter.py	(revision 417)
@@ -0,0 +1,97 @@
+#
+# 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 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.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/OdtConverter.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/OdtConverter.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/OdtConverter.zcfg	(revision 417)
@@ -0,0 +1,43 @@
+[OdtConverter]
+ Title = Convert raster data from one format to another. 
+ Abstract = Converts raster data between different formats.
+ 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 to use as source for convertion.
+   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 for convertion.
+   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.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/Xml2Pdf.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/Xml2Pdf.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/Xml2Pdf.zcfg	(revision 417)
@@ -0,0 +1,39 @@
+[Xml2Pdf]
+ Title = Convert raster data from one format to another. 
+ Abstract = Converts raster data between different formats.
+ 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.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/oo_service.py
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/oo_service.py	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/openoffice/cgi-env/oo_service.py	(revision 417)
@@ -0,0 +1,120 @@
+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.3.0-rc1/zoo-project/zoo-services/qrencode/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/Makefile	(revision 417)
@@ -0,0 +1,10 @@
+ZRPATH=../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${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} ${MACOS_LD_FLAGS}
+
+clean:
+	rm -f cgi-env/*.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/cgi-env/QREncode.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/cgi-env/QREncode.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/cgi-env/QREncode.zcfg	(revision 417)
@@ -0,0 +1,63 @@
+[QREncode]
+ Title = Encode a string into its QR Code
+ Abstract = Multiply two values and stor 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 />
+   </LiteralData>
+  [bgcolor]
+   Title = the input string
+   Abstract = The string (RRGGBBAA) for for background color.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = string
+    <Default />
+   </LiteralData>
+  [size]
+   Title = the image size
+   Abstract = The generated image size.
+   minOccurs = 0
+   maxOccurs = 1
+   <LiteralData>
+    dataType = integer
+    <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.3.0-rc1/zoo-project/zoo-services/qrencode/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/makefile.vc	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/qrencode/qrenc-service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/qrenc-service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/qrencode/qrenc-service.c	(revision 417)
@@ -0,0 +1,1215 @@
+/*-*- 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 <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+#include <getopt.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
+
+#include "qrencode.h"
+
+#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.3.0-rc1/zoo-project/zoo-services/utils/status/Makefile
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/Makefile	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/Makefile	(revision 417)
@@ -0,0 +1,9 @@
+ZRPATH=../../..
+include ${ZRPATH}/zoo-kernel/ZOOMakefile.opts
+CFLAGS=${ZOO_CFLAGS} ${XML2CFLAGS} ${GDAL_CFLAGS} ${PYTHONCFLAGS} -DLINUX_FREE_ISSUE #-DDEBUG
+
+cgi-env/wps_status.zo: service.c
+	g++ ${CFLAGS} -shared -fpic -o cgi-env/wps_status.zo ./service.c ../../../zoo-kernel/service_internal.o ${JS_LDFLAGS} ${JSLDFLAGS} ${GDAL_LIBS} ${XML2LDFLAGS} ${MACOS_LD_FLAGS} ${ZOO_LDFLAGS} ${MACOS_LD_NET_FLAGS} `xslt-config --libs` -lfcgi
+
+clean:
+	rm -f cgi-env/wps_status.zo
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/GetStatus.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/GetStatus.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/GetStatus.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/demo.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/demo.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/demo.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/longProcess.zcfg
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/longProcess.zcfg	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/longProcess.zcfg	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/service.py
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/service.py	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/service.py	(revision 417)
@@ -0,0 +1,14 @@
+def demo(conf,inputs,outputs):
+    import zoo,time
+    i=0
+    while i < 100:
+        conf["lenv"]["status"]=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.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/updateStatus.xsl
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/updateStatus.xsl	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/cgi-env/updateStatus.xsl	(revision 417)
@@ -0,0 +1,22 @@
+<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:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+
+  <xsl:template match="/wps:ExecuteResponse/wps:Status/wps:ProcessStarted/@percentCompleted">
+    <xsl:attribute name="percentCompleted">
+      <xsl:value-of select="$value"/>
+    </xsl:attribute>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/locale/po/fr_FR.utf8.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/locale/po/fr_FR.utf8.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/locale/po/fr_FR.utf8.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/utils/status/locale/po/messages.po
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/locale/po/messages.po	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/locale/po/messages.po	(revision 417)
@@ -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.3.0-rc1/zoo-project/zoo-services/utils/status/makefile.vc
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/makefile.vc	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/makefile.vc	(revision 417)
@@ -0,0 +1,24 @@
+TROOT= $(ZOOK_DIR)
+!INCLUDE $(ZOOK_DIR)/nmake.opt
+
+FILES=$(ZOOK_DIR)/dirent.obj $(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
+
+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 /FORCE:MULTIPLE
+
+clean:
+	erase cgi-env\*_status.*
+	erase *.obj
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/service.c
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/service.c	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/service.c	(revision 417)
@@ -0,0 +1,151 @@
+/**
+ * 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"
+
+extern "C" {
+#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>
+
+  /**
+   * 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.
+   */
+#ifdef WIN32
+  __declspec(dllexport)
+#endif
+  int GetStatus(maps*& conf,maps*& inputs,maps*& outputs){
+    const char *params[2 + 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");
+    xmlInitParser();
+    struct dirent *dp;
+    DIR *dirp = opendir(tmpTmap->value);
+    char fileName[1024],xslFileName[1024];
+    int hasFile=-1;
+    if(dirp!=NULL){
+      char tmp[128];
+      sprintf(tmp,"_%s.xml",tmpMap->value);
+      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;
+	}
+      }
+    }else{
+      char tmp[1024];
+      snprintf(tmp,1024,_ss("GetStatus was unable to use the tmpPath value set in main.cfg file as directory %s."),tmpTmap->value);
+      setMapInMaps(conf,"lenv","message",tmp);
+      return SERVICE_FAILED;
+    }
+    if(hasFile<0){
+      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;
+    }
+    sprintf(xslFileName,"%s/updateStatus.xsl",tmpMmap->value);
+    xmlSubstituteEntitiesDefault(1);
+    xmlLoadExtDtdDefaultValue = 0;
+    xsltStylesheetPtr cur = NULL;
+    xmlDocPtr doc, res;
+    cur = xsltParseStylesheetFile(BAD_CAST xslFileName);
+    doc = xmlParseFile(fileName);
+    if(cur!=NULL && doc!=NULL){
+      params[0]="value";
+      params[1]=getStatus(atoi(tmpMap->value));
+      params[2]=NULL;
+      res = xsltApplyStylesheet(cur, doc, params);
+      xmlChar *xmlbuff;
+      int buffersize;
+      xmlDocDumpFormatMemory(res, &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 tmp[4];
+      sprintf(tmp,"%i",i);
+      map* tmpMap=NULL;
+      tmpMap=getMapFromMaps(conf,"lenv","sid");
+      if(tmpMap!=NULL)
+	fprintf(stderr,"Status %s %s\n",tmpMap->value,tmp);
+      setMapInMaps(conf,"lenv","status",tmp);
+      updateStatus(conf);
+#ifndef WIN32
+      sleep(1);
+#else
+      Sleep(1000);
+#endif
+      i+=5;
+    }
+    setMapInMaps(outputs,"Result","value","\"Running long process successfully\"");
+    return SERVICE_SUCCEEDED;
+  }
+
+}
Index: tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/test.sh
===================================================================
--- tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/test.sh	(revision 417)
+++ tags/rel-1.3.0-rc1/zoo-project/zoo-services/utils/status/test.sh	(revision 417)
@@ -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
