ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hi...@apache.org
Subject ant-ivy git commit: Experimental xooki to asciidoc convertor
Date Mon, 29 Dec 2014 22:20:09 GMT
Repository: ant-ivy
Updated Branches:
  refs/heads/xooki2asciidoc [created] 879ac405e


Experimental xooki to asciidoc convertor

Project: http://git-wip-us.apache.org/repos/asf/ant-ivy/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant-ivy/commit/879ac405
Tree: http://git-wip-us.apache.org/repos/asf/ant-ivy/tree/879ac405
Diff: http://git-wip-us.apache.org/repos/asf/ant-ivy/diff/879ac405

Branch: refs/heads/xooki2asciidoc
Commit: 879ac405ee80f91b574517355f029a406d123302
Parents: 0354231
Author: Nicolas Lalevée <nicolas.lalevee@hibnet.org>
Authored: Sat Dec 27 23:42:13 2014 +0100
Committer: Nicolas Lalevée <nicolas.lalevee@hibnet.org>
Committed: Mon Dec 29 18:37:46 2014 +0100

----------------------------------------------------------------------
 asciidoc-template/document.html.slim |   87 ++
 asciidoc-template/helpers.rb         |  168 +++
 build-doc.xml                        |   58 ++
 doc/xooki2asciidoc/antlib.xml        |   82 ++
 doc/xooki2asciidoc/xooki2asciidoc.js | 1569 +++++++++++++++++++++++++++++
 5 files changed, 1964 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/879ac405/asciidoc-template/document.html.slim
