You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by db...@apache.org on 2015/07/24 00:21:05 UTC

[61/75] docs commit: Moved tools to tools/ and added some tools for new doc pipeline.

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/gen_defaults.py
----------------------------------------------------------------------
diff --git a/tools/bin/gen_defaults.py b/tools/bin/gen_defaults.py
new file mode 100644
index 0000000..d5ea283
--- /dev/null
+++ b/tools/bin/gen_defaults.py
@@ -0,0 +1,43 @@
+import os
+import sys
+import yaml
+
+from util import *
+
+def main():
+
+    root_dir = sys.argv[1]
+    config   = {'defaults': list()}
+
+    # extract configuration
+    for lang_name in listdirs(root_dir):
+
+        lang_path = os.path.join(root_dir, lang_name)
+
+        # configure language scope
+        config['defaults'].append({
+            'scope': {
+                'path': 'docs/' + lang_name
+            },
+            'values': {
+                'language': lang_name,
+                'layout': 'docs-' + lang_name
+            }
+        })
+
+        # configure each version scope
+        for version_name in listdirs(lang_path):
+            config['defaults'].append({
+                'scope': {
+                    'path': 'docs/' + lang_name + '/' + version_name
+                },
+                'values': {
+                    'version': version_name,
+                    'tocfile': lang_name + '-' + version_name.replace('.', '-')
+                }
+            })
+
+    print yaml.dump(config)
+
+if __name__ == '__main__':
+    main()

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/gen_languages.py
----------------------------------------------------------------------
diff --git a/tools/bin/gen_languages.py b/tools/bin/gen_languages.py
new file mode 100644
index 0000000..cc40be8
--- /dev/null
+++ b/tools/bin/gen_languages.py
@@ -0,0 +1,26 @@
+import os
+import sys
+import yaml
+
+from util import *
+
+def main():
+
+    root_dir = sys.argv[1]
+    config   = {}
+
+    # extract configuration
+    for lang_name in listdirs(root_dir):
+
+        lang_path     = os.path.join(root_dir, lang_name)
+        version_names = list(listdirs(lang_path))
+
+        config[lang_name] = {
+            'name':     lang_name,
+            'versions': version_names
+        }
+
+    print yaml.dump(config)
+
+if __name__ == '__main__':
+    main()

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/gen_toc.py
----------------------------------------------------------------------
diff --git a/tools/bin/gen_toc.py b/tools/bin/gen_toc.py
new file mode 100644
index 0000000..753d657
--- /dev/null
+++ b/tools/bin/gen_toc.py
@@ -0,0 +1,96 @@
+import os
+import re
+import sys
+import yaml
+
+from util import *
+
+def is_underline(line):
+    return re.match(r'-+|=+|\*+', line) is not None
+
+def get_page_title(page_path):
+
+    title = ''
+
+    # read in the page and remove the front matter
+    with open(page_path, 'r') as page_file:
+        page = page_file.read()
+    page = strip_front_matter(page)
+
+    # look for hash-headings and underline-headings
+    lines         = page.splitlines()
+    previous_line = lines[0]
+
+    for line in lines[1:]:
+
+        if is_underline(line):
+            return previous_line.strip()
+
+        match = re.match(r'^#+(.+)$', line)
+        if match:
+            return match.group(1).strip()
+
+        previous_line = line
+
+    # look for the first <hX> heading
+    match = re.search(r'[\s]*<h\d[^>]*>([^<]+)<\/h\d>', page, re.DOTALL)
+    if match:
+        return match.group(1).strip()
+
+    if title == '':
+        page_file_name = os.path.basename(page_path)
+        return page_file_name.replace('.md', '').capitalize()
+
+def main():
+
+    src_dir  = sys.argv[1]
+
+    data_root = os.path.join(src_dir, '_data', 'toc')
+    docs_root = os.path.join(src_dir, 'docs')
+
+    # go through all languages
+    for lang_name in listdirs(docs_root):
+        lang_path = os.path.join(docs_root, lang_name)
+
+        # go through all versions
+        for version_name in listdirs(lang_path):
+            version_path = os.path.join(lang_path, version_name)
+
+            # get path for toc file
+            toc           = []
+            toc_file_name = lang_name + '-' + version_name.replace('.', '-') + '.yml'
+            toc_file_path = os.path.join(data_root, toc_file_name)
+
+            # walk the version doc tree
+            for dir_root, dir_names, page_names in os.walk(version_path):
+
+                # get the URL prefix for pages in this directory
+                page_prefix = dir_root.replace(src_dir, '')
+
+                # process each file
+                for page_name in page_names:
+
+                    if not page_name.endswith('.md'):
+                        continue
+
+                    # compute page URL
+                    page_url = os.path.join(page_prefix, page_name)
+                    page_url = page_url.replace('.md', '.html')
+
+                    # extract page title
+                    page_path  = os.path.join(dir_root, page_name)
+                    page_title = get_page_title(page_path)
+
+                    toc.append({
+                        'name': page_title,
+                        'url': page_url
+                    })
+
+            # write out the toc
+            toc_string = yaml.dump(toc)
+            with open(toc_file_path, 'w') as data_file:
+                data_file.write(toc_string)
+            print toc_file_path
+
+if __name__ == '__main__':
+    main()

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/genjs
----------------------------------------------------------------------
diff --git a/tools/bin/genjs b/tools/bin/genjs
new file mode 100755
index 0000000..a03d088
--- /dev/null
+++ b/tools/bin/genjs
@@ -0,0 +1,67 @@
+#!/usr/bin/env node
+
+/*
+       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.
+*/
+/*jslint node:true, nomen: true */
+
+var generator = require('../lib/docs_generator');
+var yargs = require('yargs')
+    .describe('edge', 'Generate edge version of English docs')
+    .count("verbose")
+    .alias('v', 'verbose')
+    .describe('timing', 'Species level of timing measurements. If level not provided level 0 is used.')
+    .describe('verbose', 'Increase verbosity level of produced output')
+    .describe('source', 'Path to the documentation sources. Default: docs')
+    .describe('out', 'Path where documentation would be generated. Default: public')
+    .example('./bin/genjs --out public/test en', 'Generates English docs in the directory public/test')
+    .example('./bin/genjs --timing', 'Basic timing measurements')
+    .example('./bin/genjs --timing 1', 'Detailed timing measurements')
+    .usage('Usage: $0 [-v] [...options] [--edge] [lang] [version]\n' +
+        '    <lang>: Language for which generate docs. If not specified then generate for all languages.\n' +
+        '    <version>: Version for which generate docs. If not specified then generate all versions.');
+var argv = yargs.argv;
+
+if (argv.help) {
+    yargs.showHelp();
+    process.exit(1);
+}
+
+var language = null;
+var version = null;
+if (argv.edge) {
+    language = "en";
+    version = "edge";
+} else {
+    var argumentsCount = argv._.length;
+    if (argumentsCount !== 0) {
+        if (argumentsCount === 2) {
+            language = argv._[0];
+            version = argv._[1];
+        } else {
+            var data = argv._[0];
+            if (data.length === 2) {
+                language = data;
+            } else {
+                version = data;
+            }
+        }
+    }
+}
+
+new generator(argv.source, argv.out).run(language, version, argv.verbose, argv.timing);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/genjs.bat
----------------------------------------------------------------------
diff --git a/tools/bin/genjs.bat b/tools/bin/genjs.bat
new file mode 100644
index 0000000..70c9b92
--- /dev/null
+++ b/tools/bin/genjs.bat
@@ -0,0 +1,26 @@
+:: 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.
+
+@ECHO OFF
+SET script_path="%~dp0genjs"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'genjs' script in 'bin' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/incrementversion
----------------------------------------------------------------------
diff --git a/tools/bin/incrementversion b/tools/bin/incrementversion
new file mode 100755
index 0000000..e74852f
--- /dev/null
+++ b/tools/bin/incrementversion
@@ -0,0 +1,110 @@
+#!/usr/bin/env node
+/*
+       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.
+*/
+/*jslint node:true, nomen: true */
+
+var fs = require('fs-extra'),
+    path = require('path'),
+    yargs = require('yargs')
+    .describe('edge', 'Compare edge version of English docs with Ruby version')
+    .count("verbose")
+    .alias('v', 'verbose')
+    .describe('verbose', 'Increase verbosity level of produced output')
+    .demand(2)
+    .usage('Usage: $0 [lang] [version]\n' +
+        '    <lang>: Language for which update version number.\n' +
+        '    <version>: Next version.\n');
+var argv = yargs.argv;
+
+function processEachFile(source_path, callback) {
+    var directoryEntries = fs.readdirSync(source_path);
+    directoryEntries.forEach(function (dirEntry) {
+        var fullPath = path.join(source_path, dirEntry),
+            stat;
+        if (!fs.existsSync(fullPath)) {
+            return;
+        }
+
+        stat = fs.lstatSync(fullPath);
+        if (stat.isFile()) {
+            callback(fullPath);
+            return;
+        }
+
+        if (stat.isDirectory()) {
+            processEachFile(fullPath, callback);
+            return;
+        }
+    });
+}
+
+if (argv.help) {
+    yargs.showHelp();
+    process.exit(1);
+}
+
+var language = null,
+    version = null,
+    argumentsCount = argv._.length;
+if (argumentsCount === 2) {
+    language = argv._[0];
+    version = argv._[1];
+} else {
+    yargs.showHelp();
+    process.exit(1);
+}
+
+var prevVersion = fs.readFileSync('VERSION', { encoding: 'utf8' }),
+    edge_dir = path.join('docs', language, 'edge'),
+    release_dir = path.join('docs', language, version),
+    versionShort;
+
+prevVersion = prevVersion.replace(/rc\d+$/, '').trim();
+
+if (argv.verbose > 0) {
+    console.log("Copy edge docs to " + release_dir);
+}
+
+fs.mkdirSync(release_dir);
+fs.copySync(edge_dir, release_dir);
+
+versionShort = version.replace(/rc\d+$/, '').trim();
+if (prevVersion !== versionShort) {
+    // Replace x.x.x to new version in all files.
+    processEachFile(release_dir, function (filename) {
+        if (path.extname(filename) != ".md" && path.extname(filename) != ".html") {
+            return;
+        }
+        
+        var content = fs.readFileSync(filename, { encoding: 'utf8' });
+        content.replace('x.x.x', versionShort);
+        fs.writeFileSync(filename, content);
+    });
+}
+
+// Save version number to file.
+fs.writeFileSync('VERSION', version);
+
+console.log("Generated version " + version);
+console.log("");
+console.log("Next steps:");
+console.log("  1. Review the update using `git status`");
+console.log("  2. Commit the changes as 'Version " + version + "'");
+console.log("  3. Tag the commit as '" + version + "'");
+console.log("");
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/incrementversion.bat
----------------------------------------------------------------------
diff --git a/tools/bin/incrementversion.bat b/tools/bin/incrementversion.bat
new file mode 100644
index 0000000..36464e2
--- /dev/null
+++ b/tools/bin/incrementversion.bat
@@ -0,0 +1,26 @@
+:: 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.
+
+@ECHO OFF
+SET script_path="%~dp0incrementversion"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'incrementversion' script in 'bin' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/linkify-bugs.sh
----------------------------------------------------------------------
diff --git a/tools/bin/linkify-bugs.sh b/tools/bin/linkify-bugs.sh
new file mode 100755
index 0000000..03e3dc7
--- /dev/null
+++ b/tools/bin/linkify-bugs.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+if [[ ! -z "$1" ]]; then
+    cd $1
+fi
+
+for f in *.md; do
+  echo Processing: $f
+  perl -pi -e 's/ (CB-[0-9]+)/ [$1](https:\/\/issues.apache.org\/jira\/browse\/$1)/g' "$f"
+  perl -pi -e 's/ \[(CB-[0-9]+)\] / [$1](https:\/\/issues.apache.org\/jira\/browse\/$1) /g' "$f"
+done

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/merge_files.py
----------------------------------------------------------------------
diff --git a/tools/bin/merge_files.py b/tools/bin/merge_files.py
new file mode 100644
index 0000000..dbd45fb
--- /dev/null
+++ b/tools/bin/merge_files.py
@@ -0,0 +1,127 @@
+import os
+import sys
+import json
+import re
+import shutil
+
+from util import *
+
+# constants
+CONFIG_FILE_NAME = 'config.json'
+LICENSE_LINK     = 'http://www.apache.org/licenses/LICENSE-2.0'
+
+HEADER = '''---
+license: >
+    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.
+---
+'''
+
+# globals
+bad_merges = []
+
+def merge_files(merge_spec, prefix):
+
+    num_removed = 0
+    num_created = 0
+    global bad_merges
+
+    # merge all specified files
+    for dest_name, src_names in merge_spec.items():
+
+        # start the file empty
+        output_path = os.path.join(prefix, dest_name)
+        output      = HEADER
+
+        # accumulate all source files
+        for src_name in src_names:
+            src_path = os.path.join(prefix, src_name)
+
+            # read in the source file
+            try:
+                with open(src_path, 'r') as src_file:
+                    contribution = src_file.read()
+            except IOError:
+                continue
+
+            # massage its contents
+            contribution = strip_front_matter(contribution)
+            output      += contribution + "\n"
+
+            # remove the source file
+            num_removed += 1
+            os.remove(src_path)
+            print '|-', src_path
+
+        # write the merged file
+        with open(output_path, 'w') as output_file:
+            output_file.write(output)
+            num_created += 1
+
+        # check that the merge doesn't have repeated licenses
+        status = ''
+        if output.count(LICENSE_LINK) != 1:
+            status += '\033[31m'
+            bad_merges.append(output_path)
+        else:
+            status += '\033[32m'
+        status += output_path + '\033[m'
+
+        print '\ ->', status
+
+    return num_created, num_removed
+
+def main():
+
+    base_path     = sys.argv[1]
+    total_created = 0
+    total_removed = 0
+    global bad_merges
+
+    # walk the whole doc tree
+    for root_path, dir_names, file_names in os.walk(base_path):
+
+        # find config files
+        if CONFIG_FILE_NAME in file_names:
+
+            config_file_path = os.path.join(root_path, CONFIG_FILE_NAME)
+
+            # try to read in the config
+            try:
+                with open(config_file_path, 'r') as config_file:
+                    config = json.loads(config_file.read())
+            except IOError as e:
+                continue
+
+            # merge files
+            if 'merge' in config:
+                num_created, num_removed = merge_files(config['merge'], root_path)
+                total_created += num_created
+                total_removed += num_removed
+
+            os.remove(config_file_path)
+
+    print 'created', total_created, 'files'
+    print 'removed', total_removed, 'files'
+
+    if len(bad_merges) > 0:
+        print 'bad merges'
+        for file_path in bad_merges:
+            print file_path
+
+if __name__ == '__main__':
+    main()

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/translationreport
----------------------------------------------------------------------
diff --git a/tools/bin/translationreport b/tools/bin/translationreport
new file mode 100755
index 0000000..8a805be
--- /dev/null
+++ b/tools/bin/translationreport
@@ -0,0 +1,61 @@
+#!/usr/bin/env node
+/*
+       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.
+*/
+/*jslint node:true, nomen: true */
+
+var yargs = require('yargs')
+    .describe('edge', 'Compare version of English docs with translated version')
+    .count("verbose")
+    .alias('v', 'verbose')
+    .describe('verbose', 'Increase verbosity level of produced output')
+    .describe('source', 'Path to the documentation sources. Default: public')
+    .usage('Usage: $0 [-v] [lang] [version] [--edge]\n' +
+        '    <lang>: Language for which generate docs. If not specified then generate for all languages.\n' +
+        '    <version>: Version for which generate docs. If not specified then generate all versions.\n');
+var argv = yargs.argv;
+
+if (argv.help) {
+    yargs.showHelp();
+    process.exit(1);
+}
+
+var language = null;
+var version = null;
+if (argv.edge) {
+    language = null;
+    version = "edge";
+} else {
+    var argumentsCount = argv._.length;
+    if (argumentsCount !== 0) {
+        if (argumentsCount === 2) {
+            language = argv._[0];
+            version = argv._[1];
+        } else {
+            var data = argv._[0];
+            if (data.length === 2) {
+                language = data;
+            } else {
+                version = data;
+            }
+        }
+    }
+}
+
+var validator = require('../lib/docs_validator');
+new validator().validateTranslation(argv.source, language, version, argv.verbose);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/translationreport.bat
----------------------------------------------------------------------
diff --git a/tools/bin/translationreport.bat b/tools/bin/translationreport.bat
new file mode 100644
index 0000000..564f4e1
--- /dev/null
+++ b/tools/bin/translationreport.bat
@@ -0,0 +1,26 @@
+:: 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.
+
+@ECHO OFF
+SET script_path="%~dp0translationreport"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'translationreport' script in 'bin' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/util.py
----------------------------------------------------------------------
diff --git a/tools/bin/util.py b/tools/bin/util.py
new file mode 100644
index 0000000..9f2237f
--- /dev/null
+++ b/tools/bin/util.py
@@ -0,0 +1,22 @@
+import os
+
+def strip_front_matter(text):
+
+    marker = '---'
+
+    try:
+        first_marker = text.index(marker)
+    except ValueError as e:
+        return text
+
+    second_marker = text.index(marker, first_marker + len(marker))
+    start         = second_marker + len(marker)
+
+    return text[start:]
+
+def listdirs(root_path):
+    for subdir_name in os.listdir(root_path):
+        subdir_path = os.path.join(root_path, subdir_name)
+        if not os.path.isdir(subdir_path):
+            continue
+        yield subdir_name

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/validatejsdoc
----------------------------------------------------------------------
diff --git a/tools/bin/validatejsdoc b/tools/bin/validatejsdoc
new file mode 100755
index 0000000..ef72b5a
--- /dev/null
+++ b/tools/bin/validatejsdoc
@@ -0,0 +1,66 @@
+#!/usr/bin/env node
+
+/*
+       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.
+*/
+/*jslint node:true, nomen: true */
+
+var yargs = require('yargs')
+    .describe('edge', 'Compare edge version of English docs with Ruby version')
+    .count("verbose")
+    .alias('v', 'verbose')
+    .describe('verbose', 'Increase verbosity level of produced output')
+    .usage('Usage: $0 [-v] [lang] [version] [--edge]\n' +
+        '    <lang>: Language for which generate docs. If not specified then generate for all languages.\n' +
+        '    <version>: Version for which generate docs. If not specified then generate all versions.\n');
+var argv = yargs.argv;
+
+if (argv.help) {
+    yargs.showHelp();
+    process.exit(1);
+}
+
+var language = null;
+var version = null;
+if (argv.edge) {
+    language = "en";
+    version = "edge";
+} else {
+    var argumentsCount = argv._.length;
+    if (argumentsCount !== 0) {
+        if (argumentsCount === 2) {
+            language = argv._[0];
+            version = argv._[1];
+        } else {
+            var data = argv._[0];
+            if (data.length === 2) {
+                language = data;
+            } else {
+                version = data;
+            }
+        }
+    }
+}
+
+if (argv.compare) {
+    var comparer = require('../lib/docs_comparer');
+    new comparer().compare(language, version, argv.verbose);
+} else {
+    var validator = require('../lib/docs_validator');
+    new validator().validate(language, version, argv.verbose);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/bin/validatejsdoc.bat
----------------------------------------------------------------------
diff --git a/tools/bin/validatejsdoc.bat b/tools/bin/validatejsdoc.bat
new file mode 100644
index 0000000..fe36d1c
--- /dev/null
+++ b/tools/bin/validatejsdoc.bat
@@ -0,0 +1,26 @@
+:: 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.
+
+@ECHO OFF
+SET script_path="%~dp0validatejsdoc"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'validatejsdoc' script in 'bin' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/jodoc.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/jodoc.js b/tools/lib/cordova/jodoc.js
new file mode 100644
index 0000000..3ee184d
--- /dev/null
+++ b/tools/lib/cordova/jodoc.js
@@ -0,0 +1,130 @@
+/*
+       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.
+*/
+/*jslint node: true */
+/*global which, exec */
+var fs = require("fs-extra");
+var path = require("path");
+require('shelljs/global');
+
+var JoDoc = (function () {
+    'use strict';
+
+    var JO_DOC_CLI = "jodoc",
+        TEMPLATE_PATH = path.resolve(path.join(path.dirname(module.filename), '..', '..', 'template', 'docs')),
+        useLocalJoDoc = true;
+
+    /**
+    * Creates a new instance of JoDoc
+    * @param inputDirectory Directory which contains files which has to be processed.
+    * @param outputDirectory Directory to which store generated files.
+    * @param options Options for the generation process.
+    */
+    function JoDoc(inputDirectory, outputDirectory, options) {
+        this.input_directory = inputDirectory;
+        this.output_directory = outputDirectory;
+        this.options = options;
+
+        this.template_directories = [ path.join(TEMPLATE_PATH, "default") ];
+        if (options.lang) {
+            this.template_directories.push(path.join(TEMPLATE_PATH, options.lang));
+        }
+
+        this.check_dependencies();
+    }
+
+    JoDoc.prototype.check_dependencies = function () {
+        if (!which('jodoc') && !useLocalJoDoc) {
+            console.error('The jodoc script is not in your path');
+            process.exit(1);
+        }
+
+        [this.input_directory, this.template_directories[0]].forEach(function (dir) {
+            if (!fs.existsSync(dir)) {
+                console.error("The directory " + dir + " has to be present");
+                process.exit(1);
+            }
+
+            var stat = fs.lstatSync(dir);
+            if (!stat.isDirectory()) {
+                console.error("The path " + dir + " is not directory.");
+                process.exit(1);
+            }
+        });
+    };
+
+    JoDoc.prototype.run = function () {
+        var self = this,
+            currentDirectory = process.cwd(),
+            nullDevice = "/dev/null",
+            templateFile = path.join(this.output_directory, "index.html"),
+            commandLine,
+            child,
+            executableName;
+        // Copy HTML template assets
+        this.template_directories.forEach(function (templateDir) {
+            if (!fs.existsSync(templateDir)) {
+                if (self.options.verbose > 0) {
+                    console.log("Template folder " + templateDir + " not exists, skipping");
+                }
+
+                return;
+            }
+
+            var stat = fs.lstatSync(templateDir);
+            if (!stat.isDirectory()) {
+                return;
+            }
+
+            fs.copySync(templateDir, self.output_directory);
+        });
+
+        process.chdir(this.input_directory);
+
+        executableName = JO_DOC_CLI;
+        if (useLocalJoDoc) {
+            executableName = path.join(module.filename, "../../../node_modules/.bin/jodoc");
+        }
+
+        commandLine = executableName + " --output \"" + this.output_directory + "\" --title \"Cordova API Documentation\" --template \"" + templateFile + "\" ./";
+        if (self.options.verbose > 0) {
+            console.log("Running joDoc-js with command line:");
+            console.log(commandLine);
+        }
+
+        if (this.options.verbose < 2) {
+            commandLine = commandLine + " > " + nullDevice + " 2> " + nullDevice;
+        }
+
+        if (this.options.verbose > 1) {
+            console.info("Running jodoc from " + this.input_directory + " directory");
+            console.info(commandLine);
+        }
+
+        child = exec(commandLine);
+        if (child.code !== 0) {
+            console.error("Error during execution of jodoc. Error code is: " + child.code);
+            process.exit(child.code);
+        }
+
+        process.chdir(currentDirectory);
+    };
+
+    return JoDoc;
+}());
+module.exports = JoDoc;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/addtitle.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/addtitle.js b/tools/lib/cordova/post/addtitle.js
new file mode 100644
index 0000000..5920f92
--- /dev/null
+++ b/tools/lib/cordova/post/addtitle.js
@@ -0,0 +1,72 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var path = require("path");
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var AddTitle = (function () {
+    'use strict';
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function AddTitle(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Adding title";
+    }
+
+    AddTitle.prototype.run = function (file, $) {
+        if (path.extname(file) !== ".html") {
+            return;
+        }
+
+        if (this.options.verbose > 1) {
+            console.log("Add title to file " + file);
+        }
+
+        var title_source,
+            title_target,
+            title;
+        title_source = $('#content > h1');
+        if (title_source.length === 0) {
+            return null;
+        }
+
+        title_source = $(title_source[0]);
+        title_target = $('#subheader > h1');
+        if (title_target.length === 0) {
+            return null;
+        }
+
+        title_target = $(title_target[0]);
+        if (this.options.verbose > 1) {
+            console.log("Change title from " + title_target.text() + " to " + title_source.text());
+        }
+
+        title = title_source.text();
+        title_target.text(title);
+        return title;
+    };
+
+    return AddTitle;
+}());
+module.exports = AddTitle;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/index.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/index.js b/tools/lib/cordova/post/index.js
new file mode 100644
index 0000000..4200635
--- /dev/null
+++ b/tools/lib/cordova/post/index.js
@@ -0,0 +1,29 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var AddTitle = require("./addtitle"),
+    UpdateIndex = require("./updateindex"),
+    UpdateKeywordIndex = require("./updatekeywordindex"),
+    TableOfContents = require("./tableofcontents"),
+    VersionMenu = require("./versionmenu"),
+    NavigationMenu = require("./navigationmenu"),
+    Prettify = require("./prettify"),
+    NoIndex = require("./noindex"),
+    StepProcessor = require("./stepprocessor");
+module.exports = [StepProcessor, /*AddTitle,*/ UpdateIndex, UpdateKeywordIndex/*, TableOfContents, VersionMenu, NavigationMenu, Prettify, NoIndex*/];

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/navigationmenu.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/navigationmenu.js b/tools/lib/cordova/post/navigationmenu.js
new file mode 100644
index 0000000..869d223
--- /dev/null
+++ b/tools/lib/cordova/post/navigationmenu.js
@@ -0,0 +1,120 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var cheerio = require('cheerio'),
+    FileHelpers = require("../../file_helpers");
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var NavigationMenu = (function () {
+    'use strict';
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function NavigationMenu(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Building navigation menu";
+        this.sections = [];
+
+        var filename = path.join(FileHelpers.getTmpDirectory(), 'jodoc', 'index.md.html'),
+            $,
+            h1_set,
+            ul_set,
+            count,
+            i,
+            links,
+            appendLink;
+        if (!fs.existsSync(filename)) {
+            throw new Error("index.md.html was not generated in " + FileHelpers.getTmpDirectory() + "/jodoc");
+        }
+        $ = cheerio.load(fs.readFileSync(filename));
+        h1_set   = $('#home > h1');
+        ul_set   = $('#home > ul');
+        count    = h1_set.length;
+
+        function getAppender(links) {
+            function appendLink(index, element) {
+                links.push(element);
+            }
+
+            return appendLink;
+        }
+        
+        for (i = 0; i < count; i += 1) {
+            links = [];
+            appendLink = getAppender(links);
+
+            $('li > h2 > a', ul_set[i]).each(appendLink);
+
+            this.sections.push({
+                'title': $(h1_set[i]).text(),
+                'links': links
+            });
+        }
+    }
+
+    NavigationMenu.prototype.run = function (file, $) {
+        var i,
+            section;
+        if (path.extname(file) !== ".html") {
+            return;
+        }
+
+        if (this.options.verbose > 1) {
+            console.log("Appending file to nav menu " + file);
+        }
+
+        for (i = 0; i < this.sections.length; i += 1) {
+            section = this.sections[i];
+            this.insertTitle(section.title, $);
+            this.insertLinks(section.links, $);
+        }
+    };
+
+    NavigationMenu.prototype.insertTitle = function (title, $) {
+        var element = cheerio("<h1></h1>");
+        element.text(title);
+        $('#sidebar').first().append(element).append("\n");
+    };
+
+    NavigationMenu.prototype.insertLinks = function (links, $) {
+        var ul = cheerio("<ul></ul>"),
+            li,
+            i,
+            link;
+
+        ul.append("\n");
+        for (i = 0; i < links.length; i += 1) {
+            link = links[i];
+            li = cheerio("<li></li>");
+            li.append(link);
+            ul.append(li).append("\n");
+        }
+
+        $('#sidebar').first().append(ul).append("\n");
+    };
+
+    return NavigationMenu;
+}());
+module.exports = NavigationMenu;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/noindex.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/noindex.js b/tools/lib/cordova/post/noindex.js
new file mode 100644
index 0000000..0dae885
--- /dev/null
+++ b/tools/lib/cordova/post/noindex.js
@@ -0,0 +1,106 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var cheerio = require('cheerio'),
+    FileHelpers = require("../../file_helpers");
+
+/**
+* Preprocessor which adds meta tag robot=noindex, to all not latest versions of the docs.
+*/
+var NoIndex = (function () {
+    'use strict';
+    var latestVersion = null;
+
+    function getLatestIndex() {
+        // skip if we have the latest version
+        if (latestVersion !== null) {
+            return latestVersion;
+        }
+
+        // collect all english versions because they are the most up-to-date
+        var docs_path = FileHelpers.getDefaultInputDirectory(),
+            versions  = [],
+            lang_dir = path.join(docs_path, 'en'),
+            version_dirs,
+            last;
+
+        version_dirs = fs.readdirSync(lang_dir);
+        version_dirs.forEach(function (version) {
+            var configFile = path.join(lang_dir, version, "config.json"),
+                configData = JSON.parse(fs.readFileSync(configFile));
+            versions.push(version);
+        });
+
+        // sort the version list because Dir does not guarantee an order
+        versions.sort().reverse();
+
+        // we want the latest stable release
+        // if edge is the most recent, remove it
+        last = versions.shift();
+        if (last === 'edge') {
+            last = versions.shift();
+        }
+
+        // return the latest version
+        latestVersion = last;
+        return last;
+    }
+
+    function createNoIndexMeta() {
+        var element = cheerio("<meta></meta>");
+        element.attr('name', 'robots');
+        element.attr('label', 'noindex');
+        return element;
+    }
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function NoIndex(options) {
+        latestVersion = getLatestIndex();
+        this.options = options || { verbose: 0 };
+        this.stage = "Insert noindex";
+    }
+
+    NoIndex.prototype.run = function (file, $) {
+        if (!file.match(/\.html$/)) {
+            return null;
+        }
+
+        var version = this.options.version,
+            language = this.options.lang,
+            meta_tags;
+        if (latestVersion === version && language === 'en') {
+            if (this.options.verbose > 1) {
+                console.log("File belongs to language " + language + " and version " + version + " which is assumed to be latest");
+            }
+
+            return;
+        }
+
+        meta_tags = $('head meta');
+        meta_tags.append(createNoIndexMeta());
+    };
+
+    return NoIndex;
+}());
+module.exports = NoIndex;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/prettify.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/prettify.js b/tools/lib/cordova/post/prettify.js
new file mode 100644
index 0000000..66975a7
--- /dev/null
+++ b/tools/lib/cordova/post/prettify.js
@@ -0,0 +1,54 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var path = require("path");
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var Prettify = (function () {
+    'use strict';
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function Prettify(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Prettify";
+    }
+
+    Prettify.prototype.run = function (file, $) {
+        if (path.extname(file) !== ".html") {
+            return;
+        }
+
+        if (this.options.verbose > 1) {
+            console.log("Prettify file " + file);
+        }
+
+        var element;
+        element = $('#content pre');
+        element.attr('class', 'prettyprint');
+        return element;
+    };
+
+    return Prettify;
+}());
+module.exports = Prettify;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/stepprocessor.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/stepprocessor.js b/tools/lib/cordova/post/stepprocessor.js
new file mode 100644
index 0000000..14dd28a
--- /dev/null
+++ b/tools/lib/cordova/post/stepprocessor.js
@@ -0,0 +1,105 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var cheerio = require('cheerio');
+var AddTitle = require("./addtitle"),
+    TableOfContents = require("./tableofcontents"),
+    VersionMenu = require("./versionmenu"),
+    NavigationMenu = require("./navigationmenu"),
+    Prettify = require("./prettify"),
+    NoIndex = require("./noindex");
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var StepProcessor = (function () {
+    'use strict';
+
+    /**
+    * Creates a new instance of StepProcessor
+    * @param options Options for the generation process.
+    */
+    function StepProcessor(options) {
+        var self = this;
+        this.options = options || { verbose: 0, timing: -1 };
+        this.stage = "Step 1";
+        this.processors = [AddTitle,  TableOfContents, VersionMenu, NavigationMenu, Prettify, NoIndex].map(function (StepConstructor) {
+            var stepObject;
+            self.captureExecutionTime(" Substep init " + StepConstructor, 2, function () {
+                stepObject = new StepConstructor(self.options);
+            });
+            return stepObject;
+        });
+    }
+
+    StepProcessor.prototype.run = function (file) {
+        var self = this,
+            $,
+            steps;
+        if (path.extname(file) !== ".html") {
+            return;
+        }
+
+        $ = cheerio.load(fs.readFileSync(file));
+        this.processors.forEach(function (stepObject) {
+            self.captureExecutionTime(" Substep run: " + stepObject.stage, 2, function () {
+                stepObject.run(file, $);
+            });
+        });
+        // Save all content to file
+        fs.writeFileSync(file, $.html());
+    };
+    
+    StepProcessor.prototype.captureExecutionTime = function (step_name, level, callback) {
+        var startDate,
+            finishDate,
+            timingLevel = -1,
+            secondsPassed;
+        if (this.options.timing) {
+            if (this.options.timing === true) {
+                timingLevel = 0;
+            } else {
+                timingLevel = this.options.timing;
+            }
+        }
+        
+        if (timingLevel >= level) {
+            startDate = new Date();
+            if (this.options.verbose > 0) {
+                console.log(startDate, "Start " + step_name);
+            }
+        }
+        
+        callback.apply(this);
+        if (timingLevel >= level) {
+            finishDate = new Date();
+            if (this.options.verbose > 0) {
+                console.log(finishDate, "Finish " + step_name);
+            }
+            
+            secondsPassed = (finishDate.valueOf() - startDate.valueOf()) / 1000;
+            console.log(step_name + ". Total time: ", secondsPassed);
+        }
+    };
+
+    return StepProcessor;
+}());
+module.exports = StepProcessor;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/tableofcontents.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/tableofcontents.js b/tools/lib/cordova/post/tableofcontents.js
new file mode 100644
index 0000000..565e42b
--- /dev/null
+++ b/tools/lib/cordova/post/tableofcontents.js
@@ -0,0 +1,116 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var cheerio = require('cheerio');
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var TableOfContents = (function () {
+    'use strict';
+
+    /**
+    * Creates a new instance of TableOfContents
+    * @param options Options for the generation process.
+    */
+    function TableOfContents(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Building TOC";
+    }
+
+    TableOfContents.prototype.run = function (file, doc) {
+        var filenamePart = path.basename(file),
+            option_set = [],
+            current_h1 = "",
+            indentation = "\xa0\xa0\xa0\xa0\xa0\xa0",
+            select,
+            subheader;
+        if (filenamePart === "_index.html" || filenamePart === "index.html" || filenamePart === "index.md.html") {
+            return;
+        }
+
+        if (path.extname(file) !== ".html") {
+            return;
+        }
+
+        doc("#content h1, #content h2").each(function (index, elementDom) {
+            var element = cheerio(elementDom),
+                child = element.children().first(),
+                option,
+                s,
+                anchorName,
+                anchor;
+            if (elementDom.name === 'h1') {
+                current_h1 = element.text();
+                option = cheerio("<option></option");
+                anchorName =  child.attr('name');
+                if (anchorName !== null && anchorName !== undefined) {
+                    anchorName = encodeURIComponent(anchorName);
+                    option.attr('value', anchorName.replace(/\s/g, '%20'));
+                }
+
+                option.text(element.text());
+                option_set.push(option);
+            } else {
+                // Remove all leading and trailing non-word characters
+                // Replace all inner non-word characters with an underscore
+                // Replace all spaces since encodeURIComponent not produce correct URI
+                s = element.text()
+                    .replace(/^\W+|\W+$/g, '')
+                    .replace(/\W+/g, '_').toLowerCase();
+                option = cheerio("<option></option>");
+                anchorName = current_h1 + "_" + s;
+                anchorName = encodeURIComponent(anchorName);
+                anchorName = anchorName.replace(/%2520/g, '%20');
+                option.attr('value', anchorName);
+                option.text(indentation + "- " + element.text());
+                option_set.push(option);
+
+                anchor = cheerio("<a></a>");
+                anchor.attr('name', anchorName);
+                anchor.text(element.text());
+                element.text('');
+                element.append(anchor);
+            }
+        });
+
+        // Return if one or less elements found (useless selection box)
+        if (option_set.length <= 1) {
+            return null;
+        }
+
+        // Add select menu to the subheader
+        select = cheerio("<select></select>");
+        option_set.forEach(function (optionGroup) {
+            select.append(optionGroup);
+        });
+        subheader = doc("#subheader > small").first();
+        if (subheader.length === 0) {
+            return null;
+        }
+
+        subheader.append(select);
+        return option_set;
+    };
+
+    return TableOfContents;
+}());
+module.exports = TableOfContents;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/updateindex.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/updateindex.js b/tools/lib/cordova/post/updateindex.js
new file mode 100644
index 0000000..a8f3a79
--- /dev/null
+++ b/tools/lib/cordova/post/updateindex.js
@@ -0,0 +1,65 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var cheerio = require('cheerio');
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var UpdateIndex = (function () {
+    'use strict';
+    var header_title  = 'Home';
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function UpdateIndex(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Update index";
+        this.header_title = header_title;
+    }
+
+    UpdateIndex.prototype.run = function (file) {
+        if (path.basename(file) !== "index.md.html") {
+            return false;
+        }
+
+        if (this.options.verbose > 1) {
+            console.info("Update index");
+        }
+
+        var $ = cheerio.load(fs.readFileSync(file)),
+            title_target;
+        title_target = $('#subheader > h1');
+        if (title_target.length !== 0) {
+            title_target = $(title_target[0]);
+            title_target.text(header_title);
+        }
+
+        fs.writeFileSync(file, $.html());
+        fs.renameSync(file, path.join(path.dirname(file), "index.html"));
+        return true;
+    };
+
+    return UpdateIndex;
+}());
+module.exports = UpdateIndex;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/updatekeywordindex.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/updatekeywordindex.js b/tools/lib/cordova/post/updatekeywordindex.js
new file mode 100644
index 0000000..e5a48f9
--- /dev/null
+++ b/tools/lib/cordova/post/updatekeywordindex.js
@@ -0,0 +1,80 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var cheerio = require('cheerio');
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var UpdateKeywordIndex = (function () {
+    'use strict';
+    var header_title  = 'Keyword Index',
+        content_title = 'Keyword Index';
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function UpdateKeywordIndex(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Update keywork index";
+        this.header_title = header_title;
+        this.content_title = content_title;
+    }
+
+    UpdateKeywordIndex.prototype.run = function (file) {
+        if (path.basename(file) !== "_index.html") {
+            return false;
+        }
+
+        if (this.options.verbose > 1) {
+            console.info("Update keyword index");
+        }
+
+        var $ = cheerio.load(fs.readFileSync(file)),
+            element,
+            content;
+        element = $('#subheader > h1');
+        if (element.length !== 0) {
+            element = $(element[0]);
+            element.text(header_title);
+        }
+
+        element = $('#content > h1');
+        if (element.length !== 0) {
+            element = $(element[0]);
+            element.text(content_title);
+        }
+
+        element = $('#content > hr');
+        if (element.length !== 0) {
+            element = $(element[0]);
+            element.remove();
+        }
+
+        content = $.html();
+        content = content.replace(/"index\.md\.html/g, '"index.html');
+        fs.writeFileSync(file, content);
+    };
+
+    return UpdateKeywordIndex;
+}());
+module.exports = UpdateKeywordIndex;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/post/versionmenu.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/post/versionmenu.js b/tools/lib/cordova/post/versionmenu.js
new file mode 100644
index 0000000..84bda9b
--- /dev/null
+++ b/tools/lib/cordova/post/versionmenu.js
@@ -0,0 +1,143 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var cheerio = require('cheerio');
+
+/**
+* Preprocessor which updates top stripe with header or the page.
+*/
+var VersionMenu = (function () {
+    'use strict';
+    var languages = null,
+        versions = null;
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function VersionMenu(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Populate version menu";
+        if (languages === null) {
+            languages = [];
+            versions = [];
+            this.buildVersionsData();
+        }
+        
+        this.generatedMenu = this.generateMenu();
+    }
+
+    VersionMenu.prototype.run = function (file, $) {
+        if (path.extname(file) !== ".html") {
+            return;
+        }
+
+        if (this.options.verbose > 1) {
+            console.info("Building version menu for file " + file);
+        }
+
+        var element;
+
+        element = $('#header small select').first();
+        this.generatedMenu.forEach(function (optionGroup) {
+            element.append(optionGroup).append("\n");
+        });
+    };
+
+    VersionMenu.prototype.buildVersionsData = function () {
+        var docs_path = path.resolve(path.join(module.filename, '..', '..', '..', '..', 'docs')),
+            lang_dirs,
+            lang_labels = [];
+
+        lang_dirs = fs.readdirSync(docs_path);
+        lang_dirs.forEach(function (lang) {
+            versions[lang] = [];
+            var lang_dir = path.join(docs_path, lang),
+                version_dirs;
+            version_dirs = fs.readdirSync(lang_dir);
+            version_dirs.forEach(function (version) {
+                var configFile = path.join(lang_dir, version, "config.json"),
+                    configData = JSON.parse(fs.readFileSync(configFile));
+                versions[lang].push(version);
+                lang_labels[lang] = configData.language;
+            });
+
+            languages.push({ lang: lang, label: lang_labels[lang] });
+        });
+        languages = languages.sort(function (a, b) {
+            if (a.label === b.label) {
+                return 0;
+            }
+
+            if (a.label > b.label) {
+                return 1;
+            }
+
+            return -1;
+        });
+    };
+
+    VersionMenu.prototype.generateMenu = function () {
+        var result = [],
+            langGroup,
+            versionData,
+            versionOption,
+            lang,
+            versionIndex,
+            version,
+            mapper,
+            key;
+
+        mapper = function (item) {
+            return item;
+        };
+
+        for (key in languages) {
+            if (languages.hasOwnProperty(key)) {
+                lang = languages[key].lang;
+                langGroup = cheerio("<optgroup></optgroup>");
+                langGroup.append("\n");
+                langGroup.attr('label', languages[key].label);
+                langGroup.attr('value', lang);
+
+                versionData = versions[lang].map(mapper).reverse();
+                for (versionIndex = 0; versionIndex < versionData.length; versionIndex = versionIndex + 1) {
+                    version = versionData[versionIndex];
+                    versionOption = cheerio("<option></option>");
+                    if (this.options.version === version && this.options.lang === lang) {
+                        versionOption.attr('selected', 'selected');
+                    }
+
+                    versionOption.attr('value', version);
+                    versionOption.text(version);
+                    langGroup.append(versionOption).append("\n");
+                }
+
+                result.push(langGroup);
+            }
+        }
+
+        return result;
+    };
+
+    return VersionMenu;
+}());
+module.exports = VersionMenu;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/pre/filemerger.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/pre/filemerger.js b/tools/lib/cordova/pre/filemerger.js
new file mode 100644
index 0000000..e55da60
--- /dev/null
+++ b/tools/lib/cordova/pre/filemerger.js
@@ -0,0 +1,109 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra"),
+    path = require("path"),
+    FileHelpers = require("../../file_helpers");
+
+var FileMerger = (function () {
+    'use strict';
+
+    var config = null;
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function FileMerger(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Merge files";
+
+        config = null;
+    }
+
+    FileMerger.prototype.run = function (file) {
+        if (this.options.verbose > 1) {
+            console.log("Merge file " + file);
+        }
+
+        if (file.match(/\/guide\//)) {
+            return null;
+        }
+
+        if (!fs.existsSync(file)) {
+            return null;
+        }
+
+        this.filename  = path.basename(file);
+        this.directory = path.dirname(file);
+
+        var filesToAppend,
+            cfg = this.config(),
+            i,
+            filepath;
+        if (!cfg.hasOwnProperty(this.filename)) {
+            return null;
+        }
+
+        filesToAppend = cfg[this.filename];
+        for (i = 0; i < filesToAppend.length; i += 1) {
+            filepath = filesToAppend[i];
+
+            // skip the file that we're merging into because it's listed in config.json
+            if (path.basename(filepath) === this.filename) {
+                if (this.options.verbose > 0) {
+                    console.log("Skipping " + filesToAppend[i] + " from " + this.filename + " section since it has same base name as file to merge");
+                }
+            } else {
+                filepath = path.join(FileHelpers.getTmpDirectory(), 'docs', filepath);
+                fs.appendFileSync(file, "\n\n---\n");
+                if (!fs.existsSync(filepath)) {
+                    console.log("File " + filepath + " is missing and thus don't merged with " + file);
+                } else {
+                    fs.appendFileSync(file, fs.readFileSync(filepath, "utf-8").trim());
+                    fs.removeSync(filepath);
+                }
+            }
+        }
+    };
+
+    FileMerger.prototype.config = function () {
+        if (config !== null) {
+            return config;
+        }
+
+        var directory = this.directory,
+            file,
+            configJSON;
+        while (config === null) {
+            file = path.join(directory, 'config.json');
+            if (fs.existsSync(file)) {
+                configJSON = fs.readFileSync(file);
+                config = JSON.parse(configJSON).merge;
+            } else {
+                directory = fs.dirname(directory);
+            }
+        }
+
+        return config;
+    };
+
+    return FileMerger;
+}());
+module.exports = FileMerger;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/pre/index.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/pre/index.js b/tools/lib/cordova/pre/index.js
new file mode 100644
index 0000000..db3de0b
--- /dev/null
+++ b/tools/lib/cordova/pre/index.js
@@ -0,0 +1,22 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var FileMerger = require("./filemerger"),
+    YamlFrontMatter = require("./yamlfrontmatter");
+module.exports = [YamlFrontMatter, FileMerger];

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/cordova/pre/yamlfrontmatter.js
----------------------------------------------------------------------
diff --git a/tools/lib/cordova/pre/yamlfrontmatter.js b/tools/lib/cordova/pre/yamlfrontmatter.js
new file mode 100644
index 0000000..fc8ef4e
--- /dev/null
+++ b/tools/lib/cordova/pre/yamlfrontmatter.js
@@ -0,0 +1,67 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra"),
+    path = require("path"),
+    yaml = require("js-yaml");
+
+var YamlFrontMatter = (function () {
+    'use strict';
+
+    /**
+    * Creates a new instance of FileMerger
+    * @param options Options for the generation process.
+    */
+    function YamlFrontMatter(options) {
+        this.options = options || { verbose: 0 };
+        this.stage = "Starting YAML stripping";
+    }
+
+    YamlFrontMatter.prototype.run = function (file) {
+        if (this.options.verbose > 1) {
+            console.log("String YAML from file " + file);
+        }
+
+        var content = fs.readFileSync(file, "utf8"),
+            yamlRegexStripper = /^(---\s*\n[\s\S]*?\n?)^(---\s*$\n?)/m,
+            match = yamlRegexStripper.exec(content),
+            yamlData;
+        if (match === null) {
+            return {};
+        }
+
+        try {
+            yamlData = yaml.safeLoad(match[1]);
+        } catch (yamle) {
+            console.error("File: " + file);
+            if (this.options.verbose > 1) {
+                console.error("YAML Exception during processing following content:\n" + content);
+            }
+
+            throw yamle;
+        }
+
+        content = content.substr(match[0].length);
+        fs.writeFileSync(file, content);
+        return yamlData;
+    };
+
+    return YamlFrontMatter;
+}());
+module.exports = YamlFrontMatter;

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/5f554950/tools/lib/docs_comparer.js
----------------------------------------------------------------------
diff --git a/tools/lib/docs_comparer.js b/tools/lib/docs_comparer.js
new file mode 100644
index 0000000..9548e16
--- /dev/null
+++ b/tools/lib/docs_comparer.js
@@ -0,0 +1,251 @@
+/*
+       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.
+*/
+/*jslint node: true */
+var fs = require("fs-extra");
+var path = require("path");
+var JoDoc = require("./cordova/jodoc");
+var FileHelpers = require("./file_helpers");
+var cheerio = require('cheerio');
+var jsdiff = require('diff');
+require('colors');
+
+var DocsComparer = (function () {
+    'use strict';
+
+    function processEachFile(source_path, fileCallback, directoryCallback) {
+        var directoryEntries = fs.readdirSync(source_path);
+        directoryEntries.forEach(function (dirEntry) {
+            var fullPath = path.join(source_path, dirEntry),
+                stat;
+            if (!fs.existsSync(fullPath)) {
+                return;
+            }
+
+            stat = fs.lstatSync(fullPath);
+            if (stat.isFile()) {
+                fileCallback(fullPath);
+                return;
+            }
+
+            if (stat.isDirectory()) {
+                if (directoryCallback(fullPath)) {
+                    processEachFile(fullPath, fileCallback, directoryCallback);
+                }
+
+                return;
+            }
+        });
+    }
+
+    /**
+    * Creates a new instance of DocsComparer
+    * @param inputDirectory Directory which contains files which has to be processed.
+    * @param outputDirectory Directory to which store generated files.
+    */
+    function DocsComparer(originalDirectory, outputDirectory) {
+        this.original_directory = originalDirectory || path.join(FileHelpers.getRootDirectory(), "public");
+        this.output_directory = outputDirectory || path.join(FileHelpers.getRootDirectory(), "public/test");
+    }
+
+    /**
+    * Compares two sets of documentation
+    * @param language Language which has to be compared.
+    * @param version Version which files has to be compared.
+    * @param verbose_mode Verbosity level.
+    */
+    DocsComparer.prototype.compare = function (language, version, verbose_mode) {
+        var self = this,
+            ignore_list = ['.', '..', '.DS_Store', 'test'];
+
+        verbose_mode = verbose_mode || 0;
+        if (verbose_mode > 0) {
+            console.log("Comparing docs for lang " + language + " and version " + version);
+            console.log("Clearing output directory");
+        }
+
+        fs.readdirSync(this.original_directory).forEach(function (language_dir) {
+            if (ignore_list.indexOf(language_dir) !== -1) {
+                return;
+            }
+
+            if (language && language_dir !== language) {
+                return;
+            }
+
+            var language_path = path.join(self.original_directory, language_dir);
+
+            fs.readdirSync(language_path).forEach(function (version_dir) {
+                if (ignore_list.indexOf(version_dir) !== -1) {
+                    return;
+                }
+
+                if (version && version_dir !== version) {
+                    return;
+                }
+
+                var output_path = path.join(self.output_directory, language_dir, version_dir),
+                    input_path = path.join(self.original_directory, language_dir, version_dir),
+                    options = {
+                        lang: language_dir,
+                        version: version_dir,
+                        verbose: verbose_mode
+                    };
+
+                console.log(" => Comparing the Cordova Documentation for " + version_dir + "-" + language_dir + "...");
+                self.process(input_path, output_path, options);
+            });
+        });
+    };
+    DocsComparer.prototype.process = function (original_directory, output_path, options) {
+        var self = this,
+            compareFiles;
+        console.log("Processing " + original_directory + " and " + output_path);
+        compareFiles = function (fileName) {
+            var relativePath = path.relative(original_directory, fileName),
+                targetFile,
+                originalFileStat,
+                targetFileStat,
+                originalFileSize,
+                targetFileSize;
+            targetFile = path.join(output_path, relativePath);
+            if (!fs.existsSync(targetFile)) {
+                console.error("Path " + relativePath + " is missing in the new docs");
+                return;
+            }
+
+            if (/\.html$/.test(relativePath)) {
+                // Compare HTML content.
+                self.compareHtml(fileName, targetFile, relativePath, options);
+            } else {
+                originalFileStat = fs.statSync(fileName);
+                targetFileStat = fs.statSync(targetFile);
+                originalFileSize = originalFileStat.size;
+                targetFileSize = targetFileStat.size;
+                self.compareFileSize(fileName, targetFile, relativePath, options);
+            }
+        };
+        processEachFile(original_directory, compareFiles, function (directoryName) {
+            var relativePath = path.relative(original_directory, directoryName),
+                targetFile;
+            targetFile = path.join(output_path, relativePath);
+            if (!fs.existsSync(targetFile)) {
+                console.error("Dir " + relativePath + "/ is missing in the new docs");
+                return;
+            }
+
+            // console.log(relativePath + "\\");
+            return true;
+        });
+    };
+
+    DocsComparer.prototype.compareHtml = function (sourceFile, targetFile, relativePath, options) {
+        if (options.verbose > 0) {
+            console.log("Compare " + relativePath);
+        }
+
+        if (relativePath === "_index.html") {
+            if (options.lang === "zh" || options.lang === "ja" || options.lang === "ko" || options.lang === "ru") {
+                console.log("File " + relativePath + " is skipped for the Asian languages and Russian, since this is results in out of memory exception");
+                return;
+            }
+        }
+
+        var cheerioOptions = {
+                normalizeWhitespace: true,
+                xmlMode: true
+            },
+            sourceDom = cheerio.load(fs.readFileSync(sourceFile), cheerioOptions),
+            targetDom = cheerio.load(fs.readFileSync(targetFile), cheerioOptions);
+
+        // This is identical subsets
+        this.compareDomSubset(sourceDom, targetDom, "head", relativePath, options);
+        this.compareDomSubset(sourceDom, targetDom, "#sidebar", relativePath, options);
+        this.compareDomSubset(sourceDom, targetDom, "#header", relativePath, options);
+        this.compareDomSubset(sourceDom, targetDom, "#content", relativePath, options);
+
+        // Almost identical subsets
+        this.compareDomSubset(sourceDom, targetDom, "#subheader", relativePath, options);
+    };
+
+    DocsComparer.prototype.compareDomSubset = function (sourceDom, targetDom, subset, relativePath, options) {
+        var sourceHtml = sourceDom(subset).html(),
+            targetHtml = targetDom(subset).html(),
+            diff,
+            changed = false;
+
+        diff = jsdiff.diffChars(sourceHtml, targetHtml);
+        diff.forEach(function (part) {
+            changed = part.added || part.removed;
+        });
+        if (changed) {
+            console.error("Subset of DOM '" + subset + "' for path " + relativePath + " is different.");
+            if (options.verbose > 0) {
+                diff.forEach(function (part) {
+                    // green for additions, red for deletions
+                    // grey for common parts
+                    var color = part.added ? 'green' : (part.removed ? 'red' : 'grey');
+                    process.stderr.write(part.value[color]);
+                });
+
+                console.log();
+            }
+        }
+    };
+
+    DocsComparer.prototype.compareDom = function (sourceDom, targetDom, relativePath, options) {
+        var sourceHtml = sourceDom.html(),
+            targetHtml = targetDom.html(),
+            diff,
+            changed = false;
+
+        diff = jsdiff.diffChars(sourceHtml, targetHtml);
+        diff.forEach(function (part) {
+            changed = part.added || part.removed;
+        });
+        if (changed) {
+            console.error("DOM for path " + relativePath + " is different.");
+            if (options.verbose > 0) {
+                diff.forEach(function (part) {
+                    // green for additions, red for deletions
+                    // grey for common parts
+                    var color = part.added ? 'green' : (part.removed ? 'red' : 'grey');
+                    process.stderr.write(part.value[color]);
+                });
+
+                console.log();
+            }
+        }
+    };
+
+    DocsComparer.prototype.compareFileSize = function (sourceFile, targetFile, relativePath) {
+        var originalFileStat = fs.statSync(sourceFile),
+            targetFileStat = fs.statSync(targetFile),
+            originalFileSize = originalFileStat.size,
+            targetFileSize = targetFileStat.size;
+
+        if (originalFileSize !== targetFileSize) {
+            console.error("Path " + relativePath + " is different. Old size: " + originalFileSize + ". New size: " + targetFileSize);
+        }
+
+        return originalFileSize !== targetFileSize;
+    };
+
+    return DocsComparer;
+}());
+module.exports = DocsComparer;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org