You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by sg...@apache.org on 2020/06/30 05:35:10 UTC

[freemarker-generator] branch master updated: FREEMARKER-147 Complete Maven site documentation (#16)

This is an automated email from the ASF dual-hosted git repository.

sgoeschl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/freemarker-generator.git


The following commit(s) were added to refs/heads/master by this push:
     new 4c39e8e  FREEMARKER-147 Complete Maven site documentation (#16)
4c39e8e is described below

commit 4c39e8ea7a000139f53105bddf3e2048ecbc2219
Author: Siegfried Goeschl <si...@gmail.com>
AuthorDate: Tue Jun 30 07:35:03 2020 +0200

    FREEMARKER-147 Complete Maven site documentation (#16)
---
 README.md                                          |   12 +-
 freemarker-generator-base/README.md                |    3 +-
 .../generator/base/datasource/DataSources.java     |   17 +-
 .../generator/base/template/TemplateOutput.java    |    4 +-
 .../generator/base/template/TemplateSource.java    |   23 +-
 .../base/template/TemplateTransformations.java     |    3 +
 .../generator/base/uri/UriFragmentParser.java      |    2 +-
 .../freemarker/generator/base/util/ListUtils.java  |    5 +-
 .../freemarker/generator/base/util/Validate.java   |    2 +-
 .../src/site/markdown/index.md                     |    4 +-
 .../generator/datasource/DataSourcesTest.java      |    1 -
 .../template/TemplateSourceFactoryTest.java        |   11 +-
 .../CHANGELOG.md                                   |    9 +-
 freemarker-generator-cli/README.md                 | 1584 +-------------------
 .../examples/templates/dataframe/example.ftl       |   14 +-
 .../examples/templates/info.ftl                    |   67 -
 .../templates/json/dataframe/github-users.ftl      |   20 +
 freemarker-generator-cli/pom.xml                   |   22 +-
 .../src/main/assembly/dist.xml                     |   41 -
 .../org/apache/freemarker/generator/cli/Main.java  |    4 +-
 .../markdown/cli/advanced/cli-configuration.md     |   77 +
 .../src/site/markdown/cli/concepts/data-models.md  |   37 +-
 .../src/site/markdown/cli/concepts/data-sources.md |   37 +-
 .../src/site/markdown/cli/concepts/design-goals.md |   17 +
 .../src/site/markdown/cli/concepts/named-uris.md   |   10 +-
 .../{user-parameters.md => passing-data.md}        |   23 +-
 .../site/markdown/cli/concepts/template-loading.md |   60 +
 .../src/site/markdown/cli/concepts/tools.md        |   22 +
 .../site/markdown/cli/concepts/transformation.md   |    4 +-
 .../markdown/cli/introduction/getting-started.md   |  142 ++
 .../site/markdown/cli/usage/running-examples.md}   |  644 ++------
 .../site/markdown/cli/usage/transforming-csv.md    |   80 +
 .../markdown/cli/usage/transforming-directories.md |   26 +-
 .../dataframe.md => usage/using-dataframes.md}     |   49 +-
 .../src/site/markdown/index.md                     |   29 +-
 .../site/resources/images/examples}/contract.png   |  Bin
 .../resources/images/examples}/excel-to-html.png   |  Bin
 .../site/resources/images/examples}/github.png     |  Bin
 .../images/examples}/locker-test-users-pdf.png     |  Bin
 .../resources/images/examples}/transactions.png    |  Bin
 .../freemarker/generator/cli/ManualTest.java       |    5 +-
 .../{examples => }/templates/cat.ftl               |    1 -
 .../templates/csv/csv/transform.ftl                |    7 +-
 freemarker-generator-cli/templates/info.ftl        |    2 +-
 .../templates/lib/commons-csv.ftl                  |    8 +-
 freemarker-generator-maven-plugin/CHANGELOG.md     |   12 +
 freemarker-generator-maven-plugin/pom.xml          |   23 -
 freemarker-generator-tools/README.md               |   36 +-
 freemarker-generator-tools/pom.xml                 |    4 +-
 .../generator/tools/commonscsv/CommonsCSVTool.java |   13 +-
 .../{ => impl}/CommonsCSVPrinterFacade.java        |    2 +-
 .../generator/tools/dataframe/DataFrameTool.java   |   16 +-
 .../{converter => impl}/CSVConverter.java          |    2 +-
 .../{converter => impl}/ConverterUtils.java        |   10 +-
 .../{converter => impl}/ListConverter.java         |    3 +-
 .../{converter => impl}/MapConverter.java          |    4 +-
 .../generator/tools/excel/ExcelTool.java           |    8 +-
 .../generator/tools/freemarker/FreeMarkerTool.java |   19 +-
 .../freemarker/generator/tools/grok/GrokTool.java  |    1 +
 .../tools/grok/{ => impl}/GrokWrapper.java         |    2 +-
 .../generator/tools/system/SystemTool.java         |    4 +-
 .../src/site/markdown/index.md                     |   67 +-
 .../tools/commonscsv/CommonsCSVToolTest.java       |    1 +
 .../generator/tools/grok/GrokToolTest.java         |    1 +
 pom.xml                                            |    7 +-
 src/site/markdown/index.md                         |    2 -
 travis.sh                                          |   22 +-
 67 files changed, 1010 insertions(+), 2377 deletions(-)