----------------------------------------------------------------------
diff --git a/asciidoc-template/document.html.slim b/asciidoc-template/document.html.slim
new file mode 100644
index 0000000..81e99a8
--- /dev/null
+++ b/asciidoc-template/document.html.slim
@@ -0,0 +1,87 @@
+doctype transitional
+/!
+/!   Licensed to the Apache Software Foundation (ASF) under one
+/!   or more contributor license agreements.  See the NOTICE file
+/!   distributed with this work for additional information
+/!   regarding copyright ownership.  The ASF licenses this file
+/!   to you under the Apache License, Version 2.0 (the
+/!   "License"); you may not use this file except in compliance
+/!   with the License.  You may obtain a copy of the License at
+/!
+/!     http://www.apache.org/licenses/LICENSE-2.0
+/!
+/!   Unless required by applicable law or agreed to in writing,
+/!   software distributed under the License is distributed on an
+/!   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+/!   KIND, either express or implied.  See the License for the
+/!   specific language governing permissions and limitations
+/!   under the License.
+- page = IvyDocHelpers.page(attr("basedir"), attr("docfile"))
+html lang=(attr :lang, 'en' unless attr? :nolang)
+  head
+    meta http-equiv="Content-Type" content="text/html; charset=utf-8"
+    meta name='generator' content="Asciidoctor #{attr 'asciidoctor-version'}"
+    title=((doctitle :sanitize => true) || (attr 'untitled-label'))
+    link rel="stylesheet" type="text/css" href="#{page.relativeRoot}style/style.css"
+    script src="#{page.relativeRoot}js/jquery.pack.js" type="text/javascript"
+    script src="#{page.relativeRoot}js/jquery.treeview.js" type="text/javascript"
+    javascript:
+      $(document).ready(function(){$("#treemenu").Treeview({speed: "fast",store: true});});
+  body
+    div id="body"
+      table id="header" summary="Navigation elements." border="0" cellpadding="0" cellspacing="0" width="100%"
+        tr
+          td id="home" width="30%"
+            a href="http://ant.apache.org/" title="Apache Ant"
+              img src="#{page.relativeRoot}images/ant-group-logo.gif" alt="Apache Ant" border="0"/
+          td class="product" width="70%" align="right" valign="middle"
+            img src="#{page.relativeRoot}images/logo.png" alt="ivy" border="0"/
+      table id="top-menu" summary="Navigation elements." border="0" cellpadding="0" cellspacing="0" width="100%"
+        tr
+          td
+            div id="navcontainer"
+              a<> href="http://www.apache.org/" Apache&#153;
+              | &gt;
+              a<> href="http://ant.apache.org/" Apache Ant&#153;
+              | &gt;
+              a<> href="http://ant.apache.org/ivy/" Apache Ivy&#153;
+              | &gt;
+              = page.breadCrumb
+      table id="content" border="0" cellpadding="0" cellspacing="0" width="100%"
+        tr
+          td id="sidebar-left"
+            div class="block block-book" id="block-book-0"
+            h2 Apache Ivy&#153;
+            div class="content"
+              = page.menu()
+              center
+                iframe src="http://www.apache.org/ads/buttonbar.html" style="border-width:0;" frameborder="0" scrolling="no" width="135" height="265"
+          td valign="top"
+            div id="main"
+              h1 class="title" = page.title
+              #content=content
+      table id="footer-menu" summary="Navigation elements." border="0" cellpadding="0" cellspacing="0" width="100%"
+        tr
+          td align="center" valign="middle"
+            div class="primary-links"
+              | ::
+              a href="index.html" Home
+              | ::
+              a href="reference.html" Reference
+              | ::
+              a href="tutorial.html" Tutorials
+              | ::
+              a href="dev.html" Developer's doc
+              | ::
+      div id="footer-message" class="footer"
+        hr/
+        i
+          | Copyright &#169; 2014 The Apache Software Foundation, Licensed under the
+          a href="http://www.apache.org/licenses/LICENSE-2.0.txt" Apache License, Version 2.0
+          | .
+        br/
+        i
+          | Apache Ivy, Apache Ant, Ivy, Ant, Apache, the Apache Ivy logo, the Apache Ant logo and the Apache feather logo are trademarks of The Apache Software Foundation.
+        br/
+        i
+          | All other marks mentioned may be trademarks or registered trademarks of their respective owners.

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/879ac405/asciidoc-template/helpers.rb
----------------------------------------------------------------------
diff --git a/asciidoc-template/helpers.rb b/asciidoc-template/helpers.rb
new file mode 100644
index 0000000..b11768b
--- /dev/null
+++ b/asciidoc-template/helpers.rb
@@ -0,0 +1,168 @@
+# Add custom functions to this module that you want to use in your Slim
+# templates. Within the template you must namespace the function
+# (unless someone can show me how to include them in the evaluation context).
+# You can change the namespace to whatever you want.
+
+require 'json'
+
+module IvyDocHelpers
+
+    class Page
+        attr_accessor :id, :title, :url, :allChildIds, :children, :parent
+
+        def initialize()
+            @id = ""
+            @title = ""
+            @url = ""
+            @allChildIds = []
+            @children = []
+            @parent = nil
+        end
+
+        def link(printpage)
+            l = ''
+            if self.url
+                l += '<a href="' + printpage.relativeRoot + self.url + '"'
+                if self.id == printpage.id
+                    l += ' class="current"'
+                end
+                l += '>' + self.title + '</a>'
+            else
+                l += self.title
+            end
+            return l
+        end
+
+        def relativeRoot()
+            p = ''
+            (self.id.split("/").length-1).times do |e|
+                p += '../'
+            end
+            return p
+        end
+
+        def breadCrumb()
+            b = '<span class="breadCrumb">'
+            b += breadCrumbStep(self)
+            b += '</span>'
+            return b
+        end
+
+        def breadCrumbStep(page)
+            b = ' '
+            if page.parent && page.parent.parent
+                b += breadCrumbStep(page.parent)
+                b += ' &gt; '
+            end
+            b += page.link(page)
+            return b
+        end
+
+        def rootpage()
+            if self.parent
+                return self.parent.rootpage()
+            else
+                return self
+            end
+        end
+
+        def menu()
+            return innermenu(rootpage())
+        end
+
+        def innermenu(page)
+            m = '<ul id="treemenu" class="treeview">' + "\n"
+            page.children.each do |p|
+                m += '<li id="xooki-' + p.id + '"'
+                if p.children.length > 0
+                    m += ' class="submenu"'
+                end
+                m += '>'
+                m += p.link(self)
+                if p.children.length > 0
+                    m += '<ul class="'
+                    if p.allChildIds.include? self.id
+                        m += 'open'
+                    else
+                        m += 'closed'
+                    end
+                    m += '">'
+                    m += innermenu(p)
+                    m += '</ul>'
+                end
+                m += "</li>\n"
+            end
+            m += "</ul>\n"
+            return m
+        end
+
+    end
+
+    def self.page(basedir, docfile)
+        rootpage = loadPages(basedir)
+        pageId = docfile[basedir.length+1..docfile.rindex(/\./)-1]
+        p = findPage(rootpage, pageId)
+        if !p
+            p = Page.new
+        end
+        return p
+    end
+
+    def self.loadPages(basedir)
+        rootpage = Page.new
+        toc = JSON.parse(IO.read(basedir + "/toc.json"))
+        toc['children'].each do |child|
+            rootpage.children << loadPage(basedir, rootpage, child, "")
+        end
+        return rootpage
+    end
+
+    def self.loadPage(basedir, parent, node, path)
+        p = Page.new
+        p.title = node['title']
+        p.parent = parent
+        if node.has_key?("importRoot")
+            p.id = path + child['importRoot'] + '/' + node['importNode']
+            p.url = p.id + ".html"
+            toc = JSON.parse(IO.read(basedir + '/' + child['importRoot'] + "/toc.json"))
+            toc['children'].each do |child|
+                p.children << loadPage(basedir, p, child, path + child['importRoot'] + '/')
+            end
+        else
+            p.id = node['id']
+            if !(node.has_key?("isAbstract"))
+                if node.has_key?("url")
+                    p.url = node['url']
+                else
+                    p.url = path + node['id'] + ".html"
+                end
+            end
+            if node.has_key?("children")
+                node['children'].each do |child|
+                    p.children << loadPage(basedir, p, child, path)
+                end
+            end
+        end
+        p.children.each { |cp| p.allChildIds += cp.allChildIds }
+        if p.id
+            p.allChildIds << p.id
+        end
+        return p
+    end
+
+    def self.findPage(parent, pageId)
+        parent.children.each do |p|
+            if p.id == pageId
+                return p
+            end
+            if p.children.length > 0
+                found = findPage(p, pageId)
+                if found
+                    return found
+                end
+            end
+        end
+        return nil
+    end
+
+end

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/879ac405/build-doc.xml
----------------------------------------------------------------------
diff --git a/build-doc.xml b/build-doc.xml
new file mode 100644
index 0000000..e9316f9
--- /dev/null
+++ b/build-doc.xml
@@ -0,0 +1,58 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+-->
+<project name="doc" xmlns:ivy="antlib:org.apache.ivy.ant"
+    xmlns:xooki="antlib:xooki"
+	xmlns:asciidoctor="antlib:org.asciidoctor.ant">
+	<import file="build-release.xml"/>
+
+	<target name="generate-asciidoc" depends="generate-doc-init">
+        <mkdir dir="${build.dir}/asciidoc" />
+        <!-- requires java 6 jdk in path and Apache Ant 1.7 -->
+        <taskdef uri="antlib:xooki" file="${doc.src.dir}/xooki2asciidoc/antlib.xml" />
+        <xooki:toAsciidoc destDir="${build.dir}/asciidoc" checkUpToDate="true" xookidir="${doc.src.dir}/xooki2asciidoc">
+            <fileset dir="${doc.tmp.dir}">
+                <include name="**/*.html"/>
+                <exclude name="template*.html"/>
+                <exclude name="*Template.html"/>
+                <exclude name="conflict-solving-algo.html"/>
+                <exclude name="use.html"/>
+                <exclude name="samples/**"/>
+                <exclude name="js/**"/>
+                <exclude name="reports/**"/>
+                <exclude name="xooki/**"/>
+            </fileset>
+        </xooki:toAsciidoc>
+        <copy file="${doc.tmp.dir}/toc.json" todir="${build.dir}/asciidoc" />
+    </target>
+
+	<target name="generate-doc" depends="init-ivy,generate-doc-init">
+		<ivy:cachepath pathid="asciidoctor.path">
+		   <dependency org="org.asciidoctor" name="asciidoctor-ant" rev="1.5.0" />
+		</ivy:cachepath>
+		<taskdef uri="antlib:org.asciidoctor.ant" resource="org/asciidoctor/ant/antlib.xml" classpathref="asciidoctor.path" />
+		<asciidoctor:convert sourceDirectory="${build.dir}/asciidoc" outputDirectory="${doc.build.dir}" backend="xhtml5" templateDir="asciidoc-template" preserveDirectories="true">
+			<attribute key="basedir" value="${build.dir}/asciidoc" />
+		</asciidoctor:convert>
+        <copy todir="${doc.build.dir}">
+            <fileset dir="${doc.src.dir}" includes="images/**,style/**,samples/**,js/**,ivy.xsd" />
+            <fileset dir="${doc.tmp.dir}" includes="tutorial/log/multi-project-general-publishall.txt" />
+        </copy>
+    </target>
+
+</project>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/879ac405/doc/xooki2asciidoc/antlib.xml
----------------------------------------------------------------------
diff --git a/doc/xooki2asciidoc/antlib.xml b/doc/xooki2asciidoc/antlib.xml
new file mode 100644
index 0000000..8f4d2e2
--- /dev/null
+++ b/doc/xooki2asciidoc/antlib.xml
@@ -0,0 +1,82 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+-->
+<antlib>
+    <scriptdef name="toAsciidoc" language="javascript">
+        <element name="fileset" type="fileset"/>
+        <attribute name="destDir"/>
+        <attribute name="xookidir"/>
+        <attribute name="checkUpToDate"/>
+        <attribute name="printerFriendly"/>
+        <![CDATA[
+        importClass(java.io.File);
+
+        var xookidir = attributes.get("xookidir");
+        if (xookidir == null) {
+            xookidir = project.getProperty("basedir") + "/xooki";
+        }
+
+        filesets = elements.get("fileset")
+        for (j = 0; j < filesets.size(); j++) {
+            fs = filesets.get(j);
+            srcDir = fs.getDir(project);
+
+            // Get the files (array) of that fileset
+            ds = fs.getDirectoryScanner(project);
+            srcFiles = ds.getIncludedFiles();
+
+            // iterate over that array
+            print('processing ' + srcFiles.length + ' source files...');
+            for (i = 0; i < srcFiles.length; i++) {
+
+                // get the values via Java API
+                var file = new File(fs.getDir(project), srcFiles[i]);
+
+                var basedir = file.getParent();
+                var filename = file.getName();
+                var filepath = srcFiles[i].substring(0, srcFiles[i].lastIndexOf(project.getProperty("file.separator")) + 1);
+
+                if (attributes.get("checkuptodate") == "true") {
+                    p = "xooki." + file.getAbsolutePath().replace(' ','_') + ".uptodate";
+                    upToDate = project.createTask("uptodate");
+                    upToDate.setProperty(p);
+                    upToDate.setSrcfile(file);
+                    upToDate.setTargetFile(new File(attributes.get("destdir") + "/" + filepath + "/" + filename));
+                    upToDate.perform();
+                    if (project.getProperty(p) != null) {
+                        self.log(srcFiles[i]+" is up to date", 3);
+                        continue;
+                    }
+                }
+
+                exec = project.createTask("exec");
+                exec.setDir(new File(basedir));
+                exec.setExecutable("jrunscript");
+                exec.setTaskName("generate");
+                exec.createArg().setValue(xookidir + "/xooki2asciidoc.js");
+                exec.createArg().setValue(filename);
+                exec.createArg().setValue(attributes.get("destdir") + "/" + filepath);
+                if (attributes.get("printerfriendly") == "true") {
+                    exec.createArg().setValue("print");
+                }
+                exec.perform();
+            }
+        }
+        ]]>
+    </scriptdef>
+</antlib>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/879ac405/doc/xooki2asciidoc/xooki2asciidoc.js
----------------------------------------------------------------------
diff --git a/doc/xooki2asciidoc/xooki2asciidoc.js b/doc/xooki2asciidoc/xooki2asciidoc.js
new file mode 100644
index 0000000..554924e
--- /dev/null
+++ b/doc/xooki2asciidoc/xooki2asciidoc.js
@@ -0,0 +1,1569 @@
+/*
+	Copyright (c) 2006-2007, The Xooki project
+	http://xooki.sourceforge.net/
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+	
+	Some code is largely inspired by code found in the dojo toolkit, 
+	see http://dojotoolkit.org/ for more information.
+*/
+
+/*
+This script can be either embedded in a xooki page for in browser processing, or used in batch using rhino or java 6 javascript tool:
+jrunscript path/to/xooki.js inputFileFromXookiSite.html [path/to/dir/to/put/generated/file]
+
+Be sure to be in the directory where the html input to process is when running this command.
+ */
+var batchMode = (typeof arguments != 'undefined');
+
+var xooki = {};
+xooki.console = ""; // used for debugging purpose only, and only when the debug div is not yet created
+xooki.config = {};
+xooki.c = xooki.config;
+
+function t(msg) {
+    // returns the internationalized version of the message, or the message if no translation is available
+    // t stands for translate
+// FIXME
+//    if (typeof xooki.c == "object" 
+//        && typeof xooki.c.messages == "object" 
+//        && typeof xooki.c.messages[msg] == "string") {
+//        msg = xooki.c.messages[msg];
+//    }
+    var arr = [];
+    for (var i=1; i<arguments.length; i++) {
+        arr.push(arguments[i]);
+    }
+    return xooki.string.substituteParams(msg, arr);
+}
+
+function css(clss) {
+    // returns the css class or id configured, or the given class (or id) if no one is configured
+    if (typeof xooki.c.css[clss] != "undefined") {
+        return xooki.c.css[clss];
+    } else {
+        return clss;
+    } 
+}
+function u(path) {
+  // convert a path relative to the root to a full URL
+  // u stands for Url
+  if (batchMode) {
+	return xooki.c.relativeRoot+path;
+  } else {
+	return xooki.c.root + path;
+  }
+}
+function lu(path) {
+  // convert a path relative to the local root to a full URL
+  // l stands for local, u stands for Url
+  if (batchMode) {
+	return xooki.c.localRelativeRoot+path;
+  } else {
+	return xooki.c.localRoot + path;
+  }
+}
+function cu(urlCfgProp) {
+  // get a path from a configuration path and convert it to an URL
+  // cu stands for Configured Url
+  if (typeof xooki.c.path[urlCfgProp] == "undefined") {
+    xooki.warn(t("path not configured in xooki: '${0}'", urlCfgProp));
+    return "";
+  }
+  return u(xooki.c.path[urlCfgProp]);
+}
+function pu(id) {
+  // returns the url of the page identified by id
+  // pu stands for Page Url
+  return u(id+".html");
+}
+xooki.p = function(path) {
+  // get a xooki full path from a xooki relative path
+  // p stands for path
+  return xooki.c.path.install+"/"+path;
+}
+xooki.u = function(path) {
+  // convert a path relative to the xooki installation dir to a full URL
+  return u(xooki.p(path));
+}
+xooki.cu = function(urlCfgProp) {
+  // get a xooki path from a configuration path and convert it to an URL
+  if (typeof xooki.c.path[urlCfgProp] == "undefined") {
+    xooki.warn(t("path not configured in xooki: '${0}'", urlCfgProp));
+  }
+  return xooki.u(xooki.c.path[urlCfgProp]);
+}
+
+xooki.util = {
+    isArray: function(it) {
+    	return (it && it instanceof Array || typeof it == "array"); // Boolean
+    },
+    mix: function(src, into, override) {
+        if (typeof override == "undefined") {
+            override = true;
+        }
+        if (typeof into == "undefined") {
+            into = {};
+        }
+        for (var k in src) {
+            if (typeof src[k] == "object" && !xooki.util.isArray(src[k])) {
+                if (override || typeof into[k] == "object" || typeof into[k] == "undefined") {
+                    if (typeof into[k] != "object") {
+                        into[k] = {};
+                    }
+                    xooki.util.mix(src[k], into[k], override);
+                }
+            } else if (override || typeof into[k] == "undefined") {
+                into[k] = src[k];
+            }
+        }
+        return into;
+    },
+    initArray: function(a) {
+        if (this.isArray(a)) return a;
+        else return {};
+    }
+}
+
+xooki.url = {
+        newXmlHttpRequest: function() {
+        // we first try to use ActiveX, because IE7 has a direct support for XmlHttpRequest object, 
+        // but which doesn't work with file urls
+        	if(window.ActiveXObject)
+        	{
+        		try { req = new ActiveXObject("Msxml2.XMLHTTP");
+        		} catch(e) {
+        			try { req = new ActiveXObject("Microsoft.XMLHTTP");
+        			} catch(e) { req = false; }
+        		}
+        	}
+        	else if(window.XMLHttpRequest) {
+        		try { req = new XMLHttpRequest();
+        		} catch(e) { req = false; }
+        	}
+        
+        	return req;	
+        },
+                
+        loadURL: function( url, warnOnError ) {
+        	req = this.newXmlHttpRequest();
+        	if(req) {
+        		try {
+        			req.open("GET", url, false);
+        			req.send("");
+        	
+        			return req.responseText;
+        		} catch (e) {
+                    if (warnOnError != false)
+                        xooki.error(e, t("problem while loading URL ${0}", url));
+                    else
+                        xooki.debug(t("problem while loading URL ${0}: ${1}", url, e));
+                }		
+        	}
+        	return null;
+        },
+        
+        asyncLoadURL: function( url, callback, obj ) {
+        	var req = this.newXmlHttpRequest();
+        	if(req) {
+        		try {
+        			req.open("GET", url, true);
+				    req.onreadystatechange=function() {
+				        if (req.readyState == 4) {
+				           if (req.status == 200 || req.status == 0) {
+				              callback(req.responseText, obj);
+				           }
+				        }
+				     };  			
+				     req.send("");
+        		} catch (e) {
+        			xooki.error(e, t("problem while loading URL ${0}", url));
+                }		
+        	}
+        },
+
+        include: function(script_filename) {
+            document.write('<' + 'script');
+            document.write(' language="javascript"');
+            document.write(' type="text/javascript"');
+            document.write(' src="' + xooki.u(script_filename) + '">');
+            document.write('</' + 'script' + '>');
+        },
+        
+        evalURL: function( url, warnOnErrorUrl ) {
+            script = this.loadURL(url, warnOnErrorUrl);
+            if (script != null) {
+                try {
+                    eval(script);
+                } catch (e) {
+        			xooki.error(e, t("error while executing script from URL ${0}", url));
+                }
+            }
+        },
+
+        action: function(action) {        
+            // returns the url for an action on the same page
+            loc = batchMode?'':xooki.pageURL;
+            if (loc.indexOf("#") != -1) {
+                loc = loc.substring(0, loc.indexOf("#"));
+            }
+            return loc+"?action="+action;
+        }
+
+    };
+    
+xooki.string = {
+
+    substituteParams: function(/*string*/template, /* object - optional or ... */hash) {
+    // borrowed from dojo
+    // summary:
+    //	Performs parameterized substitutions on a string. Throws an exception if any parameter is unmatched.
+    //
+    // description:
+    //	For example,
+    //		dojo.string.substituteParams("File '${0}' is not found in directory '${1}'.","foo.html","/temp");
+    //	returns
+    //		"File 'foo.html' is not found in directory '/temp'."
+    //
+    // template: the original string template with ${values} to be replaced
+    // hash: name/value pairs (type object) to provide substitutions.  Alternatively, substitutions may be
+    //	included as an array
+    
+        var map;
+        if (typeof hash == "object" && hash.length) { // array
+            map = {};
+            for (var i in hash) {
+                map[i+""] = hash[i];
+            }
+        } else {
+            map = hash;
+        }
+    
+    	return template.replace(/\$\{(\w+)\}/g, function(match, key){
+    		if(typeof(map[key]) != "undefined" && map[key] != null){
+    			return map[key];
+    		}
+    		xooki.warn("Substitution not found: " + key);
+    		return key;
+    	}); // string
+	},
+	
+	processTemplate: function(/*string*/template, /* object */hash) {
+	   if (typeof template.process == "function") {
+	       return template.process(hash);
+       } else {
+            return this.substituteParams(template, hash);
+       }
+    },
+
+    exceptionText: function(e, message) {
+    	var s = e.description ? e.description : e.toString();
+    	return message ? message+":\n"+s : s;
+    },
+    
+    findXmlSection: function(str, element, from) {
+        return this.findSection(str, new RegExp('<'+element+'(\\s*\\w+="[^\\"]*")*>'), new RegExp('</'+element+'>'), from);
+    },
+    
+    find: function(/*string*/str, /*string or regexp*/exp, /*number, optional*/from) {
+        // find an expression (string or regexp) in a string, from an optional index
+        // the object returned has two properties:
+        // begin: the index in str of the matching find
+        // end: the index in str of the end of the matching find
+        // returns null if no match is found
+        if (typeof from != "number") {
+            from = 0;
+        }
+        if (typeof exp == "string") {
+            var result = {};
+            result.begin = str.indexOf(exp,from);
+            if (result.begin >= 0) {
+                result.end = result.begin + exp.length;
+                return result;
+            }
+        } else {
+            var m;
+            if (from > 0) {
+                // I haven't found any other way to start from the given index
+                m = exp.exec(str.substring(from));
+            } else {
+                m = exp.exec(str);
+            }
+            if (m != null) {                
+                var result = {};
+                result.begin = m.index + from;
+                result.end = result.begin + m[0].length;
+                result.matcher = m;
+                return result;
+            }
+        }
+        return null;
+    },
+    
+    findSection: function(/*string*/str, /*string or regexp*/open, /*string or regexp*/close, /*number, optional*/from) {
+        // finds a section delimited by open and close tokens in the given string
+        // the algorithm looks for matching open and close tokens
+        // the returned object has the following properties:
+        //   outerStart: the index in str where the first open token was found
+        //   innerStart: the index in str just after the found open token
+        //   innerEnd: the index in str where the matching close token was found
+        //   outerEnd: the index in str just after the matching close token
+        //   children: an array of similar objects if nested sections where found
+        // if no section is found (no open token, an open token with no matching 
+        // close token, or a close token before an open token), null is returned
+        //
+        // for instance if open=='(' and close==')' then the section will find
+        // a section delimited by the first found open parenthesis and the matching
+        // close parentethis, taking into account other opening parentethis
+        // examples:
+        // findSection("a(test)b", "(", ")") == {outerStart: 1, innerStart:2, innerEnd:6, outerEnd:7, children:[]}
+        // findSection("a(te(s)(t))b", "(", ")") == {outerStart: 1, innerStart:2, innerEnd:10, outerEnd:11, 
+        //      children:[
+        //          {outerStart: 4, innerStart:5, innerEnd:6, outerEnd:7, children:[]},
+        //          {outerStart: 7, innerStart:8, innerEnd:9, outerEnd:10, children:[]}
+        //      ]}
+        
+        var openResult = this.find(str, open, from);        
+        if (openResult == null) {
+            print('no open\n');
+            return null;
+        }
+        if (openResult.end <= openResult.begin) {
+            print('empty open\n');
+            // empty match are not allowed
+            return null;
+        }
+        var closeResult = this.find(str, close, openResult.end);        
+        if (closeResult == null) {
+            print('no close\n');
+            return null;
+        }
+        if (closeResult.end <= closeResult.begin) {
+            print('empty close\n');
+            // empty match are not allowed
+            return null;
+        }
+        
+        //print('matched !' + str.substring(openResult.begin, closeResult.end) + '\n');
+
+        var children = [];
+        var child = this.findSection(str, open, close, openResult.end);
+        while (child != null) {
+            if (child.outerStart > closeResult.begin) {
+                break;
+            }
+            if (child.outerEnd > closeResult.begin) {
+                closeResult = this.find(str, close, child.outerEnd);        
+                if (closeResult == null) {
+                    // unmatched open token
+                    return null;
+                }
+            }
+            children.push(child);
+            child = this.findSection(str, open, close, child.outerEnd);
+        }
+
+        //print('found !' + str.substring(openResult.begin, closeResult.end) + '\n');
+
+        return {
+            outerStart: openResult.begin,
+            innerStart: openResult.end,
+            matcherStart: openResult.matcher,
+            innerEnd: closeResult.begin,
+            outerEnd: closeResult.end,
+            matcherEnd: closeResult.matcher,
+            children: children
+        };        
+    },
+    
+    mul: function (/*string*/ s, /*int*/ n) {
+        r = '';
+        for (var i=0; i < n; i++) {
+    		r += s;
+    	}
+        return r;
+    }
+};
+    
+xooki.json = {
+        evalJson: function (str) {
+            try {
+                return eval("("+str+")");
+            } catch (e) {
+                return null;
+            }
+        },
+        
+        loadURL: function (url) {
+            return this.evalJson(xooki.url.loadURL(url));
+        }
+    };
+
+// Displays an alert of an exception description with optional message
+xooki.warn = function(e, message) {
+    xooki.display(xooki.string.exceptionText(e, message), "#eecccc");
+}
+
+// Displays an alert of an exception description with optional message
+xooki.error = function(e, message) {
+    xooki.display(xooki.string.exceptionText(e, message), "#ffdddd");
+}
+
+xooki.info = function(message) {
+    xooki.display(message, "#ddddff");
+}
+
+xooki.display = function(message, background) {
+    var messages = document.getElementById('xooki-messages');
+    if (messages) {
+        messages.innerHTML = '<table width="100%" border="0"><tr><td align="center">'+message+'</td></tr></table>';
+        messages.style.background = background;
+        messages.style.display = "inline";
+    } else {
+        alert(message);
+    }
+}
+
+xooki.debug = function(message) {
+    var console = typeof document == 'undefined' ? false : document.getElementById('xooki-console');
+    if (console) {
+        console.value += message + "\n";
+    } else {
+        xooki.console += message + "\n";
+    }
+}
+
+xooki.debugShowDetail = function (message) {
+    var detail = typeof document == 'undefined' ? false : document.getElementById('xooki-debug-detail');
+    if (detail) {
+        detail.value=message;
+    } else {
+        alert(message);
+    }
+}
+
+
+xooki.html = {
+    hide: function(divid) {
+	   document.getElementById(divid).style.display = 'none';
+    },
+
+    show: function (divid) {
+	   document.getElementById(divid).style.display = '';
+    },
+    
+    pageLink: function(page) {
+    	if (page.isAbstract) {
+    		return page.title;
+    	} else {
+    		return '<a href="'+(page.url != null ? page.url : pu(page.id))+'" '+(page.id == xooki.page.id?'class="current"':'')+'>'+page.title+'</a>';
+    	}
+    },
+	
+	// insert  the given  header in the html head
+	// can be used only when the browser is still in the head !
+	addHeader: function(/* string */ head) {
+		document.write(head);
+	},
+	
+	setBody: function( /* string */ body) {
+		document.body.innerHTML = body;
+	}
+};
+
+xooki.component = {
+    childrenList: function () {
+    	if (xooki.page.children.length > 0) {
+    		childrenList = '<ul class="'+css('childrenList')+'">\n';
+    		for (var i in xooki.page.children) {
+    			childrenList+='<li>'+xooki.html.pageLink(xooki.page.children[i])+'</li>\n';
+    		}
+    		childrenList += "</ul>\n";
+    		return childrenList;
+    	} else {
+    	   return "";
+        }
+    },
+    
+    menu: function () {
+    	var menu = '<ul id="'+css("treemenu")+'" class="treeview">\n';
+    	menu += (function (page) {
+        	var menu = '';
+        	for (var i in page.children) {
+                if (typeof page.children[i] == 'object') {
+            		smenu = arguments.callee(page.children[i]);
+            		if (smenu != '') {
+                        menu += '<li id="xooki-'+page.children[i].id+'" class="submenu">'+xooki.html.pageLink(page.children[i]);
+            			if (smenu.indexOf('id="xooki-'+xooki.page.id+'"') != -1 
+            				|| page.children[i].id == xooki.page.id) {
+            				// either a descendant or the node processed is the current page node
+            				// we specify that the menu must be opened by default
+            				menu += '<ul class="open"';
+    	        			menu += '>'+smenu+'</ul>';
+            			} else {
+    						menu += '<ul class="closed"';
+    	        			menu += '>'+smenu+'</ul>';
+    					}
+            		} else {
+                        menu += '<li id="xooki-'+page.children[i].id+'">'+xooki.html.pageLink(page.children[i]);
+                    }
+            		menu += '</li>\n';
+                }
+        	}
+        	return menu;
+        })(xooki.toc);
+    	menu += '</ul>\n';
+    	return menu;
+    },
+    
+    messages: function () {
+        return '<div id="xooki-messages" onclick="xooki.html.hide(\'xooki-messages\')" style="zIndex:999;display:none;position:absolute;top:30px;padding:10px;border-style:solid;background:#eeeeee;"></div>';
+    },
+
+    debugPanel: function () {
+        return '<div id="xooki-debug" style="display:none;margin-top:15px;padding:10px;border-style:solid;background:#eeeeee;"><strong>Xooki Console</strong><br/><textarea cols="100" rows="15" id="xooki-console">'+xooki.console+'</textarea><hr/><a href="javascript:xooki.debugShowDetail(document.getElementById(\'xooki-body\').innerHTML)">content</a> <a href="javascript:xooki.debugShowDetail(xooki.c.body)">xooki body</a> <a href="javascript:xooki.debugShowDetail(document.body.innerHTML)">whole body</a> <a href="javascript:xooki.action.evaluate()">evaluate</a><br/><textarea cols="100" rows="15" id="xooki-debug-detail"></textarea></div>';
+    },
+
+    printerFriendlyLocation: function () {
+        return xooki.url.action("print");
+    },
+
+    printerFriendlyLink: function () {
+        return '<a href="'+this.printerFriendlyLocation()+'">'+t('Printer Friendly')+'</a>';
+    },
+
+    breadCrumb: function () {
+        var breadCrumb = '<span class="breadCrumb">';
+		breadCrumb += (function (page) {
+        	var breadCrumb = xooki.html.pageLink(page);
+			if (page.meta.level >= 1) {
+				breadCrumb = arguments.callee(page.meta.parent) + " &gt; " + breadCrumb;
+			}
+        	return breadCrumb;
+        })(xooki.page);
+		breadCrumb += '</span>';
+		return breadCrumb;
+    }
+};
+
+xooki.render = {};
+xooki.render.printerFriendlyAsyncLoader = function(source, arr) {
+	var root = arr[0];
+	var page = arr[1];
+    if (source == null) {
+        return;
+    }
+	var level = page.meta.level - root.meta.level + 1;
+	
+    // compute printer friendly block
+    var beginIndex = source.indexOf('<textarea id="xooki-source">');
+    beginIndex += '<textarea id="xooki-source">'.length;
+    var endIndex = source.lastIndexOf('</textarea>');
+    source = source.substring(beginIndex, endIndex);
+    
+    var printerFriendly = "<h"+level+">"+page.title+"</h"+level+">";
+    printerFriendly += xooki.input.format.main(source, level) + "<hr/>";
+    // inject block in page
+    var pf = document.getElementById('xooki-printerFriendly');
+    pf.innerHTML += printerFriendly;    
+    
+    // continue recursive loading
+   	var nextPage = xooki.toc.getNextPage(page, root);
+   	if (nextPage != null) {
+    	xooki.url.asyncLoadURL(pu(nextPage.id), xooki.render.printerFriendlyAsyncLoader, [root, nextPage]);
+   	}
+};
+
+xooki.render.printerFriendlyAsync = function() {
+	xooki.c.body = xooki.c.messages
+	+ "<div id='xooki-printerFriendly'></div>" // div where printer friendly content will be put
+    + xooki.c.debugPanel;
+    
+    document.body.innerHTML = xooki.string.processTemplate(xooki.template.body, xooki.c);
+    
+    // start async loading of content
+    xooki.url.asyncLoadURL(pu(xooki.page.id), xooki.render.printerFriendlyAsyncLoader, [xooki.page, xooki.page]);
+};
+
+xooki.render.printerFriendlySync = function() {
+	xooki.c.body = xooki.c.messages
+    + (function (page, level) {
+        var source = xooki.url.loadURL(pu(page.id));
+        if (source == null) {
+            return "";
+        }
+        var beginIndex = source.indexOf('<textarea id="xooki-source">');
+        beginIndex += '<textarea id="xooki-source">'.length;
+        var endIndex = source.lastIndexOf('</textarea>');
+        source = source.substring(beginIndex, endIndex);
+        
+        var printerFriendly = "<div class='toc-title toc-title-"+level+"'>"+page.title+"</div>";
+        printerFriendly += xooki.input.format.main(source, level);
+        for (var i=0; i <page.children.length; i++) {
+            printerFriendly += "<hr/>";
+            printerFriendly += arguments.callee(page.children[i], level+1);
+        }
+        return printerFriendly;
+    })(xooki.page, 1);
+    
+    xooki.html.setBody(xooki.string.processTemplate(xooki.template.body, xooki.c));
+};
+
+xooki.render.printerFriendly = function() {
+    for (var k in xooki.component) {
+        xooki.c[k] = xooki.component[k]();
+    }
+    
+	if (batchMode) {
+		xooki.render.printerFriendlySync();
+	} else {
+		xooki.render.printerFriendlyAsync();
+	}
+};
+
+
+xooki.render.page = function() {
+    // realize all components available
+    for (var k in xooki.component) {
+        xooki.c[k] = xooki.component[k]();
+    }
+    
+    xooki.input.source();
+    
+    if (xooki.c.allowEdit) {
+    	xooki.c.body = xooki.c.messages
+            + xooki.c.toolbar
+            + '<div id="xooki-content">' 
+                + '<div id="xooki-body"></div>'
+            + '</div>'
+            + xooki.c.editZone
+            + xooki.c.debugPanel;
+    } else {
+    	xooki.c.body = xooki.c.messages
+            + '<div id="xooki-content">' 
+                + '<div id="xooki-body"></div>'
+            + '</div>'
+            + xooki.c.debugPanel;
+    }
+
+    xooki.html.setBody(xooki.string.processTemplate(xooki.template.body, xooki.c));
+    
+    xooki.input.applyChanges();
+};
+
+xooki.render.main = function() {
+    if (xooki.c.action == "print") {
+        // render the printer friendly version of the page
+        this.printerFriendly();
+    } else {
+        // render the page normally
+        this.page();
+    }
+};
+
+xooki.input = {
+    source: function() {
+        if (typeof document != 'undefined' && document.getElementById('xooki-source') != null) {
+            this._source = document.getElementById('xooki-source').value;
+        }
+        return this._source;
+    },
+    processed: function() {
+        return this.format.main(this.source());
+    },
+    
+    format: {
+        getInputFilters: function (inputFormat) {
+            return xooki.c[inputFormat+"InputFormat"];
+        },
+        define: function (inputFormat, filters) {
+            // define a new inputFormat
+            // inputFormat: the new input format name
+            // filters: an array of input filter names
+            xooki.c[inputFormat+"InputFormat"] = filters;
+        },
+        main: function(source, level) {
+            // formats an input source
+            if (xooki.c.inputFormat && typeof this.getInputFilters(xooki.c.inputFormat) != "undefined") {
+                format = xooki.c.inputFormat;
+            } else {
+                format = xooki.c.defaultInputFormat;
+            }
+            filters = this.getInputFilters(format);
+            for (var i in filters) {
+                if (typeof filters[i] == 'string') {
+    				xooki.debug('processing filter '+filters[i]);
+                    f = xooki.input.filters[filters[i]];
+                    if (typeof f == "function") {
+                    	try {
+                        	source = f(source, level); // process filter
+                        } catch (e) {
+    	                    xooki.error(e, t("error occurred while processing filter ${0}", filters[i]));
+                        }
+                    } else {
+                        xooki.error(t("unknown filter ${0} used in input format ${1}", filters[i], format));
+                    }
+                }
+            }
+            return source;
+        }
+    }, 
+    
+    filters: {
+        shortcuts: function (input) {
+            // handle shortcut links like this:
+            //    [[svn:build.xml]] => <a href="https://xooki.svn.sourceforge.net/svnroot/xooki/trunk/build.xml">build.xml</a>
+            //    [[svn:test/example.js a good example]] => <a href="https://xooki.svn.sourceforge.net/svnroot/xooki/trunk/test/example.js">a good example</a>
+            // needs to be configured in xooki config like this
+            //      xooki.c.shortcuts.<any shortcut>.url = base url of the shortcut. 
+            //      ex: xooki.c.shortcuts.svn.url = https://xooki.svn.sourceforge.net/svnroot/xooki/trunk/
+            return input.replace(new RegExp("\\[\\[([^:\n]+):([^\\]\n]+)\\]\\]", "g"), function (str, prefix, code, offset, s) {
+            	if (typeof xooki.c.shortcuts == "undefined" || typeof xooki.c.shortcuts[prefix] == "undefined") {
+                    xooki.debug('unknown shortcut '+prefix);
+            		return str;
+            	}
+                var index = code.indexOf(' ');
+                var path = index>0?code.substring(0,index):code;
+                
+                var title = index>0?code.substring(index+1):path;
+                var pre = typeof xooki.c.shortcuts[prefix].pre == "undefined"?'':xooki.c.shortcuts[prefix].pre;
+                var post = typeof xooki.c.shortcuts[prefix].post == "undefined"?'':xooki.c.shortcuts[prefix].post;
+                return 'link:'+pre+path+post+'['+title+']';
+            });
+        },
+        
+        xookiLinks: function (input) {
+            // handle xooki links like this:
+            //    [[page/id]]
+            //    [[page/id My Title]]
+            return input.replace(new RegExp("\\[\\[([^\\]]+)\\]\\]", "g"), function (str, code, offset, s) {
+                var index = code.indexOf(' ');
+                var id = (index>0?code.substring(0,index):code);
+                
+                var title;
+                var url;
+                var invalid = false;
+                
+                if (typeof xooki.toc.pages[xooki.toc.importRoot + id] != "undefined") {
+               	    title = xooki.toc.pages[xooki.toc.importRoot + id].title;
+                    url = pu(xooki.toc.importRoot + id);
+               	} else if (xooki.toc.importRoot.length > 0 && typeof xooki.toc.pages[id] != "undefined") {
+               	    title = xooki.toc.pages[id].title;
+                    url = pu(id);
+               	} else {
+                    invalid = true;
+               		title = code;
+               		url = u(id);
+               	}
+                if (index>0) {
+                	title = code.substring(index+1);
+                }
+                if (invalid) {
+                    if (batchMode) {
+                        // do not output invalid links as links in batch mode
+                        return title;
+                    } else {
+                        return title+'link:'+url+'[?]';
+                    }
+                } else {
+                    return 'link:'+url+'['+title+']';
+                }
+            });
+        },
+        
+        wikiMarkup: function (input) { 
+            // handle italic
+            input = input.replace(new RegExp("\\_([^\n]+)\\_", "g"), "<em>$1</em>");
+            
+            return input;
+        },
+        
+        jira: function (input) { 
+            // auto replace jira issue ids (like IVY-12) by a link to the issue
+            // needs to be configured in xooki config like this
+            //      xooki.c.jira.ids = an array of jira projects ids (ex: ["IVY", "ANT"])
+            //      xooki.c.jira.url = the url of the jira server (ex: "http://issues.apache.org/jira")
+            if (typeof xooki.c.jira != "object") {
+                return input;
+            }
+            input = input.replace(new RegExp("(("+xooki.c.jira.ids.join("|")+")-\\d+)([^\"\\d])", "g"), 'link:'+xooki.c.jira.url+'/browse/$1[$1]$3');
+            
+            return input;
+        },
+        
+        code: function (input) {
+            codeSection = xooki.string.findXmlSection(input, "code");
+            from = 0;
+            while (codeSection != null) {
+                processedSection = "\n[source]\n----\n" 
+                    + input.substring(codeSection.innerStart, codeSection.innerEnd)
+                    + "\n----\n\n";
+                input = input.substring(0, codeSection.outerStart)
+                    + processedSection
+                    + input.substring(codeSection.outerEnd);
+                from = codeSection.outerStart + processedSection.length;
+    
+                codeSection = xooki.string.findXmlSection(input, "code", from);
+            }
+            return input;
+        },
+        
+        includes: function (input) {
+	        //[<url>] replaced by the content of the url
+	        result = "";
+	        lastStart = 0;
+	        nextPos = input.indexOf("[<" , lastStart);
+	        while( nextPos > 0 ) {
+		        result = result + input.slice(lastStart,nextPos);
+		        lastStart = nextPos;
+		        nextPos = input.indexOf(">]" , lastStart);
+		        result = result + xooki.url.loadURL(lu(input.slice(lastStart+2,nextPos)));
+		        lastStart = nextPos + 2;
+		        nextPos = input.indexOf("[<" , lastStart);
+	        }
+            return result + input.slice(lastStart);
+        },
+
+        printFormatImgFix: function (input, level) {
+			if (level == undefined || level < 3) {
+				return input;
+			}
+			return input.replace(new RegExp('<img +src *= *\\"([^\\"]*)\\"', "g"), function (str, img, offset, s) {
+				l = level;
+				while (l > 2) {
+					if (img.indexOf("../") >= 0) {
+						img = img.substring(3);
+					} else {
+						break;
+					}
+					l--;
+				}
+				return '<img src="'+img+'"';
+			});
+		},
+
+		htmltags: function(input) {
+		    print('search href\n')
+            var s = xooki.string.findSection(input, new RegExp('<a\\s*href\\s*=\\s*\\"([^\\"]*)\\"[^>]*>'), new RegExp('</a>'));
+            var from = 0;
+            while (s != null) {
+                var href = s.matcherStart[1];
+                processedSection = "link:" + href + "[" + input.substring(s.innerStart, s.innerEnd) + "]";
+                input = input.substring(0, s.outerStart) + processedSection + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+                s = xooki.string.findSection(input, new RegExp('<a\\s*href\\s*=\\s*\\"([^\\"]*)\\"[^>]*>'), new RegExp('</a>'), from);
+            }
+
+            print('search name\n')
+            s = xooki.string.findSection(input, new RegExp('<a\\s*name\\s*=\\s*\\"([^\\"]*)\\"[^>]*>'), new RegExp('</a>'));
+            from = 0;
+            while (s != null) {
+                var name = s.matcherStart[1];
+                processedSection = "[[" + name + "]]" + input.substring(s.innerStart, s.innerEnd);
+                input = input.substring(0, s.outerStart) + processedSection + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+                s = xooki.string.findSection(input, new RegExp('<a\\s*name\\s*=\\s*\\"([^\\"]*)\\"[^>]*>'), new RegExp('</a>'), from);
+            }
+
+            print('search img\n')
+            s = xooki.string.find(input, new RegExp('<img\\s*src\\s*=\\s*\\"([^\\"]*)\\"\\s*/>'));
+            from = 0;
+            while (s != null) {
+                processedSection = " image:" + s.matcher[1] + "[]"
+                input = input.substring(0, s.begin)
+                    + processedSection
+                    + input.substring(s.end);
+                from = s.begin + processedSection.length;
+                s = xooki.string.find(input, new RegExp('<img\\s*src\\s*=\\s*\\"([^\\"]*)\\"\\s*/>'), from);
+            }
+
+            print('search br\n')
+            s = xooki.string.find(input, new RegExp('<br\\s*/>'));
+            from = 0;
+            while (s != null) {
+                processedSection = "\n"
+                input = input.substring(0, s.begin)
+                    + processedSection
+                    + input.substring(s.end);
+                from = s.begin + processedSection.length;
+                s = xooki.string.find(input, new RegExp('<br\\s*/>'), from);
+            }
+
+            print('search b\n')
+            s = xooki.string.findXmlSection(input, "b");
+            from = 0;
+            print("found=" + (s != null) + "\n")
+            while (s != null) {
+                processedSection = "*" + input.substring(s.innerStart, s.innerEnd) + "*";
+                input = input.substring(0, s.outerStart) + processedSection + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+                s = xooki.string.findXmlSection(input, "b", from);
+                print("found=" + (s != null) + "\n")
+            }
+
+            print('search strong\n')
+            s = xooki.string.findXmlSection(input, "strong");
+            from = 0;
+            print("found=" + (s != null) + "\n")
+            while (s != null) {
+                processedSection = "*" + input.substring(s.innerStart, s.innerEnd) + "*";
+                input = input.substring(0, s.outerStart) + processedSection + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+                s = xooki.string.findXmlSection(input, "strong", from);
+                print("found=" + (s != null) + "\n")
+            }
+
+            print('search i\n')
+            s = xooki.string.findXmlSection(input, "i");
+            from = 0;
+            while (s != null) {
+                processedSection = "__" + input.substring(s.innerStart, s.innerEnd) + "__";
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "i", from);
+            }
+
+            print('search h1\n')
+            s = xooki.string.findXmlSection(input, "h1");
+            from = 0;
+            while (s != null) {
+                processedSection = "\n== " + input.substring(s.innerStart, s.innerEnd) + "\n";
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "h1", from);
+            }
+
+            print('search h2\n')
+            s = xooki.string.findXmlSection(input, "h2");
+            from = 0;
+            while (s != null) {
+                processedSection = "\n=== " + input.substring(s.innerStart, s.innerEnd) + "\n";
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "h2", from);
+            }
+
+            print('search h3\n')
+            s = xooki.string.findXmlSection(input, "h3");
+            from = 0;
+            while (s != null) {
+                processedSection = "\n==== " + input.substring(s.innerStart, s.innerEnd) + "\n";
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "h3", from);
+            }
+
+            print('search h4\n')
+            s = xooki.string.findXmlSection(input, "h4");
+            from = 0;
+            while (s != null) {
+                processedSection = "\n." + input.substring(s.innerStart, s.innerEnd) + "\n";
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "h4", from);
+            }
+
+            print('search center\n')
+            s = xooki.string.findXmlSection(input, "center");
+            from = 0;
+            while (s != null) {
+                processedSection = input.substring(s.innerStart, s.innerEnd);
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "center", from);
+            }
+
+            print('search tt\n')
+            s = xooki.string.findXmlSection(input, "tt");
+            from = 0;
+            while (s != null) {
+                processedSection = "`" + input.substring(s.innerStart, s.innerEnd) + "`";
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "tt", from);
+            }
+
+            print('search em\n')
+            s = xooki.string.findXmlSection(input, "em");
+            from = 0;
+            while (s != null) {
+                processedSection = "\n[NOTE]\n===============================\n" + input.substring(s.innerStart, s.innerEnd) + "\n===============================\n";
+                input = input.substring(0, s.outerStart)
+                    + processedSection
+                    + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+    
+                s = xooki.string.findXmlSection(input, "em", from);
+            }
+
+            print('search span-since\n')
+            s = xooki.string.findSection(input, new RegExp('<span\\s*class\\s*=\\s*\\"\\s*since\\s*\\"[^>]*>'), new RegExp('</span>'));
+            from = 0;
+            while (s != null) {
+                processedSection = "*__" + input.substring(s.innerStart, s.innerEnd) + "__*";
+                input = input.substring(0, s.outerStart) + processedSection + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+                s = xooki.string.findSection(input, new RegExp('<span\\s*class\\s*=\\s*\\"\\s*since\\s*\\"[^>]*>'), new RegExp('</span>'), from);
+            }
+
+            print('search ul/ol\n')
+            var htmllisttag = function(input, from, indent) {
+                var sul = xooki.string.find(input, '<ul>', from);
+                var sol = xooki.string.find(input, '<ol>', from);
+                var endtag;
+                var innerindent;
+                var s;
+                if (sul != null && (sol == null || sul.begin < sol.begin)) {
+                    s = sul;
+                    innerindent = "*" + indent
+                    endtag = "</ul>";
+                } else {
+                    s = sol;
+                    innerindent = "." + indent
+                    endtag = "</ol>";
+                }
+                if (s == null) {
+                    return input;
+                }
+                input = input.substring(0, s.begin) + input.substring(s.end);
+                from = s.begin;
+                var lastEnd = s.begin;
+                var first = true;
+                var sli = xooki.string.findXmlSection(input, "li", from);
+                while (sli != null) {
+                    s = xooki.string.find(input, endtag, from);
+                    if (s != null && s.begin < sli.outerStart) {
+                        break;
+                    }
+                    start = sli.outerStart;
+                    if (!first) {
+                        start = lastEnd;
+                    }
+                    processedSection = "\n" + innerindent + input.substring(sli.innerStart, sli.innerEnd).replace(/\\s/, ' ');
+                    input = input.substring(0, start)
+                        + processedSection
+                        + input.substring(sli.outerEnd);
+                    from = start + processedSection.length;
+                    lastEnd = from;
+                    sli = xooki.string.findXmlSection(input, "li", from);
+                    first = false;
+                }
+                s = xooki.string.find(input, endtag, from);
+                if (s == null) {
+                    print(input.substring(from, from + 100));
+                    return input;
+                }
+                input = input.substring(0, s.begin) + input.substring(s.end);
+                from = s.begin;
+                return htmllisttag(input, from, indent);
+            }
+
+            input = htmllisttag(input, 0, " ");
+
+            print('search table\n')
+            s = xooki.string.findXmlSection(input, "table");
+            from = 0;
+            print("found=" + (s != null) + "\n")
+            while (s != null) {
+                tableContent = input.substring(s.innerStart, s.innerEnd);
+                processedSection = "\n"
+
+                print('search tablehead\n')
+                s2 = xooki.string.findXmlSection(tableContent, "thead");
+                from2 = 0
+                print("found=" + (s2 != null) + "\n")
+                if (s2 != null) {
+                    tableHead = tableContent.substring(s2.innerStart, s2.innerEnd);
+                    processedSection += '[options="header"]\n'
+                    processedSection += '|=======\n'
+
+                    print('search th\n')
+                    s3 = xooki.string.findXmlSection(tableHead, "th");
+                    while (s3 != null) {
+                        processedSection += "|" + tableHead.substring(s3.innerStart, s3.innerEnd);
+                        s3 = xooki.string.findXmlSection(tableHead, "th", s3.outerEnd);
+                    }
+                    processedSection += "\n"
+                    from2 = s2.outerEnd
+                } else {
+                    processedSection += '|=======\n'
+                }
+
+                print('search tr\n')
+                s2 = xooki.string.findXmlSection(tableContent, "tr", from2);
+                while (s2 != null) {
+                    trContent = tableContent.substring(s2.innerStart, s2.innerEnd);
+
+                    print('search td\n')
+                    s3 = xooki.string.findXmlSection(trContent, "td");
+                    while (s3 != null) {
+                        processedSection += "|" + trContent.substring(s3.innerStart, s3.innerEnd);
+                        s3 = xooki.string.findXmlSection(trContent, "td", s3.outerEnd);
+                    }
+                    processedSection += "\n"
+                    
+                    from2 = s2.outerEnd;
+                    s2 = xooki.string.findXmlSection(tableContent, "tr", from2);
+                }
+
+                processedSection += '|=======\n'
+                
+                input = input.substring(0, s.outerStart) + processedSection + input.substring(s.outerEnd);
+                from = s.outerStart + processedSection.length;
+                s = xooki.string.findXmlSection(input, "table", from);
+                print("found=" + (s != null) + "\n")
+            }
+
+            return input;
+		},
+    },
+    
+    
+    applyChanges: function() {
+    	document.getElementById('xooki-body').innerHTML = xooki.input.processed();
+    }
+};
+
+
+xooki.postProcess = function() {
+	xooki.render.main();
+	window.onkeypress = keyCtrl;
+};
+
+
+if (typeof xooki.io == "undefined") {
+    xooki.io = {};
+}
+
+
+xooki.action = {}
+xooki.action.toggleDebug = function() {
+    if (xooki.c.debug) {
+    	if (document.getElementById('xooki-debug').style.display == 'none') {
+    		xooki.html.show('xooki-debug');
+    	} else {
+    		xooki.html.hide('xooki-debug');
+    	}
+	}
+}
+xooki.action.evaluate = function () {
+    var exp = prompt("Please enter javascript expression to evaluate");
+    xooki.debugShowDetail(eval(exp));
+}
+
+// TODO, review use registration
+function keyCtrl(evt) {
+	var code = xooki.c.browser.NS ? evt.which : event.keyCode;
+	var ctrl = xooki.c.browser.NS ? evt.ctrlKey : event.ctrlKey;
+  	var key = String.fromCharCode(code);
+	if (xooki.c.debug && ctrl && "d" == key) {
+		xooki.action.toggleDebug();
+		return false;
+	}
+	if (xooki.c.allowEdit && ctrl && "s" == key) {
+		xooki.action.saveChanges();
+		return false;
+	}
+	if (xooki.c.allowEdit && ctrl && "e" == key) {
+		xooki.action.toggleEdit();
+		return false;
+	}
+}
+
+// xooki engine init function
+xooki.init = function() {
+    ////////////////////////////////////////////////////////////////////////////
+    ////////////////// config init
+    ////////////////////////////////////////////////////////////////////////////
+    initConfigProperty = function(prop, value, defaultValue) {
+        if (typeof this[prop] == "undefined") {
+            if (typeof value == "undefined") {
+                this[prop] = defaultValue;
+            } else if (typeof value == "function") {
+                this[prop] = value();
+            } else {
+                this[prop] = value;
+            }
+        }
+    };
+    if (typeof xookiConfig != "undefined") {xooki.util.mix(xookiConfig, xooki.config);}
+    xooki.c.initProperty = initConfigProperty;
+    xooki.c.computeRoot = function() {
+    	root = xooki.pageURL;
+    	// remove trailing parts of the URL to go the root depending on level
+    	for (var i=0; i < xooki.c.level + 1; i++) {
+    		root = root.substring(0, root.lastIndexOf('/'));
+    	}
+    	return root + '/';
+    };
+    xooki.c.computeRelativeRoot = function() {
+    	return xooki.string.mul('../', xooki.c.level);
+    };
+    xooki.c.setImportLevel = function(level) {
+        // compute roots with old level value, for paths relative to the local (non imported) root
+        this.localRoot = this.computeRoot();
+        this.localRelativeRoot = this.computeRelativeRoot();
+        // change level and update roots
+        this.level+=level;
+        this.root = this.computeRoot();
+        this.relativeRoot = this.computeRelativeRoot();
+    };
+    xooki.c.initProperty("level", 0);
+    xooki.c.initProperty("root", xooki.c.computeRoot);
+    xooki.c.initProperty("relativeRoot", xooki.c.computeRelativeRoot);
+    xooki.c.initProperty("localRoot", xooki.c.root);
+    xooki.c.initProperty("localRelativeRoot", xooki.c.relativeRoot);
+    globalConfig = xooki.url.loadURL(u("config.json"), false);
+    if (globalConfig != null && globalConfig.length != 0) {
+        globalConfig = eval('('+globalConfig+')');
+        xooki.util.mix(globalConfig, xooki.c, false);
+    }
+    xooki.url.evalURL(u("config.js"), false);
+    xooki.url.evalURL(u("config.extra.js"), false);
+
+
+    xooki.c.initProperty("defaultInputFormat", "xooki");
+    xooki.c.initProperty("xookiInputFormat", ["xooki"]);
+    xooki.c.initProperty("allowEdit", !batchMode && xooki.pageURL.substr(0,5) == "file:");
+    
+    xooki.input.format.define("xooki", ["code", "shortcuts", "xookiLinks", "jira", "includes", "printFormatImgFix", "htmltags"]);
+    
+    xooki.c.path = (typeof xooki.c.path != "undefined")?xooki.c.path:{};
+    xooki.c.path.initProperty = initConfigProperty;
+    xooki.c.path.initProperty("install", "xooki");
+    xooki.c.path.initProperty("messages", xooki.p("messages.json"));
+    xooki.c.path.initProperty("template", "template.html");
+    xooki.c.path.initProperty("printTemplate", "printTemplate.html");
+    xooki.c.path.initProperty("toc", "toc.json");
+    xooki.c.path.initProperty("blankPageTpl", xooki.p("blankPageTpl.html"));
+    
+    
+    xooki.c.css = (typeof xooki.c.css != "undefined")?xooki.c.css:{};    
+        
+    xooki.c.messages = xooki.json.loadURL(cu("messages")); 
+	if (!batchMode) {
+	    xooki.c.browser = {
+	        NS: (window.Event) ? 1 : 0
+	    };
+    
+	    // action
+	    if (! xooki.c.action) xooki.c.action = 'render';
+	    // TODO: better handle action extraction
+		xooki.c.action = window.location.search == '?action=print'?'print':xooki.c.action;
+	}
+	
+	var match = new RegExp("^.*\\/((?:.*\\/){"+xooki.c.level+"}[^\\/]*)(?:\\.\\w+)(?:\\?.+)?$", "g").exec(xooki.pageURL);
+	if (match == null || match[1] == '') {
+		xooki.c.curPageId = "index";
+	} else {
+		xooki.c.curPageId = match[1];
+	}
+    
+    ////////////////////////////////////////////////////////////////////////////
+    ////////////////// TOC init
+    ////////////////////////////////////////////////////////////////////////////
+    xooki.toc = xooki.json.loadURL(cu("toc"));
+    xooki.toc.url = cu("toc");
+    xooki.toc.pages = {}; // to store a by id map of pages objects
+    xooki.toc.importRoot = '';
+    xooki.toc.actualRoot = xooki.toc; // this is the real root of the TOC, in case of a TOC imported, it will point to the root of the TOC on which import has been performed
+
+	// populate meta data
+	(function(page, parent, index, level, prefix) {
+        if (prefix.length > 0) {
+            page.meta = xooki.util.mix({id: page.id}, page.meta);
+            page.id = prefix + page.id;
+        }
+        xooki.toc.pages[page.id] = page;
+        
+        page.meta = xooki.util.mix({
+            index: index,
+            level: level,
+            getSerializeValue: function(o, k) {
+                if (k == 'id' && typeof this.id != 'undefined') {
+                    return this.id;
+                } else {
+                    return o[k];
+                }
+            }
+        }, page.meta);
+        page.meta.parent = parent;
+        if (typeof page.importNode != 'undefined' && !page.isImported) {
+            // this node requires to import another xooki TOC
+            importedTocUrl = u(page.importRoot + '/toc.json');
+            importedToc = xooki.json.loadURL(importedTocUrl);
+            // look for the imported node in the importedTOC and import it in main TOC
+            (function(page, parent, index, level, prefix, importedToc, node, id, populateFunction) {
+                if (node.id == id) {
+                    xooki.util.mix(node, page, false);
+                    page.id = id;
+                    page.isImported = true;
+                    page.meta = xooki.util.mix({
+                        isTransient: function(k) {
+                            // only title, importRoot and importNode should be serialized
+                            return k != 'title' && k != 'importRoot' && k != 'importNode';
+                        }
+                    }, page.meta);
+                    if (xooki.c.curPageId.indexOf(prefix) == 0) {
+                        // the current page is in this imported TOC
+                        xooki.toc.actualRoot = importedToc;
+                        xooki.toc.url = u(page.importRoot + '/toc.json');
+                        xooki.toc.importRoot = prefix;
+                    }
+                    populateFunction(page, parent, index, level, prefix);
+                    return true;
+                } else if (typeof node.children != 'undefined') {
+                    for (var i=0; i<node.children.length; i++) {
+                        if (arguments.callee(page, parent, index, level, prefix, importedToc, node.children[i], id, populateFunction)) {
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            })(page, parent, index, level, page.importRoot+'/', importedToc, importedToc, page.importNode, arguments.callee);
+        }
+        if (typeof page.children == 'undefined') {
+            page.children = [];
+        } else {
+            for (var i=0; i<page.children.length; i++) {
+                arguments.callee(page.children[i], page, i, level+1, prefix); // recurse
+            }
+        }
+    })(xooki.toc, null, 0, -1, '');
+    
+    xooki.toc.getNextPage = function(page, root) {
+        if (page.children.length > 0) {
+        	return page.children[0];
+        } else if (page.meta.parent != null) {
+        	var cur = page;
+        	var next = xooki.toc.getNextSibling(cur);
+        	while (next == null) {
+        		cur = cur.meta.parent;
+        		if (cur == null || cur == root) {
+        			return null;
+        		}
+        		next = xooki.toc.getNextSibling(cur);
+        	}
+       		return next;
+        } else {
+        	return null;
+        }
+    };
+    xooki.toc.getNextSibling = function(page) {
+    	if (page.meta.parent == null) {
+    		return null;
+    	}
+       	if (page.meta.parent.children.length > page.meta.index) {
+       		return page.meta.parent.children[page.meta.index+1];
+       	} else {
+       		return null;
+       	}
+    };
+	xooki.page = xooki.toc.pages[xooki.c.curPageId];
+
+	if (xooki.page == null) {
+		xooki.warn(t('page id not found in TOC: ${0}',xooki.c.curPageId));
+		xooki.page = xooki.toc.children[0];
+	} 
+	if (typeof xooki.config.title == 'undefined') {
+		xooki.config.title = xooki.page.title;
+	}		
+	xooki.config.page = xooki.page;
+	
+    ////////////////////////////////////////////////////////////////////////////
+    ////////////////// main template loading + head output
+    ////////////////////////////////////////////////////////////////////////////
+	xooki.template = {};
+    xooki.template.source = xooki.url.loadURL(xooki.c.action == "print"?cu("printTemplate"):cu("template"));
+	if(xooki.template.source != null) {
+        xooki.template.head = '';
+		xooki.template.body = '${title}\n====================\n\n${body}';		
+	}
+	
+
+    ////////////////////////////////////////////////////////////////////////////
+    ////////////////// includes
+    ////////////////////////////////////////////////////////////////////////////
+    if (xooki.c.allowEdit) {
+        xooki.url.include("xookiEdit.js");
+    }
+
+    for (var k in xooki.c) {
+        if (typeof xooki.c[k] == "string" || typeof xooki.c[k] == "number" || typeof xooki.c[k] == "boolean") {
+            xooki.debug(k+": "+xooki.c[k]);
+        }
+    }
+};
+
+if (batchMode) {
+	importPackage(java.io);
+	
+	xooki.io.loadFile = function( url, warnOnError ) {
+	  var str = '';
+	  try {
+      var r = new BufferedReader(new FileReader(url));
+	  line = r.readLine();
+	  while (line != null) {
+		str += line + '\n';
+		line = r.readLine();
+	  }
+	  r.close();
+	  } catch (e) {
+	  	if (warnOnError) {
+	  		throw e;
+	  	} else {
+	  		xooki.debug("error occurred while loading "+url);
+	  	}
+	  }
+	  return str;
+    };
+	
+	xooki.io.saveFile = function (fileUrl, content) {
+		p = new File(fileUrl).getParentFile();
+		if (p != null) {
+			p.mkdirs();
+		}
+		pw = new PrintWriter(new FileWriter(fileUrl));
+		pw.write(content);
+		pw.close();
+		return true;
+	}
+
+    xooki.url.loadURL = function( url, warnOnError ) {
+		return xooki.io.loadFile(url, warnOnError );
+	};
+	
+	xooki.html.addHeader = function (head) {
+		xooki.pageContent = xooki.pageContent.replace(/<\/head>/, head+'\n</head>');
+	};
+	
+	xooki.html.setBody = function(body) {
+		xooki.pageContent = xooki.pageContent.replace(/<body>(.|[^,])*<\/body>/gm, '<body>'+body+'</body>');
+	}
+	
+	xooki.url.include = function(script_filename) {
+		xooki.html.addHeader('<script language="javascript" type="text/javascript" src="'+xooki.c.relativeRoot+'xooki/'+script_filename+'"></script>');
+	};
+	
+	xooki.input.source = function() {
+		if (typeof this._source == 'undefined') {
+			xooki.debug('searching source');
+			var beg = xooki.pageContent.indexOf('<textarea id="xooki-source">');
+			beg += '<textarea id="xooki-source">'.length;
+			var end = xooki.pageContent.lastIndexOf('</textarea>');
+			this._source = xooki.pageContent.substring(beg, end);
+			xooki.debug('source found');
+		}
+		return this._source;
+	}
+	
+	xooki.render.page = function() {
+	    // realize all components available
+		xooki.debug('realizing components');
+	    for (var k in xooki.component) {
+	        xooki.c[k] = xooki.component[k]();
+	    }
+	    
+		xooki.debug('processing body');
+		xooki.c.body = xooki.input.processed();
+
+		xooki.debug('updating body');
+		var body = xooki.string.processTemplate(xooki.template.body, xooki.c);
+	    xooki.html.setBody(body);
+	};
+
+	xooki.display = function(message, background) {
+		print(message);
+	};
+	
+	xooki.debug = function (message) {
+		if (xooki.c.debug) {
+			print(message+'\n');
+		}
+	};
+	var i=0;
+	if (arguments.length > i && arguments[0] == '-debug') {
+		xooki.c.debug = true;
+		i++;
+	} else {
+		xooki.c.debug = false;
+	}
+	
+	var file = 'index.html';
+	if (arguments.length > i) {
+		file = arguments[i];
+		i++;
+	}
+	var generateTo = "gen";
+	if (arguments.length > i) {
+		generateTo = arguments[i];
+		i++;
+	}
+	xooki.c.action = 'render';
+	if (arguments.length > i) {
+		xooki.c.action = arguments[i];
+		i++;
+	}
+
+	xooki.pageURL = new File(file).toURL().toExternalForm();
+	
+	print('processing '+new File(file).getAbsolutePath()+'...\n');
+	xooki.pageContent = xooki.io.loadFile(file);
+    
+    if (xooki.pageContent.match(/<textarea\s+id="xooki\-source">/) == null) {
+        print(file + ' is not a valid xooki source. ignored.');
+    } else {	
+    	var m = /var\s+xookiConfig\s+=\s+{.*};/.exec(xooki.pageContent);
+    	if (typeof m != 'undefined' && m != null) {
+    		eval(m[0]);
+    	}
+
+        xooki.init();
+        
+        xooki.pageContent = xooki.pageContent.replace(/<script type="text\/javascript" src="[^"]*xooki.js"><\/script>/g, '');
+
+    	xooki.render.main();
+
+		var dest = generateTo.endsWith(".html") ? generateTo : generateTo+'/'+file;
+		dest = dest.substring(0, dest.length-5) + ".adoc";
+    	print('generating to '+dest);
+        xooki.pageContent = xooki.pageContent.replace(/[\s\S]*<body>/i, '');
+        xooki.pageContent = xooki.pageContent.replace(/<\/body>[\s\S]*/i, '');
+    	xooki.io.saveFile(dest, xooki.pageContent);
+    }
+} else {
+	xooki.pageURL = window.location.toString();
+    xooki.init();
+}
+


Mime
View raw message