diff --git a/README.md b/README.md
index efc2fc2..1db8027 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,6 @@ Apache FreeMarker Generator
 
 For documentation or to report bugs visit: [https://freemarker.apache.org](https://freemarker.apache.org)
 
-
 Regarding pull requests on Github
 -----------------------------------------------------------------------------
 
@@ -15,7 +14,6 @@ a [Contributor License Agreement](https://www.apache.org/dev/new-committers-guid
 For contributions that are judged to be non-trivial, you will be asked
 to actually signing a Contributor License Agreement.
 
-
 What is Apache FreeMarker Generator?
 -----------------------------------------------------------------------------
 
@@ -28,6 +26,16 @@ Currently it can be invoked as a
 * Command-line interface `freemarker-generator-cli`
 * Maven plug-in `freemarker-generator-maven-plugin`
 
+Building Apache FreeMarker Generator
+-----------------------------------------------------------------------------
+
+To create the artefacts locally run
+
+> mvn clean install
+
+To build the documentation site run
+
+> mvn clean site site:stage
 
 Licensing
 -----------------------------------------------------------------------------
diff --git a/freemarker-generator-base/README.md b/freemarker-generator-base/README.md
index 0a420f6..4a5c119 100644
--- a/freemarker-generator-base/README.md
+++ b/freemarker-generator-base/README.md
@@ -1,4 +1,5 @@
-# Overview
+Apache FreeMarker Generator Base
+=============================================================================
 
 This module provides common functionality for `freemarker-generator-cli` and `freemarker-generator-maven-plugin` such as
 
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java
index 4c6e156..9db5552 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java
@@ -16,8 +16,10 @@
  */
 package org.apache.freemarker.generator.base.datasource;
 
+import org.apache.commons.io.FilenameUtils;
 import org.apache.freemarker.generator.base.util.ClosableUtils;
 import org.apache.freemarker.generator.base.util.StringUtils;
+import org.apache.freemarker.generator.base.util.Validate;
 
 import java.io.Closeable;
 import java.util.ArrayList;
@@ -25,7 +27,6 @@ import java.util.Collection;
 import java.util.List;
 
 import static java.util.stream.Collectors.toList;
-import static org.apache.commons.io.FilenameUtils.wildcardMatch;
 
 /**
  * Container for data sources with a couple of convenience functions to select
@@ -36,13 +37,14 @@ public class DataSources implements Closeable {
     private final List<DataSource> dataSources;
 
     public DataSources(Collection<DataSource> dataSources) {
+        Validate.notNull(dataSources, "No data sources provided");
         this.dataSources = new ArrayList<>(dataSources);
     }
 
     /**
      * Get the names of all data sources.
      *
-     * @return datas ource names
+     * @return data source names
      */
     public List<String> getNames() {
         return dataSources.stream()
@@ -109,24 +111,24 @@ public class DataSources implements Closeable {
     /**
      * Find data sources based on their name and globbing pattern.
      *
-     * @param wildcard globbing pattern
+     * @param wildcard the wildcard string to match against
      * @return list of matching data sources
      */
     public List<DataSource> find(String wildcard) {
         return dataSources.stream()
-                .filter(d -> wildcardMatch(d.getName(), wildcard))
+                .filter(d -> FilenameUtils.wildcardMatch(d.getName(), wildcard))
                 .collect(toList());
     }
 
     /**
      * Find data sources based on their group and and globbing pattern.
      *
-     * @param wildcard globbing pattern
+     * @param wildcard the wildcard string to match against
      * @return list of mathching data sources
      */
     public List<DataSource> findByGroup(String wildcard) {
         return dataSources.stream()
-                .filter(d -> wildcardMatch(d.getGroup(), wildcard))
+                .filter(d -> FilenameUtils.wildcardMatch(d.getGroup(), wildcard))
                 .collect(toList());
     }
 
@@ -139,9 +141,6 @@ public class DataSources implements Closeable {
     public String toString() {
         return "DataSource{" +
                 "dataSources=" + dataSources +
-                ", names=" + getNames() +
-                ", groups=" + getGroups() +
-                ", size=" + size() +
                 '}';
     }
 }
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
index 1e5cb50..426c0f1 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
@@ -26,9 +26,11 @@ import java.io.Writer;
 import static java.util.Objects.requireNonNull;
 
 /**
- * Information about where to write the ouput of a template. Initially we
+ * Information about where to write the output of a template. Initially we
  * wanted to use a <code>FileWriter</code> but it requires actually an
  * existing output file (otherwise a FileNotFound exception is thrown).
+ * An alternative could be a "LazyFileWriter" which creates the file on
+ * the first write access.
  */
 public class TemplateOutput {
 
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSource.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSource.java
index 42c36b6..c12d35a 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSource.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSource.java
@@ -23,7 +23,7 @@ import java.nio.charset.StandardCharsets;
 
 /**
  * Information how to load a template. The template is either
- * provided as source code or as template path resolved
+ * provided as literal text or as template path resolved
  * by FreeMarker's template loader.
  */
 public class TemplateSource {
@@ -64,17 +64,38 @@ public class TemplateSource {
         this.encoding = encoding;
     }
 
+    /**
+     * Template will be loaded from path using a file-base template loader.
+     *
+     * @param path template path
+     * @return file-based template source
+     */
     public static TemplateSource fromPath(String path) {
         Validate.notEmpty(path, "Template path is empty");
         return new TemplateSource(path, path, StandardCharsets.UTF_8);
     }
 
+    /**
+     * Template will be loaded from path using a file-base template loader.
+     *
+     * @param path template path
+     * @param encoding character encoding og template
+     * @return file-based template source
+     */
+
     public static TemplateSource fromPath(String path, Charset encoding) {
         Validate.notEmpty(path, "Template path is empty");
         Validate.notNull(encoding, "Template encoding is null");
         return new TemplateSource(path, path, encoding);
     }
 
+    /**
+     * Template will be loaded from a literal content.
+     *
+     * @param name name of the template
+     * @param code template code
+     * @return template source
+     */
     public static TemplateSource fromCode(String name, String code) {
         Validate.notEmpty(name, "Template name is empty");
         Validate.notEmpty(code, "Template code is empty");
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformations.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformations.java
index ed65111..6c09b60 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformations.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformations.java
@@ -22,6 +22,9 @@ import java.util.List;
 
 import static java.util.Objects.requireNonNull;
 
+/**
+ * Keeps track of all transformations being executed.
+ */ 
 public class TemplateTransformations {
 
     private final List<TemplateTransformation> templateTransformations;
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/UriFragmentParser.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/UriFragmentParser.java
index 839cba7..2242b90 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/UriFragmentParser.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/UriFragmentParser.java
@@ -24,7 +24,7 @@ import static java.util.stream.Collectors.toMap;
 import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty;
 
 /**
- * Parses the URI fragment as list of name/value pairs seperated by an ampersand.
+ * Parses the URI fragment as list of name/value pairs separated by an ampersand.
  */
 public class UriFragmentParser {
 
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
index e04d16a..369bf90 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
@@ -58,7 +58,10 @@ public class ListUtils {
      * @return copied array
      */
     public static <T> T coalesce(List<T> list) {
-        return list.stream().filter(Objects::nonNull).findFirst().orElseGet(() -> null);
+        return list.stream()
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElse(null);
     }
 
     /**
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java
index af2b497..114b61d 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java
@@ -19,7 +19,7 @@ package org.apache.freemarker.generator.base.util;
 import java.io.File;
 
 /**
- * Simple validation methods designed for interal use.
+ * Simple validation methods designed for internal use.
  */
 public final class Validate {
 
diff --git a/freemarker-generator-base/src/site/markdown/index.md b/freemarker-generator-base/src/site/markdown/index.md
index 2fd9f95..212345d 100644
--- a/freemarker-generator-base/src/site/markdown/index.md
+++ b/freemarker-generator-base/src/site/markdown/index.md
@@ -1 +1,3 @@
-TBD
\ No newline at end of file
+# Apache FreeMarker CLI Base
+
+This package contains infrastructure code not depending on `Apache FreeMarker` directly since `DataSources` and their creation might be useful for un-related command-line tools.
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesTest.java
index b4cf812..c97de8f 100644
--- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesTest.java
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesTest.java
@@ -90,7 +90,6 @@ public class DataSourcesTest {
         assertEquals("unknown", dataSources().get(0).getName());
         assertEquals("pom.xml", dataSources().get(1).getName());
         assertEquals("server.invalid", dataSources().get(2).getName());
-        assertEquals("unknown", dataSources().getFirst().getName());
         assertEquals(3, dataSources.getList().size());
         assertEquals(3, dataSources.size());
         assertFalse(dataSources.isEmpty());
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateSourceFactoryTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateSourceFactoryTest.java
index 1d84c90..7a40e52 100644
--- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateSourceFactoryTest.java
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateSourceFactoryTest.java
@@ -31,9 +31,8 @@ public class TemplateSourceFactoryTest {
 
     private static final String ANY_TEMPLATE_PATH = "any/template/path.ftl";
     private static final String ANY_FILE_NAME = "pom.xml";
-    private static final String ANY_URL = "https://jsonplaceholder.typicode.com/posts/2";
+    private static final String ANY_URL = "https://raw.githubusercontent.com/apache/freemarker-generator/master/freemarker-generator-cli/templates/info.ftl";
     private static final String ANY_ENVIRONMENT_VARIABLE = "env:///PWD";
-    private static final String ANY_NAMED_URI = "content:www=https://www.google.com?foo=bar#contenttype=application/json";
 
     @Test
     public void shouldCreateFromTemplatePath() {
@@ -66,7 +65,7 @@ public class TemplateSourceFactoryTest {
     }
 
     @Test
-    @Ignore("Requires internet access")
+    // @Ignore("Requires internet access")
     public void shouldCreateFromUrl() {
         final TemplateSource templateSource = TemplateSourceFactory.create(ANY_URL);
 
@@ -77,11 +76,11 @@ public class TemplateSourceFactoryTest {
     }
 
     @Test
-    @Ignore("Requires internet access")
+    // @Ignore("Requires internet access")
     public void shouldCreateFromNamedUri() {
-        final TemplateSource templateSource = TemplateSourceFactory.create(ANY_NAMED_URI);
+        final TemplateSource templateSource = TemplateSourceFactory.create("info=" + ANY_URL);
 
-        assertNotNull(templateSource.getName());
+        assertEquals("info", templateSource.getName());
         assertEquals(Origin.CODE, templateSource.getOrigin());
         assertNull(templateSource.getPath());
         assertFalse(templateSource.getCode().isEmpty());
diff --git a/CHANGELOG.md b/freemarker-generator-cli/CHANGELOG.md
similarity index 88%
rename from CHANGELOG.md
rename to freemarker-generator-cli/CHANGELOG.md
index 2d33b61..32ab747 100644
--- a/CHANGELOG.md
+++ b/freemarker-generator-cli/CHANGELOG.md
@@ -12,7 +12,6 @@ All notable changes to this project will be documented in this file. We try to a
 * [FREEMARKER-135] Support user-supplied names for `DataSource` on the command line
 * [FREEMARKER-129] Support `DataSource` exclude pattern in addition to include pattern
 * [FREEMARKER-129] User-defined parameters are passed as `-Pkey=value` instead of using system properties
-* [FREEMARKER-129] Add `freemarker-generator-maven-plugin-sample` for better testing of the Maven plugin
 * [FREEMARKER-129] Migrate `freemarker-cli` into `freemarker-generator` project (see [https://github.com/sgoeschl/freemarker-cli](https://github.com/sgoeschl/freemarker-cli))
 
 ### Changed
@@ -24,12 +23,9 @@ All notable changes to this project will be documented in this file. We try to a
 * [FREEMARKER-129] Use `freemarker.configuration.setting` in `freemarker-cli.properties` to configure FreeMarker
 * [FREEMARKER-129] Provide a `toString()` metheod for all tools
 * [FREEMARKER-129] Use version "0.X.Y" to cater for API changes according to [Semantic Versioning](https://semver.org)
-* [FREEMARKER-129] Change artifact `freemarker-maven-plugin` to `freemarker-generator-maven-plugin`
-* [FREEMARKER-128] Update `freemarker-maven-plugin` to Apache FreeMarker 2.3.29
-
-### Deleted
 
 ### Fixed 
+* [FREEMARKER-147] Complete Maven site documenation
 * [FREEMARKER-127] Site build fails with missing "org/apache/maven/doxia/siterenderer/DocumentContent"
 
 [FREEMARKER-127]: https://issues.apache.org/jira/browse/FREEMARKER-127
@@ -42,4 +38,5 @@ All notable changes to this project will be documented in this file. We try to a
 [FREEMARKER-139]: https://issues.apache.org/jira/browse/FREEMARKER-139
 [FREEMARKER-142]: https://issues.apache.org/jira/browse/FREEMARKER-142
 [FREEMARKER-144]: https://issues.apache.org/jira/browse/FREEMARKER-144
-[FREEMARKER-146]: https://issues.apache.org/jira/browse/FREEMARKER-146
\ No newline at end of file
+[FREEMARKER-146]: https://issues.apache.org/jira/browse/FREEMARKER-146
+[FREEMARKER-147]: https://issues.apache.org/jira/browse/FREEMARKER-147
\ No newline at end of file
diff --git a/freemarker-generator-cli/README.md b/freemarker-generator-cli/README.md
index 70179f2..097a4b5 100644
--- a/freemarker-generator-cli/README.md
+++ b/freemarker-generator-cli/README.md
@@ -1,211 +1,15 @@
-# Apache FreeMarker Generator CLI
+Apache FreeMarker Generator CLI
+=============================================================================
 
-# 1. Is This Project For You?
+This module provides provides the CLI for `Apache FreeMarker`.
 
-You somehow found this GitHub project and wonder if it solves a problem you might have?!
+* Requires JDK 1.8+ on Linux, Mac OSX and Windows
+* Add the bin/freemarker-cli or bin/freemarker-cli.bat to your PATH variable
 
-* You need to transform some structured text document (CSV, HTML, JSON, XML, YAML, Java Property files, access logs) into CSV, HTML, Markdown or Confluence markup?
-* You need to convert an Excel document into CSV, HTML or Markdown?
-* You need to create a nice-looking PDF from some boring-looking CSV or JSON content ?
+Now you can have a look at the command line options
 
-The goal of `freemarker-cli` is to automate repeated transformation tasks 
-
-* Which are too boring to be done manually 
-* Which happen not often enough to write a dedicated script or program
-
-# 2. Once Upon A Time
-
-In December 2015 I needed a little bit of test data management for a customer project - to make a long story short (after writing a few more Groovy scripts) it boiled down to transforming one or more JSON files to something human readable.
-
-What are the options?
-
-* The cool kids say 'Node.js' - but they always say 'Node.js' 
-* Some fancy Groovy scripts using Groovy's markup builder - but the syntax looks a bit odd
-* Using 'JsonPath' and 'Velocity' to reuse good & old stuff
-
-So I went with 'Apache Groovy', 'JsonPath' and 'Apache Velocity'
-
-* Playing with Groovy over the public holidays
-* Groovy has a built-in package manager which makes distribution a breeze
-* Providing samples to transform JSON to Markdown
-
-Using Velocity actually created some minor issues so I migrated to [Apache FreeMarker](https://freemarker.apache.org) during Christmas 2016
-
-* Velocity 1.7 was released 2010 and only recently there was a new release
-* I was painful to get Velocity Tools working
-* Velocity XML processing support is also painful
-* Spring 4.3 deprecated Velocity support which could affect me in the long run
-* FreeMarker has no additional dependencies and things are just working :-)
-
-While I love Apache Velocity (Apache Turbine anyone?) I decided to give FreeMarker a chance and migrated my [velocity-cli](https://github.com/sgoeschl/velocity-cli) to FreeMarker.
-
-Some years later the not-so-small-any-longer-and-not-having-tests Groovy script was still growing so I decided 
-
-* To ditch Groovy and migrate to plain JDK 8
-* Write unit tests since I had no more excuses
-* To ditch Commons CLI and migrate to [Picocli](https://picocli.info)
-
-# 3. Design Goals
-
-* Create a proper command-line tool which has Unix look & feel
-* Handle arbitrary large input and output data
-* Support multiple source files/directories for a single transformation
-* Support transformation of Property files using plain-vanilla JDK
-* Support transformation of CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)
-* Support transformation of JSON using [Jayway's JSONPath](https://github.com/jayway/JsonPath) and [GSON](https://github.com/google/gson)
-* Support transformation of Excel using [Apache POI](https://poi.apache.org)
-* Support transformation of YAML using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)
-* Support transformation of HTML using [JSoup](https://jsoup.org)
-* Support transformation of structured logfiles using [Grok](https://github.com/thekrakken/java-grok)
-* XML & XPath is supported by FreeMarker [out-of-the-box](http://freemarker.org/docs/xgui.html)
-* Support for reading a data source content from STDIN to integrate with command line tools
-* Support execution of arbitrary commands using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)
-* Add some commonly useful information such as `System Properties`, `Enviroment Variables`
-* Support embedding the code in existing applications
-
-# 4. Installation
-
-Download the latest release from [GitHub](https://github.com/sgoeschl/freemarker-cli/releases), e.g. [freemarker-cli-2.0.0-BETA-5-app.tar.gz](https://github.com/sgoeschl/freemarker-cli/releases/download/v2.0.0-BETA-4/freemarker-cli-2.0.0-BETA-5-app.tar.gz) and unpack it into of a directory of your choice, e.g `/Application/Java/freemarker-cli`
-
-It is recommended 
-
-* To add `bin/freemarker-cli` or `bin/freemarker-cli.bat` to your executable path
-* To create a `~/.freemarker-cli` directory to store your custom FTL templates
-
-You can test the installation by executing
-
-```text
-> ./bin/freemarker-cli -t templates/info.ftl
-FreeMarker CLI Information
-------------------------------------------------------------------------------
-FreeMarker version     : 2.3.30
-Template name          : info.ftl
-Language               : en
-Locale                 : en_US
-Timestamp              : Jun 18, 2020 10:55:04 AM
-Output encoding        : UTF-8
-Output format          : plainText
-
-FreeMarker CLI Template Directories
-------------------------------------------------------------------------------
-[#1] /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler
-[#2] /Users/sgoeschl/.freemarker-cli
-
-FreeMarker CLI Tools
-------------------------------------------------------------------------------
-- CSVTool              : Process CSV files using Apache Commons CSV (see https://commons.apache.org/proper/commons-csv/)
-- DataFrameTool        : Bridge to nRo/DataFrame (see https://github.com/nRo/DataFrame)
-- ExcelTool            : Process Excels files (XLS, XLSX) using Apache POI (see https://poi.apache.org)
-- ExecTool             : Execute command line tools using Apache Commons Exec (see https://commons.apache.org/proper/commons-exec/)
-- FreeMarkerTool       : Expose useful Apache FreeMarker classes
-- GrokTool             : Process text files using Grok expressions (see https://github.com/thekrakken/java-grok)
-- GsonTool             : Process JSON files using GSON (see https://github.com/google/gson)
-- JsonPathTool         : Process JSON files using Java JSON Path (see https://github.com/json-path/JsonPath)
-- JsoupTool            : Process  HTML files using Jsoup (see https://jsoup.org)
-- PropertiesTool       : Process JDK properties files
-- SystemTool           : Expose System-related utility methods
-- UUIDTool             : Create UUIDs
-- XmlTool              : Process XML files using Apache FreeMarker (see https://freemarker.apache.org/docs/xgui.html)
-- YamlTool             : Process YAML files using SnakeYAML(see https://bitbucket.org/asomov/snakeyaml/wiki/Home)
-
-FreeMarker CLI Data Model
----------------------------------------------------------------------------
-- CSVTool
-- DataFrameTool
-- DataSources
-- ExcelTool
-- ExecTool
-- FreeMarkerTool
-- GrokTool
-- GsonTool
-- JsonPathTool
-- JsoupTool
-- PropertiesTool
-- SystemTool
-- UUIDTool
-- XmlTool
-- YamlTool
 ```
-
-There a many examples (see below) available you can execute - run `./run-examples.sh` and have a look at the generated output
-
-```text
-./run-examples.sh 
-templates/info.ftl
-examples/templates/demo.ftl
-templates/csv/html/transform.ftl
-examples/templates/csv/md/transform.ftl
-examples/templates/csv/shell/curl.ftl
-examples/templates/csv/md/filter.ftl
-examples/templates/csv/fo/transform.ftl
-fop -fo target/out/locker-test-users.fo target/out/locker-test-users.pdf
-examples/templates/csv/fo/transactions.ftl
-fop -fo target/out/transactions.fo target/out/transactions-fo.pdf
-templates/csv/html/transform.ftl
-wkhtmltopdf -O landscape target/out/transactions.html target/out/transactions-html.pdf
-examples/templates/dataframe/example.ftl
-examples/templates/accesslog/combined-access.ftl
-examples/templates/excel/dataframe/transform.ftl
-templates/excel/html/transform.ftl
-templates/excel/md/transform.ftl
-templates/excel/csv/transform.ftl
-examples/templates/excel/csv/custom.ftl
-examples/templates/html/csv/dependencies.ftl
-examples/templates/json/csv/swagger-endpoints.ftl
-templates/json/yaml/transform.ftl
-examples/templates/json/md/github-users.ftl
-examples/templates/properties/csv/locker-test-users.ftl
-examples/data/template
-examples/templates/yaml/txt/transform.ftl
-templates/yaml/json/transform.ftl
-examples/templates/xml/txt/recipients.ftl
-Created the following sample files in ./target/out
-total 1576
--rw-r--r--  1 sgoeschl  staff     646 Jun 18 10:56 combined-access.log.txt
--rw-r--r--  1 sgoeschl  staff   22548 Jun 18 10:56 contract.html
--rw-r--r--  1 sgoeschl  staff    7933 Jun 18 10:56 contract.md
--rw-r--r--  1 sgoeschl  staff     784 Jun 18 10:56 curl.sh
--rw-r--r--  1 sgoeschl  staff     232 Jun 18 10:56 customer.txt
--rw-r--r--  1 sgoeschl  staff    6488 Jun 18 10:56 dataframe.txt
--rw-r--r--  1 sgoeschl  staff   15632 Jun 18 10:56 demo.txt
--rw-r--r--  1 sgoeschl  staff    1310 Jun 18 10:56 dependencies.csv
--rw-r--r--  1 sgoeschl  staff    2029 Jun 18 10:56 github-users-curl.md
--rw-r--r--  1 sgoeschl  staff    2630 Jun 18 10:56 info.txt
--rw-r--r--  1 sgoeschl  staff    8075 Jun 18 10:56 interactive-dataframe.txt
--rw-r--r--  1 sgoeschl  staff      66 Jun 18 10:56 interactive-html.txt
--rw-r--r--  1 sgoeschl  staff      16 Jun 18 10:56 interactive-json.txt
--rw-r--r--  1 sgoeschl  staff   25090 Jun 18 10:56 interactive-swagger.json
--rw-r--r--  1 sgoeschl  staff   16870 Jun 18 10:56 interactive-swagger.yaml
--rw-r--r--  1 sgoeschl  staff      10 Jun 18 10:56 interactive-xml.txt
--rw-r--r--  1 sgoeschl  staff     285 Jun 18 10:56 locker-test-users.csv
--rw-r--r--  1 sgoeschl  staff    6341 Jun 18 10:56 locker-test-users.fo
--rw-r--r--  1 sgoeschl  staff    5526 Jun 18 10:56 locker-test-users.pdf
--rw-r--r--  1 sgoeschl  staff     921 Jun 18 10:56 recipients.txt
--rw-r--r--  1 sgoeschl  staff     910 Jun 18 10:56 sales-records.md
--rw-r--r--  1 sgoeschl  staff    2453 Jun 18 10:56 swagger-spec.csv
--rw-r--r--  1 sgoeschl  staff   25090 Jun 18 10:56 swagger-spec.json
--rw-r--r--  1 sgoeschl  staff   16870 Jun 18 10:56 swagger-spec.yaml
-drwxr-xr-x  4 sgoeschl  staff     128 Jun 18 10:49 template
--rw-r--r--  1 sgoeschl  staff     156 Jun 18 10:56 test-multiple-sheets.xlsx.csv
--rw-r--r--  1 sgoeschl  staff    1917 Jun 18 10:56 test-multiple-sheets.xlsx.html
--rw-r--r--  1 sgoeschl  staff     389 Jun 18 10:56 test-multiple-sheets.xlsx.md
--rw-r--r--  1 sgoeschl  staff     157 Jun 18 10:56 test-transform-xls.csv
--rw-r--r--  1 sgoeschl  staff    1439 Jun 18 10:56 test.xls.dataframe.txt
--rw-r--r--  1 sgoeschl  staff    1556 Jun 18 10:56 test.xls.html
--rw-r--r--  1 sgoeschl  staff    1558 Jun 18 10:56 test.xslx.html
--rw-r--r--  1 sgoeschl  staff   25760 Jun 18 10:56 transactions-fo.pdf
--rw-r--r--  1 sgoeschl  staff   66016 Jun 18 10:56 transactions-html.pdf
--rw-r--r--  1 sgoeschl  staff  330129 Jun 18 10:56 transactions.fo
--rw-r--r--  1 sgoeschl  staff   51008 Jun 18 10:56 transactions.html
-
-```
-
-Please note that generated PDF files are very likely not found since they require `wkhtmltopdf` and `Apache FOP` installation.
-
-# 5. Usage
-
-```text
-> ./bin/freemarker-cli  -h
+freemarker-cli -h
 Usage: freemarker-cli (-t=<templates> [-t=<templates>]... |
                       -i=<interactiveTemplate>) [-hV] [--stdin] [-b=<baseDir>]
                       [--config=<configFile>] [--data-source-exclude=<exclude>]
@@ -245,1317 +49,85 @@ Apache FreeMarker CLI
                             template to process
       --times=<times>       re-run X times for profiling
   -V, --version             Print version information and exit.
-
 ```
 
-# 6. Examples
+Check the version of the `Apache FreeMarker CLI`
 
-The examples were tested with JDK 1.8 on Mac OS X
-
-```text
-> java -version
-java version "1.8.0_192"
-Java(TM) SE Runtime Environment (build 1.8.0_192-b12)
-Java HotSpot(TM) 64-Bit Server VM (build 25.192-b12, mixed mode)
 ```
-It is assumed that you run the examples from the `freemarker-cli` installation directory.
-
-## 6.1 Transforming GitHub JSON To Markdown
-
-A simple example with real JSON data to be transformed into Markdown
-
-### Invocation
-
-You can either use the existing JSON sample
-
-> ./bin/freemarker-cli -t examples/templates/json/md/github-users.ftl examples/data/json/github-users.json
-
-or pipe a cURL response
-
-> curl -s https://api.github.com/users | ./bin/freemarker-cli -t examples/templates/json/md/github-users.ftl --stdin
-
-### FreeMarker Template
-
-```text
-<#ftl output_format="plainText" >
-<#assign json = JsonPathTool.parse(DataSources.get(0))>
-<#assign users = json.read("$[*]")>
-<#--------------------------------------------------------------------------->
-# GitHub Users
-
-Report generated at ${.now?iso_utc}
-
-<#compress>
-<#list users as user>
-<#assign userAvatarUrl = user.avatar_url>
-<#assign userHomeUrl = user.html_url>
-# ${user.login}
-
-| User                                                    | Homepage                                      |
-|:--------------------------------------------------------|:----------------------------------------------|
-| <img src="${user.avatar_url}" width="48" height="48"/> | [${userHomeUrl}](${userHomeUrl})               |
-</#list>
-</#compress>
+freemarker-cli -V
+version=0.1.0-SNAPSHOT, time=2020-06-25T21:48:02+0200, commit=b320d00094be8789086ad6153d9d3fcaf4b8c75f
 ```
 
-creates the following output
-
-![](./site/image/github.png)
-
-## 6.2 CSV to HTML/Markdown Transformation
-
-Sometimes you have a CSV file which needs to be translated in Markdown or HTML - there are on-line solutions available such as [CSV To Markdown Table Generator](https://donatstudios.com/CsvToMarkdownTable) but having a local solution gives you more flexibility.
-
-```text
-> ./bin/freemarker-cli -t templates/csv/md/transform.ftl examples/data/csv/contract.csv
-> ./bin/freemarker-cli -t templates/csv/html/transform.ftl examples/data/csv/contract.csv
-```
-
-The FreeMarker template is shown below
-
-```text
-<#ftl output_format="plainText">
-<#assign cvsFormat = CSVTool.formats["DEFAULT"].withHeader()>
-<#assign csvParser = CSVTool.parse(DataSources.get(0), cvsFormat)>
-<#assign csvHeaders = csvParser.getHeaderMap()?keys>
-<#assign csvRecords = csvParser.records>
-<#--------------------------------------------------------------------------->
-<#compress>
-<@writeHeaders headers=csvHeaders/>
-<@writeColums columns=csvRecords/>
-</#compress>
-<#--------------------------------------------------------------------------->
-<#macro writeHeaders headers>
-| ${csvHeaders?join(" | ", "")} |
-    <#list csvHeaders as csvHeader>| --------</#list>|
-</#macro>
-<#--------------------------------------------------------------------------->
-<#macro writeColums columns>
-    <#list columns as column>
-    | ${column.iterator()?join(" | ", "")} |
-    </#list>
-</#macro>
-```
-
-The resulting file actually looks pleasant when compared to raw CSV
-
-![Contract CSV to HTML](./site/image/contract.png "Contract CSV to HTML")
-
-## 6.3 Transform XML To Plain Text
-
-Of course you can also transform a XML document
-
-```text
-> ./bin/freemarker-cli -t examples/templates/xml/txt/recipients.ftl examples/data/xml/recipients.xml
-```
-
-using the following template
-
-```text
-<#ftl output_format="plainText" >
-<#assign xml = XmlTool.parse(DataSources.get(0))>
-<#list xml.recipients.person as recipient>
-To: ${recipient.name}
-${recipient.address}
-
-Dear ${recipient.name},
-
-Thank you for your interest in our products. We will be sending you a catalog shortly.
-To take advantage of our free gift offer, please fill in the survey attached to this
-letter and return it to the address on the reverse. Only one participant is allowed for
-each household.
-
-Sincere salutations,
-
-
-D. H.
-
----------------------------------------------------------------------------------------
-</#list>
+Or run the examples 
 
 ```
-
-which generates the following output
-
-```text
-To: John Smith
-3033 Long Drive, Houston, TX
-
-Dear John Smith,
-
-Thank you for your interest in our products. We will be sending you a catalog shortly.
-To take advantage of our free gift offer, please fill in the survey attached to this
-letter and return it to the address on the reverse. Only one participant is allowed for
-each household.
-
-Sincere salutations,
-
-
-D. H.
-```
-
-## 6.4 Transform JSON To CSV
-
-One day I was asked a to prepare a CSV files containing REST endpoints described by Swagger - technically this is a JSON to CSV transformation. Of course I could create that CSV manually but writing a FTL template doing that was simply more fun and saves time in the future.
-
-```text
-<#ftl output_format="plainText" strip_text="true">
-<#assign json = JsonPathTool.parse(DataSources.get(0))>
-<#assign basePath = json.read("$.basePath")>
-<#assign paths = json.read("$.paths")>
-
-<#compress>
-    ENDPOINT;METHOD;CONSUMES;PRODUCES;SUMMARY;DESCRIPTION
-    <#list paths as endpoint,metadata>
-        <#assign relative_url = basePath + endpoint>
-        <#assign methods = metadata?keys>
-        <#list methods as method>
-            <#assign summary = sanitize(paths[endpoint][method]["summary"]!"")>
-            <#assign description = sanitize(paths[endpoint][method]["description"]!"")>
-            <#assign consumes = join(paths[endpoint][method]["consumes"]![])>
-            <#assign produces = join(paths[endpoint][method]["produces"]![])>
-            ${relative_url};${method?upper_case};${consumes};${produces};${summary};${description}
-        </#list>
-    </#list>
-</#compress>
-${'\n'}
-
-<#function sanitize str>
-    <#return (((str?replace(";", ","))?replace("(\\n)+", "",'r')))?truncate(250)>
-</#function>
-
-<#function join list>
-    <#if list?has_content>
-        <#return list?join(", ")>
-    <#else>
-        <#return "">
-    </#if>
-</#function>
-```
-
-Invoking the FTL template
-
-> ./bin/freemarker-cli -t examples/templates/json/csv/swagger-endpoints.ftl examples/data/json/swagger-spec.json 
-
-gives you
-
-```text
-ENDPOINT;METHOD;CONSUMES;PRODUCES;SUMMARY;DESCRIPTION
-/api/pets;GET;;;;Returns all pets from the system that the user has access to
-/api/pets;POST;;;;Creates a new pet in the store. Duplicates are allowed
-/api/pets/{id};GET;;;;Returns a user based on a single ID, if the user does not have access to the pet
-/api/pets/{id};DELETE;;;;Deletes a single pet based on the ID supplied
-```
-
-## 6.5 Transforming Excel Documents
-
-Another day my project management asked me to create a CSV configuration file based on an Excel documents - as usual manual copying was not an option due to required data cleanup and data transformation. So I thought about Apache POI which support XLS and XLSX documents - integration of Apache POI was a breeze but the resulting code was not particularly useful example. So a more generic transformation was provided to show the transformation of Excel documents ...
-
-```text
-> ./bin/freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test.xls
-> ./bin/freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test.xlsx
-> ./bin/freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test-multiple-sheets.xlsx
-> ./bin/freemarker-cli -t templates/excel/md/transform.ftl examples/data/excel/test-multiple-sheets.xlsx
-```
-
-The provided FTL transforms an Excel into a HTML document supporting multiple Excel sheets
-
-```text
-<#ftl output_format="HTML" >
-<#assign dataSource = DataSources.get(0)>
-<#assign name = dataSource.name>
-<#assign workbook = ExcelTool.parse(dataSource)>
-<#assign date = .now?iso_utc>
-<#--------------------------------------------------------------------------->
-<!DOCTYPE html>
-<html>
-<head>
-    <title>${name}</title>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
-</head>
-<body>
-<div class="container-fluid">
-    <h1>Excel Test
-        <small>${name}, ${date}</small>
-    </h1>
-    <@writeSheets workbook/>
-</div>
-</body>
-</html>
-
-<#--------------------------------------------------------------------------->
-<#-- writeSheets                                                           -->
-<#--------------------------------------------------------------------------->
-<#macro writeSheets workbook>
-    <#assign sheets = ExcelTool.getSheets(workbook)>
-    <#list sheets as sheet>
-        <@writeSheet sheet/>
-    </#list>
-</#macro>
-
-<#--------------------------------------------------------------------------->
-<#-- writeSheet                                                            -->
-<#--------------------------------------------------------------------------->
-<#macro writeSheet sheet>
-    <#assign rows = ExcelTool.toTable(sheet)>
-    <h2>${sheet.getSheetName()}</h2>
-    <@writeRows rows/>
-</#macro>
-
-<#--------------------------------------------------------------------------->
-<#-- writeRows                                                             -->
-<#--------------------------------------------------------------------------->
-<#macro writeRows rows>
-    <table class="table table-striped">
-        <#list rows as row>
-            <#if row?is_first>
-                <tr>
-                    <th>#</th>
-                    <#list row as column>
-                        <th>${column}</th>
-                    </#list>
-                </tr>
-            <#else>
-                <tr>
-                    <td>${row?index}</td>
-                    <#list row as column>
-                        <td>${column}</td>
-                    </#list>
-                </tr>
-            </#if>
-        </#list>
-    </table>
-</#macro>
-```
-
-but the result looks reasonable
-
-![](./site/image/excel-to-html.png)
-
-## 6.6 Transform Property Files To CSV
-
-In this sample we transform all property files found in a directory (recursive search using include pattern) to a CSV file
-
-```text
-> ./bin/freemarker-cli --data-source-include *.properties -t examples/templates/properties/csv/locker-test-users.ftl examples/data/properties
-TENANT,SITE,USER_ID,DISPOSER_ID,PASSWORD,SMS_OTP,NAME,DESCRIPTION
-TENANT_A,fat,user_0004,user_0004,password_0004,,,
-TENANT_B,fat,user_0001,user_0001,password_0001,,,
-TENANT_B,uat,user_0003,user_0003,password_0003,,,
-TENANT_C,fat,user_0002,user_0002,password_0004,000000,,Many products
-```
-
-The FTL uses a couple of interesting features
-
-* We process a list of property files
-* The `strip_text` and `compress` strips any white-spaces and line-breaks from the output so we can create a proper CSV file
-* We use FTL functions to extract the `tenant` and `site`, e.g. `extractTenant`
-* We add a manual line break using ```${'\n'}```
-
-```text
-<#ftl output_format="plainText" strip_text="true">
-<#compress>
-    TENANT,SITE,USER_ID,DISPOSER_ID,PASSWORD,SMS_OTP,NAME,DESCRIPTION
-    <#list DataSources.list as dataSource>
-        <#assign properties = PropertiesTool.parse(dataSource)>
-        <#assign environments = properties["ENVIRONMENTS"]!"">
-        <#assign tenant = extractTenant(environments)>
-        <#assign site = extractSite(environments)>
-        <#assign userId = properties["USER_ID"]!"">
-        <#assign disposerId = properties["USER_ID"]!"">
-        <#assign password = properties["PASSWORD"]!"">
-        <#assign smsOtp = properties["SMS_OTP"]!"">
-        <#assign name = properties["NAME"]!"">
-        <#assign description = properties["DESCRIPTION"]!"">
-        ${tenant},${site},${userId},${disposerId},${password},${smsOtp},${name},${description}
-    </#list>
-</#compress>
-${'\n'}
-
-<#function extractSite environments>
-</#function>
-
-<#function extractTenant environments>
-</#function>
-
-```
-
-## 6.7 Transform CSV To XML-FO
-
-For a POC (proof of concept) I created a sample transformation from CSV to XML-FO in order to create a PDF document using [Apache FOP](https://xmlgraphics.apache.org/fop) using the following template file
-
-```text
-<#ftl output_format="XML" >
-<#assign dataSource = DataSources.get(0)>
-<#assign name = dataSource.name>
-<#assign cvsFormat = CSVTool.formats.DEFAULT.withDelimiter('\t').withHeader()>
-<#assign csvParser = CSVTool.parse(dataSource, cvsFormat)>
-<#assign csvHeaders = csvParser.getHeaderMap()?keys>
-<#assign csvRecords = csvParser.records>
-<#--------------------------------------------------------------------------->
-<?xml version="1.0" encoding="UTF-8"?>
-
-<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
-    <fo:layout-master-set>
-        <fo:simple-page-master master-name="first"
-                               page-height="21cm"
-                               page-width="29.7cm"
-                               margin-top="1cm"
-                               margin-bottom="1cm"
-                               margin-left="1cm"
-                               margin-right="1cm">
-            <fo:region-body margin-top="1cm"/>
-            <fo:region-before extent="1cm"/>
-            <fo:region-after extent="-1.2cm"/>
-        </fo:simple-page-master>
-    </fo:layout-master-set>
-    <fo:page-sequence master-reference="first">
-        <fo:static-content flow-name="xsl-region-before">
-            <fo:block line-height="10pt" font-size="8pt" text-align="left">Transaction Export - ${.now}</fo:block>
-        </fo:static-content>
-        <fo:static-content flow-name="xsl-region-after">
-            <fo:block line-height="6pt" font-size="6pt" text-align="end">Page <fo:page-number/></fo:block>
-        </fo:static-content>
-        <fo:flow flow-name="xsl-region-body">
-            <fo:table table-layout="fixed" width="100%" border-collapse="separate">
-                <fo:table-column column-width="8%"/>
-                <fo:table-column column-width="10%"/>
-                <fo:table-column column-width="12%"/>
-                <fo:table-column column-width="8%"/>
-                <fo:table-column column-width="7%"/>
-                <fo:table-column column-width="5%"/>
-                <fo:table-column column-width="5%"/>
-                <fo:table-column column-width="5%"/>
-                <fo:table-column column-width="35%"/>
-                <fo:table-column column-width="5%"/>
-                <@writeTableHeader headers=csvHeaders/>
-                <@writeTableBody columns=csvRecords/>
-            </fo:table>
-        </fo:flow>
-    </fo:page-sequence>
-</fo:root>
-
-<#--------------------------------------------------------------------------->
-<#macro writeTableHeader headers>
-    <fo:table-header>
-        <fo:table-row>
-            <#list headers as header>
-                <fo:table-cell border-style="solid" border-width="0.1pt" padding-left="1.0px" padding-right="1.0px">
-                    <fo:block font-size="6pt" font-weight="bold">${header}</fo:block>
-                </fo:table-cell>
-            </#list>
-        </fo:table-row>
-    </fo:table-header>
-</#macro>
-
-<#--------------------------------------------------------------------------->
-<#macro writeTableBody columns>
-    <fo:table-body>
-        <#list columns as column>
-            <fo:table-row>
-                <#list column.iterator() as field>
-                    <fo:table-cell border-style="solid" border-width="0.1pt" padding-left="1.0px" padding-right="1.0px">
-                        <fo:block font-size="6pt">${field}</fo:block>
-                    </fo:table-cell>
-                </#list>
-            </fo:table-row>
-        </#list>
-    </fo:table-body>
-</#macro>
-
-```
-
-In order to create the PDF you need to execute the following commands (assuming that you have Apache FOP installed)
-
-```text
-> ./bin/freemarker-cli -t examples/templates/csv/fo/transform.ftl examples/data/csv/locker-test-users.csv > sample.fo
-> fop -fo sample.fo sample.pdf
-Dec 29, 2018 10:24:30 PM org.apache.fop.events.LoggingEventListener processEvent
-WARNING: Font "Symbol,normal,700" not found. Substituting with "Symbol,normal,400".
-Dec 29, 2018 10:24:30 PM org.apache.fop.events.LoggingEventListener processEvent
-WARNING: Font "ZapfDingbats,normal,700" not found. Substituting with "ZapfDingbats,normal,400".
-Dec 29, 2018 10:24:30 PM org.apache.fop.events.LoggingEventListener processEvent
-INFO: Rendered page #1.
-```
-
-The result does not look very impressive but it is a PDF :-)
-
-![](./site/image/locker-test-users-pdf.png)
-
-Further along the line of the POC we converted a transaction export from CSV to PDF using Apache FOP
-
-```text
-> ./bin/freemarker-cli -t examples/templates/csv/fo/transactions.ftl examples/data/csv/transactions.csv > transactions.fo
-> fop -fo transactions.fo transactions.pdf
-Jan 16, 2019 11:15:21 PM org.apache.fop.events.LoggingEventListener processEvent
-WARNING: Font "Symbol,normal,700" not found. Substituting with "Symbol,normal,400".
-Jan 16, 2019 11:15:21 PM org.apache.fop.events.LoggingEventListener processEvent
-WARNING: Font "ZapfDingbats,normal,700" not found. Substituting with "ZapfDingbats,normal,400".
-Jan 16, 2019 11:15:21 PM org.apache.fop.events.LoggingEventListener processEvent
-WARNING: The contents of fo:block line 1 exceed the available area in the inline-progression direction by 11027 millipoints. (See position 1519:51)
-Jan 16, 2019 11:15:22 PM org.apache.fop.events.LoggingEventListener processEvent
-INFO: Rendered page #1.
-Jan 16, 2019 11:15:22 PM org.apache.fop.events.LoggingEventListener processEvent
-INFO: Rendered page #2.
-```
-
-![](./site/image/transactions.png)
-
-## 6.8 Transforming HTML To CSV
-
-Recently I got the rather unusual question how to determine the list of dependencies of an application - one easy way is the Maven "dependencies.html" but this is unstructured data. Having said that the Jsoup library is perfectly able to parse most real-life HTML and provides a DOM model
-
-```text
-<#ftl output_format="plainText" strip_text="true">
-<#assign dataSource = DataSources.get(0)>
-<#assign html = JsoupTool.parse(dataSource)>
-
-<#compress>
-    <@writeHeader/>
-    <@writeDependencies "Project_Dependencies_compile"/>
-    <@writeDependencies "Project_Transitive_Dependencies_compile"/>
-    <@writeDependencies "Project_Transitive_Dependencies_runtime"/>
-    <@writeDependencies "Project_Transitive_Dependencies_provided"/>
-</#compress>
-
-<#macro writeHeader>
-    GroupId,ArtifactId,Version,Type,Licenses
-</#macro>
-
-<#macro writeDependencies section>
-    <#assign selection = html.select("a[name=${section}]")>
-    <#if selection?has_content>
-        <#assign table = selection[0].nextElementSibling().child(2).child(0)>
-        <#assign rows = table.children()>
-        <#list rows as row>
-            <#if !row?is_first>
-                <#assign groupId = row.child(0).text()>
-                <#assign artificatId = row.child(1).text()>
-                <#assign version = row.child(2).text()>
-                <#assign type = row.child(3).text()>
-                <#assign licences = row.child(4).text()?replace(",", "")>
-                ${groupId},${artificatId},${version},${type},${licences}
-            </#if>
-        </#list>
-    </#if>
-</#macro>
-
-
-```
-
-Your dependencies as CSV can be generated as shown below
-
-```text
-> ./bin/freemarker-cli -t examples/templates/html/csv/dependencies.ftl examples/data/html/dependencies.html 
-GroupId,ArtifactId,Version,Type,Licenses
-com.jayway.jsonpath,json-path,2.4.0,jar,The Apache Software License Version 2.0
-commons-cli,commons-cli,1.4,jar,Apache License Version 2.0
-org.apache.commons,commons-csv,1.5,jar,Apache License Version 2.0
-org.apache.poi,poi,4.0.1,jar,The Apache Software License Version 2.0
-org.apache.poi,poi-ooxml,3.17,jar,The Apache Software License Version 2.0
-org.apache.poi,poi-ooxml-schemas,3.17,jar,The Apache Software License Version 2.0
-org.freemarker,freemarker,2.3.28,jar,Apache License Version 2.0
-org.jsoup,jsoup,1.11.3,jar,The MIT License
-org.slf4j,slf4j-api,1.7.21,jar,MIT License
-org.slf4j,slf4j-log4j12,1.7.21,jar,MIT License
-com.github.virtuald,curvesapi,1.04,jar,BSD License
-commons-codec,commons-codec,1.11,jar,Apache License Version 2.0
-log4j,log4j,1.2.17,jar,The Apache Software License Version 2.0
-net.minidev,accessors-smart,1.2,jar,The Apache Software License Version 2.0
-net.minidev,json-smart,2.3,jar,The Apache Software License Version 2.0
-org.apache.commons,commons-collections4,4.2,jar,Apache License Version 2.0
-org.apache.commons,commons-math3,3.6.1,jar,Apache License Version 2.0
-org.apache.xmlbeans,xmlbeans,2.6.0,jar,The Apache Software License Version 2.0
-org.ow2.asm,asm,5.0.4,jar,BSD
-stax,stax-api,1.0.1,jar,The Apache Software License Version 2.0
-```
-
-## 6.9 Transform CSV To Shell Script
-
-For a customer project we wanted to record REST request / responses using WireMock - really quick and dirty. So we decided to avoid any sophisticated test tool but generate a ready-to-use shell script executing cURL commands. It turned out that handling of dollar signs is a bit tricky
-
-* Using ```noparse``` directive to disable parsing of dollar signs
-* Using ```${r"${MY_BASE_URL}"``` to generate output with dollar signs
-
-and the final FTL is found below
-
-```text
-<#ftl output_format="plainText">
-<#assign cvsFormat = CSVTool.formats["DEFAULT"].withHeader()>
-<#assign csvParser = CSVTool.parse(DataSources.get(0), cvsFormat)>
-<#assign records = csvParser.records>
-<#assign csvMap = CSVTool.toMap(records, "disposer")>
-<#--------------------------------------------------------------------------->
-#!/bin/sh
-
-<#noparse>
-MY_BASE_URL=${MY_BASE_URL:=https://postman-echo.com}
-</#noparse>
- 
-echo "time,user,status,duration,size"
-<#list records as record>
-date "+%FT%H:%M:%S" | tr -d '\n'; curl --write-out ',${record.disposer},%{http_code},%{time_total},%{size_download}\n' --silent --show-error --output /dev/null "${r"${MY_BASE_URL}"}/get"
-</#list>
-```
-
-Rendering the FreeMarker template 
-
-```
-> ./bin/freemarker-cli -t ./examples/templates/csv/shell/curl.ftl examples/data/csv/user.csv
-```
-
-generates the following shell script
-
-```
-#!/bin/sh
-
-MY_BASE_URL=${MY_BASE_URL:=https://postman-echo.com}
- 
-echo "time,user,status,duration,size"
-date "+%FT%H:%M:%S" | tr -d '\n'; curl --write-out ',AAAAAAA,%{http_code},%{time_total},%{size_download}\n' --silent --show-error --output /dev/null "${MY_BASE_URL}/get"
-date "+%FT%H:%M:%S" | tr -d '\n'; curl --write-out ',BBBBBBB,%{http_code},%{time_total},%{size_download}\n' --silent --show-error --output /dev/null "${MY_BASE_URL}/get"
-date "+%FT%H:%M:%S" | tr -d '\n'; curl --write-out ',CCCCCCC,%{http_code},%{time_total},%{size_download}\n' --silent --show-error --output /dev/null "${MY_BASE_URL}/get"
-date "+%FT%H:%M:%S" | tr -d '\n'; curl --write-out ',DDDDDDD,%{http_code},%{time_total},%{size_download}\n' --silent --show-error --output /dev/null "${MY_BASE_URL}/get"
-```
-
-Looks a bit complicated but lets dissect the things
-
-* `date "+%FT%H:%M:%S" | tr -d '\n'` creates a timestamp and removes the line feed
-* `curl --write-out` allows to print runtime data (see [https://ec.haxx.se/usingcurl-writeout.html](https://ec.haxx.se/usingcurl-writeout.html))
-
-Executing the result shell script creates the following output (which is a nice CSV for further processing)
-
-```
-time,user,status,duration,size
-2019-09-27T21:02:52,AAAAAAA,200,0.522473,206
-2019-09-27T21:02:53,BBBBBBB,200,0.498093,206
-2019-09-27T21:02:54,CCCCCCC,200,0.529013,206
-2019-09-27T21:02:54,DDDDDDD,200,0.528268,206
-```
-
-## 6.10 Unleashing The Power Of Grok
-
-Think of `Grok` as modular regular expressions with a pre-defined functionality to parse access logs or any other data where you can't comprehend the regular expression any longer, one very simple example is `QUOTEDSTRING`
-
-```
-QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))
-```
-
-And with `Grok` the `QUOTEDSTRING` is just a building block for an even more complex regular expession such as `COMBINEDAPACHELOG`
-
-> bin/freemarker-cli -t examples/templates/accesslog/combined-access.ftl examples/data/accesslog/combined-access.log 
-
-which gives you the following output
-
-```
-TIMESTAMP;VERB;REQUEST;HTTPVERSION
-19/Jun/2005:06:44:17 +0200;GET;/wximages/wxwidgets02-small.png;1.1
-19/Jun/2005:06:46:05 +0200;GET;/wximages/wxwidgets02-small.png;1.1
-19/Jun/2005:06:47:37 +0200;GET;/wximages/wxwidgets02-small.png;1.1
-19/Jun/2005:06:48:40 +0200;GET;/wiki.pl?WxWidgets_Bounties;1.1
-19/Jun/2005:06:50:49 +0200;GET;/wiki.pl?WxWidgets_Compared_To_Other_Toolkits;1.1
-19/Jun/2005:06:50:49 +0200;GET;/wxwiki.css;1.1
-19/Jun/2005:06:50:49 +0200;GET;/wximages/wxwidgets02-small.png;1.1
-19/Jun/2005:06:50:50 +0200;GET;/favicon.ico;1.1
-19/Jun/2005:06:52:36 +0200;GET;/wximages/wxwidgets02-small.png;1.1
-19/Jun/2005:06:53:14 +0200;GET;/;1.0
-```
-
-using the following FreeMarker template
-
-```text
-<#ftl output_format="plainText" strip_whitespace=true>
-<#assign grok = GrokTool.compile("%{COMBINEDAPACHELOG}")>
-<#assign dataSource = DataSources.get(0)>
-<#assign lines = dataSource.getLineIterator()>
-
-<#compress>
-    TIMESTAMP;VERB;REQUEST;HTTPVERSION
-    <#list lines as line>
-        <#assign parts = grok.match(line)>
-        <#assign timestamp = parts["timestamp"]>
-        <#assign verb = parts["verb"]>
-        <#assign request = parts["request"]>
-        <#assign httpversion = parts["httpversion"]>
-        ${timestamp};${verb};${request};${httpversion}
-    </#list>
-</#compress>
-```
-
-While this looks small and tidy there are some nifty features
-
-* `GrokTool.compile("%{COMBINEDAPACHELOG}")` builds the `Grok` instance to parse access logs in `Combined Format`
-* The data source is streamed line by line and not loaded into memory in one piece
-* This also works for using `stdin` so are able to parse GB of access log or other files
-
-## 6.11 CSV Transformation
-
-Sometimes you have a CSV file which is not quite right - you need to change the format. Lets have a look how `freemarker-cli` can help
-
-> bin/freemarker-cli -PCVS_IN_DELIMITER=COMMA -PCSV_TARGET_DELIMITER=PIPE -t templates/csv/csv/transform.ftl ./examples/data/csv/contract.csv 
-
-renders the following template
-
-```text
-<#ftl output_format="plainText" strip_text="true">
-<#assign csvParser = CSVTool.parse(DataSources.get(0))>
-<#assign csvPrinter = CSVTool.printer(SystemTool.writer)>
-<#--
-    Print each record directly to the underyling writer without materializing the CSV in memory.
-    FreeMarker and CSV output are out of sync but millions of records can processed without
-    running out of memory.
--->
-<#compress>
-    <#list csvParser.iterator() as record>
-        ${csvPrinter.printRecord(record)}
-    </#list>
-</#compress>
-```
-
-and generates the following output
-
-```text
-contract_id|seller_company_name|customer_company_name|customer_duns_number|contract_affiliate|FERC_tariff_reference|contract_service_agreement_id|contract_execution_date|contract_commencement_date|contract_termination_date|actual_termination_date|extension_provision_description|class_name|term_name|increment_name|increment_peaking_name|product_type_name|product_name|quantity|units_for_contract|rate|rate_minimum|rate_maximum|rate_description|units_for_rate|point_of_receipt_control_area|po [...]
-C71|The Electric Company|The Power Company|456543333|N|FERC Electric Tariff Original Volume No. 10|2|2/15/2001|2/15/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||||||ES
-C72|The Electric Company|Utility A|38495837|n|FERC Electric Tariff Original Volume No. 10|15|7/25/2001|8/1/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||||||ES
-C73|The Electric Company|Utility B|493758794|N|FERC Electric Tariff Original Volume No. 10|7|6/8/2001|7/6/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||" "|" "|||ep
-C74|The Electric Company|Utility C|594739573|n|FERC Electric Tariff Original Volume No. 10|25|6/8/2001|7/6/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||" "|" "|||ep
-```
-
-Some useful hints
-
-* For available CSV formats please see [Apache Commons CSV User Guide](http://commons.apache.org/proper/commons-csv/user-guide.html)
-* Stripping the Excel BOM (Byte Order Mark) works out-of-box
-
-## 6.12 Executing Arbitrary Commands
-
-Using Apache Commons Exec allows to execute arbitrary commands - nice but dangerous. It was recently quite useful to to invoke AWS CLI to generate a Confluence page about the overall setup of our AWS accounts. 
-
-A few snippets to illustrate the points
-
-```text
-<#ftl output_format="plainText" strip_whitespace="true">
-<#assign profile = SystemTool.getProperty("profile", "default")>
-<#assign ec2Instances = ec2Instances()/>
-
-h3. AWS EC2 Instance
-<@printEc2Instances ec2Instances/>
-
-<#function ec2Instances>
-    <#local json = awsCliToJson("aws ec2 describe-instances --profile ${profile}")>
-    <#local instances = json.read("$.Reservations[*].Instances[*]")>
-    <#return instances?sort_by(['InstanceType'])>
-</#function>
-
-<#function awsCliToJson line>
-    <#local output = ExecTool.execute(line)>
-    <#return JsonPathTool.parse(output)>
-</#function>
-
-<#function getAwsEc2InstanceTag tags name>
-    <#return tags?filter(x -> x["Key"] == name)?first["Value"]!"">
-</#function>
-
-<#macro printEc2Instances ec2Instances>
-    <#compress>
-        || NAME || INSTANCE_TYPE || VCPUS || STATE || PRIVATE_IP_ADDRESS ||
-        <#list ec2Instances as ec2Instance>
-            <#assign instanceType = ec2Instance["InstanceType"]>
-            <#assign arn = ec2Instance["IamInstanceProfile"]["Arn"]>
-            <#assign privateIpAddress = ec2Instance["PrivateIpAddress"]>
-            <#assign state = ec2Instance["State"]["Name"]>
-            <#assign launchTime = ec2Instance["LaunchTime"]>
-
-            <#assign coreCount = ec2Instance["CpuOptions"]["CoreCount"]?number>
-            <#assign threadsPerCore = ec2Instance["CpuOptions"]["ThreadsPerCore"]?number>
-            <#assign nrOfVirtualCpus = coreCount * threadsPerCore>
-
-            <#assign tags = ec2Instance["Tags"]/>
-            <#assign awsCloudFormationStackId = getAwsEc2InstanceTag(tags, "aws:cloudformation:stack-id")>
-            <#assign awsCloudFormationStackName = getAwsEc2InstanceTag(tags, "aws:cloudformation:stack-name")>
-            <#assign name = getAwsEc2InstanceTag(tags, "Name")>
-            <#assign country = getAwsEc2InstanceTag(tags, "Country")>
-            <#assign environment = getAwsEc2InstanceTag(tags, "Environment")>
-
-            | ${name} | ${instanceType} | ${nrOfVirtualCpus} | ${state} | ${privateIpAddress} |
-        </#list>
-    </#compress>
-</#macro>
-```
-
-## 6.13 Interactive Templates
-
-Sometime you need to apply a CSS, JSON or XPath query in ad ad-hoc way without installing `xmllint`, `jq` or `pup` - in this case you can pass a FreeMarker template in an interactive fashion
-
-```text
-> bin/freemarker-cli -i 'Hello ${SystemTool.envs["USER"]}'; echo
-Hello sgoeschl
-
-> bin/freemarker-cli -i '${JsonPathTool.parse(DataSources.first).read("$.info.title")}' examples/data/json/swagger-spec.json; echo
-Swagger Petstore
-
-> bin/freemarker-cli -i 'Post Title : ${JsonPathTool.parse(DataSources.first).read("$.title")}' https://jsonplaceholder.typicode.com/posts/2; echo
-Post Title : qui est esse
-
-> bin/freemarker-cli -i '${XmlTool.parse(DataSources.first)["recipients/person[1]/name"]}' examples/data/xml/recipients.xml; echo
-John Smith
-
-> bin/freemarker-cli -i '${JsoupTool.parse(DataSources.first).select("a")[0]}' examples/data/html/dependencies.html; echo
-<a href="${project.url}" title="FreeMarker CLI">FreeMarker CLI</a>
-
-> ./bin/freemarker-cli -i '<#list SystemTool.envs as name,value>${name} ==> ${value}${"\n"}</#list>'
-TERM ==> xterm-256color
-LANG ==> en_US
-DISPLAY ==> :0.0
-SHELL ==> /bin/bash
-EDITOR ==> vi
-```
-
-## 6.14 Filtering & Transforming CSV
-
-During an integration project we imported large transactions CSV files (500.000+ records) and in case of import failures the developers would be happy to get a nice outline of the transactions causing the problem (the CSV records have 60+ columns) - in essence it is filtering (based on some primary key) and and transforming into a human-readable output format (Markdown).
-
-So lets start the filtering & transformation using the following command line
-
-```text
-> bin/freemarker-cli -e UTF-8 -l de_AT -Pcolumn="Order ID" \
-  -Pvalues=226939189,957081544 \
-  -t examples/templates/csv/md/filter.ftl examples/data/csv/sales-records.csv
-```
-
-and Apache FreeMarker template
-
-```text
-<#ftl output_format="plainText" strip_text="true">
-<#assign dataSource = DataSources.get(0)>
-<#assign parser = parser(dataSource)>
-<#assign headers = parser.getHeaderNames()>
-<#assign column = SystemTool.getParameter("column")>
-<#assign values = SystemTool.getParameter("values")?split(",")>
-
-<#compress>
-    <@writePageHeader dataSource/>
-    <#-- Process each line without materializing the whole file in memory -->
-    <#list parser.iterator() as record>
-        <#if filter(record)>
-            <@writeCsvRecord headers record/>
-        </#if>
-    </#list>
-</#compress>
-
-<#function parser dataSource>
-    <#assign format = CSVTool.formats[SystemTool.getParameter("format", "DEFAULT")]>
-    <#assign delimiter = CSVTool.toDelimiter(SystemTool.getParameter("delimiter", format.getDelimiter()))>
-    <#return CSVTool.parse(dataSource, format.withFirstRecordAsHeader().withDelimiter(delimiter))>
-</#function>
-
-<#function filter record>
-    <#return values?seq_contains(record.get(column))>
-</#function>
-
-<#macro writePageHeader dataSource>
-    # ${dataSource.name}
-</#macro>
-
-<#macro writeCsvRecord headers record>
-    ## Line ${record.getRecordNumber()}
-    | Column    | Value                       |
-    | --------- | --------------------------- |
-    <#list headers as header>
-    | ${header} | ${record.get(header)}       |
-    </#list>
-</#macro>
-```
-
-yields
-
-```
-# sales-records.csv
-## Line 1
-| Column | Value |
-| --------- | --------------------------- |
-| Region | Central America and the Caribbean |
-| Country | Antigua and Barbuda |
-| Item Type | Baby Food |
-| Sales Channel | Online |
-| Order Priority | M |
-| Order Date | 12/20/2013 |
-| Order ID | 957081544 |
-| Ship Date | 1/11/2014 |
-| Units Sold | 552 |
-| Unit Price | 255.28 |
-| Unit Cost | 159.42 |
-| Total Revenue | 140914.56 |
-| Total Cost | 87999.84 |
-| Total Profit | 52914.72 |
-## Line 4.998
-| Column | Value |
-| --------- | --------------------------- |
-| Region | Asia |
-| Country | Myanmar |
-| Item Type | Baby Food |
-| Sales Channel | Offline |
-| Order Priority | H |
-| Order Date | 11/23/2016 |
-| Order ID | 226939189 |
-| Ship Date | 12/10/2016 |
-| Units Sold | 5204 |
-| Unit Price | 255.28 |
-| Unit Cost | 159.42 |
-| Total Revenue | 1328477.12 |
-| Total Cost | 829621.68 |
-| Total Profit | 498855.44 |
-```
-
-## 6.15 Converting Between JSON And YAML
-
-Sometimes we simply need to transform a JSON into an equivalent YAML or the other way around
-
-```
-> ./bin/freemarker-cli -t templates/yaml/json/transform.ftl examples/data/yaml/swagger-spec.yaml 
-> ./bin/freemarker-cli -i '${GsonTool.toJson(YamlTool.parse(DataSources.get(0)))}' examples/data/yaml/swagger-spec.yaml
-> ./bin/freemarker-cli -i '${GsonTool.toJson(yaml)}' -m yaml=examples/data/yaml/swagger-spec.yaml
-
-> ./bin/freemarker-cli -t templates/json/yaml/transform.ftl examples/data/json/swagger-spec.json
-> ./bin/freemarker-cli -i '${YamlTool.toYaml(GsonTool.parse(DataSources.get(0)))}' examples/data/json/swagger-spec.json
-> ./bin/freemarker-cli -i '${YamlTool.toYaml(json)}' -m json=examples/data/json/swagger-spec.json
-```
-
-## 6.16 Using DataFrames
-
-The `DataFrameTool` uses [nRo/DataFrame](https://github.com/nRo/DataFrame) to convert tabular data into a `DataFrame`.
-
-A `DataFrame` allows declartive filtering and transformation of tabular data, i.e. less code to write.
-
-Currently the following sources are supported
-
-* Apache Commons CSV Parser
-* JSON arrays represented as collection of maps
-* Excel sheets represented as rows
-
-### CSV Examples
-
-[nRo/DataFrame]("https://raw.githubusercontent.com/nRo/DataFrame/master/src/test/resources/users.csv") provides the following CSV file
-
-```
-name;age;country
-Schmitt;24;Germany
-Parker;45;USA
-Meier;20;Germany
-Schmitt;30;France
-Peter;44;Germany
-Meier;24;Germany
-Green;33;UK
-Schmitt;30;Germany
-Meier;30;Germany
-```
-
-and create a `DateFrame` using the following code
-
-```
-<#assign cvsFormat = CSVTool.formats["DEFAULT"].withHeader().withDelimiter(';')>
-<#assign csvParser = CSVTool.parse(DataSources.get(0), cvsFormat)>
-<#assign users = DataFrameTool.toDataFrame(csvParser)>
-```
-
-#### Select By Age
-
-```
-${DataFrameTool.print(users.select("(age > 40)"))}
-```
-
-which shows 
-
-```
-┌────────────┬────────────┬────────────┐
-│#name       │#age        │#country    │
-├────────────┼────────────┼────────────┤
-│Parker      │45          │USA         │
-├────────────┼────────────┼────────────┤
-│Peter       │44          │Germany     │
-└────────────┴────────────┴────────────┘
-```
-
-#### Complex Select & Sort
-
-Now we want to create a new `DataFrame` by selecting `name` and `country`
-
-```
-<#assign country = "Germany">
-${DataFrameTool.print(users
-    .select("(name == 'Schmitt' || name == 'Meier') && country == '${country}'")
-    .sort("name", DataFrameTool.sortOrder["ASCENDING"]))}
-```
-
-which shows
-
-```
-┌────────────┬────────────┬────────────┐
-│#name       │#age        │#country    │
-├────────────┼────────────┼────────────┤
-│Meier       │20          │Germany     │
-├────────────┼────────────┼────────────┤
-│Meier       │24          │Germany     │
-├────────────┼────────────┼────────────┤
-│Meier       │30          │Germany     │
-├────────────┼────────────┼────────────┤
-│Schmitt     │24          │Germany     │
-├────────────┼────────────┼────────────┤
-│Schmitt     │30          │Germany     │
-└────────────┴────────────┴────────────┘
-```
-
-#### Count Column Values
-
-Let's assume we want to count the records for each `country`
-
-```
-${DataFrameTool.print(users.getColumn("country").transform(DataFrameTool.transformer["COUNT"]))}
-```
-
-returns the following `DataFrame`
-
-```
-┌────────────┬────────────┐
-│#country    │#counts     │
-├────────────┼────────────┤
-│Germany     │6           │
-├────────────┼────────────┤
-│USA         │1           │
-├────────────┼────────────┤
-│France      │1           │
-├────────────┼────────────┤
-│UK          │1           │
-└────────────┴────────────┘
-```
-
-#### Group By Age And Country
-
-Let's assume that we want to group the `DataFrame` by `age` and `country`
-
-```
-${DataFrameTool.print(users.groupBy("age", "country").sort("age"))}
-``` 
-
-which results in 
-
-```
-┌────────────┬────────────┐
-│#age        │#country    │
-├────────────┼────────────┤
-│20          │Germany     │
-├────────────┼────────────┤
-│24          │Germany     │
-├────────────┼────────────┤
-│30          │France      │
-├────────────┼────────────┤
-│30          │Germany     │
-├────────────┼────────────┤
-│33          │UK          │
-├────────────┼────────────┤
-│44          │Germany     │
-├────────────┼────────────┤
-│45          │USA         │
-└────────────┴────────────┘
-```
-
-### JSON Examples
-
-Here we load a `examples/data/json/github-users.json` which represents a tabular data be 
-being parsed as a list of maps and print the JSOB as dataframe
-
-```
-./bin/freemarker-cli -i '${DataFrameTool.print(DataFrameTool.fromMaps(GsonTool.parse(DataSources.get(0))))}' examples/data/json/github-users.json
-
-┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
-│#login      │#id         │#avatar_ur  │#gravatar_  │#url        │#html_url   │#followers  │#following  │#gists_url  │#starred_u  │#subscript  │#organizat  │#repos_url  │#events_ur  │#received_  │#type       │#site_admi  │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│mojombo     │1.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│defunkt     │2.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │true        │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│pjhyett     │3.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │true        │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│wycats      │4.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│ezmobius    │5.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│ivey        │6.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│evanphx     │7.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-└────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
-```
-
-### Excel Examples
-
-Let's transform an Excel Sheet to a `DataFrame` being printed using the following template
-
-```
-<#assign dataSource = DataSources.get(0)>
-<#assign workbook = ExcelTool.parse(dataSource)>
-<#list ExcelTool.getSheets(workbook) as sheet>
-    <#assign table = ExcelTool.toTable(sheet)>
-    <#assign df = DataFrameTool.fromRows(table, true)>
-    ${DataFrameTool.print(df)}<#t>
-</#list>
-```
-
-which is rendered by the following command line invocation
-
-```
-./bin/freemarker-cli -t examples/templates/excel/dataframe/transform.ftl examples/data/excel/test.xls
-
-┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
-│#Text       │#Date       │#Number     │#Currency   │#Time       │#Percentag  │#Forumula   │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│Row 1       │01/01/17    │100.00      │€100.00     │10:00       │50.00%      │C2*F2       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│Row 2       │01/01/17    │100.00      │€100.00     │10:00       │50.00%      │C3*F3       │
-└────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
-```
-
-## 6.17 Using Advanced FreeMarker Features
-
-There is a `demo.ftl` which shows some advanced FreeMarker functionality
-
-* Invoking a Java constructor
-* Invoke a static method of non-instantiable class
-* Work with Java enumerations
-* Access System properties
-* Access Environment variables
-
-Running 
-
-> ./bin/freemarker-cli -t examples/templates/demo.ftl 
-
-gives you
-
-```text
-1) FreeMarker Special Variables
----------------------------------------------------------------------------
-FreeMarker version     : 2.3.30
-Template name          : demo.ftl
-Language               : en
-Locale                 : en_US
-Timestamp              : Jun 18, 2020 11:13:51 AM
-Output encoding        : UTF-8
-Output format          : plainText
-
-2) Invoke a constructor of a Java class
----------------------------------------------------------------------------
-new java.utilDate(1000 * 3600 * 24): Jan 2, 1970 1:00:00 AM
-
-3) Invoke a static method of an non-constructor class
----------------------------------------------------------------------------
-Random UUID              : ac6c8bb2-a8cf-423e-ad6b-a4eff09b1fb9
-System.currentTimeMillis : 1,592,471,631,655
-
-4) Access an Enumeration
----------------------------------------------------------------------------
-java.math.RoundingMode#UP: UP
-
-5) Loop Over The Values Of An Enumeration
----------------------------------------------------------------------------
-- java.math.RoundingMode.UP
-- java.math.RoundingMode.DOWN
-- java.math.RoundingMode.CEILING
-- java.math.RoundingMode.FLOOR
-- java.math.RoundingMode.HALF_UP
-- java.math.RoundingMode.HALF_DOWN
-- java.math.RoundingMode.HALF_EVEN
-- java.math.RoundingMode.UNNECESSARY
-
-6) Display list of data sources
----------------------------------------------------------------------------
-List all data sources:
-
-7) SystemTool
----------------------------------------------------------------------------
-Host name       : W0GL5179.home
-Command line    : -t, examples/templates/demo.ftl
-System property : sgoeschl
-Timestamp       : 1592471631667
-Environment var : sgoeschl
-
-8) Access System Properties
----------------------------------------------------------------------------
-app.dir      : 
-app.home     : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler
-app.pid      : 13037
-basedir      : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler
-java.version : 1.8.0_192
-user.name    : sgoeschl
-user.dir     : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler
-user.home    : /Users/sgoeschl
-
-9) List Environment Variables
----------------------------------------------------------------------------
-- PATH ==> /Users/sgoeschl/bin:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/bin:/usr/local/opt/ruby/bin:HOME/.gem/ruby/2.7.0/bin:/usr/local/Cellar/git/2.19.1/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Applications/Java/apache-fop-2.3:/Applications/Java/freemarker-cli-2.0.0-BETA-2/bin:
-- GIT_HOME ==> /usr/local/Cellar/git/2.19.1
-- JAVA_8_HOME ==> /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home
-- JAVA_HOME ==> /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home
-- FOP_HOME ==> /Applications/Java/apache-fop-2.3
-- TERM ==> xterm-256color
-- LANG ==> en_US
-- MAVEN_OPTS ==> -Xmx2048m
-- DISPLAY ==> :0.0
-- JAVA_11_HOME ==> /Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home
-- BEEONE_NEXUS_CREDENTIALS ==> H50N0OB:fRidnevo0420!
-- JAVA_9_HOME ==> /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home
-- LOGNAME ==> sgoeschl
-- XPC_SERVICE_NAME ==> 0
-- PWD ==> /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler
-- TERM_PROGRAM_VERSION ==> 433
-- RUBY_HOME ==> /usr/local/opt/ruby
-- JAVA_MAIN_CLASS_13037 ==> org.apache.freemarker.generator.cli.Main
-- SHELL ==> /bin/bash
-- PROFILE_TYPE ==> development
-- TERM_PROGRAM ==> Apple_Terminal
-- LSCOLORS ==> ExFxCxDxBxegedabagacad
-- PROFILE_ENV ==> default
-- SECURITYSESSIONID ==> 186a8
-- USER ==> sgoeschl
-- CLICOLOR ==> 1
-- GATLING_HOME ==> /Applications/Java/gatling-3.1.2
-- LaunchInstanceID ==> E8DE55F6-626E-4D15-B3B4-FFE4704CEF4E
-- TMPDIR ==> /var/folders/cd/jbgc9cg14ld7dlsqk44tpmrw0000gn/T/
-- SSH_AUTH_SOCK ==> /private/tmp/com.apple.launchd.DTdlBj20Ka/Listeners
-- EDITOR ==> vi
-- XPC_FLAGS ==> 0x0
-- FREEMARKER_CLI_HOME ==> /Applications/Java/freemarker-cli-2.0.0-BETA-2
-- TERM_SESSION_ID ==> 2745D6A3-543A-4DE3-830B-945678460311
-- LC_ALL ==> en_US.utf-8
-- __CF_USER_TEXT_ENCODING ==> 0x1F5:0x0:0x0
-- LC_CTYPE ==> UTF-8
-- HOME ==> /Users/sgoeschl
-- SHLVL ==> 1
-
-10) List System Properties
----------------------------------------------------------------------------
-- java.runtime.name ==> Java(TM) SE Runtime Environment
-- java.vm.version ==> 25.192-b12
-- java.vm.vendor ==> Oracle Corporation
-- java.vendor.url ==> http://java.oracle.com/
-- path.separator ==> :
-- java.vm.name ==> Java HotSpot(TM) 64-Bit Server VM
-- file.encoding.pkg ==> sun.io
-- user.country ==> AT
-
-11) Access DataSources
----------------------------------------------------------------------------
-Get the number of documents:
-- 0
-List all files containing "README" in the name
-List all files having "md" extension
-Get all documents
-
-12) FreeMarker CLI Tools
----------------------------------------------------------------------------
-- CSVTool              : Process CSV files using Apache Commons CSV (see https://commons.apache.org/proper/commons-csv/)
-- DataFrameTool        : Bridge to nRo/DataFrame (see https://github.com/nRo/DataFrame)
-- ExcelTool            : Process Excels files (XLS, XLSX) using Apache POI (see https://poi.apache.org)
-- ExecTool             : Execute command line tools using Apache Commons Exec (see https://commons.apache.org/proper/commons-exec/)
-- FreeMarkerTool       : Expose useful Apache FreeMarker classes
-- GrokTool             : Process text files using Grok expressions (see https://github.com/thekrakken/java-grok)
-- GsonTool             : Process JSON files using GSON (see https://github.com/google/gson)
-- JsonPathTool         : Process JSON files using Java JSON Path (see https://github.com/json-path/JsonPath)
-- JsoupTool            : Process  HTML files using Jsoup (see https://jsoup.org)
-- PropertiesTool       : Process JDK properties files
-- SystemTool           : Expose System-related utility methods
-- UUIDTool             : Create UUIDs
-- XmlTool              : Process XML files using Apache FreeMarker (see https://freemarker.apache.org/docs/xgui.html)
-- YamlTool             : Process YAML files using SnakeYAML(see https://bitbucket.org/asomov/snakeyaml/wiki/Home)
-
-13) Document Data Model
----------------------------------------------------------------------------
-- CSVTool
-- DataFrameTool
-- DataSources
-- ExcelTool
-- ExecTool
-- FreeMarkerTool
-- GrokTool
-- GsonTool
-- JsonPathTool
-- JsoupTool
-- PropertiesTool
-- SystemTool
-- UUIDTool
-- XmlTool
-- YamlTool
-
-14) Create a UUID
----------------------------------------------------------------------------
-UUIDTool Random UUID  : 832a20fb-ac22-460a-b5d0-33c6fcc126d2
-UUIDTool Named UUID   : 298415f9-e888-3d98-90e7-6c0d63ad14dc
-
-15) Printing Special Characters
----------------------------------------------------------------------------
-German Special Characters: äöüßÄÖÜ
-
-16) Locale-specific output
----------------------------------------------------------------------------
-Small Number :  1.23
-Large Number :  12,345,678.90
-Date         :  Jun 18, 2020
-Time         :  11:13:51 AM
-
-17) Execute a program
----------------------------------------------------------------------------
-> date
-Thu Jun 18 11:13:51 CEST 2020
-```
-
-# 7. Design Considerations
-
-## 7.1 How It Works
-
-* The user-supplied files are loaded or input is read from `stdin`
-* The FreeMarker data model containing the data sources and tools is created and passed to the template
-* The generated output is written to the user-supplied file or to `stdout`
-
-## 7.2 FreeMarker Data Model
-
-Within the script a FreeMarker data model is set up and passed to the template - it contains the data sources to be processed and the following tools
-
-| Entry                 | Description                                                                                               |
-|-----------------------|-----------------------------------------------------------------------------------------------------------|
-| CSVTool               | Process CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)              |
-| DataFrameTool         | Bridge to [nRo/DataFrame](https://github.com/nRo/DataFrame)                                            |
-| ExecTool              | Execute command line tools using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)   |
-| ExcelTool             | Process Excels files (XLS, XLSX) using [Apache POI](https://poi.apache.org)                               |
-| DataSources           | Helper class to find data sources, e.g. by name, extension or index                                       |
-| FreeMarkerTool        | Expose useful FreeMarker classes                                                                          |
-| GrokTool              | Process text files using [Grok](https://github.com/thekrakken/java-grok) instead of regular expressions   |
-| GsonTool              | Process JSON files using [GSON](https://github.com/google/gson)                                           |
-| JsonPathTool          | Process JSON file using [Java JSON Path](https://github.com/json-path/JsonPath)                           |
-| JsoupTool             | Processing HTML files using [Jsoup](https://jsoup.org)                                                    |
-| PropertiesTool        | Process JDK properties files                                                                              |
-| SystemTool            | System-related utility methods                                                                            |
-| UUIDTool              | Create UUIDs                                                                                              |
-| XmlTool               | Process XML files using [Apache FreeMarker](https://freemarker.apache.org/docs/xgui.html)                 |
-| YamlTool              | Process YAML files using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)                    |
-
-
-# 8. Tips & Tricks
-
-## 8.1 Template Base Directory
-
-When doing some ad-hoc scripting it is useful to rely on a base directory to resolve the FTL templates
-
-* As a default the FTL templates are resolved relative to the script directory
-* The caller can provide a `-b` or `--basedir` command line parameter
-
-```text
-./bin/freemarker-cli -b examples/templates -t json/md/github-users.ftl examples/data/json/github-users.json; echo
+./run-examples.sh 
+templates/info.ftl
+examples/templates/demo.ftl
+templates/csv/html/transform.ftl
+templates/csv/md/transform.ftl
+examples/templates/csv/shell/curl.ftl
+examples/templates/csv/md/filter.ftl
+examples/templates/csv/fo/transform.ftl
+fop -fo target/out/locker-test-users.fo target/out/locker-test-users.pdf
+examples/templates/csv/fo/transactions.ftl
+fop -fo target/out/transactions.fo target/out/transactions-fo.pdf
+templates/csv/html/transform.ftl
+wkhtmltopdf -O landscape target/out/transactions.html target/out/transactions-html.pdf
+examples/templates/dataframe/example.ftl
+examples/templates/accesslog/combined-access.ftl
+examples/templates/excel/dataframe/transform.ftl
+templates/excel/html/transform.ftl
+templates/excel/md/transform.ftl
+templates/excel/csv/transform.ftl
+examples/templates/excel/csv/custom.ftl
+examples/templates/html/csv/dependencies.ftl
+examples/templates/json/csv/swagger-endpoints.ftl
+templates/json/yaml/transform.ftl
+examples/templates/json/md/github-users.ftl
+examples/templates/properties/csv/locker-test-users.ftl
+examples/data/template
+examples/templates/yaml/txt/transform.ftl
+templates/yaml/json/transform.ftl
+examples/templates/xml/txt/recipients.ftl
+Created the following sample files in ./target/out
+total 1464
+-rw-r--r--  1 sgoeschl  staff     646 Jun 28 08:21 combined-access.log.txt
+-rw-r--r--  1 sgoeschl  staff   25676 Jun 28 08:20 contract.html
+-rw-r--r--  1 sgoeschl  staff    7933 Jun 28 08:20 contract.md
+-rw-r--r--  1 sgoeschl  staff     784 Jun 28 08:20 curl.sh
+-rw-r--r--  1 sgoeschl  staff     232 Jun 28 08:21 customer.txt
+-rw-r--r--  1 sgoeschl  staff    6486 Jun 28 08:21 dataframe.txt
+-rw-r--r--  1 sgoeschl  staff   15563 Jun 28 08:20 demo.txt
+-rw-r--r--  1 sgoeschl  staff    1310 Jun 28 08:21 dependencies.csv
+-rw-r--r--  1 sgoeschl  staff    2029 Jun 28 08:21 github-users-curl.md
+-rw-r--r--  1 sgoeschl  staff    2624 Jun 28 08:20 info.txt
+-rw-r--r--  1 sgoeschl  staff    8075 Jun 28 08:20 interactive-dataframe.txt
+-rw-r--r--  1 sgoeschl  staff      66 Jun 28 08:20 interactive-html.txt
+-rw-r--r--  1 sgoeschl  staff      16 Jun 28 08:20 interactive-json.txt
+-rw-r--r--  1 sgoeschl  staff   25090 Jun 28 08:20 interactive-swagger.json
+-rw-r--r--  1 sgoeschl  staff   16870 Jun 28 08:20 interactive-swagger.yaml
+-rw-r--r--  1 sgoeschl  staff      10 Jun 28 08:20 interactive-xml.txt
+-rw-r--r--  1 sgoeschl  staff     285 Jun 28 08:21 locker-test-users.csv
+-rw-r--r--  1 sgoeschl  staff    6341 Jun 28 08:20 locker-test-users.fo
+-rw-r--r--  1 sgoeschl  staff    5526 Jun 28 08:20 locker-test-users.pdf
+-rw-r--r--  1 sgoeschl  staff     921 Jun 28 08:21 recipients.txt
+-rw-r--r--  1 sgoeschl  staff     910 Jun 28 08:20 sales-records.md
+-rw-r--r--  1 sgoeschl  staff    2453 Jun 28 08:21 swagger-spec.csv
+-rw-r--r--  1 sgoeschl  staff   25090 Jun 28 08:21 swagger-spec.json
+-rw-r--r--  1 sgoeschl  staff   16870 Jun 28 08:21 swagger-spec.yaml
+drwxr-xr-x  4 sgoeschl  staff     128 Jun 28 08:21 template
+-rw-r--r--  1 sgoeschl  staff     154 Jun 28 08:21 test-multiple-sheets.xlsx.csv
+-rw-r--r--  1 sgoeschl  staff    1917 Jun 28 08:21 test-multiple-sheets.xlsx.html
+-rw-r--r--  1 sgoeschl  staff     389 Jun 28 08:21 test-multiple-sheets.xlsx.md
+-rw-r--r--  1 sgoeschl  staff     155 Jun 28 08:21 test-transform-xls.csv
+-rw-r--r--  1 sgoeschl  staff    1439 Jun 28 08:21 test.xls.dataframe.txt
+-rw-r--r--  1 sgoeschl  staff    1556 Jun 28 08:21 test.xls.html
+-rw-r--r--  1 sgoeschl  staff    1558 Jun 28 08:21 test.xslx.html
+-rw-r--r--  1 sgoeschl  staff   25758 Jun 28 08:20 transactions-fo.pdf
+-rw-r--r--  1 sgoeschl  staff   66016 Jun 28 08:21 transactions-html.pdf
+-rw-r--r--  1 sgoeschl  staff  330128 Jun 28 08:20 transactions.fo
+-rw-r--r--  1 sgoeschl  staff   51008 Jun 28 08:21 transactions.html
 ```
 
-## 8.2 Using Pipes
-
-When doing ad-hoc scripting it useful to pipe the output of one command directly into "freemarker-cli"
 
-```text
-cat examples/data/json/github-users.json | ./bin/freemarker-cli -t examples/templates/json/md/github-users.ftl --stdin; echo
-```
diff --git a/freemarker-generator-cli/examples/templates/dataframe/example.ftl b/freemarker-generator-cli/examples/templates/dataframe/example.ftl
index d1eef7b..9929d21 100644
--- a/freemarker-generator-cli/examples/templates/dataframe/example.ftl
+++ b/freemarker-generator-cli/examples/templates/dataframe/example.ftl
@@ -1,4 +1,3 @@
-<#ftl output_format="plainText">
 <#--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -16,7 +15,7 @@
   under the License.
 -->
 <#assign dataSource = DataSources.get(0)>
-<#assign csvParser = CSVTool.parse(dataSource, csvInFormat())>
+<#assign csvParser = CSVTool.parse(dataSource, CSVTool.formats["DATAFRAME"])>
 <#assign users = DataFrameTool.fromCSVParser(csvParser)>
 
 Original Data
@@ -45,14 +44,3 @@ ${DataFrameTool.print(users.getColumn("country").transform(DataFrameTool.transfo
 Group By Age & Country
 =============================================================================
 ${DataFrameTool.print(users.groupBy("country", "age").sort("country"))}
-<#--------------------------------------------------------------------------->
-<#function csvInFormat>
-    <#assign format = CSVTool.formats[CSV_SOURCE_FORMAT!"DEFAULT"]>
-    <#assign delimiter = CSVTool.toDelimiter(CSV_SOURCE_DELIMITER!format.getDelimiter())>
-    <#assign withHeader = CSV_SOURCE_WITH_HEADER!"false">
-    <#assign format = format.withDelimiter(delimiter)>
-    <#if withHeader?boolean>
-        <#assign format = format.withHeader()>
-    </#if>
-    <#return format>
-</#function>
diff --git a/freemarker-generator-cli/examples/templates/info.ftl b/freemarker-generator-cli/examples/templates/info.ftl
deleted file mode 100644
index 565e2ec..0000000
--- a/freemarker-generator-cli/examples/templates/info.ftl
+++ /dev/null
@@ -1,67 +0,0 @@
-<#ftl output_format="plainText" strip_whitespace=true>
-<#--
-  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.
--->
-FreeMarker CLI Information
-------------------------------------------------------------------------------
-FreeMarker version     : ${.version}
-Template name          : ${.current_template_name}
-Language               : ${.lang}
-Locale                 : ${.locale}
-Timestamp              : ${.now}
-Output encoding        : ${.output_encoding}
-Output format          : ${.output_format}
-
-FreeMarker CLI Template Directories
-------------------------------------------------------------------------------
-<#list SystemTool.getTemplateDirectories() as directory>
-[#${directory?counter}] ${directory}
-</#list>
-
-FreeMarker CLI Tools
-------------------------------------------------------------------------------
-<#list .data_model?keys?sort as key>
-<#if key?ends_with("Tool")>
-- ${key?right_pad(20)} : ${.data_model[key]}
-</#if>
-</#list>
-
-FreeMarker CLI Data Model
----------------------------------------------------------------------------
-<#list .data_model?keys?sort as key>
-- ${key}<#lt>
-</#list>
-
-<#if DataSources.list?has_content>
-FreeMarker CLI DataSources
-------------------------------------------------------------------------------
-<#list DataSources.list as dataSource>
-    [#${dataSource?counter}], name=${dataSource.name}, group=${dataSource.group}, contentType=${dataSource.contentType}, charset=${dataSource.charset}, length=${dataSource.length} Bytes
-    URI : ${dataSource.uri}
-</#list>
-</#if>
-
-<#if SystemTool.parameters?has_content>
-FreeMarker CLI Parameters
-------------------------------------------------------------------------------
-<#list SystemTool.parameters as key,value>
-<#if value?is_hash>
-- ${key} ==> { <#list value as name,value>${name}=${value} </#list>}
-<#else>
-- ${key} ==> ${value}
-</#if>
-</#list>
-</#if>
diff --git a/freemarker-generator-cli/examples/templates/json/dataframe/github-users.ftl b/freemarker-generator-cli/examples/templates/json/dataframe/github-users.ftl
new file mode 100644
index 0000000..a6547fc
--- /dev/null
+++ b/freemarker-generator-cli/examples/templates/json/dataframe/github-users.ftl
@@ -0,0 +1,20 @@
+<#ftl output_format="plainText" >
+<#--
+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.
+-->
+<#assign json = GsonTool.parse(DataSources.get(0))>
+<#assign dataframe = DataFrameTool.fromMaps(json)>
+${DataFrameTool.print(dataframe)}
diff --git a/freemarker-generator-cli/pom.xml b/freemarker-generator-cli/pom.xml
index 47756a9..81ee0ac 100644
--- a/freemarker-generator-cli/pom.xml
+++ b/freemarker-generator-cli/pom.xml
@@ -67,14 +67,13 @@
                 <artifactId>maven-antrun-plugin</artifactId>
                 <executions>
                     <execution>
+                        <id>package</id>
                         <phase>package</phase>
                         <configuration>
                             <target>
+                                <copy file="CHANGELOG.md" todir="./target/appassembler" />
                                 <copy file="README.md" todir="./target/appassembler" />
                                 <copy file="./src/main/scripts/run-examples.sh" todir="./target/appassembler" />
-                                <copy todir="./target/appassembler/site">
-                                    <fileset dir="site" />
-                                </copy>
                                 <copy todir="./target/appassembler/templates">
                                     <fileset dir="templates" />
                                 </copy>
@@ -99,7 +98,6 @@
                         <configuration>
                             <tarLongFileMode>gnu</tarLongFileMode>
                             <descriptors>
-                                <descriptor>${basedir}/src/main/assembly/dist.xml</descriptor>
                                 <descriptor>${basedir}/src/main/assembly/app.xml</descriptor>
                             </descriptors>
                         </configuration>
@@ -126,6 +124,20 @@
                         </goals>
                     </execution>
                 </executions>
+                <configuration>
+                    <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
+                    <prefix>git</prefix>
+                    <verbose>false</verbose>
+                    <generateGitPropertiesFile>true</generateGitPropertiesFile>
+                    <generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties
+                    </generateGitPropertiesFilename>
+                    <format>properties</format>
+                    <gitDescribe>
+                        <skip>false</skip>
+                        <always>false</always>
+                        <dirty>-dirty</dirty>
+                    </gitDescribe>
+                </configuration>
             </plugin>
         </plugins>
     </build>
@@ -177,7 +189,7 @@
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-simple</artifactId>
+            <artifactId>slf4j-nop</artifactId>
         </dependency>
         <!-- Testing -->
         <dependency>
diff --git a/freemarker-generator-cli/src/main/assembly/dist.xml b/freemarker-generator-cli/src/main/assembly/dist.xml
deleted file mode 100644
index 80dc5b4..0000000
--- a/freemarker-generator-cli/src/main/assembly/dist.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<!--
-    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.
--->
-<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
-          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
-    <id>dist</id>
-    <formats>
-        <format>tar.gz</format>
-    </formats>
-    <fileSets>
-        <fileSet>
-            <directory>${project.basedir}</directory>
-            <outputDirectory>${file.separator}</outputDirectory>
-            <useDefaultExcludes>true</useDefaultExcludes>
-            <excludes>
-                <exclude>./src/**</exclude>
-                <exclude>./target/**</exclude>
-                <exclude>./.idea/**</exclude>
-                <exclude>./*.iml</exclude>
-                <exclude>./pom.xml</exclude>
-                <exclude>./pom.xml</exclude>
-            </excludes>
-        </fileSet>
-    </fileSets>
-</assembly>
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
index 6315aa0..7e86f85 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
@@ -66,7 +66,7 @@ public class Main implements Callable<Integer> {
         public String interactiveTemplate;
     }
 
-    @Option(names = { "-b", "--basedir" }, description = "optional template base directory")
+    @Option(names = { "-b", "--basedir" }, description = "additional template base directory")
     String baseDir;
 
     @Option(names = { "-D", "--system-property" }, description = "set system property")
@@ -87,7 +87,7 @@ public class Main implements Callable<Integer> {
     @Option(names = { "-P", "--param" }, description = "set parameter")
     Map<String, String> parameters;
 
-    @Option(names = { "-s", "--data-source" }, description = "data source used for redering")
+    @Option(names = { "-s", "--data-source" }, description = "data source used for rendering")
     List<String> dataSources;
 
     @Option(names = { "--config" }, defaultValue = FREEMARKER_CLI_PROPERTY_FILE, description = "FreeMarker CLI configuration file")
diff --git a/freemarker-generator-cli/src/site/markdown/cli/advanced/cli-configuration.md b/freemarker-generator-cli/src/site/markdown/cli/advanced/cli-configuration.md
new file mode 100644
index 0000000..cde2cd1
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/advanced/cli-configuration.md
@@ -0,0 +1,77 @@
+## CLI Configuration
+ 
+The `Apache FreeMarker CLI` configuration can be tweaked to
+
+* Change the underlying `Apache FreeMarker Configuration`
+* Instantiate custom tools
+* Storing user-specific templates 
+
+### Apache FreeMarker CLI Properties File
+
+`Apache FreeMarker CLI` reads the `conf/freemarker-cli.properties`
+
+```
+#############################################################################
+# General FreeMarker Configuration
+# See https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#setSetting-java.lang.String-java.lang.String-
+#############################################################################
+# freemarker.configuration.setting.locale=JVM default
+
+#############################################################################
+# Configure FreeMarker Tools (name -> implementation class)
+#############################################################################
+freemarker.tools.CSVTool=org.apache.freemarker.generator.tools.commonscsv.CommonsCSVTool
+freemarker.tools.DataFrameTool=org.apache.freemarker.generator.tools.dataframe.DataFrameTool
+freemarker.tools.ExcelTool=org.apache.freemarker.generator.tools.excel.ExcelTool
+freemarker.tools.ExecTool=org.apache.freemarker.generator.tools.commonsexec.CommonsExecTool
+freemarker.tools.FreeMarkerTool=org.apache.freemarker.generator.tools.freemarker.FreeMarkerTool
+freemarker.tools.GrokTool=org.apache.freemarker.generator.tools.grok.GrokTool
+freemarker.tools.GsonTool=org.apache.freemarker.generator.tools.gson.GsonTool
+freemarker.tools.JsonPathTool=org.apache.freemarker.generator.tools.jsonpath.JsonPathTool
+freemarker.tools.JsoupTool=org.apache.freemarker.generator.tools.jsoup.JsoupTool
+freemarker.tools.PropertiesTool=org.apache.freemarker.generator.tools.properties.PropertiesTool
+freemarker.tools.SystemTool=org.apache.freemarker.generator.tools.system.SystemTool
+freemarker.tools.UUIDTool=org.apache.freemarker.generator.tools.uuid.UUIDTool
+freemarker.tools.XmlTool=org.apache.freemarker.generator.tools.xml.XmlTool
+freemarker.tools.YamlTool=org.apache.freemarker.generator.tools.snakeyaml.SnakeYamlTool
+```
+
+Changing this file allows to tweak the underlying `Apache FreeMarker Configuration` and add custom tools.
+
+### Storing User-Specific Templates
+
+Over the time you will accumalate more and more `Apache FreeMarker` templates - some of them are stored within a project but some of the more general might be free-floating and you don't want to store them in the installation directory.
+
+To give those free-floating templates a home `Apache FreeMarker CLI` tries to read templates from `~/freemarker-cli`, e.g.
+
+```
+tree ~/.freemarker-cli/
+/Users/sgoeschl/.freemarker-cli/
+`-- templates
+    `-- json
+        |-- confluence
+        |   |-- aws
+        |   |   `-- describe.ftl
+        |-- csv
+        |   `-- swagger-endpoints.ftl
+        |-- ftl
+        |   `-- customer-user-products.ftl
+        |-- html
+        |   `-- customer-user-products.ftl
+        `-- md
+            `-- customer-user-products.ftl
+```
+
+If a  `~/freemarker-cli` is found it will be automatically added to the `FreeMarker Template Loader` (for more information see https://freemarker.apache.org/docs/pgui_config_templateloading.html)
+
+You can easily check this, e.g.  
+
+```
+> freemarker-cli -t templates/info.ftl
+
+FreeMarker CLI Template Loader Directories
+------------------------------------------------------------------------------
+[#1] /Users/sgoeschl
+[#2] /Users/sgoeschl/.freemarker-cli
+[#3] /Applications/Java/freemarker-cli-2.0.0
+``` 
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md
index c05323c..25bb3f9 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md
@@ -9,21 +9,44 @@ A `DataModel` is an eagerly loaded `DataSource` available in Apache FreeMarker's
 Expose the fields of the JSON data source in FreeMarker's model 
 
 ```
-bin/freemarker-cli --data-model https://xkcd.com/info.0.json  -i '<a href="${img}">${title}</a>'
-<a href="https://imgs.xkcd.com/comics/scenario_4.png">Scenario 4</a>
+> curl -s https://xkcd.com/info.0.json | python -m json.tool
+{
+    "alt": "The git vehicle fleet eventually pivoted to selling ice cream, but some holdovers remain. If you flag down an ice cream truck and hand the driver a floppy disk, a few hours later you'll get an invite to a git repo.",
+    "day": "24",
+    "img": "https://imgs.xkcd.com/comics/old_days_2.png",
+    "link": "",
+    "month": "6",
+    "news": "",
+    "num": 2324,
+    "safe_title": "Old Days 2",
+    "title": "Old Days 2",
+    "transcript": "",
+    "year": "2020"
+}
+
+> freemarker-cli --data-model https://xkcd.com/info.0.json  -i '<a href="${img}">${title}</a>'; echo
+<a href="https://imgs.xkcd.com/comics/old_days_2.png">Old Days 2</a>
 ```
 
 Exposed the JSON data source as variable `post` in FreeMarker's model 
 
 ```
-bin/freemarker-cli --data-model post=https://jsonplaceholder.typicode.com/posts/2 -i 'post title is: ${post.title}'
+> curl -s https://jsonplaceholder.typicode.com/posts/2 | python -m json.tool
+{
+    "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla",
+    "id": 2,
+    "title": "qui est esse",
+    "userId": 1
+}
+
+> freemarker-cli --data-model post=https://jsonplaceholder.typicode.com/posts/2 -i 'post title is: ${post.title}'; echo
 post title is: qui est esse
 ```
 
 Expose all environment variables as `env` in theFreeMarker model
  
 ```
-bin/freemarker-cli --data-model env=env:/// -i '<#list env as name,value>${name}=${value}${"\n"}</#list>'
+> freemarker-cli --data-model env=env:/// -i '<#list env as name,value>${name}=${value}${"\n"}</#list>'
 HOME=/Users/sgoeschl
 USER=sgoeschl
 ```
@@ -31,14 +54,14 @@ USER=sgoeschl
 Expose a single envionment variable in theFreeMarker model
 
 ```
-bin/freemarker-cli --data-model NAME=env:///USER -i 'Hello ${NAME}'
+> freemarker-cli --data-model NAME=env:///USER -i 'Hello ${NAME}'; echo
 Hello sgoeschl
 ```
 
 Alternatively use the short command line options, e.g.
 
 ```
-bin/freemarker-cli -m NAME=env:///USER -i 'Hello ${NAME}!'
+> freemarker-cli -m NAME=env:///USER -i 'Hello ${NAME}!'; echo
 Hello sgoeschl!
 ```
 
@@ -51,7 +74,7 @@ The following snippet shows a more advanced example
 > export DB_CONFIG='{"db_default_user":"scott","db_default_password":"tiger"}'
 > echo $DB_CONFIG 
 {"db_default_user":"scott","db_default_password":"tiger"}
-> bin/freemarker-cli -m config=env:///DB_CONFIG#mimetype=application/json  -i '<#list config as name,value>${name}=${value}${"\n"}</#list>'
+> freemarker-cli -m config=env:///DB_CONFIG#mimetype=application/json  -i '<#list config as name,value>${name}=${value}${"\n"}</#list>'
 db_default_user=scott
 db_default_password=tiger
 ```
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
index 548a65b..1a921fc 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
@@ -13,7 +13,7 @@ A `DataSource` consists of lazy-loaded data available in Apache FreeMarker's mod
 A `DataSource` can be loaded from the file system, e.g. as positional command line argument
 
 ```
-bin/freemarker-cli -t templates/info.ftl README.md
+freemarker-cli -t templates/info.ftl README.md
 
 FreeMarker CLI DataSources
 ------------------------------------------------------------------------------
@@ -24,7 +24,7 @@ FreeMarker CLI DataSources
 from an URL
 
 ```
-bin/freemarker-cli --data-source xkcd=https://xkcd.com/info.0.json -t templates/info.ftl
+freemarker-cli --data-source xkcd=https://xkcd.com/info.0.json -t templates/info.ftl
 
 FreeMarker CLI DataSources
 ------------------------------------------------------------------------------
@@ -36,7 +36,7 @@ or from an environment variable, e.g. `NGINX_CONF` having a JSON payload
 
 ```
 export NGINX_CONF='{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}'
-bin/freemarker-cli -t templates/info.ftl -s conf=env:///NGINX_CONF#mimetype=application/json
+freemarker-cli -t templates/info.ftl -s conf=env:///NGINX_CONF#mimetype=application/json
 
 FreeMarker CLI DataSources
 ------------------------------------------------------------------------------
@@ -47,7 +47,7 @@ FreeMarker CLI DataSources
 Of course you can load multiple `DataSources` directly
 
 ```
-bin/freemarker-cli -t templates/info.ftl README.md xkcd=https://xkcd.com/info.0.json
+freemarker-cli -t templates/info.ftl README.md xkcd=https://xkcd.com/info.0.json
  
 FreeMarker CLI DataSources
 ------------------------------------------------------------------------------
@@ -60,7 +60,7 @@ FreeMarker CLI DataSources
 or load them from a directory
 
 ```
-bin/freemarker-cli -t templates/info.ftl -s examples/data/
+freemarker-cli -t templates/info.ftl -s examples/data
 FreeMarker CLI DataSources
 ------------------------------------------------------------------------------
     [#1], name=combined-access.log, group=default, contentType=text/plain, charset=UTF-8, length=2,068 Bytes
@@ -74,7 +74,7 @@ FreeMarker CLI DataSources
 which can be combined with `include` and `exclude` filters
 
 ```
-bin/freemarker-cli -t templates/info.ftl -s examples/data --data-source-include=*.json
+freemarker-cli -t templates/info.ftl -s examples/data --data-source-include=*.json
 
 FreeMarker CLI DataSources
 ------------------------------------------------------------------------------
@@ -82,5 +82,30 @@ FreeMarker CLI DataSources
     URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/json/github-users.json
     [#2], name=swagger-spec.json, group=default, contentType=application/json, charset=UTF-8, length=24,948 Bytes
     URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/json/swagger-spec.json
+```
+
+### Selecting A DataSource
+
+After loading one or more `DataSource` it needs to be selected for template processing - the `DataSources` instance 
+exposed in the data model provides
+
+* Selecting by index  
+* Selecting by name
+* Filter by the globbing pattern (see [Apache Commons IO](https://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/filefilter/WildcardFileFilter.html))
+
+A few FTL examples
 
 ```
+<#assign dataSource = DataSources.get(0)>
+
+<#assign dataSource = DataSources.get("user.csv)>
+
+<#list DataSources.find("*.md") as dataSource>
+- ${dataSource.name}
+</#list>
+```
+
+
+
+ 
+
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/design-goals.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/design-goals.md
new file mode 100644
index 0000000..0d2e07c
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/design-goals.md
@@ -0,0 +1,17 @@
+## Design Goals
+
+* Create a proper command-line tool which has Unix look & feel
+* Handle arbitrary large input and output data
+* Support multiple source files/directories for a single transformation
+* Support transformation of Property files using plain-vanilla JDK
+* Support transformation of CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)
+* Support transformation of JSON using [Jayway's JSONPath](https://github.com/jayway/JsonPath) and [GSON](https://github.com/google/gson)
+* Support transformation of Excel using [Apache POI](https://poi.apache.org)
+* Support transformation of YAML using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)
+* Support transformation of HTML using [JSoup](https://jsoup.org)
+* Support transformation of structured logfiles using [Grok](https://github.com/thekrakken/java-grok)
+* XML & XPath is supported by FreeMarker [out-of-the-box](http://freemarker.org/docs/xgui.html)
+* Support for reading a data source content from STDIN to integrate with command line tools
+* Support execution of arbitrary commands using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)
+* Add some commonly useful information such as `System Properties`, `Enviroment Variables`
+* Support embedding the code in existing applications
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md
index 1c99b27..58f9faa 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md
@@ -1,4 +1,4 @@
-# Named URIs
+## Named URIs
 
 Named URIs allow to identify `DataSources` and pass additional information 
 
@@ -29,7 +29,7 @@ For our purposes, the scheme and the path components are especially important, t
 The following Named URI loads a "user.csv" and the data source is available as `my_users` 
 
 ```
-bin/freemarker-cli -t templates/info.ftl my_users=examples/data/csv/user.csv
+freemarker-cli -t templates/info.ftl my_users=examples/data/csv/user.csv
 [#1], name=my_users, group=default, contentType=text/csv, charset=UTF-8, length=376 Bytes
 URI : file:examples/data/csv/user.csv
 ```
@@ -37,7 +37,7 @@ URI : file:examples/data/csv/user.csv
 A Named URI allows to pass additional information as part of the fragment, e.g. the charset of the text file 
 
 ```
-bin/freemarker-cli -t templates/info.ftl my_users=examples/data/csv/user.csv#charset=UTF-16
+freemarker-cli -t templates/info.ftl my_users=examples/data/csv/user.csv#charset=UTF-16
 [#1], name=my_users, group=default, contentType=text/csv, charset=UTF-16, length=376 Bytes
 URI : file:examples/data/csv/user.csv
 ```
@@ -45,7 +45,7 @@ URI : file:examples/data/csv/user.csv
 In addition to the simplified file syntax full URIs can be used
 
 ```
-bin/freemarker-cli -t templates/info.ftl http://google.com?foo=bar
+freemarker-cli -t templates/info.ftl http://google.com?foo=bar
 [#1], name=google.com, group=default, contentType=text/html, charset=ISO-8859-1, length=-1 Bytes
 URI : http://google.com?foo=bar
 ```
@@ -53,7 +53,7 @@ URI : http://google.com?foo=bar
 and also combined with a name
 
 ```
-bin/freemarker-cli -t templates/info.ftl page=http://google.com?foo=bar
+freemarker-cli -t templates/info.ftl page=http://google.com?foo=bar
 [#1], name=page, group=default, contentType=text/html, charset=ISO-8859-1, length=-1 Bytes
 URI : http://google.com?foo=bar
 ```
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/user-parameters.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/passing-data.md
similarity index 58%
rename from freemarker-generator-cli/src/site/markdown/cli/concepts/user-parameters.md
rename to freemarker-generator-cli/src/site/markdown/cli/concepts/passing-data.md
index 46f2d2e..eb6110e 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/user-parameters.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/passing-data.md
@@ -1,4 +1,19 @@
-# User-Supplied Parameters
+## Passing Configuration Data
+
+`Apache FreeMarker CLI` provides multiple ways to pass configuration data used in in templates
+
+* System properties
+* Parameters 
+
+### User-Supplied System Poperties
+
+User-supplied system properties are added to the JVM's system properties
+
+```
+> freemarker-cli -Dfoo1=foo1 -D foo2=foo2 -t templates/info.ftl 
+```
+ 
+### User-Supplied Parameters
 
 User-supplied parameters allow to pass additional information to an Apache FreeMarker template 
 
@@ -8,7 +23,7 @@ User-supplied parameters allow to pass additional information to an Apache FreeM
 Pass a simple name/value pair on the command line 
 
 ```
-> bin/freemarker-cli -t templates/info.ftl -P key=value
+> freemarker-cli -t templates/info.ftl -P key=value
 
 User Supplied Parameters
 ------------------------------------------------------------------------------
@@ -18,7 +33,7 @@ User Supplied Parameters
 By providing a `group` you can create nested maps
 
 ```
-> bin/freemarker-cli -t templates/info.ftl -P foo1:group=bar1 -P foo2:group=bar2
+> freemarker-cli -t templates/info.ftl -P foo1:group=bar1 -P foo2:group=bar2
 
 User Supplied Parameters
 ------------------------------------------------------------------------------
@@ -28,7 +43,7 @@ User Supplied Parameters
 It is also possible to mix and match the two approaches
 
 ```
-> bin/freemarker-cli -t templates/info.ftl -P foo1:group=bar1 -P foo2:group=bar2 -P key=value
+> freemarker-cli -t templates/info.ftl -P foo1:group=bar1 -P foo2:group=bar2 -P key=value
 
 User Supplied Parameters
 ------------------------------------------------------------------------------
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/template-loading.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/template-loading.md
new file mode 100644
index 0000000..f54228e
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/template-loading.md
@@ -0,0 +1,60 @@
+## Template Loading
+
+In order the render a template it needs to be loaded first - there are multiple ways of creating/loading a template
+
+* Using a [FreeMarker Template Loader](https://freemarker.apache.org/docs/pgui_config_templateloading.html) and abstract template paths 
+* Load a template without template loader (aka free-style template loading), e.g. absolute template file, a directory or an URL
+* Provide the template directly on the command-line (aka interactive template)
+
+### FreeMarker MultiTemplateLoader
+
+`Apache FreeMarker CLI` uses a `MultiTemplateLoader` searching for templates in the following directories
+
+* Current working directory
+* Optional `~/.freemarker-cli` directory
+* `Apache FreeMarker CLI` installation directory
+
+You can check the currently used template loader directories easily on the command line, e.g.
+
+```
+freemarker-cli -t templates/info.ftl
+
+FreeMarker CLI Template Loader Directories
+------------------------------------------------------------------------------
+[#1] /Users/sgoeschl/work/github/apache/freemarker-generator
+[#2] /Users/sgoeschl/.freemarker-cli
+[#3] /Applications/Java/freemarker-cli-2.0.0
+```
+
+The main benefit of `MultiTemplateLoader` is the use of abstract template paths finding a template in the template loader directories
+
+```
+freemarker-cli -t templates/info.ftl
+``` 
+
+and [Template Includes](https://freemarker.apache.org/docs/ref_directive_include.html)
+
+```
+<#import "/templates/lib/commons-csv.ftl" as csv />
+```  
+
+### Free-Style Template Loading
+
+The previosly described `Template Loaders` do not support absolute template files or arbitraRY URLS - this behaviour 
+stems from security aspects when running `Apache FreeMarker` on the server side. For a command-line tool this is mostly
+irrelevant therefore any template file outside of the template loader directories can be loaded 
+
+This example loads the `info.ftl` directly from a GitHub URL
+
+```
+freemarker-cli -t https://raw.githubusercontent.com/apache/freemarker-generator/master/freemarker-generator-cli/templates/info.ftl
+```
+
+### Interactive Template Loading
+
+The template can be defined directly on the command line in case of trivial transformations
+
+```
+freemarker-cli -i '${GsonTool.toJson(yaml)}' -m yaml=examples/data/yaml/swagger-spec.yaml
+```
+
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/tools.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/tools.md
new file mode 100644
index 0000000..c07a01a
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/tools.md
@@ -0,0 +1,22 @@
+## Tools
+
+A `Apache FreeMarker CLI Tool` is just a POJO (plain old Java object) that is "useful" in a template and is not meant to be rendered in the output.
+
+The following tools are currently implemented
+
+| Tool                  | Description                                                                                               |
+|-----------------------|-----------------------------------------------------------------------------------------------------------|
+| CSVTool               | Process CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)              |
+| DataFrameTool         | Bridge to [nRo/DataFrame](https://github.com/nRo/DataFrame)                                               |
+| ExecTool              | Execute command line tools using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)   |
+| ExcelTool             | Process Excels files (XLS, XLSX) using [Apache POI](https://poi.apache.org)                               |
+| FreeMarkerTool        | Expose useful FreeMarker classes                                                                          |
+| GrokTool              | Process text files using [Grok](https://github.com/thekrakken/java-grok) instead of regular expressions   |
+| GsonTool              | Process JSON files using [GSON](https://github.com/google/gson)                                           |
+| JsonPathTool          | Process JSON file using [Java JSON Path](https://github.com/json-path/JsonPath)                           |
+| JsoupTool             | Processing HTML files using [Jsoup](https://jsoup.org)                                                    |
+| PropertiesTool        | Process JDK properties files                                                                              |
+| SystemTool            | System-related utility methods                                                                            |
+| UUIDTool              | Create UUIDs                                                                                              |
+| XmlTool               | Process XML files using [Apache FreeMarker](https://freemarker.apache.org/docs/xgui.html)                 |
+| YamlTool              | Process YAML files using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)                    |
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
index 966743b..388a681 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
@@ -1,5 +1,7 @@
 ## Transformation
 
+The `freemarker-cli` generates text output based on FreeMarker templates and data
+
 * A command line invocation requires 1..n `templates` and 0..n `data sources` / `data models` 
 * A command line invocation is mapped to a series of `transformations`
 * The `transformation` consists of exactly one `template`, 0..n `data sources` / `data models` and an `output`
@@ -9,4 +11,4 @@
     * an output directory
 * When the output is written to a directory
     * the structure of the input directory is preserved
-    * a "ftl" file externsion is removed
+    * a `ftl` file externsion is removed
diff --git a/freemarker-generator-cli/src/site/markdown/cli/introduction/getting-started.md b/freemarker-generator-cli/src/site/markdown/cli/introduction/getting-started.md
new file mode 100644
index 0000000..a288348
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/introduction/getting-started.md
@@ -0,0 +1,142 @@
+## Getting Started
+
+### Installation
+
+* Requires JDK 1.8+ on Linux, Mac OSX and Windows
+* Download [freemarker-generator-cli-0.1.0-SNAPSHOT-app.tar.gz] or [freemarker-generator-cli-0.1.0-SNAPSHOT-app.zip]
+* Unpack the archive in a directory of your choice
+* Add the `bin/freemarker-cli` or `bin/freemarker-cli.bat` to your `PATH` variable
+
+### Verify Installation
+
+On my local box (Mac OS 10.15.5) I use the following setup
+
+```
+export FREEMARKER_CLI_HOME=/Applications/Java/freemarker-cli-2.0.0
+export PATH=$PATH:$FREEMARKER_CLI_HOME/bin
+```
+
+Afterwards `Apache FreeMarker CLI` can be executed from the command line
+
+```
+> which freemarker-cli
+/Applications/Java/freemarker-cli-2.0.0/bin/freemarker-cli
+```
+
+and check the version of `Apache FreeMarker CLI`
+
+```
+> freemarker-cli -V
+version=0.1.0-SNAPSHOT, time=2020-06-25T21:48:02+0200, commit=b320d00094be8789086ad6153d9d3fcaf4b8c75f
+```
+
+### Command Line Options
+
+`Apache FreeMarker CLI` provides command line help as shown below
+
+```
+> freemarker-cli -h
+Usage: freemarker-cli (-t=<templates> [-t=<templates>]... |
+                      -i=<interactiveTemplate>) [-hV] [--stdin] [-b=<baseDir>]
+                      [--config=<configFile>] [--data-source-exclude=<exclude>]
+                      [--data-source-include=<include>] [-e=<inputEncoding>]
+                      [-l=<locale>] [-o=<outputFile>]
+                      [--output-encoding=<outputEncoding>] [--times=<times>]
+                      [-D=<String=String>]... [-m=<dataModels>]...
+                      [-P=<String=String>]... [-s=<dataSources>]...
+                      [<sources>...]
+Apache FreeMarker CLI
+      [<sources>...]        data source files and/or directories
+  -b, --basedir=<baseDir>   optional template base directory
+      --config=<configFile> FreeMarker CLI configuration file
+  -D, --system-property=<String=String>
+                            set system property
+      --data-source-exclude=<exclude>
+                            file exclude pattern for data sources
+      --data-source-include=<include>
+                            file include pattern for data sources
+  -e, --input-encoding=<inputEncoding>
+                            encoding of data source
+  -h, --help                Show this help message and exit.
+  -i, --interactive=<interactiveTemplate>
+                            interactive template to process
+  -l, --locale=<locale>     locale being used for the output, e.g. 'en_US'
+  -m, --data-model=<dataModels>
+                            data model used for rendering
+  -o, --output=<outputFile> output file or directory
+      --output-encoding=<outputEncoding>
+                            encoding of output, e.g. UTF-8
+  -P, --param=<String=String>
+                            set parameter
+  -s, --data-source=<dataSources>
+                            data source used for redering
+      --stdin               read data source from stdin
+  -t, --template=<templates>
+                            template to process
+      --times=<times>       re-run X times for profiling
+  -V, --version             Print version information and exit.
+```
+
+### The Info Template
+
+The distribution ships with a couple of FreeMarker templates and the `templates/info.ftl` is particularly helpful 
+to better understand `Apache FreeMarker CLI`
+
+```
+> freemarker-cli -t templates/info.ftl
+FreeMarker CLI Information
+------------------------------------------------------------------------------
+FreeMarker version     : 2.3.30
+Template name          : templates/info.ftl
+Language               : en
+Locale                 : en_US
+Timestamp              : Jun 26, 2020 10:44:15 AM
+Output encoding        : UTF-8
+Output format          : plainText
+
+FreeMarker CLI Template Loader Directories
+------------------------------------------------------------------------------
+[#1] /Users/sgoeschl/work/github/apache/freemarker-generator
+[#2] /Users/sgoeschl/.freemarker-cli
+[#3] /Applications/Java/freemarker-cli-2.0.0
+
+FreeMarker CLI Tools
+------------------------------------------------------------------------------
+- CSVTool              : Process CSV files using Apache Commons CSV (see https://commons.apache.org/proper/commons-csv/)
+- DataFrameTool        : Bridge to [nRo/DataFrame](https://github.com/nRo/DataFrame)
+- ExcelTool            : Process Excels files (XLS, XLSX) using Apache POI (see https://poi.apache.org)
+- ExecTool             : Execute command line tools using Apache Commons Exec (see https://commons.apache.org/proper/commons-exec/)
+- FreeMarkerTool       : Expose advanced Apache FreeMarker classes
+- GrokTool             : Process text files using Grok expressions (see https://github.com/thekrakken/java-grok)
+- GsonTool             : Process JSON files using GSON (see https://github.com/google/gson)
+- JsonPathTool         : Process JSON files using Java JSON Path (see https://github.com/json-path/JsonPath)
+- JsoupTool            : Process  HTML files using Jsoup (see https://jsoup.org)
+- PropertiesTool       : Process JDK properties files
+- SystemTool           : Expose System-related utility methods
+- UUIDTool             : Create UUIDs
+- XmlTool              : Process XML files using Apache FreeMarker (see https://freemarker.apache.org/docs/xgui.html)
+- YamlTool             : Process YAML files using SnakeYAML(see https://bitbucket.org/asomov/snakeyaml/wiki/Home)
+
+FreeMarker CLI Data Model
+---------------------------------------------------------------------------
+- CSVTool
+- DataFrameTool
+- DataSources
+- ExcelTool
+- ExecTool
+- FreeMarkerTool
+- GrokTool
+- GsonTool
+- JsonPathTool
+- JsoupTool
+- PropertiesTool
+- SystemTool
+- UUIDTool
+- XmlTool
+- YamlTool
+```
+
+* The "FreeMarker CLI Information" section provides insights into configuration and currently processed template.
+* The "FreeMarker CLI Template Loader Directories" shows the template directories being searched to resolve a template path
+* The "FreeMarker CLI Tools" section list the available tools
+* The "FreeMarker CLI Data Model" section shows all available entries in the current FreeMarker context 
diff --git a/freemarker-generator-cli/README.md b/freemarker-generator-cli/src/site/markdown/cli/usage/running-examples.md
similarity index 51%
copy from freemarker-generator-cli/README.md
copy to freemarker-generator-cli/src/site/markdown/cli/usage/running-examples.md
index 70179f2..9b329a1 100644
--- a/freemarker-generator-cli/README.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/running-examples.md
@@ -1,140 +1,15 @@
-# Apache FreeMarker Generator CLI
+## Running Examples
 
-# 1. Is This Project For You?
-
-You somehow found this GitHub project and wonder if it solves a problem you might have?!
-
-* You need to transform some structured text document (CSV, HTML, JSON, XML, YAML, Java Property files, access logs) into CSV, HTML, Markdown or Confluence markup?
-* You need to convert an Excel document into CSV, HTML or Markdown?
-* You need to create a nice-looking PDF from some boring-looking CSV or JSON content ?
-
-The goal of `freemarker-cli` is to automate repeated transformation tasks 
-
-* Which are too boring to be done manually 
-* Which happen not often enough to write a dedicated script or program
-
-# 2. Once Upon A Time
-
-In December 2015 I needed a little bit of test data management for a customer project - to make a long story short (after writing a few more Groovy scripts) it boiled down to transforming one or more JSON files to something human readable.
-
-What are the options?
-
-* The cool kids say 'Node.js' - but they always say 'Node.js' 
-* Some fancy Groovy scripts using Groovy's markup builder - but the syntax looks a bit odd
-* Using 'JsonPath' and 'Velocity' to reuse good & old stuff
-
-So I went with 'Apache Groovy', 'JsonPath' and 'Apache Velocity'
-
-* Playing with Groovy over the public holidays
-* Groovy has a built-in package manager which makes distribution a breeze
-* Providing samples to transform JSON to Markdown
-
-Using Velocity actually created some minor issues so I migrated to [Apache FreeMarker](https://freemarker.apache.org) during Christmas 2016
-
-* Velocity 1.7 was released 2010 and only recently there was a new release
-* I was painful to get Velocity Tools working
-* Velocity XML processing support is also painful
-* Spring 4.3 deprecated Velocity support which could affect me in the long run
-* FreeMarker has no additional dependencies and things are just working :-)
-
-While I love Apache Velocity (Apache Turbine anyone?) I decided to give FreeMarker a chance and migrated my [velocity-cli](https://github.com/sgoeschl/velocity-cli) to FreeMarker.
-
-Some years later the not-so-small-any-longer-and-not-having-tests Groovy script was still growing so I decided 
-
-* To ditch Groovy and migrate to plain JDK 8
-* Write unit tests since I had no more excuses
-* To ditch Commons CLI and migrate to [Picocli](https://picocli.info)
-
-# 3. Design Goals
-
-* Create a proper command-line tool which has Unix look & feel
-* Handle arbitrary large input and output data
-* Support multiple source files/directories for a single transformation
-* Support transformation of Property files using plain-vanilla JDK
-* Support transformation of CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)
-* Support transformation of JSON using [Jayway's JSONPath](https://github.com/jayway/JsonPath) and [GSON](https://github.com/google/gson)
-* Support transformation of Excel using [Apache POI](https://poi.apache.org)
-* Support transformation of YAML using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)
-* Support transformation of HTML using [JSoup](https://jsoup.org)
-* Support transformation of structured logfiles using [Grok](https://github.com/thekrakken/java-grok)
-* XML & XPath is supported by FreeMarker [out-of-the-box](http://freemarker.org/docs/xgui.html)
-* Support for reading a data source content from STDIN to integrate with command line tools
-* Support execution of arbitrary commands using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)
-* Add some commonly useful information such as `System Properties`, `Enviroment Variables`
-* Support embedding the code in existing applications
-
-# 4. Installation
-
-Download the latest release from [GitHub](https://github.com/sgoeschl/freemarker-cli/releases), e.g. [freemarker-cli-2.0.0-BETA-5-app.tar.gz](https://github.com/sgoeschl/freemarker-cli/releases/download/v2.0.0-BETA-4/freemarker-cli-2.0.0-BETA-5-app.tar.gz) and unpack it into of a directory of your choice, e.g `/Application/Java/freemarker-cli`
-
-It is recommended 
-
-* To add `bin/freemarker-cli` or `bin/freemarker-cli.bat` to your executable path
-* To create a `~/.freemarker-cli` directory to store your custom FTL templates
-
-You can test the installation by executing
-
-```text
-> ./bin/freemarker-cli -t templates/info.ftl
-FreeMarker CLI Information
-------------------------------------------------------------------------------
-FreeMarker version     : 2.3.30
-Template name          : info.ftl
-Language               : en
-Locale                 : en_US
-Timestamp              : Jun 18, 2020 10:55:04 AM
-Output encoding        : UTF-8
-Output format          : plainText
-
-FreeMarker CLI Template Directories
-------------------------------------------------------------------------------
-[#1] /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler
-[#2] /Users/sgoeschl/.freemarker-cli
-
-FreeMarker CLI Tools
-------------------------------------------------------------------------------
-- CSVTool              : Process CSV files using Apache Commons CSV (see https://commons.apache.org/proper/commons-csv/)
-- DataFrameTool        : Bridge to nRo/DataFrame (see https://github.com/nRo/DataFrame)
-- ExcelTool            : Process Excels files (XLS, XLSX) using Apache POI (see https://poi.apache.org)
-- ExecTool             : Execute command line tools using Apache Commons Exec (see https://commons.apache.org/proper/commons-exec/)
-- FreeMarkerTool       : Expose useful Apache FreeMarker classes
-- GrokTool             : Process text files using Grok expressions (see https://github.com/thekrakken/java-grok)
-- GsonTool             : Process JSON files using GSON (see https://github.com/google/gson)
-- JsonPathTool         : Process JSON files using Java JSON Path (see https://github.com/json-path/JsonPath)
-- JsoupTool            : Process  HTML files using Jsoup (see https://jsoup.org)
-- PropertiesTool       : Process JDK properties files
-- SystemTool           : Expose System-related utility methods
-- UUIDTool             : Create UUIDs
-- XmlTool              : Process XML files using Apache FreeMarker (see https://freemarker.apache.org/docs/xgui.html)
-- YamlTool             : Process YAML files using SnakeYAML(see https://bitbucket.org/asomov/snakeyaml/wiki/Home)
-
-FreeMarker CLI Data Model
----------------------------------------------------------------------------
-- CSVTool
-- DataFrameTool
-- DataSources
-- ExcelTool
-- ExecTool
-- FreeMarkerTool
-- GrokTool
-- GsonTool
-- JsonPathTool
-- JsoupTool
-- PropertiesTool
-- SystemTool
-- UUIDTool
-- XmlTool
-- YamlTool
-```
-
-There a many examples (see below) available you can execute - run `./run-examples.sh` and have a look at the generated output
+There a many examples (see below) available you can execute - The examples were tested with JDK 1.8 on Mac OS X.
+                                                             
+Run `run-examples.sh` in the `Apache Freemarker CLI` installation directory and have a look at the generated output. 
 
 ```text
 ./run-examples.sh 
 templates/info.ftl
 examples/templates/demo.ftl
 templates/csv/html/transform.ftl
-examples/templates/csv/md/transform.ftl
+templates/csv/md/transform.ftl
 examples/templates/csv/shell/curl.ftl
 examples/templates/csv/md/filter.ftl
 examples/templates/csv/fo/transform.ftl
@@ -160,121 +35,60 @@ examples/templates/yaml/txt/transform.ftl
 templates/yaml/json/transform.ftl
 examples/templates/xml/txt/recipients.ftl
 Created the following sample files in ./target/out
-total 1576
--rw-r--r--  1 sgoeschl  staff     646 Jun 18 10:56 combined-access.log.txt
--rw-r--r--  1 sgoeschl  staff   22548 Jun 18 10:56 contract.html
--rw-r--r--  1 sgoeschl  staff    7933 Jun 18 10:56 contract.md
--rw-r--r--  1 sgoeschl  staff     784 Jun 18 10:56 curl.sh
--rw-r--r--  1 sgoeschl  staff     232 Jun 18 10:56 customer.txt
--rw-r--r--  1 sgoeschl  staff    6488 Jun 18 10:56 dataframe.txt
--rw-r--r--  1 sgoeschl  staff   15632 Jun 18 10:56 demo.txt
--rw-r--r--  1 sgoeschl  staff    1310 Jun 18 10:56 dependencies.csv
--rw-r--r--  1 sgoeschl  staff    2029 Jun 18 10:56 github-users-curl.md
--rw-r--r--  1 sgoeschl  staff    2630 Jun 18 10:56 info.txt
--rw-r--r--  1 sgoeschl  staff    8075 Jun 18 10:56 interactive-dataframe.txt
--rw-r--r--  1 sgoeschl  staff      66 Jun 18 10:56 interactive-html.txt
--rw-r--r--  1 sgoeschl  staff      16 Jun 18 10:56 interactive-json.txt
--rw-r--r--  1 sgoeschl  staff   25090 Jun 18 10:56 interactive-swagger.json
--rw-r--r--  1 sgoeschl  staff   16870 Jun 18 10:56 interactive-swagger.yaml
--rw-r--r--  1 sgoeschl  staff      10 Jun 18 10:56 interactive-xml.txt
--rw-r--r--  1 sgoeschl  staff     285 Jun 18 10:56 locker-test-users.csv
--rw-r--r--  1 sgoeschl  staff    6341 Jun 18 10:56 locker-test-users.fo
--rw-r--r--  1 sgoeschl  staff    5526 Jun 18 10:56 locker-test-users.pdf
--rw-r--r--  1 sgoeschl  staff     921 Jun 18 10:56 recipients.txt
--rw-r--r--  1 sgoeschl  staff     910 Jun 18 10:56 sales-records.md
--rw-r--r--  1 sgoeschl  staff    2453 Jun 18 10:56 swagger-spec.csv
--rw-r--r--  1 sgoeschl  staff   25090 Jun 18 10:56 swagger-spec.json
--rw-r--r--  1 sgoeschl  staff   16870 Jun 18 10:56 swagger-spec.yaml
-drwxr-xr-x  4 sgoeschl  staff     128 Jun 18 10:49 template
--rw-r--r--  1 sgoeschl  staff     156 Jun 18 10:56 test-multiple-sheets.xlsx.csv
--rw-r--r--  1 sgoeschl  staff    1917 Jun 18 10:56 test-multiple-sheets.xlsx.html
--rw-r--r--  1 sgoeschl  staff     389 Jun 18 10:56 test-multiple-sheets.xlsx.md
--rw-r--r--  1 sgoeschl  staff     157 Jun 18 10:56 test-transform-xls.csv
--rw-r--r--  1 sgoeschl  staff    1439 Jun 18 10:56 test.xls.dataframe.txt
--rw-r--r--  1 sgoeschl  staff    1556 Jun 18 10:56 test.xls.html
--rw-r--r--  1 sgoeschl  staff    1558 Jun 18 10:56 test.xslx.html
--rw-r--r--  1 sgoeschl  staff   25760 Jun 18 10:56 transactions-fo.pdf
--rw-r--r--  1 sgoeschl  staff   66016 Jun 18 10:56 transactions-html.pdf
--rw-r--r--  1 sgoeschl  staff  330129 Jun 18 10:56 transactions.fo
--rw-r--r--  1 sgoeschl  staff   51008 Jun 18 10:56 transactions.html
-
+total 1464
+-rw-r--r--  1 sgoeschl  staff     646 Jun 27 16:38 combined-access.log.txt
+-rw-r--r--  1 sgoeschl  staff   25676 Jun 27 16:38 contract.html
+-rw-r--r--  1 sgoeschl  staff    7933 Jun 27 16:38 contract.md
+-rw-r--r--  1 sgoeschl  staff     784 Jun 27 16:38 curl.sh
+-rw-r--r--  1 sgoeschl  staff     232 Jun 27 16:38 customer.txt
+-rw-r--r--  1 sgoeschl  staff    6486 Jun 27 16:38 dataframe.txt
+-rw-r--r--  1 sgoeschl  staff   15613 Jun 27 16:38 demo.txt
+-rw-r--r--  1 sgoeschl  staff    1310 Jun 27 16:38 dependencies.csv
+-rw-r--r--  1 sgoeschl  staff    2029 Jun 27 16:38 github-users-curl.md
+-rw-r--r--  1 sgoeschl  staff    2627 Jun 27 16:38 info.txt
+-rw-r--r--  1 sgoeschl  staff    8075 Jun 27 16:38 interactive-dataframe.txt
+-rw-r--r--  1 sgoeschl  staff      66 Jun 27 16:38 interactive-html.txt
+-rw-r--r--  1 sgoeschl  staff      16 Jun 27 16:38 interactive-json.txt
+-rw-r--r--  1 sgoeschl  staff   25090 Jun 27 16:38 interactive-swagger.json
+-rw-r--r--  1 sgoeschl  staff   16870 Jun 27 16:38 interactive-swagger.yaml
+-rw-r--r--  1 sgoeschl  staff      10 Jun 27 16:38 interactive-xml.txt
+-rw-r--r--  1 sgoeschl  staff     285 Jun 27 16:38 locker-test-users.csv
+-rw-r--r--  1 sgoeschl  staff    6341 Jun 27 16:38 locker-test-users.fo
+-rw-r--r--  1 sgoeschl  staff    5526 Jun 27 16:38 locker-test-users.pdf
+-rw-r--r--  1 sgoeschl  staff     921 Jun 27 16:38 recipients.txt
+-rw-r--r--  1 sgoeschl  staff     910 Jun 27 16:38 sales-records.md
+-rw-r--r--  1 sgoeschl  staff    2453 Jun 27 16:38 swagger-spec.csv
+-rw-r--r--  1 sgoeschl  staff   25090 Jun 27 16:38 swagger-spec.json
+-rw-r--r--  1 sgoeschl  staff   16870 Jun 27 16:38 swagger-spec.yaml
+drwxr-xr-x  4 sgoeschl  staff     128 Jun 27 16:38 template
+-rw-r--r--  1 sgoeschl  staff     154 Jun 27 16:38 test-multiple-sheets.xlsx.csv
+-rw-r--r--  1 sgoeschl  staff    1917 Jun 27 16:38 test-multiple-sheets.xlsx.html
+-rw-r--r--  1 sgoeschl  staff     389 Jun 27 16:38 test-multiple-sheets.xlsx.md
+-rw-r--r--  1 sgoeschl  staff     155 Jun 27 16:38 test-transform-xls.csv
+-rw-r--r--  1 sgoeschl  staff    1439 Jun 27 16:38 test.xls.dataframe.txt
+-rw-r--r--  1 sgoeschl  staff    1556 Jun 27 16:38 test.xls.html
+-rw-r--r--  1 sgoeschl  staff    1558 Jun 27 16:38 test.xslx.html
+-rw-r--r--  1 sgoeschl  staff   25757 Jun 27 16:38 transactions-fo.pdf
+-rw-r--r--  1 sgoeschl  staff   66016 Jun 27 16:38 transactions-html.pdf
+-rw-r--r--  1 sgoeschl  staff  330128 Jun 27 16:38 transactions.fo
+-rw-r--r--  1 sgoeschl  staff   51008 Jun 27 16:38 transactions.html
 ```
 
 Please note that generated PDF files are very likely not found since they require `wkhtmltopdf` and `Apache FOP` installation.
 
-# 5. Usage
-
-```text
-> ./bin/freemarker-cli  -h
-Usage: freemarker-cli (-t=<templates> [-t=<templates>]... |
-                      -i=<interactiveTemplate>) [-hV] [--stdin] [-b=<baseDir>]
-                      [--config=<configFile>] [--data-source-exclude=<exclude>]
-                      [--data-source-include=<include>] [-e=<inputEncoding>]
-                      [-l=<locale>] [-o=<outputFile>]
-                      [--output-encoding=<outputEncoding>] [--times=<times>]
-                      [-D=<String=String>]... [-m=<dataModels>]...
-                      [-P=<String=String>]... [-s=<dataSources>]...
-                      [<sources>...]
-Apache FreeMarker CLI
-      [<sources>...]        data source files and/or directories
-  -b, --basedir=<baseDir>   optional template base directory
-      --config=<configFile> FreeMarker CLI configuration file
-  -D, --system-property=<String=String>
-                            set system property
-      --data-source-exclude=<exclude>
-                            file exclude pattern for data sources
-      --data-source-include=<include>
-                            file include pattern for data sources
-  -e, --input-encoding=<inputEncoding>
-                            encoding of data source
-  -h, --help                Show this help message and exit.
-  -i, --interactive=<interactiveTemplate>
-                            interactive template to process
-  -l, --locale=<locale>     locale being used for the output, e.g. 'en_US'
-  -m, --data-model=<dataModels>
-                            data model used for rendering
-  -o, --output=<outputFile> output file or directory
-      --output-encoding=<outputEncoding>
-                            encoding of output, e.g. UTF-8
-  -P, --param=<String=String>
-                            set parameter
-  -s, --data-source=<dataSources>
-                            data source used for redering
-      --stdin               read data source from stdin
-  -t, --template=<templates>
-                            template to process
-      --times=<times>       re-run X times for profiling
-  -V, --version             Print version information and exit.
-
-```
-
-# 6. Examples
-
-The examples were tested with JDK 1.8 on Mac OS X
-
-```text
-> java -version
-java version "1.8.0_192"
-Java(TM) SE Runtime Environment (build 1.8.0_192-b12)
-Java HotSpot(TM) 64-Bit Server VM (build 25.192-b12, mixed mode)
-```
-It is assumed that you run the examples from the `freemarker-cli` installation directory.
-
-## 6.1 Transforming GitHub JSON To Markdown
+### 1. Transforming GitHub JSON To Markdown
 
 A simple example with real JSON data to be transformed into Markdown
 
-### Invocation
-
 You can either use the existing JSON sample
 
-> ./bin/freemarker-cli -t examples/templates/json/md/github-users.ftl examples/data/json/github-users.json
+> freemarker-cli -t examples/templates/json/md/github-users.ftl examples/data/json/github-users.json
 
 or pipe a cURL response
 
-> curl -s https://api.github.com/users | ./bin/freemarker-cli -t examples/templates/json/md/github-users.ftl --stdin
+> curl -s https://api.github.com/users | freemarker-cli -t examples/templates/json/md/github-users.ftl --stdin
 
-### FreeMarker Template
+Below you see the Apache FreeMarker Template
 
 ```text
 <#ftl output_format="plainText" >
@@ -300,15 +114,15 @@ Report generated at ${.now?iso_utc}
 
 creates the following output
 
-![](./site/image/github.png)
+![](../../images/examples/github.png)
 
-## 6.2 CSV to HTML/Markdown Transformation
+### 2. CSV to HTML/Markdown Transformation
 
 Sometimes you have a CSV file which needs to be translated in Markdown or HTML - there are on-line solutions available such as [CSV To Markdown Table Generator](https://donatstudios.com/CsvToMarkdownTable) but having a local solution gives you more flexibility.
 
 ```text
-> ./bin/freemarker-cli -t templates/csv/md/transform.ftl examples/data/csv/contract.csv
-> ./bin/freemarker-cli -t templates/csv/html/transform.ftl examples/data/csv/contract.csv
+> freemarker-cli -t templates/csv/md/transform.ftl examples/data/csv/contract.csv
+> freemarker-cli -t templates/csv/html/transform.ftl examples/data/csv/contract.csv
 ```
 
 The FreeMarker template is shown below
@@ -339,14 +153,14 @@ The FreeMarker template is shown below
 
 The resulting file actually looks pleasant when compared to raw CSV
 
-![Contract CSV to HTML](./site/image/contract.png "Contract CSV to HTML")
+![Contract CSV to HTML](../../images/examples/contract.png "Contract CSV to HTML")
 
-## 6.3 Transform XML To Plain Text
+### 3. Transform XML To Plain Text
 
 Of course you can also transform a XML document
 
 ```text
-> ./bin/freemarker-cli -t examples/templates/xml/txt/recipients.ftl examples/data/xml/recipients.xml
+> freemarker-cli -t examples/templates/xml/txt/recipients.ftl examples/data/xml/recipients.xml
 ```
 
 using the following template
@@ -394,7 +208,7 @@ Sincere salutations,
 D. H.
 ```
 
-## 6.4 Transform JSON To CSV
+### 4. Transform JSON To CSV
 
 One day I was asked a to prepare a CSV files containing REST endpoints described by Swagger - technically this is a JSON to CSV transformation. Of course I could create that CSV manually but writing a FTL template doing that was simply more fun and saves time in the future.
 
@@ -435,7 +249,7 @@ ${'\n'}
 
 Invoking the FTL template
 
-> ./bin/freemarker-cli -t examples/templates/json/csv/swagger-endpoints.ftl examples/data/json/swagger-spec.json 
+> freemarker-cli -t examples/templates/json/csv/swagger-endpoints.ftl examples/data/json/swagger-spec.json 
 
 gives you
 
@@ -447,15 +261,15 @@ ENDPOINT;METHOD;CONSUMES;PRODUCES;SUMMARY;DESCRIPTION
 /api/pets/{id};DELETE;;;;Deletes a single pet based on the ID supplied
 ```
 
-## 6.5 Transforming Excel Documents
+### 5. Transforming Excel Documents
 
 Another day my project management asked me to create a CSV configuration file based on an Excel documents - as usual manual copying was not an option due to required data cleanup and data transformation. So I thought about Apache POI which support XLS and XLSX documents - integration of Apache POI was a breeze but the resulting code was not particularly useful example. So a more generic transformation was provided to show the transformation of Excel documents ...
 
 ```text
-> ./bin/freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test.xls
-> ./bin/freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test.xlsx
-> ./bin/freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test-multiple-sheets.xlsx
-> ./bin/freemarker-cli -t templates/excel/md/transform.ftl examples/data/excel/test-multiple-sheets.xlsx
+> freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test.xls
+> freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test.xlsx
+> freemarker-cli -t templates/excel/html/transform.ftl examples/data/excel/test-multiple-sheets.xlsx
+> freemarker-cli -t templates/excel/md/transform.ftl examples/data/excel/test-multiple-sheets.xlsx
 ```
 
 The provided FTL transforms an Excel into a HTML document supporting multiple Excel sheets
@@ -532,14 +346,14 @@ The provided FTL transforms an Excel into a HTML document supporting multiple Ex
 
 but the result looks reasonable
 
-![](./site/image/excel-to-html.png)
+![](../../images/examples/excel-to-html.png)
 
-## 6.6 Transform Property Files To CSV
+### 6. Transform Property Files To CSV
 
 In this sample we transform all property files found in a directory (recursive search using include pattern) to a CSV file
 
 ```text
-> ./bin/freemarker-cli --data-source-include *.properties -t examples/templates/properties/csv/locker-test-users.ftl examples/data/properties
+> freemarker-cli --data-source-include *.properties -t examples/templates/properties/csv/locker-test-users.ftl examples/data/properties
 TENANT,SITE,USER_ID,DISPOSER_ID,PASSWORD,SMS_OTP,NAME,DESCRIPTION
 TENANT_A,fat,user_0004,user_0004,password_0004,,,
 TENANT_B,fat,user_0001,user_0001,password_0001,,,
@@ -582,7 +396,7 @@ ${'\n'}
 
 ```
 
-## 6.7 Transform CSV To XML-FO
+### 7. Transform CSV To XML-FO
 
 For a POC (proof of concept) I created a sample transformation from CSV to XML-FO in order to create a PDF document using [Apache FOP](https://xmlgraphics.apache.org/fop) using the following template file
 
@@ -670,7 +484,7 @@ For a POC (proof of concept) I created a sample transformation from CSV to XML-F
 In order to create the PDF you need to execute the following commands (assuming that you have Apache FOP installed)
 
 ```text
-> ./bin/freemarker-cli -t examples/templates/csv/fo/transform.ftl examples/data/csv/locker-test-users.csv > sample.fo
+> freemarker-cli -t examples/templates/csv/fo/transform.ftl examples/data/csv/locker-test-users.csv > sample.fo
 > fop -fo sample.fo sample.pdf
 Dec 29, 2018 10:24:30 PM org.apache.fop.events.LoggingEventListener processEvent
 WARNING: Font "Symbol,normal,700" not found. Substituting with "Symbol,normal,400".
@@ -682,12 +496,12 @@ INFO: Rendered page #1.
 
 The result does not look very impressive but it is a PDF :-)
 
-![](./site/image/locker-test-users-pdf.png)
+![](../../images/examples/locker-test-users-pdf.png)
 
 Further along the line of the POC we converted a transaction export from CSV to PDF using Apache FOP
 
 ```text
-> ./bin/freemarker-cli -t examples/templates/csv/fo/transactions.ftl examples/data/csv/transactions.csv > transactions.fo
+> freemarker-cli -t examples/templates/csv/fo/transactions.ftl examples/data/csv/transactions.csv > transactions.fo
 > fop -fo transactions.fo transactions.pdf
 Jan 16, 2019 11:15:21 PM org.apache.fop.events.LoggingEventListener processEvent
 WARNING: Font "Symbol,normal,700" not found. Substituting with "Symbol,normal,400".
@@ -701,9 +515,9 @@ Jan 16, 2019 11:15:22 PM org.apache.fop.events.LoggingEventListener processEvent
 INFO: Rendered page #2.
 ```
 
-![](./site/image/transactions.png)
+![](../../images/examples/transactions.png)
 
-## 6.8 Transforming HTML To CSV
+### 8. Transforming HTML To CSV
 
 Recently I got the rather unusual question how to determine the list of dependencies of an application - one easy way is the Maven "dependencies.html" but this is unstructured data. Having said that the Jsoup library is perfectly able to parse most real-life HTML and provides a DOM model
 
@@ -748,7 +562,7 @@ Recently I got the rather unusual question how to determine the list of dependen
 Your dependencies as CSV can be generated as shown below
 
 ```text
-> ./bin/freemarker-cli -t examples/templates/html/csv/dependencies.ftl examples/data/html/dependencies.html 
+> freemarker-cli -t examples/templates/html/csv/dependencies.ftl examples/data/html/dependencies.html 
 GroupId,ArtifactId,Version,Type,Licenses
 com.jayway.jsonpath,json-path,2.4.0,jar,The Apache Software License Version 2.0
 commons-cli,commons-cli,1.4,jar,Apache License Version 2.0
@@ -772,7 +586,7 @@ org.ow2.asm,asm,5.0.4,jar,BSD
 stax,stax-api,1.0.1,jar,The Apache Software License Version 2.0
 ```
 
-## 6.9 Transform CSV To Shell Script
+### 9. Transform CSV To Shell Script
 
 For a customer project we wanted to record REST request / responses using WireMock - really quick and dirty. So we decided to avoid any sophisticated test tool but generate a ready-to-use shell script executing cURL commands. It turned out that handling of dollar signs is a bit tricky
 
@@ -803,7 +617,7 @@ date "+%FT%H:%M:%S" | tr -d '\n'; curl --write-out ',${record.disposer},%{http_c
 Rendering the FreeMarker template 
 
 ```
-> ./bin/freemarker-cli -t ./examples/templates/csv/shell/curl.ftl examples/data/csv/user.csv
+> freemarker-cli -t ./examples/templates/csv/shell/curl.ftl examples/data/csv/user.csv
 ```
 
 generates the following shell script
@@ -835,7 +649,7 @@ time,user,status,duration,size
 2019-09-27T21:02:54,DDDDDDD,200,0.528268,206
 ```
 
-## 6.10 Unleashing The Power Of Grok
+### 10. Unleashing The Power Of Grok
 
 Think of `Grok` as modular regular expressions with a pre-defined functionality to parse access logs or any other data where you can't comprehend the regular expression any longer, one very simple example is `QUOTEDSTRING`
 
@@ -890,46 +704,7 @@ While this looks small and tidy there are some nifty features
 * The data source is streamed line by line and not loaded into memory in one piece
 * This also works for using `stdin` so are able to parse GB of access log or other files
 
-## 6.11 CSV Transformation
-
-Sometimes you have a CSV file which is not quite right - you need to change the format. Lets have a look how `freemarker-cli` can help
-
-> bin/freemarker-cli -PCVS_IN_DELIMITER=COMMA -PCSV_TARGET_DELIMITER=PIPE -t templates/csv/csv/transform.ftl ./examples/data/csv/contract.csv 
-
-renders the following template
-
-```text
-<#ftl output_format="plainText" strip_text="true">
-<#assign csvParser = CSVTool.parse(DataSources.get(0))>
-<#assign csvPrinter = CSVTool.printer(SystemTool.writer)>
-<#--
-    Print each record directly to the underyling writer without materializing the CSV in memory.
-    FreeMarker and CSV output are out of sync but millions of records can processed without
-    running out of memory.
--->
-<#compress>
-    <#list csvParser.iterator() as record>
-        ${csvPrinter.printRecord(record)}
-    </#list>
-</#compress>
-```
-
-and generates the following output
-
-```text
-contract_id|seller_company_name|customer_company_name|customer_duns_number|contract_affiliate|FERC_tariff_reference|contract_service_agreement_id|contract_execution_date|contract_commencement_date|contract_termination_date|actual_termination_date|extension_provision_description|class_name|term_name|increment_name|increment_peaking_name|product_type_name|product_name|quantity|units_for_contract|rate|rate_minimum|rate_maximum|rate_description|units_for_rate|point_of_receipt_control_area|po [...]
-C71|The Electric Company|The Power Company|456543333|N|FERC Electric Tariff Original Volume No. 10|2|2/15/2001|2/15/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||||||ES
-C72|The Electric Company|Utility A|38495837|n|FERC Electric Tariff Original Volume No. 10|15|7/25/2001|8/1/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||||||ES
-C73|The Electric Company|Utility B|493758794|N|FERC Electric Tariff Original Volume No. 10|7|6/8/2001|7/6/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||" "|" "|||ep
-C74|The Electric Company|Utility C|594739573|n|FERC Electric Tariff Original Volume No. 10|25|6/8/2001|7/6/2001|||Evergreen|N/A|N/A|N/A|N/A|MB|ENERGY|0||" "|" "|" "|Market Based||||" "|" "|||ep
-```
-
-Some useful hints
-
-* For available CSV formats please see [Apache Commons CSV User Guide](http://commons.apache.org/proper/commons-csv/user-guide.html)
-* Stripping the Excel BOM (Byte Order Mark) works out-of-box
-
-## 6.12 Executing Arbitrary Commands
+### 11. Executing Arbitrary Commands
 
 Using Apache Commons Exec allows to execute arbitrary commands - nice but dangerous. It was recently quite useful to to invoke AWS CLI to generate a Confluence page about the overall setup of our AWS accounts. 
 
@@ -985,7 +760,7 @@ h3. AWS EC2 Instance
 </#macro>
 ```
 
-## 6.13 Interactive Templates
+## 12. Interactive Templates
 
 Sometime you need to apply a CSS, JSON or XPath query in ad ad-hoc way without installing `xmllint`, `jq` or `pup` - in this case you can pass a FreeMarker template in an interactive fashion
 
@@ -1005,7 +780,7 @@ John Smith
 > bin/freemarker-cli -i '${JsoupTool.parse(DataSources.first).select("a")[0]}' examples/data/html/dependencies.html; echo
 <a href="${project.url}" title="FreeMarker CLI">FreeMarker CLI</a>
 
-> ./bin/freemarker-cli -i '<#list SystemTool.envs as name,value>${name} ==> ${value}${"\n"}</#list>'
+> freemarker-cli -i '<#list SystemTool.envs as name,value>${name} ==> ${value}${"\n"}</#list>'
 TERM ==> xterm-256color
 LANG ==> en_US
 DISPLAY ==> :0.0
@@ -1013,7 +788,7 @@ SHELL ==> /bin/bash
 EDITOR ==> vi
 ```
 
-## 6.14 Filtering & Transforming CSV
+## 13. Filtering & Transforming CSV
 
 During an integration project we imported large transactions CSV files (500.000+ records) and in case of import failures the developers would be happy to get a nice outline of the transactions causing the problem (the CSV records have 60+ columns) - in essence it is filtering (based on some primary key) and and transforming into a human-readable output format (Markdown).
 
@@ -1109,214 +884,21 @@ yields
 | Total Profit | 498855.44 |
 ```
 
-## 6.15 Converting Between JSON And YAML
+### 14. Converting Between JSON And YAML
 
 Sometimes we simply need to transform a JSON into an equivalent YAML or the other way around
 
 ```
-> ./bin/freemarker-cli -t templates/yaml/json/transform.ftl examples/data/yaml/swagger-spec.yaml 
-> ./bin/freemarker-cli -i '${GsonTool.toJson(YamlTool.parse(DataSources.get(0)))}' examples/data/yaml/swagger-spec.yaml
-> ./bin/freemarker-cli -i '${GsonTool.toJson(yaml)}' -m yaml=examples/data/yaml/swagger-spec.yaml
-
-> ./bin/freemarker-cli -t templates/json/yaml/transform.ftl examples/data/json/swagger-spec.json
-> ./bin/freemarker-cli -i '${YamlTool.toYaml(GsonTool.parse(DataSources.get(0)))}' examples/data/json/swagger-spec.json
-> ./bin/freemarker-cli -i '${YamlTool.toYaml(json)}' -m json=examples/data/json/swagger-spec.json
-```
-
-## 6.16 Using DataFrames
-
-The `DataFrameTool` uses [nRo/DataFrame](https://github.com/nRo/DataFrame) to convert tabular data into a `DataFrame`.
-
-A `DataFrame` allows declartive filtering and transformation of tabular data, i.e. less code to write.
-
-Currently the following sources are supported
-
-* Apache Commons CSV Parser
-* JSON arrays represented as collection of maps
-* Excel sheets represented as rows
-
-### CSV Examples
-
-[nRo/DataFrame]("https://raw.githubusercontent.com/nRo/DataFrame/master/src/test/resources/users.csv") provides the following CSV file
+> freemarker-cli -t templates/yaml/json/transform.ftl examples/data/yaml/swagger-spec.yaml 
+> freemarker-cli -i '${GsonTool.toJson(YamlTool.parse(DataSources.get(0)))}' examples/data/yaml/swagger-spec.yaml
+> freemarker-cli -i '${GsonTool.toJson(yaml)}' -m yaml=examples/data/yaml/swagger-spec.yaml
 
+> freemarker-cli -t templates/json/yaml/transform.ftl examples/data/json/swagger-spec.json
+> freemarker-cli -i '${YamlTool.toYaml(GsonTool.parse(DataSources.get(0)))}' examples/data/json/swagger-spec.json
+> freemarker-cli -i '${YamlTool.toYaml(json)}' -m json=examples/data/json/swagger-spec.json
 ```
-name;age;country
-Schmitt;24;Germany
-Parker;45;USA
-Meier;20;Germany
-Schmitt;30;France
-Peter;44;Germany
-Meier;24;Germany
-Green;33;UK
-Schmitt;30;Germany
-Meier;30;Germany
-```
-
-and create a `DateFrame` using the following code
-
-```
-<#assign cvsFormat = CSVTool.formats["DEFAULT"].withHeader().withDelimiter(';')>
-<#assign csvParser = CSVTool.parse(DataSources.get(0), cvsFormat)>
-<#assign users = DataFrameTool.toDataFrame(csvParser)>
-```
-
-#### Select By Age
-
-```
-${DataFrameTool.print(users.select("(age > 40)"))}
-```
-
-which shows 
-
-```
-┌────────────┬────────────┬────────────┐
-│#name       │#age        │#country    │
-├────────────┼────────────┼────────────┤
-│Parker      │45          │USA         │
-├────────────┼────────────┼────────────┤
-│Peter       │44          │Germany     │
-└────────────┴────────────┴────────────┘
-```
-
-#### Complex Select & Sort
-
-Now we want to create a new `DataFrame` by selecting `name` and `country`
-
-```
-<#assign country = "Germany">
-${DataFrameTool.print(users
-    .select("(name == 'Schmitt' || name == 'Meier') && country == '${country}'")
-    .sort("name", DataFrameTool.sortOrder["ASCENDING"]))}
-```
-
-which shows
-
-```
-┌────────────┬────────────┬────────────┐
-│#name       │#age        │#country    │
-├────────────┼────────────┼────────────┤
-│Meier       │20          │Germany     │
-├────────────┼────────────┼────────────┤
-│Meier       │24          │Germany     │
-├────────────┼────────────┼────────────┤
-│Meier       │30          │Germany     │
-├────────────┼────────────┼────────────┤
-│Schmitt     │24          │Germany     │
-├────────────┼────────────┼────────────┤
-│Schmitt     │30          │Germany     │
-└────────────┴────────────┴────────────┘
-```
-
-#### Count Column Values
-
-Let's assume we want to count the records for each `country`
-
-```
-${DataFrameTool.print(users.getColumn("country").transform(DataFrameTool.transformer["COUNT"]))}
-```
-
-returns the following `DataFrame`
-
-```
-┌────────────┬────────────┐
-│#country    │#counts     │
-├────────────┼────────────┤
-│Germany     │6           │
-├────────────┼────────────┤
-│USA         │1           │
-├────────────┼────────────┤
-│France      │1           │
-├────────────┼────────────┤
-│UK          │1           │
-└────────────┴────────────┘
-```
-
-#### Group By Age And Country
 
-Let's assume that we want to group the `DataFrame` by `age` and `country`
-
-```
-${DataFrameTool.print(users.groupBy("age", "country").sort("age"))}
-``` 
-
-which results in 
-
-```
-┌────────────┬────────────┐
-│#age        │#country    │
-├────────────┼────────────┤
-│20          │Germany     │
-├────────────┼────────────┤
-│24          │Germany     │
-├────────────┼────────────┤
-│30          │France      │
-├────────────┼────────────┤
-│30          │Germany     │
-├────────────┼────────────┤
-│33          │UK          │
-├────────────┼────────────┤
-│44          │Germany     │
-├────────────┼────────────┤
-│45          │USA         │
-└────────────┴────────────┘
-```
-
-### JSON Examples
-
-Here we load a `examples/data/json/github-users.json` which represents a tabular data be 
-being parsed as a list of maps and print the JSOB as dataframe
-
-```
-./bin/freemarker-cli -i '${DataFrameTool.print(DataFrameTool.fromMaps(GsonTool.parse(DataSources.get(0))))}' examples/data/json/github-users.json
-
-┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
-│#login      │#id         │#avatar_ur  │#gravatar_  │#url        │#html_url   │#followers  │#following  │#gists_url  │#starred_u  │#subscript  │#organizat  │#repos_url  │#events_ur  │#received_  │#type       │#site_admi  │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│mojombo     │1.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│defunkt     │2.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │true        │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│pjhyett     │3.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │true        │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│wycats      │4.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│ezmobius    │5.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│ivey        │6.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│evanphx     │7.00000000  │https:/...  │            │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │https:/...  │User        │false       │
-└────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
-```
-
-### Excel Examples
-
-Let's transform an Excel Sheet to a `DataFrame` being printed using the following template
-
-```
-<#assign dataSource = DataSources.get(0)>
-<#assign workbook = ExcelTool.parse(dataSource)>
-<#list ExcelTool.getSheets(workbook) as sheet>
-    <#assign table = ExcelTool.toTable(sheet)>
-    <#assign df = DataFrameTool.fromRows(table, true)>
-    ${DataFrameTool.print(df)}<#t>
-</#list>
-```
-
-which is rendered by the following command line invocation
-
-```
-./bin/freemarker-cli -t examples/templates/excel/dataframe/transform.ftl examples/data/excel/test.xls
-
-┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
-│#Text       │#Date       │#Number     │#Currency   │#Time       │#Percentag  │#Forumula   │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│Row 1       │01/01/17    │100.00      │€100.00     │10:00       │50.00%      │C2*F2       │
-├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
-│Row 2       │01/01/17    │100.00      │€100.00     │10:00       │50.00%      │C3*F3       │
-└────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
-```
-
-## 6.17 Using Advanced FreeMarker Features
+### 15. Using Advanced FreeMarker Features
 
 There is a `demo.ftl` which shows some advanced FreeMarker functionality
 
@@ -1328,7 +910,7 @@ There is a `demo.ftl` which shows some advanced FreeMarker functionality
 
 Running 
 
-> ./bin/freemarker-cli -t examples/templates/demo.ftl 
+> freemarker-cli -t examples/templates/demo.ftl 
 
 gives you
 
@@ -1506,56 +1088,4 @@ Time         :  11:13:51 AM
 ---------------------------------------------------------------------------
 > date
 Thu Jun 18 11:13:51 CEST 2020
-```
-
-# 7. Design Considerations
-
-## 7.1 How It Works
-
-* The user-supplied files are loaded or input is read from `stdin`
-* The FreeMarker data model containing the data sources and tools is created and passed to the template
-* The generated output is written to the user-supplied file or to `stdout`
-
-## 7.2 FreeMarker Data Model
-
-Within the script a FreeMarker data model is set up and passed to the template - it contains the data sources to be processed and the following tools
-
-| Entry                 | Description                                                                                               |
-|-----------------------|-----------------------------------------------------------------------------------------------------------|
-| CSVTool               | Process CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)              |
-| DataFrameTool         | Bridge to [nRo/DataFrame](https://github.com/nRo/DataFrame)                                            |
-| ExecTool              | Execute command line tools using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)   |
-| ExcelTool             | Process Excels files (XLS, XLSX) using [Apache POI](https://poi.apache.org)                               |
-| DataSources           | Helper class to find data sources, e.g. by name, extension or index                                       |
-| FreeMarkerTool        | Expose useful FreeMarker classes                                                                          |
-| GrokTool              | Process text files using [Grok](https://github.com/thekrakken/java-grok) instead of regular expressions   |
-| GsonTool              | Process JSON files using [GSON](https://github.com/google/gson)                                           |
-| JsonPathTool          | Process JSON file using [Java JSON Path](https://github.com/json-path/JsonPath)                           |
-| JsoupTool             | Processing HTML files using [Jsoup](https://jsoup.org)                                                    |
-| PropertiesTool        | Process JDK properties files                                                                              |
-| SystemTool            | System-related utility methods                                                                            |
-| UUIDTool              | Create UUIDs                                                                                              |
-| XmlTool               | Process XML files using [Apache FreeMarker](https://freemarker.apache.org/docs/xgui.html)                 |
-| YamlTool              | Process YAML files using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)                    |
-
-
-# 8. Tips & Tricks
-
-## 8.1 Template Base Directory
-
-When doing some ad-hoc scripting it is useful to rely on a base directory to resolve the FTL templates
-
-* As a default the FTL templates are resolved relative to the script directory
-* The caller can provide a `-b` or `--basedir` command line parameter
-
-```text
-./bin/freemarker-cli -b examples/templates -t json/md/github-users.ftl examples/data/json/github-users.json; echo
-```
-
-## 8.2 Using Pipes
-
-When doing ad-hoc scripting it useful to pipe the output of one command directly into "freemarker-cli"
-
-```text
-cat examples/data/json/github-users.json | ./bin/freemarker-cli -t examples/templates/json/md/github-users.ftl --stdin; echo
-```
+```
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-csv.md b/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-csv.md
new file mode 100644
index 0000000..e6c056d
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-csv.md
@@ -0,0 +1,80 @@
+## Transforming CSV
+
+A common task is changing the output format of a CSV file therefore `Apache FreeMarker CLI` ships with a ready-to-use
+templates to convert CSVs
+
+* Convert a CSV into a different format
+* Convert a CSV into Markdown or HTML
+
+### Convert CSV To A Different Output Format
+
+Let's assume that a CSV file in [DEFAULT format](https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#DEFAULT) 
+should be converted into a [Microsoft Excel format](https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#EXCEL).
+This allows opening the CSV directly in Excel without going to the tedious CSV import dialog.
+
+The following command line prints the converted CSV to `stdout`
+
+```
+freemarker-cli \
+ -PCSV_SOURCE_FORMAT=DEFAULT \
+ -PCSV_TARGET_FORMAT=EXCEL \
+ -PCSV_TARGET_DELIMITER=SEMICOLON \
+ -t templates/csv/csv/transform.ftl \
+ https://raw.githubusercontent.com/apache/freemarker-generator/master/freemarker-generator-cli/examples/data/csv/contract.csv 
+```  
+
+The command line invocation seems a bit complex at first so let's look at it more closely
+
+* `CSV_SOURCE_FORMAT` defines the CSV source format for reading the CSV
+* `CSV_TARGET_FORMAT` defines the CSV tagrte format for writing the CSV
+* `CSV_TARGET_DELIMITER` explicitely sets the delimiter of the target CSV to a semicolon since this expected by Excel for my current locale
+
+### Convert CSV To Markdown
+
+When doing documentation it is sometimes helpful to convert a CSV into its Markdown representation (AsciiDoc 
+actually allows including CSV directly)
+
+The following command line prints the resulting MarkDown to `stdout`
+
+```
+freemarker-cli \
+ -PCSV_SOURCE_FORMAT=DEFAULT \
+ -t templates/csv/md/transform.ftl \
+ https://raw.githubusercontent.com/apache/freemarker-generator/master/freemarker-generator-cli/examples/data/csv/contract.csv 
+```  
+
+Please note that most MarkDown tools expect a header row (see [Create a table without a header in Markdown](https://stackoverflow.com/questions/17536216/create-a-table-without-a-header-in-markdown))
+
+### Convert CSV To HTML
+
+Of course it is possible to convert a CSV to HTML as well
+
+```
+freemarker-cli \
+ -PCSV_SOURCE_FORMAT=DEFAULT \
+ -t templates/csv/html/transform.ftl \
+ https://raw.githubusercontent.com/apache/freemarker-generator/master/freemarker-generator-cli/examples/data/csv/contract.csv 
+```  
+
+### CSV Configuration Options
+
+The following options can be passed to template (as user-supplied parameters)
+
+| Parameter                 | Default Value     | Description                                               |
+|---------------------------|-------------------|-----------------------------------------------------------|
+| CSV_SOURCE_FORMAT         | DEFAULT           | Source CSV format                                         |
+| CSV_SOURCE_DELIMITER      | COMMA             | Symbolic name of delimiter, e.g. "COLON" or "SEMICOLON"   |
+| CSV_SOURCE_WITH_HEADER    | true              | Whether the first rows are headers                        |
+| CSV_TAGRGET_FORMAT        | DEFAULT           | Target CSV format                                         |
+| CSV_TARGET_DELIMITER      | COMMA             | Symbolic name of delimiter, e.g. "COLON" or "SEMICOLON"   |
+| CSV_TARGET_WITH_HEADER    | true              | Whether the first rows are headers                        |
+                                                            
+The delimiters are passed as symbolic names since passing seperators breaks command line handling
+
+* COMMA
+* HASH
+* PIPE
+* RS (ASCII record separator)
+* SEMICOLON
+* SPACE
+* TAB
diff --git a/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-directories.md b/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-directories.md
index 9f6a36f..ad694fb 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-directories.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-directories.md
@@ -1,11 +1,11 @@
 ## Transforming Directories
 
-FreeMarker CLI supports the transformation of directories
+`Apache FreeMarker CLI` supports the transformation of directories
 
 * Transform an input directory recursively into an output directory
 * If a template has a ".ftl" extension this extension will be removed after processing
-* Only a single directory is support
-* Currently no inclusion / exclusion patterns for templates are supported
+* Only a single directory is supported (for now)
+* Currently no inclusion / exclusion patterns for templates are supported (for now)
 
 The following sample files are used
 
@@ -13,7 +13,7 @@ The following sample files are used
 * template/nginx/nginx.conf.ftl
 
 ```
-appassembler> tree examples/data/template/
+tree examples/data/template/
 examples/data/template/
 |-- application.properties
 `-- nginx
@@ -39,7 +39,7 @@ server {
 If no output directory is provided all output is written to `stdout`
 
 ```
-bin/freemarker-cli -t examples/data/template/
+freemarker-cli -t examples/data/template/
 # == application.properties ==================================================
 server.name=localhost
 server.logs=/var/log/nginx
@@ -60,7 +60,7 @@ The transformed templates are written to an `out` directory
 * `nginx.conf.ftl` was changed to `nginx.conf" during the transformation
 
 ```
-bin/freemarker-cli -t examples/data/template/ -o out; tree out
+freemarker-cli -t examples/data/template/ -o out; tree out
 out
 |-- application.properties
 `-- nginx
@@ -74,7 +74,7 @@ out
 A user-supplied parameter `NGINX_HOSTNAME` is used to render the templates
 
 ```
-bin/freemarker-cli -t examples/data/template/ -P NGINX_HOSTNAME=localhost
+freemarker-cli -t examples/data/template/ -P NGINX_HOSTNAME=localhost
 # == application.properties ==================================================
 server.name=localhost
 server.logs=/var/log/nginx
@@ -97,7 +97,7 @@ All environment variables can be copied to the top-level data model by providing
 
 ```
 export NGINX_PORT=8080
-bin/freemarker-cli -t examples/data/template/ -m env:///
+freemarker-cli -t examples/data/template/ -m env:///
 # == application.properties ==================================================
 server.name=localhost
 server.logs=/var/log/nginx
@@ -117,7 +117,7 @@ Instead of environment variables an environment file (aka properties file) can b
 
 ```
 echo "NGINX_PORT=8080" > nginx.env
-bin/freemarker-cli -t examples/data/template/ -m nginx.env 
+freemarker-cli -t examples/data/template/ -m nginx.env 
 # == application.properties ==================================================
 server.name=localhost
 server.logs=/var/log/nginx
@@ -137,7 +137,7 @@ Another option is passing the information as JSON file
 
 ```
 echo '{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}' > nginx.json
-bin/freemarker-cli -t examples/data/template/ -m nginx.json 
+freemarker-cli -t examples/data/template/ -m nginx.json 
 # == application.properties ==================================================
 server.name=localhost
 server.logs=/var/log/nginx
@@ -157,7 +157,7 @@ Yet another option is using a YAML file
 
 ```
 echo -e "- NGINX_PORT": "\"8443\"\n- NGINX_HOSTNAME": "localhost" > nginx.yaml
-bin/freemarker-cli -t examples/data/template/ -m nginx.yaml 
+freemarker-cli -t examples/data/template/ -m nginx.yaml 
 # == application.properties ==================================================
 server.name=localhost
 server.logs=/var/log/nginx
@@ -180,7 +180,7 @@ In the cloud it is common to pass JSON configuration as environment variable
 
 ```
 export NGINX_CONF='{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}'
-bin/freemarker-cli -t examples/data/template/ -m env:///NGINX_CONF#mimetype=application/json
+freemarker-cli -t examples/data/template/ -m env:///NGINX_CONF#mimetype=application/json
 # == application.properties ==================================================
 server.name=localhost
 server.logs=/var/log/nginx
@@ -200,7 +200,7 @@ For testing purpose it is useful to override certain settings
 
 ```
 export NGINX_CONF='{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}'
-bin/freemarker-cli -t examples/data/template/ -PNGINX_HOSTNAME=www.mydomain.com -m env:///NGINX_CONF#mimetype=application/json
+freemarker-cli -t examples/data/template/ -PNGINX_HOSTNAME=www.mydomain.com -m env:///NGINX_CONF#mimetype=application/json
 # == application.properties ==================================================
 server.name=www.mydomain.com
 server.logs=/var/log/nginx
diff --git a/freemarker-generator-cli/src/site/markdown/cli/tools/dataframe.md b/freemarker-generator-cli/src/site/markdown/cli/usage/using-dataframes.md
similarity index 92%
rename from freemarker-generator-cli/src/site/markdown/cli/tools/dataframe.md
rename to freemarker-generator-cli/src/site/markdown/cli/usage/using-dataframes.md
index 83809ed..25c0c0e 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/tools/dataframe.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/using-dataframes.md
@@ -1,8 +1,8 @@
-# DataFrameTool
+## DataFrames
 
-The `DataFrameTool` uses [nRo/DataFrame](https://github.com/nRo/DataFrame) to convert tabular data into a `DataFrame`.
+A `DataFrame` allows declarative filtering and transformation of tabular data, i.e. less code to write. 
 
-A `DataFrame` allows declartive filtering and transformation of tabular data, i.e. little code to write.
+The `DataFrameTool` uses [nRo/DataFrame](https://github.com/nRo/DataFrame) to convert tabular data into a `DataFrame`.
 
 Currently the following sources are supported
 
@@ -10,7 +10,7 @@ Currently the following sources are supported
 * JSON arrays represented as collection of maps
 * Excel sheets represented as rows
 
-## CSV Examples
+### Working With CSV
 
 [nRo/DataFrame]("https://raw.githubusercontent.com/nRo/DataFrame/master/src/test/resources/users.csv") provides the following CSV file
 
@@ -27,15 +27,27 @@ Schmitt;30;Germany
 Meier;30;Germany
 ```
 
-and create a `DateFrame` using the following code
+and create a `DateFrame` using the following code snippet
+
+```
+<#assign dataSource = DataSources.get(0)>
+<#assign csvParser = CSVTool.parse(dataSource, CSVTool.formats["DATAFRAME"])>
+<#assign users = DataFrameTool.fromCSVParser(csvParser)>
+```
+
+The example can be executed by running
+
+```
+bin/freemarker-cli -PCSV_SOURCE_FORMAT=DATAFRAME -t examples/templates/dataframe/example.ftl examples/data/csv/dataframe.csv
+```
+
+or
 
 ```
-<#assign cvsFormat = CSVTool.formats["DEFAULT"].withHeader().withDelimiter(';')>
-<#assign csvParser = CSVTool.parse(DataSources.get(0), cvsFormat)>
-<#assign users = DataFrameTool.toDataFrame(csvParser)>
+bin/freemarker-cli -PCSV_SOURCE_FORMAT=DATAFRAME -t examples/templates/dataframe/example.ftl https://raw.githubusercontent.com/nRo/DataFrame/master/src/test/resources/users.csv
 ```
 
-### Select By Age
+#### Select By Age
 
 ```
 ${DataFrameTool.print(users.select("(age > 40)"))}
@@ -53,7 +65,7 @@ which shows
 └────────────┴────────────┴────────────┘
 ```
 
-### Complex Select & Sort
+#### Complex Select & Sort
 
 Now we want to create a new `DataFrame` by selecting `name` and `country`
 
@@ -82,7 +94,7 @@ which shows
 └────────────┴────────────┴────────────┘
 ```
 
-### Count Column Values
+#### Count Column Values
 
 Let's assume we want to count the records for each `country`
 
@@ -106,7 +118,7 @@ returns the following `DataFrame`
 └────────────┴────────────┘
 ```
 
-### Group By Age And Country
+#### Group By Age And Country
 
 Let's assume that we want to group the `DataFrame` by `age` and `country`
 
@@ -136,13 +148,14 @@ which results in
 └────────────┴────────────┘
 ```
 
-## JSON Examples
+### Working With JSON
 
-Here we load a `examples/data/json/github-users.json` which represents a tabular data be 
-being parsed as a list of maps and print the JSOB as dataframe
+Here we load a `examples/data/json/github-users.json` which represents a tabular 
+data being parsed as a list of maps and print the JSON as dataframe. Technically
+it is a list of maps hence we invoke `DataFrameTool.fromMaps()
 
 ```
-./bin/freemarker-cli \
+freemarker-cli \
   -i '${DataFrameTool.print(DataFrameTool.fromMaps(GsonTool.parse(DataSources.get(0))))}' \
   examples/data/json/github-users.json
 
@@ -165,7 +178,7 @@ being parsed as a list of maps and print the JSOB as dataframe
 └────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
 ```
 
-## Excel Examples
+### Working With Excel
 
 Let's transform an Excel Sheet to a `DataFrame` being printed using the following template
 
@@ -182,7 +195,7 @@ Let's transform an Excel Sheet to a `DataFrame` being printed using the followin
 which is rendered by the following command line invocation
 
 ```
-./bin/freemarker-cli -t examples/templates/excel/dataframe/transform.ftl examples/data/excel/test.xls
+freemarker-cli -t examples/templates/excel/dataframe/transform.ftl examples/data/excel/test.xls
 
 ┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
 │#Text       │#Date       │#Number     │#Currency   │#Time       │#Percentag  │#Forumula   │
diff --git a/freemarker-generator-cli/src/site/markdown/index.md b/freemarker-generator-cli/src/site/markdown/index.md
index 2eb0dfd..a3ecefa 100644
--- a/freemarker-generator-cli/src/site/markdown/index.md
+++ b/freemarker-generator-cli/src/site/markdown/index.md
@@ -1,17 +1,36 @@
 ## FreeMarker Generator CLI
 
+`Apache FreeMarker CLI` is a command-line interface for [Apache FreeMarker](https://freemarker.apache.org/) 
+
+* Requires JDK 1.8+ on Linux, Mac OSX and Windows
+* Use stdin, files and URLs to load data and templates 
+* Reads a variety of structured data formats such as access logs, CSV, Excel, JSON, HTML, YAML, XML
+* Provides JSONPath, XPath and DataFrames for advanced data manipulation
+* Transform a directory with a single command-line invocation
+* Made for the heavy lifting of data by using lazy-loading and streaming 
+
+### Getting Started
+
+* [Installation](cli/introduction/getting-started.html)
+* [Running Examples](cli/usage/running-examples.html)
+
 ### Concepts
 
+* [Design Goals](cli/concepts/design-goals.html)
 * [Named URIs](cli/concepts/named-uris.html)
 * [Data Sources](cli/concepts/data-sources.html)
 * [Data Models](cli/concepts/data-models.html)
-* [User-Supplied Parameters](cli/concepts/user-parameters.html)
+* [Passing Configuration Data](cli/concepts/passing-data.html)
+* [Template Loading](cli/concepts/template-loading.html)
 * [Transformation](cli/concepts/transformation.html)
-
-### Tools
-
-* [DataFrameTool](cli/tools/dataframe.html)
+* [Tools](cli/concepts/tools.html)
 
 ### Usage
 
 * [Transforming Directories](cli/usage/transforming-directories.html)
+* [Using DataFrames](cli/usage/using-dataframes.html)
+* [Transforming CSV](cli/usage/transforming-csv.html)
+
+### Advanced Topics
+
+* [FreeMarker CLI Configuration](cli/advanced/cli-configuration.html)
diff --git a/freemarker-generator-cli/site/image/contract.png b/freemarker-generator-cli/src/site/resources/images/examples/contract.png
similarity index 100%
rename from freemarker-generator-cli/site/image/contract.png
rename to freemarker-generator-cli/src/site/resources/images/examples/contract.png
diff --git a/freemarker-generator-cli/site/image/excel-to-html.png b/freemarker-generator-cli/src/site/resources/images/examples/excel-to-html.png
similarity index 100%
rename from freemarker-generator-cli/site/image/excel-to-html.png
rename to freemarker-generator-cli/src/site/resources/images/examples/excel-to-html.png
diff --git a/freemarker-generator-cli/site/image/github.png b/freemarker-generator-cli/src/site/resources/images/examples/github.png
similarity index 100%
rename from freemarker-generator-cli/site/image/github.png
rename to freemarker-generator-cli/src/site/resources/images/examples/github.png
diff --git a/freemarker-generator-cli/site/image/locker-test-users-pdf.png b/freemarker-generator-cli/src/site/resources/images/examples/locker-test-users-pdf.png
similarity index 100%
rename from freemarker-generator-cli/site/image/locker-test-users-pdf.png
rename to freemarker-generator-cli/src/site/resources/images/examples/locker-test-users-pdf.png
diff --git a/freemarker-generator-cli/site/image/transactions.png b/freemarker-generator-cli/src/site/resources/images/examples/transactions.png
similarity index 100%
rename from freemarker-generator-cli/site/image/transactions.png
rename to freemarker-generator-cli/src/site/resources/images/examples/transactions.png
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java
index faa6080..2b7f456 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java
@@ -24,8 +24,11 @@ import java.util.Arrays;
 public class ManualTest {
 
     private static final String SPACE = " ";
+    private static final String CMD = "-V";
     // private static final String CMD = "-PCSV_SOURCE_FORMAT=DATAFRAME -t examples/templates/dataframe/example.ftl https://raw.githubusercontent.com/nRo/DataFrame/master/src/test/resources/users.csv";
-    private static final String CMD = "-PCSV_SOURCE_WITH_HEADER=true -PCSV_SOURCE_FORMAT=DEFAULT -PCSV_TARGET_FORMAT=EXCEL -t templates/csv/md/transform.ftl examples/data/csv/contract.csv";
+    // private static final String CMD = "-PCSV_SOURCE_WITH_HEADER=false -PCSV_SOURCE_FORMAT=DEFAULT -PCSV_TARGET_FORMAT=EXCEL -PCSV_TARGET_WITH_HEADER=true -t templates/csv/csv/transform.ftl examples/data/csv/contract.csv";
+    // private static final String CMD = "-t examples/templates/json/dataframe/github-users.ftl examples/data/json/github-users.json";
+
 
     public static void main(String[] args) {
         Main.execute(toArgs(CMD));
diff --git a/freemarker-generator-cli/examples/templates/cat.ftl b/freemarker-generator-cli/templates/cat.ftl
similarity index 94%
rename from freemarker-generator-cli/examples/templates/cat.ftl
rename to freemarker-generator-cli/templates/cat.ftl
index a878261..c912c12 100644
--- a/freemarker-generator-cli/examples/templates/cat.ftl
+++ b/freemarker-generator-cli/templates/cat.ftl
@@ -1,4 +1,3 @@
-<#ftl output_format="plainText" strip_whitespace=true>
 <#--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
diff --git a/freemarker-generator-cli/templates/csv/csv/transform.ftl b/freemarker-generator-cli/templates/csv/csv/transform.ftl
index 656131d..ef8cf26 100644
--- a/freemarker-generator-cli/templates/csv/csv/transform.ftl
+++ b/freemarker-generator-cli/templates/csv/csv/transform.ftl
@@ -18,7 +18,12 @@
 <#import "/templates/lib/commons-csv.ftl" as csv />
 <#assign dataSource = DataSources.get(0)>
 <#assign csvParser = CSVTool.parse(dataSource, csv.sourceFormat())>
-<#assign csvPrinter = CSVTool.printer(csv.targetFormat())>
+<#assign csvTargetFormat = csv.targetFormat()>
+<#assign csvPrinter = CSVTool.printer(csvTargetFormat)>
+<#assign csvHeaders = (csvParser.getHeaderMap()!{})?keys>
+<#if csvHeaders?has_content && csvTargetFormat.getSkipHeaderRecord()>
+    ${csvPrinter.printRecord(csvHeaders)}<#t>
+</#if>
 <#list csvParser.iterator() as record>
     ${csvPrinter.printRecord(record)}<#t>
 </#list>
\ No newline at end of file
diff --git a/freemarker-generator-cli/templates/info.ftl b/freemarker-generator-cli/templates/info.ftl
index 838ac29..11275b6 100644
--- a/freemarker-generator-cli/templates/info.ftl
+++ b/freemarker-generator-cli/templates/info.ftl
@@ -25,7 +25,7 @@ Timestamp              : ${.now}
 Output encoding        : ${.output_encoding}
 Output format          : ${.output_format}
 
-FreeMarker CLI Template Directories
+FreeMarker CLI Template Loader Directories
 ------------------------------------------------------------------------------
 <#list SystemTool.getTemplateDirectories() as directory>
 [#${directory?counter}] ${directory}
diff --git a/freemarker-generator-cli/templates/lib/commons-csv.ftl b/freemarker-generator-cli/templates/lib/commons-csv.ftl
index 4082fa8..4e3c771 100644
--- a/freemarker-generator-cli/templates/lib/commons-csv.ftl
+++ b/freemarker-generator-cli/templates/lib/commons-csv.ftl
@@ -27,10 +27,10 @@
 <#function sourceFormat>
     <#assign format = CSVTool.formats[CSV_SOURCE_FORMAT!"DEFAULT"]>
     <#assign delimiter = CSVTool.toDelimiter(CSV_SOURCE_DELIMITER!format.getDelimiter())>
-    <#assign withHeader = CSV_SOURCE_WITH_HEADER!"false">
+    <#assign withHeader = CSV_SOURCE_WITH_HEADER!"true">
     <#assign format = format.withDelimiter(delimiter)>
     <#if withHeader?boolean>
-        <#assign format = format.withHeader()>
+        <#assign format = format.withFirstRecordAsHeader()>
     </#if>
     <#return format>
 </#function>
@@ -46,10 +46,10 @@
 <#function targetFormat>
     <#assign format = CSVTool.formats[CSV_TARGET_FORMAT!"DEFAULT"]>
     <#assign delimiter = CSVTool.toDelimiter(CSV_TARGET_DELIMITER!format.getDelimiter())>
-    <#assign withHeader = CSV_TARGET_WITH_HEADER!"false">
+    <#assign withHeader = CSV_TARGET_WITH_HEADER!"true">
     <#assign format = format.withDelimiter(delimiter)>
     <#if withHeader?boolean>
-        <#assign format = format.withHeader>
+        <#assign format = format.withFirstRecordAsHeader()>
     </#if>
     <#return format>
 </#function>
diff --git a/freemarker-generator-maven-plugin/CHANGELOG.md b/freemarker-generator-maven-plugin/CHANGELOG.md
new file mode 100644
index 0000000..015a87f
--- /dev/null
+++ b/freemarker-generator-maven-plugin/CHANGELOG.md
@@ -0,0 +1,12 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. We try to adhere to https://github.com/olivierlacan/keep-a-changelog.
+
+## 0.1.0-SNAPSHOT
+
+### Changed
+* [FREEMARKER-129] Change artifact `freemarker-maven-plugin` to `freemarker-generator-maven-plugin`
+* [FREEMARKER-128] Update `freemarker-maven-plugin` to Apache FreeMarker 2.3.29
+
+[FREEMARKER-128]: https://issues.apache.org/jira/browse/FREEMARKER-128
+[FREEMARKER-129]: https://issues.apache.org/jira/browse/FREEMARKER-129
diff --git a/freemarker-generator-maven-plugin/pom.xml b/freemarker-generator-maven-plugin/pom.xml
index e028aa8..be360ec 100644
--- a/freemarker-generator-maven-plugin/pom.xml
+++ b/freemarker-generator-maven-plugin/pom.xml
@@ -40,8 +40,6 @@
         <jmockit.version>1.32</jmockit.version>
         <org.testng.version>6.8</org.testng.version>
         <assertj-core.version>3.8.0</assertj-core.version>
-        <clover-target-percentage>100</clover-target-percentage>
-        <clover-phase>pre-site</clover-phase>
     </properties>
 
     <dependencies>
@@ -153,27 +151,6 @@
                     </execution>
                 </executions>
             </plugin>
-            <plugin>
-                <groupId>org.openclover</groupId>
-                <artifactId>clover-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>clover</id>
-                        <phase>${clover-phase}</phase>
-                        <goals>
-                            <goal>instrument-test</goal>
-                            <goal>clover</goal>
-                            <goal>check</goal>
-                        </goals>
-                        <configuration>
-                            <targetPercentage>${clover-target-percentage}</targetPercentage>
-                            <generateHtml>true</generateHtml>
-                            <generateXml>true</generateXml>
-                            <jdk>${maven.compiler.source}</jdk>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
     </build>
 
diff --git a/freemarker-generator-tools/README.md b/freemarker-generator-tools/README.md
index e624eb2..0c49388 100644
--- a/freemarker-generator-tools/README.md
+++ b/freemarker-generator-tools/README.md
@@ -1,35 +1,21 @@
 Apache FreeMarker Generator Tools
 =============================================================================
 
-A "tool" is just a POJO (plain old java object) that is "useful" in a template and is not meant to be rendered in the output. 
+The following tools are currently implemented
 
-Design Considerations
-------------------------------------------------------------------------------
-
-* A tool shall expose a default constructor and/or a constructor taking a `Map<String, Object> settings`
-* A tool processing data sources shall provide a `parse(Datasource)` method
-* A tool shall be stateless, multi-thread safe and potentially long-lived to enable usage in a different context
-* A tool shall support arbitrary large source data sources and process them efficiently
-* A tool shall expose a `toString()` method for documentation purposes
-
-Available Tools
-------------------------------------------------------------------------------
-
-The following tools are currently provided
-
-| Helper                | Description                                                                                               |
+| Tool                  | Description                                                                                               |
 |-----------------------|-----------------------------------------------------------------------------------------------------------|
 | CSVTool               | Process CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)              |
+| DataFrameTool         | Bridge to [nRo/DataFrame](https://github.com/nRo/DataFrame)                                               |
 | ExecTool              | Execute command line tools using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)   |
 | ExcelTool             | Process Excels files (XLS, XLSX) using [Apache POI](https://poi.apache.org)                               |
-| FreeMarkerTool        | Expose useful Apache FreeMarker classes                                                                   |
-| GrokTool              | Process text files using [Grok](https://github.com/thekrakken/java-grok) expressions                      |
-| JsonPathTool          | Process JSON files using [Java JSON Path](https://github.com/json-path/JsonPath)                          |
-| JsoupTool             | Process  HTML files using [Jsoup](https://jsoup.org)                                                      |
+| FreeMarkerTool        | Expose useful FreeMarker classes                                                                          |
+| GrokTool              | Process text files using [Grok](https://github.com/thekrakken/java-grok) instead of regular expressions   |
+| GsonTool              | Process JSON files using [GSON](https://github.com/google/gson)                                           |
+| JsonPathTool          | Process JSON file using [Java JSON Path](https://github.com/json-path/JsonPath)                           |
+| JsoupTool             | Processing HTML files using [Jsoup](https://jsoup.org)                                                    |
 | PropertiesTool        | Process JDK properties files                                                                              |
-| SystemTool            | Expose System-related utility methods                                                                     |
-| XmlTool               | Process XML files using [Apache FreeMarker](https://freemarker.apache.org/docs/xgui.html)                 |
-| YamlTool              | Process YAML files using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)                    |
+| SystemTool            | System-related utility methods                                                                            |
 | UUIDTool              | Create UUIDs                                                                                              |
-
-
+| XmlTool               | Process XML files using [Apache FreeMarker](https://freemarker.apache.org/docs/xgui.html)                 |
+| YamlTool              | Process YAML files using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)                    |
\ No newline at end of file
diff --git a/freemarker-generator-tools/pom.xml b/freemarker-generator-tools/pom.xml
index 57c6b59..256987a 100644
--- a/freemarker-generator-tools/pom.xml
+++ b/freemarker-generator-tools/pom.xml
@@ -122,10 +122,12 @@
     <reporting>
         <plugins>
             <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-javadoc-plugin</artifactId>
             </plugin>
             <plugin>
+                <artifactId>maven-jxr-plugin</artifactId>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.rat</groupId>
                 <artifactId>apache-rat-plugin</artifactId>
                 <configuration>
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java
index 7d2eab6..1dcda46 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java
@@ -22,6 +22,7 @@ import org.apache.commons.csv.CSVRecord;
 import org.apache.commons.io.input.BOMInputStream;
 import org.apache.freemarker.generator.base.datasource.DataSource;
 import org.apache.freemarker.generator.base.util.StringUtils;
+import org.apache.freemarker.generator.tools.commonscsv.impl.CommonsCSVPrinterFacade;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -72,7 +73,7 @@ public class CommonsCSVTool {
         }
 
         try {
-            // We don't need to close the underyling ByteArrayInputStream
+            // We don't need to close the underlying ByteArrayInputStream
             return parse(toInputStream(csv, UTF_8), UTF_8, format);
         } catch (IOException e) {
             throw new RuntimeException("Failed to parse CSV", e);
@@ -115,7 +116,7 @@ public class CommonsCSVTool {
 
     /**
      * Map the given value of the CVS record into (key to record). If duplicates
-     * are encountered return the first occurence of the CVS record. The map
+     * are encountered return the first occurrence of the CVS record. The map
      * retains the insertion order of they keys.
      *
      * @param records records to process
@@ -128,7 +129,7 @@ public class CommonsCSVTool {
 
     /**
      * Map the given value of the CVS record into (key to record). If duplicates
-     * are encountered return the first occurence of the CVS record. The map
+     * are encountered return the first occurrence of the CVS record. The map
      * retains the insertion order of they keys.
      *
      * @param records records to process
@@ -162,8 +163,8 @@ public class CommonsCSVTool {
     }
 
     /**
-     * Maps the sybmolic name of a delimiter to a single character since it
-     * is not possible to define commony used delimiters on the command line.
+     * Maps the symbolic name of a delimiter to a single character since it
+     * is not possible to define commonly used delimiters on the command line.
      *
      * @param name symbolic name of delimiter
      * @return CSV delimiter
@@ -238,7 +239,7 @@ public class CommonsCSVTool {
     private static Map<String, CSVFormat> createCSVFormats() {
         final Map<String, CSVFormat> result = new HashMap<>();
         result.put("DEFAULT", CSVFormat.DEFAULT);
-        result.put("DATAFRAME", CSVFormat.DEFAULT.withDelimiter(';').withFirstRecordAsHeader());
+        result.put("DATAFRAME", CSVFormat.RFC4180.withDelimiter(';').withFirstRecordAsHeader());
         result.put("EXCEL", CSVFormat.EXCEL);
         result.put("INFORMIX_UNLOAD", CSVFormat.INFORMIX_UNLOAD);
         result.put("INFORMIX_UNLOAD_CSV", CSVFormat.INFORMIX_UNLOAD_CSV);
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVPrinterFacade.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/impl/CommonsCSVPrinterFacade.java
similarity index 97%
rename from freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVPrinterFacade.java
rename to freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/impl/CommonsCSVPrinterFacade.java
index b8c0574..c8e8ac5 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVPrinterFacade.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/impl/CommonsCSVPrinterFacade.java
@@ -1,4 +1,4 @@
-package org.apache.freemarker.generator.tools.commonscsv;
+package org.apache.freemarker.generator.tools.commonscsv.impl;
 
 import org.apache.commons.csv.CSVFormat;
 import org.apache.commons.csv.CSVPrinter;
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/DataFrameTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/DataFrameTool.java
index bef1b7a..640d798 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/DataFrameTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/DataFrameTool.java
@@ -23,9 +23,9 @@ import de.unknownreality.dataframe.sort.SortColumn.Direction;
 import de.unknownreality.dataframe.transform.ColumnDataFrameTransform;
 import de.unknownreality.dataframe.transform.CountTransformer;
 import org.apache.commons.csv.CSVParser;
-import org.apache.freemarker.generator.tools.dataframe.converter.CSVConverter;
-import org.apache.freemarker.generator.tools.dataframe.converter.ListConverter;
-import org.apache.freemarker.generator.tools.dataframe.converter.MapConverter;
+import org.apache.freemarker.generator.tools.dataframe.impl.CSVConverter;
+import org.apache.freemarker.generator.tools.dataframe.impl.ListConverter;
+import org.apache.freemarker.generator.tools.dataframe.impl.MapConverter;
 
 import java.io.StringWriter;
 import java.util.Collection;
@@ -43,7 +43,9 @@ import static de.unknownreality.dataframe.DataFrameWriter.DEFAULT_PRINT_FORMAT;
 public class DataFrameTool {
 
     /**
-     * Create a default data frame.
+     * Create an empty data frame.
+     *
+     * @return data frame
      */
     public DataFrame create() {
         return new DefaultDataFrame();
@@ -81,7 +83,7 @@ public class DataFrameTool {
     }
 
     /**
-     * Provide a convinience map with predefined sort orders to be used by templates.
+     * Provide a convenience map with predefined sort orders to be used by templates.
      *
      * @return available sort orders
      */
@@ -93,7 +95,7 @@ public class DataFrameTool {
     }
 
     /**
-     * Provide a convinience map with predefined transformers.
+     * Provide a convenience map with predefined transformers.
      *
      * @return available transformers
      */
@@ -107,6 +109,7 @@ public class DataFrameTool {
      * Print the <code>DataFrame</code> to the FreeMarker writer.
      *
      * @param dataFrame data frame
+     * @return text representation of data frame
      */
     public String print(DataFrame dataFrame) {
         final StringWriter writer = new StringWriter();
@@ -119,6 +122,7 @@ public class DataFrameTool {
         return "Bridge to [nRo/DataFrame](https://github.com/nRo/DataFrame)";
     }
 
+    @SuppressWarnings("rawtypes")
     private static CountTransformer countTransformer(boolean ignoreNA) {
         return new CountTransformer(ignoreNA);
     }
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/CSVConverter.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/CSVConverter.java
similarity index 97%
rename from freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/CSVConverter.java
rename to freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/CSVConverter.java
index 055b508..5745c35 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/CSVConverter.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/CSVConverter.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.freemarker.generator.tools.dataframe.converter;
+package org.apache.freemarker.generator.tools.dataframe.impl;
 
 import de.unknownreality.dataframe.DataFrame;
 import de.unknownreality.dataframe.DataFrameBuilder;
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/ConverterUtils.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/ConverterUtils.java
similarity index 93%
rename from freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/ConverterUtils.java
rename to freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/ConverterUtils.java
index 5237f52..09beacd 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/ConverterUtils.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/ConverterUtils.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.freemarker.generator.tools.dataframe.converter;
+package org.apache.freemarker.generator.tools.dataframe.impl;
 
 import de.unknownreality.dataframe.DataFrame;
 import de.unknownreality.dataframe.DataFrameBuilder;
@@ -30,15 +30,15 @@ public class ConverterUtils {
     }
 
     static String getAlphaColumnName(int num) {
-        String result = "";
+        final StringBuilder result = new StringBuilder();
         while (num > 0) {
             num--; // 1 => a, not 0 => a
             final int remainder = num % 26;
             final char digit = (char) (remainder + 65);
-            result = digit + result;
+            result.insert(0, digit);
             num = (num - remainder) / 26;
         }
-        return result;
+        return result.toString();
     }
 
     private static DataFrameBuilder addColumn(DataFrameBuilder builder, String columnName, Class<?> columnType) {
@@ -66,7 +66,7 @@ public class ConverterUtils {
             case "java.util.Date":
                 return builder.addStringColumn(columnName);
             default:
-                throw new RuntimeException("Unable to add colum for the following type: " + columnType.getName());
+                throw new RuntimeException("Unable to add column for the following type: " + columnType.getName());
         }
     }
 
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/ListConverter.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/ListConverter.java
similarity index 91%
rename from freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/ListConverter.java
rename to freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/ListConverter.java
index ecf891a..4f83d04 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/ListConverter.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/ListConverter.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.freemarker.generator.tools.dataframe.converter;
+package org.apache.freemarker.generator.tools.dataframe.impl;
 
 import de.unknownreality.dataframe.DataFrame;
 import org.apache.freemarker.generator.base.table.Table;
@@ -28,6 +28,7 @@ public class ListConverter {
      * that the rows represent tabular data.
      *
      * @param rows rows to build the data frame
+     * @param withFirstRowAsColumnNames column names as first row?
      * @return <code>DataFrame</code>
      */
     public static DataFrame toDataFrame(List<List<Object>> rows, boolean withFirstRowAsColumnNames) {
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/MapConverter.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/MapConverter.java
similarity index 92%
rename from freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/MapConverter.java
rename to freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/MapConverter.java
index d8906c1..bc1a287 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/converter/MapConverter.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/MapConverter.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.freemarker.generator.tools.dataframe.converter;
+package org.apache.freemarker.generator.tools.dataframe.impl;
 
 import de.unknownreality.dataframe.DataFrame;
 import org.apache.freemarker.generator.base.table.Table;
@@ -22,8 +22,6 @@ import org.apache.freemarker.generator.base.table.Table;
 import java.util.Collection;
 import java.util.Map;
 
-import static java.util.Collections.singletonList;
-
 public class MapConverter {
 
     /**
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
index b5ead1d..d9bb473 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
@@ -53,7 +53,7 @@ public class ExcelTool {
             // make sure that the workbook is closed together with the data source
             return dataSource.addClosable(workbook);
         } catch (IOException e) {
-            throw new RuntimeException("Failed to parse Ecxel data source: " + dataSource, e);
+            throw new RuntimeException("Failed to parse Excel data source: " + dataSource, e);
         }
     }
 
@@ -94,7 +94,7 @@ public class ExcelTool {
     /**
      * EXPERIMENTAL FEATURE
      * <p>
-     * Transform the sheet to table contaning raw Java objects, e.g. Date, Double, ...
+     * Transform the sheet to table containing raw Java objects, e.g. Date, Double, ...
      *
      * @param sheet Excel sheet
      * @return Table containing cells as raw Java objects
@@ -121,8 +121,8 @@ public class ExcelTool {
         final List<Object> columnValues = new ArrayList<>();
         for (int columnIndex = 0; columnIndex < row.getLastCellNum(); columnIndex++) {
             final Cell cell = row.getCell(columnIndex, CREATE_NULL_AS_BLANK);
-            final String formatedCellValue = dataFormatter.formatCellValue(cell).trim();
-            columnValues.add(formatedCellValue);
+            final String formattedCellValue = dataFormatter.formatCellValue(cell).trim();
+            columnValues.add(formattedCellValue);
         }
         return columnValues;
     }
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/freemarker/FreeMarkerTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/freemarker/FreeMarkerTool.java
index 45b43e6..217aa8f 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/freemarker/FreeMarkerTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/freemarker/FreeMarkerTool.java
@@ -22,11 +22,19 @@ import freemarker.template.Configuration;
 import freemarker.template.TemplateHashModel;
 import freemarker.template.utility.ObjectConstructor;
 
+/**
+ * Exposes useful Apache FreeMarker classes for advanced FTL usage.
+ */
 public class FreeMarkerTool {
 
-    private BeansWrapper beansWrapper;
-    private ObjectConstructor objectConstructor;
+    private volatile BeansWrapper beansWrapper;
+    private volatile ObjectConstructor objectConstructor;
 
+    /**
+     * See <a href="https://freemarker.apache.org/docs/api/freemarker/template/utility/ObjectConstructor.html">FreeMarker ObjectConstructor</a>.
+     *
+     * @return ObjectConstructor
+     */
     public synchronized ObjectConstructor getObjectConstructor() {
         if (objectConstructor == null) {
             objectConstructor = new ObjectConstructor();
@@ -34,6 +42,11 @@ public class FreeMarkerTool {
         return objectConstructor;
     }
 
+    /**
+     * See <a href="https://freemarker.apache.org/docs/api/freemarker/ext/beans/BeansWrapper.html">FreeMarker BeansWrapper</a>.
+     *
+     * @return BeansWrapper
+     */
     public synchronized BeansWrapper getBeansWrapper() {
         if (beansWrapper == null) {
             beansWrapper = new BeansWrapperBuilder(Configuration.VERSION_2_3_30).build();
@@ -51,7 +64,7 @@ public class FreeMarkerTool {
 
     @Override
     public String toString() {
-        return "Expose useful Apache FreeMarker classes";
+        return "Expose advanced Apache FreeMarker classes";
     }
 }
 
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java
index 984d22c..0beab72 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java
@@ -18,6 +18,7 @@ package org.apache.freemarker.generator.tools.grok;
 
 import io.krakens.grok.api.Grok;
 import io.krakens.grok.api.GrokCompiler;
+import org.apache.freemarker.generator.tools.grok.impl.GrokWrapper;
 
 public class GrokTool {
 
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokWrapper.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/impl/GrokWrapper.java
similarity index 95%
rename from freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokWrapper.java
rename to freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/impl/GrokWrapper.java
index 7a6931e..626a94f 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokWrapper.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/impl/GrokWrapper.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.freemarker.generator.tools.grok;
+package org.apache.freemarker.generator.tools.grok.impl;
 
 import io.krakens.grok.api.Grok;
 import org.apache.freemarker.generator.base.util.StringUtils;
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java
index 3f038f7..36a8139 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java
@@ -125,7 +125,7 @@ public class SystemTool {
     }
 
     /**
-     * Convinience lookup of a configuration value based on
+     * Convenience lookup of a configuration value based on
      * user-supplied parameters, system properties and
      * environment variables.
      *
@@ -140,7 +140,7 @@ public class SystemTool {
     }
 
     /**
-     * Convinience lookup of a configuration value based on
+     * Convenience lookup of a configuration value based on
      * user-supplied parameters, system properties and
      * environment variables.
      *
diff --git a/freemarker-generator-tools/src/site/markdown/index.md b/freemarker-generator-tools/src/site/markdown/index.md
index 2fd9f95..19d0bb2 100644
--- a/freemarker-generator-tools/src/site/markdown/index.md
+++ b/freemarker-generator-tools/src/site/markdown/index.md
@@ -1 +1,66 @@
-TBD
\ No newline at end of file
+# Apache FreeMarker CLI Tools
+
+## Overview 
+
+The implementation of the `Apache FreeMarker CLI Tools` was inspired by [Apache Velocity Tools](https://velocity.apache.org/tools/devel/) - a `tool` is just a POJO (plain old Java object) that is "useful" in a template and is not meant to be rendered in the output.
+
+Let's have a look at the anatomy and life-cycle of a `Apache FreeMarker CLI Tool`
+
+* The meta-data, e.g. class name, is read from `freemarker-cli.properties`
+* It provides a default constructor
+* Its `toString` methods prints a short description
+* It exposes public methods being used directly by the template
+* It is instantiated once and is multi-thread-safe
+
+## Available Tools
+
+The following `tools` are currently implemented
+
+| Tool                  | Description                                                                                               |
+|-----------------------|-----------------------------------------------------------------------------------------------------------|
+| CSVTool               | Process CSV files using [Apache Commons CSV](https://commons.apache.org/proper/commons-csv/)              |
+| DataFrameTool         | Bridge to [nRo/DataFrame](https://github.com/nRo/DataFrame)                                               |
+| ExecTool              | Execute command line tools using [Apache Commons Exec](https://commons.apache.org/proper/commons-exec/)   |
+| ExcelTool             | Process Excels files (XLS, XLSX) using [Apache POI](https://poi.apache.org)                               |
+| FreeMarkerTool        | Expose useful FreeMarker classes                                                                          |
+| GrokTool              | Process text files using [Grok](https://github.com/thekrakken/java-grok) instead of regular expressions   |
+| GsonTool              | Process JSON files using [GSON](https://github.com/google/gson)                                           |
+| JsonPathTool          | Process JSON file using [Java JSON Path](https://github.com/json-path/JsonPath)                           |
+| JsoupTool             | Processing HTML files using [Jsoup](https://jsoup.org)                                                    |
+| PropertiesTool        | Process JDK properties files                                                                              |
+| SystemTool            | System-related utility methods                                                                            |
+| UUIDTool              | Create UUIDs                                                                                              |
+| XmlTool               | Process XML files using [Apache FreeMarker](https://freemarker.apache.org/docs/xgui.html)                 |
+| YamlTool              | Process YAML files using [SnakeYAML](https://bitbucket.org/asomov/snakeyaml/wiki/Home)                    |
+
+## Advanced Topics
+
+### Auto-closing Resources
+
+The user can create objects which need to be closed later on to avoid excessive resource usage. This is less of a concern for a short-lived CLI application but if many data sources are processed or the code is used in a different context the problem becomes more severe. 
+
+The `Excel Tool` provides the following code to keep track of `Closables` 
+
+```java
+package org.apache.freemarker.generator.tools.excel;
+
+public class ExcelTool {
+
+    public Workbook parse(DataSource dataSource) {
+        try (InputStream is = dataSource.getUnsafeInputStream()) {
+            final Workbook workbook = WorkbookFactory.create(is);
+            // make sure that the workbook is closed together with the data source
+            return dataSource.addClosable(workbook);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to parse Excel data source: " + dataSource, e);
+        }
+    }
+}
+```
+
+So what is happening here 
+
+* The `Workbook` is tracked by the originating `DataSource`
+* The `DataSource` implements the `Closable` interface
+* All `DataSources` are closed automatically when rendering is done.
+
diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVToolTest.java
index 29f8e0e..472e378 100644
--- a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVToolTest.java
+++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVToolTest.java
@@ -21,6 +21,7 @@ import org.apache.commons.csv.CSVParser;
 import org.apache.commons.csv.CSVRecord;
 import org.apache.freemarker.generator.base.datasource.DataSource;
 import org.apache.freemarker.generator.base.datasource.DataSourceFactory;
+import org.apache.freemarker.generator.tools.commonscsv.impl.CommonsCSVPrinterFacade;
 import org.junit.Test;
 
 import java.io.File;
diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/grok/GrokToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/grok/GrokToolTest.java
index 2bf21dc..30c0ed7 100644
--- a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/grok/GrokToolTest.java
+++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/grok/GrokToolTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.freemarker.generator.tools.grok;
 
+import org.apache.freemarker.generator.tools.grok.impl.GrokWrapper;
 import org.junit.Test;
 
 import java.util.Map;
diff --git a/pom.xml b/pom.xml
index 58b46f7..45cb794 100644
--- a/pom.xml
+++ b/pom.xml
@@ -123,6 +123,11 @@
                 <version>1.7.28</version>
             </dependency>
             <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-nop</artifactId>
+                <version>1.7.28</version>
+            </dependency>
+            <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
                 <version>4.13</version>
@@ -213,7 +218,7 @@
                 <plugin>
                     <groupId>pl.project13.maven</groupId>
                     <artifactId>git-commit-id-plugin</artifactId>
-                    <version>2.2.6</version>
+                    <version>4.0.0</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.rat</groupId>
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 455ebb0..bf0072c 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -2,7 +2,5 @@ The Apache FreeMarker Generator projects provides additional tools to generate t
 
 | Name                                                          | Description                                                       |
 | ------------------------------------------------------------- | ----------------------------------------------------------------- |
-| [Base](freemarker-generator-base/index.html)                  | Common functionality independent from Apache FreeMarker           |
-| [Tools](freemarker-generator-tools/index.html)                | Data source processing tools for Apache FreeMarker Generator      |
 | [CLI](freemarker-generator-cli/index.html)                    | Command-line client for Apache FreeMarker                         |
 | [Maven Plugin](freemarker-generator-maven-plugin/index.html)  | Maven plugin for Apache FreeMarker                                |
\ No newline at end of file
diff --git a/travis.sh b/travis.sh
index f76ae9d..1c55d1e 100755
--- a/travis.sh
+++ b/travis.sh
@@ -1,6 +1,24 @@
 #!/bin/sh
-mvn clean install
+# 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.
+#
+# Simulate the Travis build locally
+mvn clean install site site:stage
 cd ./freemarker-generator-cli
 sh ./run-examples.sh
 cd ../freemarker-generator-maven-plugin-sample
-mvn clean package
+mvn clean package
\ No newline at end of file